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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /*LINTLIBRARY*/ 28 29 /* 30 * I18N message number ranges 31 * This file: 12000 - 12499 32 * Shared common messages: 1 - 1999 33 */ 34 35 /* 36 * This module is part of the Fibre Channel Interface library. 37 */ 38 39 /* #define _POSIX_SOURCE 1 */ 40 41 42 /* Includes */ 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <sys/file.h> 46 #include <sys/types.h> 47 #include <sys/stat.h> 48 #include <sys/mkdev.h> 49 #include <sys/param.h> 50 #include <fcntl.h> 51 #include <unistd.h> 52 #include <string.h> 53 #include <sys/scsi/scsi.h> 54 #include <dirent.h> /* for DIR */ 55 #include <sys/vtoc.h> 56 #include <nl_types.h> 57 #include <strings.h> 58 #include <errno.h> 59 #include <sys/ddi.h> /* for max */ 60 #include <fnmatch.h> 61 #include <l_common.h> 62 #include <stgcom.h> 63 #include <l_error.h> 64 #include <g_state.h> 65 #include <g_scsi.h> 66 #include <sys/fibre-channel/ulp/fcp_util.h> 67 #include <sys/fibre-channel/impl/fc_error.h> 68 #include <sys/fibre-channel/impl/fcph.h> 69 #include <sys/socalio.h> 70 #include <libdevinfo.h> 71 #include <ctype.h> 72 #include <devid.h> 73 74 /* Some forward declarations of static functions */ 75 /* 76 * becomes extern interface for Tapestry. 77 * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *); 78 * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int); 79 */ 80 static int g_issue_fcp_ioctl(int, struct fcp_ioctl *, int); 81 static int g_set_port_state(char *, int); 82 static int g_dev_log_in_out(char *, la_wwn_t, uint16_t); 83 static int g_get_dev_port_state(char *, la_wwn_t, uint32_t *); 84 static void g_free_rls(AL_rls *); 85 static int g_scsi_inquiry_cmd80(int, uchar_t *, int); 86 static int get_fca_inq_dtype(char *, la_wwn_t, uchar_t *); 87 static int g_find_supported_inq_page(int, int); 88 static int wwn_list_name_compare(const void *, const void *); 89 static int devid_get_all(ddi_devid_t, di_node_t, char *, 90 struct mplist_struct **); 91 static int get_multipath(char *, struct dlist **, 92 struct wwn_list_struct *); 93 static int get_multipath_disk(char *, struct dlist **, 94 struct wwn_list_struct *); 95 static void mplist_free(struct mplist_struct *); 96 static int get_wwn_data(di_node_t, uchar_t **, uchar_t **); 97 static int get_dev_path(struct wwn_list_struct **, char *, char *); 98 static int insert_missing_pwwn(char *, struct wwn_list_struct **); 99 static int get_scsi_vhci_port_wwn(char *, uchar_t *); 100 static int search_wwn_entry(struct wwn_list_found_struct *, uchar_t *, 101 uchar_t *); 102 static int add_wwn_entry(struct wwn_list_found_struct **, uchar_t *, 103 uchar_t *); 104 static int string_to_wwn(uchar_t *, uchar_t *); 105 static int get_wwns(char *, uchar_t *, uchar_t *, int *, 106 struct wwn_list_found_struct **); 107 108 /* type for g_dev_map_init related routines */ 109 110 #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0) 111 112 typedef struct impl_map_dev_prop { 113 char prop_name[MAXNAMELEN]; 114 int prop_type; 115 int prop_size; 116 void *prop_data; 117 int prop_error; 118 struct impl_map_dev_prop *next; 119 } impl_map_dev_prop_t; 120 121 typedef struct impl_map_dev { 122 int flag; 123 uint_t topo; 124 impl_map_dev_prop_t *prop_list; 125 struct impl_map_dev *parent; 126 struct impl_map_dev *child; 127 struct impl_map_dev *next; 128 } impl_map_dev_t; 129 130 /* Defines */ 131 #define VERBPRINT if (verbose) (void) printf 132 133 #define DIR_MATCH_ST "*[0-9+]n" 134 #define DIR_MATCH_SSD "*s2" 135 136 #define PROP_NOEXIST 0 137 #define PROP_EXIST 1 138 139 /* Prototypes */ 140 static int create_map(char *, gfc_map_t *, int, int); 141 static char ctoi(char); 142 static int lilp_map_cmp(const void*, const void*); 143 static int devices_get_all(di_node_t, char *, char *, 144 struct wwn_list_struct **); 145 static char *my_devfs_path(di_node_t); 146 static void my_devfs_path_free(char *path); 147 static void copy_wwn_data_to_str(char *, const uchar_t *); 148 static void init_drv(char *, char *, char *); 149 150 /* static for g_dev_map_init related routines */ 151 152 static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t, 153 uchar_t *, uchar_t *, int, int); 154 static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int); 155 static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **); 156 static void free_prop_list(impl_map_dev_prop_t **); 157 static void free_child_list(impl_map_dev_t **); 158 static u_longlong_t wwnConversion(uchar_t *wwn); 159 160 uchar_t g_switch_to_alpa[] = { 161 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 162 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 163 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 164 0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 165 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97, 166 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 167 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 168 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, 169 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 170 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35, 171 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 172 0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 173 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01 174 }; 175 176 uchar_t g_sf_alpa_to_switch[] = { 177 0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 178 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00, 179 0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74, 180 0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e, 181 0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67, 182 0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00, 183 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 184 0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00, 185 0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e, 186 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 187 0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43, 188 0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00, 189 0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37, 190 0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 191 0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 192 0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c, 193 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27, 194 0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f, 195 0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00, 196 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15, 197 0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e, 198 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00, 199 0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00, 200 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 201 }; 202 203 204 205 /* 206 * Check if device is in the map. 207 * 208 * PARAMS: 209 * map - loop map returned from fc port 210 * tid - device ID for private map or 24-bit alpa for fabric map 211 * 212 * RETURNS: 213 * 1 if device present in the map. 214 * 0 otherwise. 215 * 216 */ 217 int 218 g_device_in_map(gfc_map_t *map, int tid) 219 { 220 int i, j; 221 gfc_port_dev_info_t *dev_ptr; 222 223 dev_ptr = map->dev_addr; 224 if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) || 225 (map->hba_addr.port_topology == FC_TOP_FABRIC)) { 226 for (i = 0; i < map->count; i++, dev_ptr++) { 227 if (dev_ptr-> 228 gfc_port_dev.pub_port.dev_did.port_id == tid) { 229 /* Does not count if WWN == 0 */ 230 for (j = 0; j < FC_WWN_SIZE; j++) 231 if (dev_ptr->gfc_port_dev.pub_port. 232 dev_pwwn.raw_wwn[j] != 0) 233 return (1); 234 } 235 } 236 } else { 237 for (i = 0; i < map->count; i++, dev_ptr++) { 238 if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa == 239 (int)g_switch_to_alpa[tid]) { 240 /* Does not count if WWN == 0 */ 241 for (j = 0; j < WWN_SIZE; j++) 242 if (dev_ptr->gfc_port_dev.priv_port. 243 sf_port_wwn[j] != 0) 244 return (1); 245 } 246 } 247 } 248 return (0); 249 } 250 251 /* 252 * Inserts any missing port wwns for mpxio device paths 253 * which are in ONLINE or STANDBY state. 254 */ 255 static int 256 insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr) 257 { 258 mp_pathlist_t pathlist; 259 int i, pathcnt, match; 260 struct wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found; 261 char pwwn1[WWN_S_LEN]; 262 263 /* 264 * Now check each scsi_vhci device path to find any missed 265 * port wwns and insert a new wwn list entry for the missed 266 * port wwn 267 */ 268 if (g_get_pathlist(phys_path, &pathlist)) { 269 /* Free memory for pathlist before return */ 270 S_FREE(pathlist.path_info); 271 return (L_INVALID_PATH); 272 } 273 274 pathcnt = pathlist.path_count; 275 for (i = 0; i < pathcnt; i++) { 276 /* 277 * Just search for ONLINE and STANDBY paths as 278 * those should be the only missing wwn entries. 279 * There is a very small window for an offline 280 * to have occurred between the time we retrieved 281 * the device list and a call to this function. 282 * If that happens, we just won't add it to 283 * the list which is probably a good thing. 284 */ 285 if (pathlist.path_info[i].path_state == 286 MDI_PATHINFO_STATE_ONLINE || 287 pathlist.path_info[i].path_state == 288 MDI_PATHINFO_STATE_STANDBY) { 289 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr, 290 WWN_S_LEN - 1); 291 pwwn1[WWN_S_LEN - 1] = '\0'; 292 /* 293 * Now search through wwn list for matching 294 * device path AND pwwn 295 * If it's found, continue to next path. 296 * If it's not found, add it the wwn list. 297 */ 298 match = 0; 299 300 for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL; 301 wwn_list_s = wwn_list_s->wwn_next) { 302 if (strncmp(phys_path, 303 wwn_list_s->physical_path, 304 strlen(phys_path)) == 0) { 305 wwn_list_found = wwn_list_s; 306 if (strncmp(pwwn1, 307 wwn_list_s->port_wwn_s, 308 WWN_S_LEN) == 0) { 309 match++; 310 break; 311 } 312 } 313 } 314 if (match) { 315 continue; 316 } else { 317 /* 318 * didn't find a match but the mpxio 319 * device is in the list. Retrieve 320 * the info from the wwn_list_found 321 * and add it to the list. 322 */ 323 if ((new_wwn = (struct wwn_list_struct *) 324 calloc(1, 325 sizeof (struct wwn_list_struct))) 326 == NULL) { 327 S_FREE(pathlist.path_info); 328 return (L_MALLOC_FAILED); 329 } 330 if ((new_wwn->physical_path = (char *) 331 calloc(1, 332 strlen(wwn_list_found->physical_path) 333 + 1)) == NULL) { 334 S_FREE(pathlist.path_info); 335 return (L_MALLOC_FAILED); 336 } 337 if ((new_wwn->logical_path = (char *) 338 calloc(1, 339 strlen(wwn_list_found->logical_path) 340 + 1)) == NULL) { 341 S_FREE(pathlist.path_info); 342 return (L_MALLOC_FAILED); 343 } 344 345 /* 346 * Insert new_wwn at the beginning of the list. 347 */ 348 new_wwn->wwn_next = *wwn_list_ptr; 349 (*wwn_list_ptr)->wwn_prev = new_wwn; 350 351 /* set new starting ptr */ 352 *wwn_list_ptr = new_wwn; 353 354 memcpy(new_wwn->physical_path, 355 wwn_list_found->physical_path, 356 strlen(wwn_list_found->physical_path)); 357 memcpy(new_wwn->logical_path, 358 wwn_list_found->logical_path, 359 strlen(wwn_list_found->logical_path)); 360 /* 361 * Copy found node wwn data to this new entry 362 * Node wwn is required for the wwn_list 363 * however for mpxio devices it is not 364 * relevant as it may apply to multiple 365 * target controllers, so just use what 366 * we already have in wwn_list_found. 367 */ 368 memcpy(new_wwn->node_wwn_s, 369 wwn_list_found->node_wwn_s, WWN_S_LEN); 370 memcpy(new_wwn->w_node_wwn, 371 wwn_list_found->w_node_wwn, WWN_SIZE); 372 new_wwn->device_type = 373 wwn_list_found->device_type; 374 memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN); 375 } 376 } 377 } 378 S_FREE(pathlist.path_info); 379 return (0); 380 } 381 382 /* 383 * gets the port wwn for a scsi_vhci device using ONLINE path priority 384 */ 385 static int 386 get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn) 387 { 388 mp_pathlist_t pathlist; 389 int i, pathcnt, found; 390 char pwwn1[WWN_S_LEN]; 391 392 if (g_get_pathlist(phys_path, &pathlist)) { 393 return (L_INVALID_PATH); 394 } 395 396 found = 0; 397 pathcnt = pathlist.path_count; 398 /* 399 * Look for an ONLINE path first. 400 * If that fails, get the STANDBY path port WWN 401 * If that fails, give up 402 */ 403 for (i = 0; found == 0 && i < pathcnt; i++) { 404 if (pathlist.path_info[i].path_state == 405 MDI_PATHINFO_STATE_ONLINE) { 406 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr, 407 WWN_S_LEN - 1); 408 pwwn1[WWN_S_LEN - 1] = '\0'; 409 found++; 410 } 411 } 412 413 for (i = 0; found == 0 && i < pathcnt; i++) { 414 if (pathlist.path_info[i].path_state == 415 MDI_PATHINFO_STATE_STANDBY) { 416 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr, 417 WWN_S_LEN - 1); 418 pwwn1[WWN_S_LEN - 1] = '\0'; 419 found++; 420 } 421 } 422 423 S_FREE(pathlist.path_info); 424 if (found) { 425 return (string_to_wwn((uchar_t *)pwwn1, port_wwn)); 426 } else { 427 return (-1); 428 } 429 } 430 431 /* 432 * searches wwn_list_found for the pwwn passed in 433 * and sets the corresponding nwwn on return. 434 * If no match is found, -1 is returned and nwwn is not set. 435 */ 436 static int 437 search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn, 438 uchar_t *nwwn) 439 { 440 struct wwn_list_found_struct *wwn_list_s; 441 442 for (wwn_list_s = wwn_list_found; wwn_list_s != NULL; 443 wwn_list_s = wwn_list_s->wwn_next) { 444 if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) { 445 memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE); 446 return (0); 447 } 448 } 449 return (-1); 450 } 451 452 /* 453 * adds a nwwn, pwwn entry to the next entry in wwn_list_found list 454 */ 455 static int 456 add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn, 457 uchar_t *nwwn) 458 { 459 struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL; 460 461 /* Got wwns, load data in list */ 462 if ((new_wwn = (struct wwn_list_found_struct *) 463 calloc(1, sizeof (struct wwn_list_found_struct))) == NULL) { 464 return (L_MALLOC_FAILED); 465 } 466 467 memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE); 468 memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE); 469 470 /* 471 * Insert new_wwn in the list 472 */ 473 if (*wwn_list_found != NULL) { 474 temp_wwn_list_found = (*wwn_list_found)->wwn_next; 475 (*wwn_list_found)->wwn_next = new_wwn; 476 } else { 477 *wwn_list_found = new_wwn; 478 } 479 new_wwn->wwn_next = temp_wwn_list_found; 480 481 return (0); 482 } 483 484 485 /* 486 * Create a linked list of all the WWN's for all FC_AL disks and 487 * tapes that are attached to this host. 488 * 489 * RETURN VALUES: 0 O.K. 490 * 491 * wwn_list pointer: 492 * NULL: No devices found. 493 * !NULL: Devices found 494 * wwn_list points to a linked list of wwn's. 495 */ 496 int 497 g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose) 498 { 499 struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL; 500 struct wwn_list_found_struct *wwn_list_found = NULL; 501 int err; 502 int al_pa; 503 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 504 hrtime_t start_time, end_time; 505 char *env = NULL; 506 507 /* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */ 508 if (wwn_list_ptr == NULL) { 509 return (L_NULL_WWN_LIST); 510 } 511 512 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 513 start_time = gethrtime(); 514 } 515 516 if ((err = g_devices_get_all(wwn_list_ptr)) != 0) { 517 return (err); 518 } 519 520 /* 521 * retain backward compatibility with g_get_wwn_list 522 * and retrieve the WWN for scsi_vhci devices in the 523 * same fashion 524 * Note that for scsi_vhci devices, the wwn fields are 525 * not relevant but in the previous versions 526 * we loaded the wwns so... 527 */ 528 wwn_list_p = *wwn_list_ptr; 529 while (wwn_list_p != NULL) { 530 if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) { 531 /* get port wwn of first ONLINE, STANDBY */ 532 if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path, 533 port_wwn)) == 0) { 534 if ((search_wwn_entry(wwn_list_found, port_wwn, 535 node_wwn)) != 0) { 536 if ((err = 537 get_wwns(wwn_list_p->physical_path, 538 port_wwn, 539 node_wwn, &al_pa, 540 &wwn_list_found)) != 0) { 541 g_free_wwn_list_found( 542 &wwn_list_found); 543 return (err); 544 } 545 } 546 } else { 547 /* Use g_get_wwn as a last resort */ 548 if ((err = g_get_wwn(wwn_list_p->physical_path, 549 port_wwn, node_wwn, &al_pa, 0)) != 0) { 550 /* 551 * this is a bad WWN. 552 * remove it from the wwn_list. 553 * 554 * After removing the bad WWN, 555 * wwn_list_p should point to the next 556 * node in the list. 557 */ 558 if ((wwn_list_p->wwn_prev == NULL) && 559 (wwn_list_p->wwn_next == NULL)) { 560 *wwn_list_ptr = NULL; 561 free(wwn_list_p); 562 g_free_wwn_list_found( 563 &wwn_list_found); 564 return (L_NO_DEVICES_FOUND); 565 } else if ( 566 wwn_list_p->wwn_prev == NULL) { 567 *wwn_list_ptr = 568 wwn_list_p->wwn_next; 569 free(wwn_list_p); 570 wwn_list_p = *wwn_list_ptr; 571 wwn_list_p->wwn_prev = NULL; 572 } else if ( 573 wwn_list_p->wwn_next == NULL) { 574 wwn_list_p->wwn_prev->wwn_next = 575 NULL; 576 free(wwn_list_p); 577 wwn_list_p = NULL; 578 } else { 579 wwn_list_tmp_p = 580 wwn_list_p->wwn_next; 581 wwn_list_p->wwn_prev->wwn_next = 582 wwn_list_p->wwn_next; 583 wwn_list_p->wwn_next->wwn_prev = 584 wwn_list_p->wwn_prev; 585 free(wwn_list_p); 586 wwn_list_p = wwn_list_tmp_p; 587 } 588 continue; 589 } 590 } 591 copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn); 592 copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn); 593 memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE); 594 } 595 wwn_list_p = wwn_list_p->wwn_next; 596 } 597 g_free_wwn_list_found(&wwn_list_found); 598 599 /* 600 * Now go through the list one more time to add entries for 601 * any missing port wwns. 602 * This allows a search on port wwn for any paths which are 603 * ONLINE or STANDBY. We don't care about OFFLINE as those won't 604 * and should not show up in the list 605 */ 606 for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL; 607 wwn_list_p = wwn_list_p->wwn_next) { 608 if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) { 609 if ((err = insert_missing_pwwn( 610 wwn_list_p->physical_path, wwn_list_ptr)) != 0) 611 return (err); 612 } 613 } 614 615 if (env != NULL) { 616 end_time = gethrtime(); 617 fprintf(stdout, " g_get_wwn_list: " 618 "\t\tTime = %lld millisec\n", 619 (end_time - start_time)/1000000); 620 } 621 return (0); 622 623 } 624 625 int 626 g_devices_get_all(struct wwn_list_struct **wwn_list_ptr) 627 { 628 struct wwn_list_struct *tape_ptr = NULL; 629 struct wwn_list_struct *tmp; 630 int err; 631 di_node_t root; 632 hrtime_t start_time, end_time; 633 char *env = NULL; 634 635 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 636 start_time = gethrtime(); 637 } 638 639 /* 640 * Try to prime di_drv_first_node() 641 * If there are no nodes bound, di_drv_first_node() 642 * will return nothing. 643 */ 644 init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST); 645 init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD); 646 647 if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 648 return (L_DEV_SNAPSHOT_FAILED); 649 } 650 651 if (env != NULL) { 652 end_time = gethrtime(); 653 fprintf(stdout, " di_init - /: " 654 "\t\tTime = %lld millisec\n", 655 (end_time - start_time)/1000000); 656 } 657 658 if (env != NULL) { 659 start_time = gethrtime(); 660 } 661 662 if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME, 663 wwn_list_ptr)) != 0) { 664 if (err != L_NO_DEVICES_FOUND) { 665 di_fini(root); 666 g_free_wwn_list(&tape_ptr); 667 g_free_wwn_list(wwn_list_ptr); 668 return (err); 669 } 670 } 671 672 if (env != NULL) { 673 end_time = gethrtime(); 674 fprintf(stdout, " devices_get_all - ssd: " 675 "\t\tTime = %lld millisec\n", 676 (end_time - start_time)/1000000); 677 } 678 679 if (env != NULL) { 680 start_time = gethrtime(); 681 } 682 683 if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME, 684 &tape_ptr)) != 0) { 685 di_fini(root); 686 if (err != L_NO_DEVICES_FOUND) { 687 g_free_wwn_list(&tape_ptr); 688 g_free_wwn_list(wwn_list_ptr); 689 return (err); 690 } else { 691 /* 692 * if *wwn_list_ptr == NULL 693 * we have disks but no tapes 694 * Just return 695 */ 696 if (*wwn_list_ptr != NULL) { 697 return (0); 698 } else { 699 /* 700 * No disks or tapes 701 */ 702 g_free_wwn_list(&tape_ptr); 703 g_free_wwn_list(wwn_list_ptr); 704 return (err); 705 } 706 } 707 } 708 709 if (env != NULL) { 710 end_time = gethrtime(); 711 fprintf(stdout, " devices_get_all - st: " 712 "\t\tTime = %lld millisec\n", 713 (end_time - start_time)/1000000); 714 } 715 716 /* Now link the two together */ 717 if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */ 718 /* Walk to the end of it */ 719 for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL; 720 tmp = tmp->wwn_next) 721 ; 722 tmp->wwn_next = tape_ptr; 723 tape_ptr->wwn_prev = tmp; 724 di_fini(root); 725 return (0); 726 } 727 728 /* else we have no disks */ 729 *wwn_list_ptr = tape_ptr; 730 di_fini(root); 731 return (0); 732 } 733 734 void 735 g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found) { 736 WWN_list_found *next = NULL; 737 738 /* return if wwn_list_found is NULL */ 739 if (wwn_list_found == NULL) { 740 return; 741 } 742 for (; *wwn_list_found != NULL; *wwn_list_found = next) { 743 next = (*wwn_list_found)->wwn_next; 744 g_destroy_data(*wwn_list_found); 745 *wwn_list_found = NULL; 746 } 747 } 748 749 void 750 g_free_wwn_list(struct wwn_list_struct **wwn_list) 751 { 752 WWN_list *next = NULL; 753 754 /* return if wwn_list is NULL */ 755 if (wwn_list == NULL) { 756 return; 757 } 758 759 for (; *wwn_list != NULL; *wwn_list = next) { 760 next = (*wwn_list)->wwn_next; 761 if ((*wwn_list)->physical_path != NULL) 762 (void) g_destroy_data((*wwn_list)->physical_path); 763 if ((*wwn_list)->logical_path != NULL) 764 (void) g_destroy_data((*wwn_list)->logical_path); 765 (void) g_destroy_data(*wwn_list); 766 } 767 wwn_list = NULL; 768 } 769 770 771 772 773 void 774 g_sort_wwn_list(struct wwn_list_struct **wwn_list) 775 { 776 int i, n; 777 struct wwn_list_struct **wwn_list_array; 778 struct wwn_list_struct *wwn_list_ptr; 779 struct wwn_list_struct **wwn_list_array_ptr1; 780 struct wwn_list_struct **wwn_list_array_ptr2; 781 782 /* 783 * Count the number of wwn_list in the list 784 */ 785 for (n = 0, wwn_list_ptr = *wwn_list; 786 wwn_list_ptr != NULL; 787 wwn_list_ptr = wwn_list_ptr->wwn_next) { 788 n++; 789 } 790 if (n <= 1) { 791 return; 792 } 793 794 /* 795 * Allocate a simple wwn_list array and fill it in 796 */ 797 wwn_list_array = (struct wwn_list_struct **) 798 g_zalloc((n+1) * sizeof (struct wwn_list_struct *)); 799 800 wwn_list_array_ptr1 = wwn_list_array; 801 for (wwn_list_ptr = *wwn_list; 802 wwn_list_ptr != NULL; 803 wwn_list_ptr = wwn_list_ptr->wwn_next) { 804 *wwn_list_array_ptr1++ = wwn_list_ptr; 805 } 806 *wwn_list_array_ptr1 = NULL; 807 808 /* 809 * Sort the wwn_list array 810 */ 811 qsort((void *) wwn_list_array, n, 812 sizeof (struct wwn_list_struct *), wwn_list_name_compare); 813 814 /* 815 * Rebuild the linked list wwn_list structure 816 */ 817 wwn_list_array_ptr1 = wwn_list_array; 818 *wwn_list = *wwn_list_array_ptr1; 819 wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1; 820 (*wwn_list_array_ptr1)->wwn_prev = NULL; 821 for (i = 0; i < n - 1; i++) { 822 (*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1; 823 (*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++; 824 } 825 (*wwn_list_array_ptr1)->wwn_next = NULL; 826 827 /* 828 * Clean up 829 */ 830 (void) g_destroy_data((void *)wwn_list_array); 831 } 832 833 int 834 wwn_list_name_compare(const void *arg1, const void *arg2) 835 { 836 char *s1, *s2; 837 int n1, n2; 838 char *p1, *p2; 839 840 s1 = (*((struct wwn_list_struct **)arg1))->logical_path; 841 s2 = (*((struct wwn_list_struct **)arg2))->logical_path; 842 for (;;) { 843 if (*s1 == 0 || *s2 == 0) 844 break; 845 if ((isdigit(*s1) && isdigit(*s2))) { 846 n1 = strtol(s1, &p1, 10); 847 n2 = strtol(s2, &p2, 10); 848 if (n1 != n2) { 849 return (n1 - n2); 850 } 851 s1 = p1; 852 s2 = p2; 853 } else if (*s1 != *s2) { 854 break; 855 } else { 856 s1++; 857 s2++; 858 } 859 } 860 return (*s1 - *s2); 861 } 862 863 /* 864 * Get the limited map for FC4 devices. 865 * This function is specific to FC4 866 * devices and doesn't work for FC (leadville) devices. 867 * 868 * RETURN VALUES: 869 * 0 O.K. 870 * non-zero otherwise 871 * 872 * lilpmap *map_ptr: 873 * NULL: No devices found 874 * !NULL: if devices found 875 */ 876 int 877 g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose) 878 { 879 int fd, i; 880 char drvr_path[MAXPATHLEN]; 881 struct stat stbuf; 882 883 884 /* initialize map */ 885 (void) memset(map_ptr, 0, sizeof (struct lilpmap)); 886 887 (void) strcpy(drvr_path, path); 888 /* 889 * Get the path to the :devctl driver 890 * 891 * This assumes the path looks something like this: 892 * /devices/sbus@1f,0/SUNW,socal@1,0:1 893 * or 894 * /devices/sbus@1f,0/SUNW,socal@1,0 895 * or 896 * a 1 level PCI type driver 897 */ 898 if (stat(drvr_path, &stbuf) < 0) { 899 return (L_LSTAT_ERROR); 900 } 901 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 902 /* append a port. Just try 0 since they did not give us one */ 903 (void) strcat(drvr_path, ":0"); 904 } 905 906 P_DPRINTF(" g_get_limited_map: Geting drive map from:" 907 " %s\n", drvr_path); 908 909 /* open controller */ 910 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) 911 return (L_OPEN_PATH_FAIL); 912 913 if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) { 914 I_DPRINTF(" FCIO_GETMAP ioctl failed\n"); 915 (void) close(fd); 916 return (L_FCIO_GETMAP_IOCTL_FAIL); 917 } 918 (void) close(fd); 919 920 /* 921 * Check for reasonableness. 922 */ 923 if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) { 924 return (L_INVALID_LOOP_MAP); 925 } 926 for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) { 927 if (map_ptr->lilp_list[i] > 0xef) { 928 return (L_INVALID_LOOP_MAP); 929 } 930 } 931 932 return (0); 933 } 934 935 936 /* 937 * For leadville specific HBA's ONLY. 938 * Get the host specific parameters, 939 * al_pa, hard address, node/port WWN etc. 940 * 941 * OUTPUT: 942 * fc_port_dev_t structure. 943 * 944 * RETURNS: 945 * 0 if OK 946 * non-zero in case of error. 947 */ 948 int 949 g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose) 950 { 951 int err; 952 int fd; 953 int dev_type; 954 fcio_t fcio; 955 956 /* return invalid path if host_path is NULL */ 957 if (host_path == NULL) { 958 return (L_INVALID_PATH); 959 } 960 /* return invalid arg if host_val is NULL */ 961 if (host_val == NULL) { 962 return (L_INVALID_ARG); 963 } 964 965 dev_type = g_get_path_type(host_path); 966 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) { 967 return (L_INVALID_PATH_TYPE); 968 } 969 if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) { 970 return (L_OPEN_PATH_FAIL); 971 } 972 973 /* initialize structure */ 974 (void) memset(host_val, 0, sizeof (struct fc_port_dev)); 975 976 fcio.fcio_cmd = FCIO_GET_HOST_PARAMS; 977 fcio.fcio_xfer = FCIO_XFER_READ; 978 fcio.fcio_obuf = (caddr_t)host_val; 979 fcio.fcio_olen = sizeof (fc_port_dev_t); 980 981 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) { 982 I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n"); 983 (void) close(fd); 984 return (L_FCIO_GET_HOST_PARAMS_FAIL); 985 } 986 (void) close(fd); 987 988 /* get the inquiry information for the leadville HBA. */ 989 if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn, 990 &host_val->dev_dtype)) != 0) { 991 return (err); 992 } 993 return (0); 994 } 995 996 997 998 /* 999 * Issue FCIO ioctls to the port(fp) driver. 1000 * FCIO ioctl needs to be retried when it 1001 * is returned with an EINVAL error, wait 1002 * time between retries should be atleast 1003 * WAIT_FCIO_IOCTL (too much of a time to wait!!) 1004 * 1005 * OUTPUT: 1006 * fcio_t structure 1007 * 1008 * RETURNS: 1009 * 0 if O.K. 1010 * non-zero otherwise. 1011 */ 1012 int 1013 g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose) 1014 { 1015 int ntries; 1016 1017 for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) { 1018 if (ioctl(fd, FCIO_CMD, fcio) != 0) { 1019 if ((errno == EAGAIN) && 1020 (ntries+1 < RETRY_FCIO_IOCTL)) { 1021 /* wait WAIT_FCIO_IOCTL */ 1022 (void) usleep(WAIT_FCIO_IOCTL); 1023 continue; 1024 } 1025 I_DPRINTF("FCIO ioctl failed.\n" 1026 "Error: %s. fc_error = %d (0x%x)\n", 1027 strerror(errno), fcio->fcio_errno, 1028 fcio->fcio_errno); 1029 if (errno == EINVAL) { 1030 if (fcio->fcio_errno == FC_TOOMANY) { 1031 return (L_INVALID_DEVICE_COUNT); 1032 } else { 1033 return (errno); 1034 } 1035 } 1036 /* 1037 * When port is offlined, qlc 1038 * returns the FC_OFFLINE error and errno 1039 * is set to EIO. 1040 * We do want to ignore this error, 1041 * especially when an enclosure is 1042 * removed from the loop. 1043 */ 1044 if (fcio->fcio_errno == FC_OFFLINE) 1045 break; 1046 return (-1); 1047 } 1048 break; 1049 } 1050 1051 return (0); 1052 } 1053 1054 /* 1055 * This function issues the FCP_TGT_INQUIRY ioctl to 1056 * the fcp module 1057 * 1058 * OUTPUT: 1059 * fcp_ioctl structure in fcp_data is filled in by fcp 1060 * 1061 * RETURN VALUES : 1062 * 0 on Success 1063 * Non-zero otherwise 1064 */ 1065 static int 1066 g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose) 1067 { 1068 int num_tries = 0; 1069 struct device_data *dev_data = NULL; 1070 1071 /* 1072 * Issue the ioctl to FCP 1073 * The retries are required because the driver may 1074 * need some time to respond at times. 1075 */ 1076 while (num_tries++ < RETRY_FCP_IOCTL) { 1077 /* if ioctl fails it is an error from Solaris operation. */ 1078 if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) { 1079 if (errno == EAGAIN) { 1080 (void) usleep(WAIT_FCP_IOCTL); 1081 continue; 1082 } else { 1083 break; 1084 } 1085 } 1086 dev_data = (struct device_data *)((void *)(fcp_data->list)); 1087 if (dev_data->dev_status == 0) { 1088 return (0); 1089 } 1090 1091 if (dev_data->dev_status == EAGAIN) { 1092 (void) usleep(WAIT_FCP_IOCTL); 1093 continue; 1094 } else { 1095 dev_data->dev0_type = DTYPE_UNKNOWN; 1096 return (0); 1097 } 1098 } 1099 1100 return (L_FCP_TGT_INQUIRY_FAIL); 1101 } 1102 1103 /* 1104 * Get the number of devices and also 1105 * a list of devices accessible through 1106 * the device's port as specified by path. 1107 * The calling function * is responsible for freeing the dev_list. 1108 * 1109 * Acquires inq_dtype from g_get_inq_dtype() and 1110 * stores into dev_dtype field of fc_port_dev. 1111 * 1112 * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login 1113 * and get inq dtype. 1114 * 1115 * dev_list: 1116 * NULL: No devices found, in case of an error 1117 * Non-NULL: Devices found. 1118 * ndevs: 1119 * set to the number of devices 1120 * accessible through the port. 1121 * 1122 * RETURNS: 1123 * 0 if O.K. 1124 * non-zero otherwise 1125 */ 1126 int 1127 g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs) 1128 { 1129 int num_devices = 0; 1130 int i, err, ulp_failure = 0, new_count = 0; 1131 int dev_type; 1132 int fd; 1133 char fcapath[MAXPATHLEN]; 1134 char *char_ptr; 1135 struct stat stbuf; 1136 fcio_t fcio; 1137 uint32_t port_top; 1138 fc_port_dev_t *dlist; 1139 1140 *dev_list = dlist = NULL; 1141 (void) strcpy(fcapath, path); 1142 /* 1143 * Get the path to the :devctl driver 1144 * 1145 * This assumes the path looks something like this: 1146 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 1147 * or 1148 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0 1149 * or 1150 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 1151 * or 1152 * a 1 level PCI type driver but still :devctl 1153 */ 1154 if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) { 1155 if ((char_ptr = strrchr(fcapath, '/')) == NULL) { 1156 return (L_INVALID_PATH); 1157 } 1158 *char_ptr = '\0'; /* Terminate sting */ 1159 /* append controller */ 1160 (void) strcat(fcapath, FC_CTLR); 1161 } else { 1162 if (stat(fcapath, &stbuf) < 0) { 1163 return (L_LSTAT_ERROR); 1164 } 1165 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 1166 /* append controller */ 1167 (void) strcat(fcapath, FC_CTLR); 1168 } 1169 } 1170 dev_type = g_get_path_type(fcapath); 1171 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) { 1172 return (L_INVALID_PATH_TYPE); 1173 } 1174 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) { 1175 return (L_OPEN_PATH_FAIL); 1176 } 1177 1178 /* 1179 * Get the device list from port driver 1180 */ 1181 fcio.fcio_cmd = FCIO_GET_NUM_DEVS; 1182 fcio.fcio_olen = sizeof (num_devices); 1183 fcio.fcio_xfer = FCIO_XFER_READ; 1184 fcio.fcio_obuf = (caddr_t)&num_devices; 1185 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) { 1186 I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n"); 1187 (void) close(fd); 1188 return (L_FCIO_GET_NUM_DEVS_FAIL); 1189 } 1190 if (num_devices == 0) { 1191 *ndevs = 0; 1192 (void) close(fd); 1193 return (L_NO_DEVICES_FOUND); 1194 } 1195 1196 if ((dlist = (fc_port_dev_t *)calloc(num_devices, 1197 sizeof (fc_port_dev_t))) == NULL) { 1198 (void) close(fd); 1199 return (L_MALLOC_FAILED); 1200 } 1201 bzero((caddr_t)&fcio, sizeof (fcio)); 1202 /* Get the device list */ 1203 fcio.fcio_cmd = FCIO_GET_DEV_LIST; 1204 /* Information read operation */ 1205 fcio.fcio_xfer = FCIO_XFER_READ; 1206 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t); 1207 fcio.fcio_obuf = (caddr_t)dlist; 1208 /* new device count */ 1209 fcio.fcio_alen = sizeof (new_count); 1210 fcio.fcio_abuf = (caddr_t)&new_count; 1211 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) { 1212 if (err == L_INVALID_DEVICE_COUNT) { 1213 /* 1214 * original buffer was small so allocate buffer 1215 * with a new count and retry. 1216 */ 1217 free(dlist); 1218 num_devices = new_count; 1219 new_count = 0; 1220 if ((dlist = (fc_port_dev_t *)calloc(num_devices, 1221 sizeof (fc_port_dev_t))) == NULL) { 1222 (void) close(fd); 1223 return (L_MALLOC_FAILED); 1224 } 1225 fcio.fcio_cmd = FCIO_GET_DEV_LIST; 1226 /* Information read operation */ 1227 fcio.fcio_xfer = FCIO_XFER_READ; 1228 fcio.fcio_obuf = (caddr_t)dlist; 1229 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t); 1230 /* new device count */ 1231 fcio.fcio_alen = sizeof (new_count); 1232 fcio.fcio_abuf = (caddr_t)&new_count; 1233 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) { 1234 if (err == L_INVALID_DEVICE_COUNT) { 1235 /* 1236 * No more retry. There may be severe 1237 * hardware problem so return error 1238 * here. 1239 */ 1240 I_DPRINTF(" Device count was %d" 1241 " should have been %d\n", 1242 num_devices, new_count); 1243 } else { 1244 I_DPRINTF( 1245 " FCIO_GET_DEV_LIST ioctl failed."); 1246 err = L_FCIO_GET_DEV_LIST_FAIL; 1247 } 1248 free(dlist); 1249 (void) close(fd); 1250 return (err); 1251 } 1252 } else { 1253 I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed."); 1254 free(dlist); 1255 (void) close(fd); 1256 return (L_FCIO_GET_DEV_LIST_FAIL); 1257 } 1258 } 1259 1260 /* 1261 * if new count is smaller than the original number from 1262 * FCIO_GET_NUM_DEVS, adjust new count and buffer size 1263 * and continue. 1264 */ 1265 if (new_count < num_devices) { 1266 if (new_count == 0) { 1267 *ndevs = 0; 1268 (void) close(fd); 1269 S_FREE(dlist); 1270 return (L_NO_DEVICES_FOUND); 1271 } 1272 num_devices = new_count; 1273 if ((dlist = (fc_port_dev_t *)realloc(dlist, 1274 (new_count * sizeof (fc_port_dev_t)))) 1275 == NULL) { 1276 S_FREE(dlist); 1277 (void) close(fd); 1278 return (L_MALLOC_FAILED); 1279 } 1280 } 1281 1282 *dev_list = dlist; 1283 *ndevs = num_devices; 1284 1285 /* close here since fcapath will be passed to other routines. */ 1286 (void) close(fd); 1287 1288 if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) { 1289 free(*dev_list); 1290 *dev_list = NULL; 1291 return (err); 1292 } 1293 1294 /* Get the inq_dtype for each device on dev list. */ 1295 for (i = 0; i < num_devices; i++, dlist++) { 1296 /* Get the inq_dtype for each device. */ 1297 if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn, 1298 &dlist->dev_dtype)) != 0) { 1299 /* 1300 * if g_get_inq_dtype failed on g_dev_login 1301 * or g_issue_fcp_ioctl, continue to the next 1302 * dev on dlist. 1303 * L_GET_DEV_LIST_ULP_FAILURE is returned 1304 * after processing the whole dlist. 1305 */ 1306 if ((err == L_FCIO_DEV_LOGIN_FAIL) || 1307 (err == L_FCP_TGT_INQUIRY_FAIL)) { 1308 ulp_failure = 1; 1309 dlist->dev_dtype = GFC_ERR_INQ_DTYPE; 1310 } else { 1311 (void) free(*dev_list); 1312 *dev_list = NULL; 1313 return (err); 1314 } 1315 } 1316 } 1317 1318 if (ulp_failure) { 1319 return (L_GET_DEV_LIST_ULP_FAILURE); 1320 } else { 1321 return (0); 1322 } 1323 } 1324 1325 1326 /* Constant used by g_get_inq_dtype() */ 1327 #define FCP_PATH "/devices/pseudo/fcp@0:fcp" 1328 1329 /* 1330 * Gets the inq_dtype for devices on the fabric FC driver 1331 * through an ioctl to the FCP module. 1332 * 1333 * OUTPUT: 1334 * inq_dtype is set to the dtype on success 1335 * 1336 * RETURN VALUES: 1337 * 0 on Success 1338 * Non-zero on error 1339 */ 1340 int 1341 g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype) 1342 { 1343 int dev_type, fd; 1344 int err, fcp_fd; 1345 uint32_t state; 1346 uint32_t port_top = 0; 1347 struct fcp_ioctl fcp_data; 1348 struct device_data inq_data; 1349 struct stat sbuf; 1350 1351 dev_type = g_get_path_type(fcapath); 1352 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) { 1353 return (L_INVALID_PATH_TYPE); 1354 } 1355 1356 if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) { 1357 return (err); 1358 } 1359 1360 if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) { 1361 /* 1362 * if there is an error on getting port state we will 1363 * continue to login. 1364 * state can be either of 1365 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID, 1366 * PORT_DEVICE_LOGGED_IN. Trying port login 1367 * unless already logged in. 1368 * It will be examined if there is an adverse 1369 * effect on invalid state device. 1370 */ 1371 if (((err = g_get_dev_port_state(fcapath, pwwn, &state)) 1372 != 0) || (state != PORT_DEVICE_LOGGED_IN)) { 1373 /* do port login to fabric device. */ 1374 if ((err = g_dev_login(fcapath, pwwn)) != 0) { 1375 return (err); 1376 } 1377 } 1378 } 1379 1380 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) 1381 return (L_OPEN_PATH_FAIL); 1382 1383 if (fstat(fd, &sbuf) == -1) { 1384 (void) close(fd); 1385 return (L_FSTAT_ERROR); 1386 } 1387 1388 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) { 1389 (void) close(fd); 1390 return (L_OPEN_PATH_FAIL); 1391 } 1392 1393 /* Get the minor number for an fp instance */ 1394 fcp_data.fp_minor = minor(sbuf.st_rdev); 1395 1396 fcp_data.listlen = 1; 1397 inq_data.dev_pwwn = pwwn; /* The port WWN as passed */ 1398 fcp_data.list = (caddr_t)&inq_data; 1399 1400 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) { 1401 close(fd); 1402 close(fcp_fd); 1403 return (err); 1404 } 1405 *inq_dtype = inq_data.dev0_type; 1406 1407 close(fd); 1408 close(fcp_fd); 1409 1410 return (err); 1411 } 1412 1413 /* 1414 * Gets the inq_dtype for devices on the fabric FC driver 1415 * through an ioctl to the FCP module. 1416 * 1417 * This is exactly same as g_get_inq_dtype except that it does not do 1418 * g_dev_login(). That is for the case when the FCA tries to get its own 1419 * inq_dtype and in such a case, it cannot PLOGI into itself. 1420 * 1421 * OUTPUT: 1422 * inq_dtype is set to the dtype on success 1423 * 1424 * RETURN VALUES: 1425 * 0 on Success 1426 * Non-zero on error 1427 */ 1428 static int 1429 get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype) 1430 { 1431 int dev_type, fd; 1432 int err, fcp_fd; 1433 struct fcp_ioctl fcp_data; 1434 struct device_data inq_data; 1435 struct stat sbuf; 1436 1437 dev_type = g_get_path_type(fcapath); 1438 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) { 1439 return (L_INVALID_PATH_TYPE); 1440 } 1441 1442 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) { 1443 return (L_OPEN_PATH_FAIL); 1444 } 1445 1446 if (fstat(fd, &sbuf) == -1) { 1447 (void) close(fd); 1448 return (L_FSTAT_ERROR); 1449 } 1450 1451 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) { 1452 (void) close(fd); 1453 return (L_OPEN_PATH_FAIL); 1454 } 1455 1456 /* Get the minor number for an fp instance */ 1457 fcp_data.fp_minor = minor(sbuf.st_rdev); 1458 1459 fcp_data.listlen = 1; 1460 inq_data.dev_pwwn = pwwn; /* The port WWN as passed */ 1461 fcp_data.list = (caddr_t)&inq_data; 1462 1463 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) { 1464 close(fd); 1465 close(fcp_fd); 1466 return (err); 1467 } 1468 *inq_dtype = inq_data.dev0_type; 1469 1470 close(fd); 1471 close(fcp_fd); 1472 1473 return (0); 1474 } 1475 1476 /* 1477 * This function returns the traditional g_get_dev_map. Device list 1478 * and local hba seperate. 1479 */ 1480 int 1481 g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose) 1482 { 1483 return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD)); 1484 } 1485 1486 /* 1487 * This function returns the device map with local hba in physical 1488 * order. Note: Physical order is only returned properly for 1489 * private loop. local hba is also included seperate 1490 */ 1491 int 1492 g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose) 1493 { 1494 return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP)); 1495 } 1496 1497 /* 1498 * Gets device map from nexus driver 1499 * 1500 * PARAMS: 1501 * path - must be the physical path to a device 1502 * map - loop map returned from fc port. 1503 * verbose - options. 1504 * 1505 * LOGIC: 1506 * 1. check the validity of path via g_get_path_type. 1507 * 2. If FC path, get the topology of the path via 1508 * g_get_fca_port_topology. 1509 * 1510 * 3. If FC type(Leadville statck) 1511 * g_get_dev_list to get the device node list of fc_port_dev_t. 1512 * g_get_host_params to get the fca port node of fc_port_dev_t. 1513 * 1514 * Case of fabric or public loop topology 1515 * Check if the port id > 0xffff. 1516 * Move device node and fca port node to 1517 * gfc_map structure via gfc_port_dev_info_t 1518 * pub_port union. 1519 * Issue g_get_inq_dtype to get FCP inquiry data 1520 * and store it into gfc_port_dev_info_t. 1521 * 1522 * Case of private loop topology 1523 * Check if the port id < 0xff. 1524 * Move device node and fca port node to 1525 * gfc_map structure via gfc_port_dev_info_t 1526 * priv_port union. 1527 * Issue g_get_inq_dtype to get FCP inquiry data 1528 * and store it into gfc_port_dev_info_t. 1529 * 1530 * else FC4 type(socal/sf or ifp stack) 1531 * SFIOCGMAP ioctl to get the device and hba nodes of 1532 * sf_addr_pair_t. 1533 * 1534 * 1535 * RETURNS: 1536 * 0 : if OK 1537 * non-zero: otherwise 1538 */ 1539 int 1540 create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type) 1541 { 1542 int fd, i, j, num_devices = 0, err, pathcnt = 1; 1543 char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN]; 1544 char *char_ptr; 1545 struct stat stbuf; 1546 fc_port_dev_t *dev_list, *dlistptr; 1547 uint32_t hba_port_top = 0; 1548 uint_t dev_type; 1549 sf_al_map_t sf_map; 1550 gfc_port_dev_info_t *dev_ptr; 1551 fc_port_dev_t fp_hba_port; 1552 mp_pathlist_t pathlist; 1553 int p_on = 0, p_st = 0; 1554 1555 /* return invalid path if path is NULL */ 1556 if (path == NULL) { 1557 return (L_INVALID_PATH); 1558 } 1559 /* return invalid arg if map_ptr is NULL */ 1560 if (map_ptr == NULL) { 1561 return (L_INVALID_ARG); 1562 } 1563 1564 map_ptr->dev_addr = NULL; 1565 map_ptr->count = 0; 1566 (void) strcpy(drvr_path, path); 1567 /* 1568 * Get the path to the :devctl driver 1569 * 1570 * This assumes the path looks something like this: 1571 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 1572 * or 1573 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0 1574 * or 1575 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 1576 * or 1577 * a 1 level PCI type driver but still :devctl 1578 */ 1579 if (strstr(path, SCSI_VHCI)) { 1580 (void) strcpy(drvr_path0, path); 1581 if (g_get_pathlist(drvr_path0, &pathlist)) { 1582 return (L_INVALID_PATH); 1583 } 1584 pathcnt = pathlist.path_count; 1585 p_on = p_st = 0; 1586 for (i = 0; i < pathcnt; i++) { 1587 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 1588 if (pathlist.path_info[i].path_state == 1589 MDI_PATHINFO_STATE_ONLINE) { 1590 p_on = i; 1591 break; 1592 } else if (pathlist.path_info[i].path_state == 1593 MDI_PATHINFO_STATE_STANDBY) { 1594 p_st = i; 1595 } 1596 } 1597 } 1598 if (pathlist.path_info[p_on].path_state == 1599 MDI_PATHINFO_STATE_ONLINE) { 1600 /* on_line path */ 1601 (void) strcpy(drvr_path, 1602 pathlist.path_info[p_on].path_hba); 1603 } else { 1604 /* standby or path0 */ 1605 (void) strcpy(drvr_path, 1606 pathlist.path_info[p_st].path_hba); 1607 } 1608 free(pathlist.path_info); 1609 (void) strcat(drvr_path, FC_CTLR); 1610 } else { 1611 (void) strcpy(drvr_path, path); 1612 if (strstr(drvr_path, DRV_NAME_SSD) || 1613 strstr(drvr_path, SES_NAME) || 1614 strstr(drvr_path, DRV_NAME_ST)) { 1615 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { 1616 return (L_INVALID_PATH); 1617 } 1618 *char_ptr = '\0'; /* Terminate sting */ 1619 /* append controller */ 1620 (void) strcat(drvr_path, FC_CTLR); 1621 } else { 1622 if (stat(drvr_path, &stbuf) < 0) { 1623 return (L_LSTAT_ERROR); 1624 } 1625 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 1626 /* append controller */ 1627 (void) strcat(drvr_path, FC_CTLR); 1628 } 1629 } 1630 } 1631 1632 P_DPRINTF(" g_get_dev_map: Geting drive map from:" 1633 " %s\n", drvr_path); 1634 1635 dev_type = g_get_path_type(drvr_path); 1636 if ((dev_type == 0) || !(dev_type & XPORT_MASK)) { 1637 return (L_INVALID_PATH_TYPE); 1638 } 1639 1640 /* get fiber topology */ 1641 if ((err = g_get_fca_port_topology(drvr_path, 1642 &hba_port_top, verbose)) != 0) { 1643 return (err); 1644 } 1645 1646 /* for FC devices. */ 1647 if (dev_type & FC_FCA_MASK) { 1648 /* 1649 * if g_get_dev_list fails with L_NO_DEVICES_FOUND 1650 * we still want to call g_get_host_params to try to find the 1651 * HBA. If we do not see any HBAs on the loop, the 1652 * g_get_host_params will fail when it trys to issue the target 1653 * inquiry ioctl. In this case, we would still like to return 1654 * L_NO_DEVICES_FOUND. 1655 * 1656 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and 1657 * g_get_host_params fails, the function returns 1658 * L_NO_DEVICES_FOUND 1659 */ 1660 if ((err = g_get_dev_list(drvr_path, &dev_list, 1661 &num_devices)) != 0) { 1662 /* 1663 * g_get_dev_map doesn't allow ulp failure 1664 * to continue thus we need to free dev_list 1665 * here. 1666 */ 1667 if (err == L_GET_DEV_LIST_ULP_FAILURE) { 1668 (void) free(dev_list); 1669 } 1670 if (err != L_NO_DEVICES_FOUND) { 1671 return (err); 1672 } 1673 } 1674 1675 /* Get local HBA information */ 1676 if ((err = g_get_host_params(drvr_path, &fp_hba_port, 1677 verbose)) != 0) { 1678 (void) free(dev_list); 1679 if (num_devices == 0) 1680 return (L_NO_DEVICES_FOUND); 1681 else 1682 return (err); 1683 } 1684 1685 /* If devices, other than local HBA are found */ 1686 /* allocate space for them in the gfc_map. */ 1687 if (num_devices > 0) { 1688 1689 /* If map type is on MAP_FORMAT_LILP we need */ 1690 /* to add space for the local HBA */ 1691 if (map_type == MAP_FORMAT_LILP) { 1692 map_ptr->count = ++num_devices; 1693 } else { 1694 map_ptr->count = num_devices; 1695 } 1696 1697 if ((map_ptr->dev_addr = (gfc_port_dev_info_t *) 1698 calloc(map_ptr->count, 1699 sizeof (gfc_port_dev_info_t))) == NULL) { 1700 (void) free(dev_list); 1701 return (L_MALLOC_FAILED); 1702 } 1703 } 1704 1705 /* If we want the lilp map then we need to do a little */ 1706 /* work here. The lilp map contains the local hba in */ 1707 /* the dev_addr. Once this has been added qsort the */ 1708 /* dev_addr array so it's in physical order. */ 1709 /* The lilp map will contain the local hba in the */ 1710 /* dev_addr array only when num_devices > 0 */ 1711 if (map_type == MAP_FORMAT_LILP && num_devices > 0) { 1712 1713 /* First we need to allocate one additional */ 1714 /* device to the dev_addr structure, for the */ 1715 /* local hba */ 1716 if ((dev_list = (fc_port_dev_t *)realloc(dev_list, 1717 (num_devices * sizeof (fc_port_dev_t)))) 1718 == NULL) { 1719 S_FREE(dev_list); 1720 (void) free(map_ptr->dev_addr); 1721 map_ptr->dev_addr = NULL; 1722 return (L_MALLOC_FAILED); 1723 } 1724 1725 /* Next, copy the local hba into this new loc. */ 1726 if (memcpy(dev_list+(num_devices-1), &fp_hba_port, 1727 sizeof (fc_port_dev_t)) == NULL) { 1728 (void) free(dev_list); 1729 (void) free(map_ptr->dev_addr); 1730 map_ptr->dev_addr = NULL; 1731 return (L_MEMCPY_FAILED); 1732 } 1733 1734 /* Now sort by physical location */ 1735 qsort((void*)dev_list, num_devices, 1736 sizeof (fc_port_dev_t), lilp_map_cmp); 1737 } 1738 1739 dlistptr = dev_list; 1740 dev_ptr = map_ptr->dev_addr; 1741 1742 switch (hba_port_top) { 1743 case FC_TOP_FABRIC: 1744 case FC_TOP_PUBLIC_LOOP: 1745 if (fp_hba_port.dev_did.port_id <= 0xffff) { 1746 (void) free(dlistptr); 1747 (void) free(map_ptr->dev_addr); 1748 map_ptr->dev_addr = NULL; 1749 return (L_INVALID_FABRIC_ADDRESS); 1750 } else { 1751 map_ptr->hba_addr.port_topology = hba_port_top; 1752 map_ptr->hba_addr.gfc_port_dev.pub_port = 1753 fp_hba_port; 1754 } 1755 for (i = 0; i < num_devices; i++, dev_ptr++, 1756 dev_list++) { 1757 if (dev_list->dev_did.port_id <= 0xffff) { 1758 (void) free(dlistptr); 1759 (void) free(map_ptr->dev_addr); 1760 map_ptr->dev_addr = NULL; 1761 return (L_INVALID_FABRIC_ADDRESS); 1762 } else { 1763 dev_ptr->port_topology = hba_port_top; 1764 dev_ptr->gfc_port_dev.pub_port = 1765 *dev_list; 1766 } 1767 } 1768 break; 1769 case FC_TOP_PRIVATE_LOOP: 1770 /* 1771 * Map the (new->old) structures here. 1772 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to 1773 * make sure that we don't overrun the map structure 1774 * since it can hold data for upto 126 devices. 1775 */ 1776 if (fp_hba_port.dev_did.port_id > 0xff) { 1777 (void) free(dlistptr); 1778 (void) free(map_ptr->dev_addr); 1779 map_ptr->dev_addr = NULL; 1780 return (L_INVALID_PRIVATE_LOOP_ADDRESS); 1781 } else { 1782 map_ptr->hba_addr.port_topology = hba_port_top; 1783 map_ptr->hba_addr.gfc_port_dev. 1784 priv_port.sf_al_pa = 1785 (uchar_t)fp_hba_port.dev_did.port_id; 1786 map_ptr->hba_addr.gfc_port_dev. 1787 priv_port.sf_hard_address = (uchar_t) 1788 fp_hba_port.dev_hard_addr.hard_addr; 1789 for (j = 0; j < FC_WWN_SIZE; j++) { 1790 map_ptr->hba_addr.gfc_port_dev. 1791 priv_port.sf_node_wwn[j] = 1792 fp_hba_port.dev_nwwn.raw_wwn[j]; 1793 map_ptr->hba_addr.gfc_port_dev. 1794 priv_port.sf_port_wwn[j] = 1795 fp_hba_port.dev_pwwn.raw_wwn[j]; 1796 } 1797 map_ptr->hba_addr.gfc_port_dev. 1798 priv_port.sf_inq_dtype = 1799 fp_hba_port.dev_dtype; 1800 } 1801 1802 for (i = 0; (i < num_devices && 1803 i < SF_NUM_ENTRIES_IN_MAP); 1804 i++, dev_ptr++, dev_list++) { 1805 /* 1806 * Out of 24 bits of port_id, copy only 1807 * 8 bits to al_pa. This works okay for 1808 * devices that're on a private loop. 1809 */ 1810 if (dev_list->dev_did.port_id > 0xff) { 1811 (void) free(dlistptr); 1812 (void) free(map_ptr->dev_addr); 1813 map_ptr->dev_addr = NULL; 1814 return (L_INVALID_PRIVATE_LOOP_ADDRESS); 1815 } 1816 dev_ptr->port_topology = hba_port_top; 1817 dev_ptr->gfc_port_dev.priv_port.sf_al_pa 1818 = (uchar_t)dev_list->dev_did.port_id; 1819 1820 /* Code refactorization is needed for C style */ 1821 dev_ptr->gfc_port_dev.priv_port.sf_hard_address 1822 = (uchar_t)dev_list->dev_hard_addr.hard_addr; 1823 1824 for (j = 0; j < FC_WWN_SIZE; j++) { 1825 1826 dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] = 1827 dev_list->dev_nwwn.raw_wwn[j]; 1828 dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] = 1829 dev_list->dev_pwwn.raw_wwn[j]; 1830 1831 } 1832 dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype = 1833 dev_list->dev_dtype; 1834 } 1835 break; 1836 case FC_TOP_PT_PT: 1837 (void) free(dlistptr); 1838 (void) free(map_ptr->dev_addr); 1839 map_ptr->dev_addr = NULL; 1840 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 1841 default: 1842 (void) free(dlistptr); 1843 (void) free(map_ptr->dev_addr); 1844 map_ptr->dev_addr = NULL; 1845 return (L_UNEXPECTED_FC_TOPOLOGY); 1846 } /* End of switch on port_topology */ 1847 (void) free(dlistptr); 1848 1849 } else { /* sf and fc4/pci devices */ 1850 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) 1851 return (errno); 1852 /* initialize map */ 1853 (void) memset(&sf_map, 0, sizeof (struct sf_al_map)); 1854 if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) { 1855 I_DPRINTF(" SFIOCGMAP ioctl failed.\n"); 1856 (void) close(fd); 1857 return (L_SFIOCGMAP_IOCTL_FAIL); 1858 } 1859 /* Check for reasonableness. */ 1860 if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) { 1861 (void) close(fd); 1862 return (L_INVALID_LOOP_MAP); 1863 } 1864 if (sf_map.sf_count == 0) { 1865 (void) close(fd); 1866 return (L_NO_DEVICES_FOUND); 1867 } 1868 1869 map_ptr->count = sf_map.sf_count; 1870 if ((map_ptr->dev_addr = 1871 (gfc_port_dev_info_t *)calloc(map_ptr->count, 1872 sizeof (gfc_port_dev_info_t))) == NULL) { 1873 (void) close(fd); 1874 return (L_MALLOC_FAILED); 1875 } 1876 dev_ptr = map_ptr->dev_addr; 1877 for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) { 1878 if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) { 1879 (void) free(map_ptr->dev_addr); 1880 map_ptr->dev_addr = NULL; 1881 (void) close(fd); 1882 return (L_INVALID_LOOP_MAP); 1883 } 1884 dev_ptr->port_topology = hba_port_top; 1885 dev_ptr->gfc_port_dev.priv_port = 1886 sf_map.sf_addr_pair[i]; 1887 } 1888 map_ptr->hba_addr.port_topology = hba_port_top; 1889 map_ptr->hba_addr.gfc_port_dev.priv_port = 1890 sf_map.sf_hba_addr; 1891 (void) close(fd); 1892 } 1893 1894 return (0); 1895 } 1896 1897 /* 1898 * This function consturct FC proerty list using map_dev_fc_prop_list. 1899 * 1900 * port WWN, node WWN, port addr and hard addr properties is constructed. 1901 * 1902 * return 0 if OK. 1903 * otherwise returns error code. 1904 */ 1905 static int 1906 update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo, 1907 uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr) 1908 { 1909 impl_map_dev_prop_t *prop_ptr, *pl_start = NULL, *pl_end = NULL; 1910 uchar_t *port_wwn_data, *node_wwn_data; 1911 int *port_addr_data, *hard_addr_data; 1912 1913 /* consrtruct port addr property. */ 1914 if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) { 1915 if (port_addr <= 0xffff) { 1916 return (L_INVALID_FABRIC_ADDRESS); 1917 } 1918 } else if (map_topo == FC_TOP_PRIVATE_LOOP) { 1919 if (port_addr > 0xff) { 1920 return (L_INVALID_PRIVATE_LOOP_ADDRESS); 1921 } 1922 } 1923 1924 if ((prop_ptr = (impl_map_dev_prop_t *)calloc( 1925 1, sizeof (impl_map_dev_prop_t))) == NULL) { 1926 return (L_MALLOC_FAILED); 1927 } 1928 (void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP, 1929 strlen(PORT_ADDR_PROP)); 1930 prop_ptr->prop_type = GFC_PROP_TYPE_INT; 1931 1932 if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) { 1933 free(prop_ptr); 1934 return (L_MALLOC_FAILED); 1935 } 1936 *port_addr_data = port_addr; 1937 prop_ptr->prop_data = port_addr_data; 1938 1939 pl_start = pl_end = prop_ptr; 1940 1941 /* consrtruct port WWN property. */ 1942 if ((prop_ptr = (impl_map_dev_prop_t *)calloc( 1943 1, sizeof (impl_map_dev_prop_t))) == NULL) { 1944 free_prop_list(&pl_start); 1945 return (L_MALLOC_FAILED); 1946 } 1947 (void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP, 1948 strlen(PORT_WWN_PROP)); 1949 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES; 1950 1951 if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) { 1952 free_prop_list(&pl_start); 1953 return (L_MALLOC_FAILED); 1954 } 1955 memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE); 1956 prop_ptr->prop_data = port_wwn_data; 1957 prop_ptr->prop_size = FC_WWN_SIZE; 1958 pl_end->next = prop_ptr; 1959 pl_end = prop_ptr; 1960 1961 /* consrtruct node WWN property. */ 1962 if ((prop_ptr = (impl_map_dev_prop_t *)calloc( 1963 1, sizeof (impl_map_dev_prop_t))) == NULL) { 1964 free_prop_list(&pl_start); 1965 return (L_MALLOC_FAILED); 1966 } 1967 (void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP, 1968 strlen(NODE_WWN_PROP)); 1969 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES; 1970 1971 if ((node_wwn_data = (uchar_t *)calloc( 1972 1, FC_WWN_SIZE)) == NULL) { 1973 free_prop_list(&pl_start); 1974 return (L_MALLOC_FAILED); 1975 } 1976 memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE); 1977 prop_ptr->prop_data = node_wwn_data; 1978 prop_ptr->prop_size = FC_WWN_SIZE; 1979 pl_end->next = prop_ptr; 1980 pl_end = prop_ptr; 1981 1982 /* consrtruct hard addr property. */ 1983 if ((prop_ptr = (impl_map_dev_prop_t *)calloc( 1984 1, sizeof (impl_map_dev_prop_t))) == NULL) { 1985 free_prop_list(&pl_start); 1986 return (L_MALLOC_FAILED); 1987 } 1988 (void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP, 1989 strlen(HARD_ADDR_PROP)); 1990 prop_ptr->prop_type = GFC_PROP_TYPE_INT; 1991 1992 if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) { 1993 free_prop_list(&pl_start); 1994 return (L_MALLOC_FAILED); 1995 } 1996 *hard_addr_data = hard_addr; 1997 prop_ptr->prop_data = hard_addr_data; 1998 pl_end->next = prop_ptr; 1999 pl_end = prop_ptr; 2000 2001 if (*prop_list == NULL) { 2002 *prop_list = pl_start; 2003 } else { 2004 pl_end->next = (*prop_list)->next; 2005 *prop_list = pl_start; 2006 } 2007 2008 return (0); 2009 } 2010 2011 /* 2012 * This function consturct FCP inq dtype propery. 2013 * if inq_dtype is null the property is constrcted with err info. 2014 * 2015 * L_MALLOC_FAILED is the only possible error. 2016 */ 2017 static int 2018 update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list, 2019 uchar_t *inq_dtype, int err, int exist) 2020 { 2021 impl_map_dev_prop_t *prop_ptr, *old_prop_ptr; 2022 uchar_t *inq_dtype_data; 2023 2024 if ((prop_ptr = (impl_map_dev_prop_t *)calloc( 2025 1, sizeof (impl_map_dev_prop_t))) == NULL) { 2026 return (L_MALLOC_FAILED); 2027 } 2028 2029 (void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP, 2030 strlen(INQ_DTYPE_PROP)); 2031 2032 if (inq_dtype == NULL) { 2033 prop_ptr->prop_data = NULL; 2034 prop_ptr->prop_error = err; 2035 } else { 2036 if ((inq_dtype_data = (uchar_t *)calloc( 2037 1, sizeof (uchar_t))) == NULL) { 2038 free(prop_ptr); 2039 return (L_MALLOC_FAILED); 2040 } 2041 memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t)); 2042 prop_ptr->prop_data = inq_dtype_data; 2043 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES; 2044 prop_ptr->prop_size = sizeof (uchar_t); 2045 } 2046 2047 if (*prop_list == NULL) { 2048 *prop_list = prop_ptr; 2049 } else { 2050 if (exist == PROP_EXIST) { 2051 prop_ptr->next = (*prop_list)->next; 2052 old_prop_ptr = *prop_list; 2053 *prop_list = prop_ptr; 2054 free((uchar_t *)(old_prop_ptr->prop_data)); 2055 old_prop_ptr->prop_data = NULL; 2056 S_FREE(old_prop_ptr); 2057 } else { 2058 prop_ptr->next = *prop_list; 2059 *prop_list = prop_ptr; 2060 } 2061 } 2062 2063 return (0); 2064 } 2065 2066 /* 2067 * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl() 2068 * to get the inq_dtype of input device and calls update_map_dev_FCP_prop(). 2069 * inq_dtype is set to NULL and pass error code if inq_dtype data is not 2070 * requried. 2071 * 2072 * return error from update_map_dev_FCP_prop(). 2073 */ 2074 static int 2075 handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn, 2076 impl_map_dev_prop_t **prop_list) 2077 { 2078 struct device_data inq_data; 2079 int fcp_fd, err; 2080 struct fcp_ioctl fcp_data; 2081 uchar_t inq_dtype; 2082 2083 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) { 2084 update_map_dev_FCP_prop(prop_list, NULL, 2085 L_OPEN_PATH_FAIL, PROP_NOEXIST); 2086 } 2087 2088 /* Get the minor number for an fp instance */ 2089 fcp_data.fp_minor = fp_xport_minor; 2090 2091 /* Get FCP prop for the hba first. */ 2092 fcp_data.listlen = 1; 2093 inq_data.dev_pwwn = port_wwn; 2094 fcp_data.list = (caddr_t)&inq_data; 2095 2096 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) { 2097 /* if ioctl error then set the prop_error. */ 2098 if ((err = update_map_dev_FCP_prop( 2099 prop_list, NULL, err, PROP_NOEXIST)) != 0) { 2100 return (err); 2101 } 2102 } else { 2103 inq_dtype = inq_data.dev0_type; 2104 if ((err = update_map_dev_FCP_prop( 2105 prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) { 2106 return (err); 2107 } 2108 } 2109 2110 return (0); 2111 } 2112 2113 /* 2114 * Construct device map tree from nexus driver 2115 * 2116 * PARAMS: 2117 * path - must be the physical path to a device 2118 * l_err - ptr to an error code. Set when NULL is returned. 2119 * flag - device map fomat and property type. 2120 * 2121 * LOGIC: 2122 * 1. check the validity of path via g_get_path_type. 2123 * 2. If FC path, get the topology of the path via 2124 * g_get_fca_port_topology. 2125 * 2126 * 3. If FC type(Leadville statck) 2127 * FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t. 2128 * FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t. 2129 * 2130 * root of tree is set with host_params info 2131 * FC propery is set. 2132 * FCP property is set if reqyested through flag. 2133 * Issue g_issue_fcp_ioctl to get FCP inquiry data 2134 * consruruct list of children via dev_list. 2135 * FC property is set. 2136 * FCP property is set if reqyested through flag. 2137 * Issue FCIO_DEV_LOGIN if it is fabric device. 2138 * Issue g_issue_fcp_ioctl to get FCP inquiry data. 2139 * 2140 * else FC4 type(socal/sf or ifp stack) 2141 * SFIOCGMAP ioctl to get the device and hba nodes of 2142 * sf_addr_pair_t. 2143 * FCIO_GETMAP ioctl to get hba port info. 2144 * consturct map and child tree list and 2145 * set the properties as private loop devices. 2146 * 2147 * RETURNS: 2148 * ptr to map is returned if OK. 2149 * NULL and l_err is set otherwise. 2150 */ 2151 gfc_dev_t 2152 g_dev_map_init(char *path, int *l_err, int flag) 2153 { 2154 int fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0; 2155 char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN]; 2156 char *char_ptr, *nexus_path; 2157 struct stat stbuf; 2158 fc_port_dev_t *dev_list = NULL, *dlist; 2159 uint32_t hba_port_top, state; 2160 uint_t path_type; 2161 sf_al_map_t sf_map; 2162 fc_port_dev_t fp_hba_port; 2163 mp_pathlist_t pathlist; 2164 int p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd; 2165 fcio_t fcio; 2166 struct lilpmap limited_map; 2167 impl_map_dev_t *impl_map, *impl_dev; 2168 impl_map_dev_t *mdl_start = NULL, *mdl_end = NULL; 2169 struct stat sbuf; 2170 2171 if (l_err == NULL) { 2172 return (NULL); 2173 } 2174 2175 if (path == NULL) { 2176 *l_err = L_INVALID_PATH; 2177 return (NULL); 2178 } 2179 2180 *l_err = 0; 2181 2182 (void) strcpy(drvr_path, path); 2183 /* 2184 * Get the path to the :devctl driver 2185 * 2186 * This assumes the path looks something like this: 2187 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 2188 * or 2189 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0 2190 * or 2191 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 2192 * or 2193 * a 1 level PCI type driver but still :devctl 2194 */ 2195 if (strstr(path, SCSI_VHCI)) { 2196 (void) strcpy(drvr_path0, path); 2197 if (g_get_pathlist(drvr_path0, &pathlist)) { 2198 *l_err = L_INVALID_PATH; 2199 return (NULL); 2200 } 2201 pathcnt = pathlist.path_count; 2202 p_on = p_st = 0; 2203 for (i = 0; i < pathcnt; i++) { 2204 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 2205 if (pathlist.path_info[i].path_state == 2206 MDI_PATHINFO_STATE_ONLINE) { 2207 p_on = i; 2208 break; 2209 } else if (pathlist.path_info[i].path_state == 2210 MDI_PATHINFO_STATE_STANDBY) { 2211 p_st = i; 2212 } 2213 } 2214 } 2215 if (pathlist.path_info[p_on].path_state == 2216 MDI_PATHINFO_STATE_ONLINE) { 2217 /* on_line path */ 2218 (void) strcpy(drvr_path, 2219 pathlist.path_info[p_on].path_hba); 2220 } else { 2221 /* standby or path0 */ 2222 (void) strcpy(drvr_path, 2223 pathlist.path_info[p_st].path_hba); 2224 } 2225 free(pathlist.path_info); 2226 (void) strcat(drvr_path, FC_CTLR); 2227 } else { 2228 (void) strcpy(drvr_path, path); 2229 if (strstr(drvr_path, DRV_NAME_SSD) || 2230 strstr(drvr_path, SES_NAME) || 2231 strstr(drvr_path, DRV_NAME_ST)) { 2232 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { 2233 *l_err = L_INVALID_PATH; 2234 return (NULL); 2235 } 2236 *char_ptr = '\0'; /* Terminate sting */ 2237 /* append controller */ 2238 (void) strcat(drvr_path, FC_CTLR); 2239 } else { 2240 if (stat(drvr_path, &stbuf) < 0) { 2241 *l_err = L_LSTAT_ERROR; 2242 return (NULL); 2243 } 2244 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 2245 /* append controller */ 2246 (void) strcat(drvr_path, FC_CTLR); 2247 } 2248 } 2249 } 2250 2251 P_DPRINTF(" g_dev_map_init: Geting drive map from:" 2252 " %s\n", drvr_path); 2253 2254 path_type = g_get_path_type(drvr_path); 2255 if ((path_type == 0) || !(path_type & XPORT_MASK)) { 2256 *l_err = L_INVALID_PATH_TYPE; 2257 return (NULL); 2258 } 2259 2260 /* get fiber topology */ 2261 if ((err = g_get_fca_port_topology(drvr_path, 2262 &hba_port_top, 0)) != 0) { 2263 *l_err = err; 2264 return (NULL); 2265 } 2266 2267 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) { 2268 *l_err = errno; 2269 return (NULL); 2270 } 2271 2272 /* for FC devices. */ 2273 if (path_type & FC_FCA_MASK) { 2274 /* get the number of device first. */ 2275 fcio.fcio_cmd = FCIO_GET_NUM_DEVS; 2276 fcio.fcio_olen = sizeof (num_devices); 2277 fcio.fcio_xfer = FCIO_XFER_READ; 2278 fcio.fcio_obuf = (caddr_t)&num_devices; 2279 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) { 2280 I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n"); 2281 (void) close(fd); 2282 *l_err = L_FCIO_GET_NUM_DEVS_FAIL; 2283 return (NULL); 2284 } 2285 if (num_devices != 0) { 2286 if ((dev_list = (fc_port_dev_t *)calloc(num_devices, 2287 sizeof (fc_port_dev_t))) == NULL) { 2288 (void) close(fd); 2289 *l_err = L_MALLOC_FAILED; 2290 return (NULL); 2291 } 2292 2293 bzero((caddr_t)&fcio, sizeof (fcio)); 2294 /* Get the device list */ 2295 fcio.fcio_cmd = FCIO_GET_DEV_LIST; 2296 /* Information read operation */ 2297 fcio.fcio_xfer = FCIO_XFER_READ; 2298 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t); 2299 fcio.fcio_obuf = (caddr_t)dev_list; 2300 /* new device count */ 2301 fcio.fcio_alen = sizeof (new_count); 2302 fcio.fcio_abuf = (caddr_t)&new_count; 2303 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) { 2304 if (err == L_INVALID_DEVICE_COUNT) { 2305 /* 2306 * original buffer was small so allocate 2307 * buffer with a new count and retry. 2308 */ 2309 free(dev_list); 2310 num_devices = new_count; 2311 new_count = 0; 2312 if ((dev_list = (fc_port_dev_t *) 2313 calloc(num_devices, 2314 sizeof (fc_port_dev_t))) == NULL) { 2315 (void) close(fd); 2316 *l_err = L_MALLOC_FAILED; 2317 return (NULL); 2318 } 2319 fcio.fcio_cmd = FCIO_GET_DEV_LIST; 2320 /* Information read operation */ 2321 fcio.fcio_xfer = FCIO_XFER_READ; 2322 fcio.fcio_obuf = (caddr_t)dev_list; 2323 fcio.fcio_olen = num_devices * 2324 sizeof (fc_port_dev_t); 2325 /* new device count */ 2326 fcio.fcio_alen = sizeof (new_count); 2327 fcio.fcio_abuf = (caddr_t)&new_count; 2328 if ((err = g_issue_fcio_ioctl(fd, &fcio, 2329 0)) != 0) { 2330 if (err == 2331 L_INVALID_DEVICE_COUNT) { 2332 /* 2333 * No more retry. There 2334 * may be severe 2335 * hardware problem so 2336 * return error here. 2337 */ 2338 I_DPRINTF(" Device" 2339 " count was %d" 2340 " should have been" 2341 " %d\n", 2342 num_devices, 2343 new_count); 2344 free(dev_list); 2345 (void) close(fd); 2346 2347 *l_err = L_INVALID_DEVICE_COUNT; 2348 2349 return (NULL); 2350 } else { 2351 2352 /* Code refactorization is needed for C style */ 2353 I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed."); 2354 2355 free(dev_list); 2356 (void) close(fd); 2357 2358 *l_err = L_FCIO_GET_DEV_LIST_FAIL; 2359 2360 return (NULL); 2361 } 2362 } 2363 } 2364 } 2365 } 2366 2367 /* 2368 * if new count is smaller than the original number from 2369 * FCIO_GET_NUM_DEVS, adjust new count and buffer size 2370 * and continue. 2371 */ 2372 if (new_count < num_devices) { 2373 num_devices = new_count; 2374 if (new_count > 0) { 2375 if ((dev_list = (fc_port_dev_t *) 2376 realloc(dev_list, 2377 (new_count * sizeof (fc_port_dev_t)))) 2378 == NULL) { 2379 S_FREE(dev_list); 2380 (void) close(fd); 2381 *l_err = L_MALLOC_FAILED; 2382 return (NULL); 2383 } 2384 } 2385 } 2386 2387 /* get the host param info */ 2388 (void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev)); 2389 fcio.fcio_cmd = FCIO_GET_HOST_PARAMS; 2390 fcio.fcio_xfer = FCIO_XFER_READ; 2391 fcio.fcio_obuf = (caddr_t)&fp_hba_port; 2392 fcio.fcio_olen = sizeof (fc_port_dev_t); 2393 2394 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) { 2395 I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n"); 2396 (void) close(fd); 2397 if (num_devices == 0) { 2398 *l_err = L_NO_DEVICES_FOUND; 2399 } else { 2400 free(dev_list); 2401 *l_err = L_FCIO_GET_HOST_PARAMS_FAIL; 2402 } 2403 (void) close(fd); 2404 return (NULL); 2405 } 2406 2407 /* If we want the lilp map then we need to do a little */ 2408 /* work here. The lilp map contains the local hba in */ 2409 /* the dev_addr. Once this has been added qsort the */ 2410 /* dev_addr array so it's in physical order. */ 2411 if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) { 2412 /* First we need to allocate one additional */ 2413 /* device to the dev_addr structure, for the */ 2414 /* local hba */ 2415 if (num_devices > 0) { 2416 if ((dev_list = (fc_port_dev_t *) 2417 realloc(dev_list, 2418 (++num_devices * 2419 sizeof (fc_port_dev_t)))) == NULL) { 2420 (void) close(fd); 2421 /* 2422 * In case dev_list is not null free 2423 * it. 2424 */ 2425 S_FREE(dev_list); 2426 *l_err = L_MALLOC_FAILED; 2427 return (NULL); 2428 } 2429 2430 /* 2431 * Next, copy the local hba into this new 2432 * loc. 2433 */ 2434 if (memcpy(dev_list+(num_devices-1), 2435 &fp_hba_port, 2436 sizeof (fc_port_dev_t)) == NULL) { 2437 (void) free(dev_list); 2438 (void) close(fd); 2439 *l_err = L_MEMCPY_FAILED; 2440 return (NULL); 2441 } 2442 2443 /* Now sort by physical location */ 2444 qsort((void*)dev_list, num_devices, 2445 sizeof (fc_port_dev_t), lilp_map_cmp); 2446 } 2447 } 2448 2449 2450 /* We have dev list info and host param info. */ 2451 /* Now constructs map tree with these info. */ 2452 /* First consturct the root of the map tree */ 2453 /* with host param. */ 2454 if ((impl_map = (impl_map_dev_t *)calloc( 2455 1, sizeof (impl_map_dev_t))) == NULL) { 2456 (void) free(dev_list); 2457 (void) close(fd); 2458 *l_err = L_MALLOC_FAILED; 2459 return (NULL); 2460 } 2461 impl_map->flag = flag; 2462 impl_map->topo = hba_port_top; 2463 2464 /* consturct hba property list. */ 2465 if ((err = update_map_dev_fc_prop(&impl_map->prop_list, 2466 hba_port_top, fp_hba_port.dev_pwwn.raw_wwn, 2467 fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id, 2468 fp_hba_port.dev_hard_addr.hard_addr)) != 0) { 2469 (void) free(dev_list); 2470 (void) close(fd); 2471 g_dev_map_fini(impl_map); 2472 *l_err = err; 2473 return (NULL); 2474 } 2475 2476 if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) { 2477 if (fstat(fd, &sbuf) == -1) { 2478 (void) free(dev_list); 2479 (void) close(fd); 2480 g_dev_map_fini(impl_map); 2481 *l_err = L_FSTAT_ERROR; 2482 return (NULL); 2483 } 2484 if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev), 2485 fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) { 2486 (void) free(dev_list); 2487 (void) close(fd); 2488 g_dev_map_fini(impl_map); 2489 *l_err = err; 2490 return (NULL); 2491 } 2492 } 2493 2494 /* consturct child for each device and */ 2495 /* set device property list. */ 2496 dlist = dev_list; 2497 for (i = 0; i < num_devices; i++, dlist++) { 2498 if ((impl_dev = (impl_map_dev_t *)calloc( 2499 1, sizeof (impl_map_dev_t))) == NULL) { 2500 (void) free(dev_list); 2501 (void) close(fd); 2502 g_dev_map_fini(impl_map); 2503 *l_err = L_MALLOC_FAILED; 2504 return (NULL); 2505 } 2506 /* set the map as parent */ 2507 impl_dev->parent = impl_map; 2508 if ((err = update_map_dev_fc_prop(&impl_dev->prop_list, 2509 hba_port_top, dlist->dev_pwwn.raw_wwn, 2510 dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id, 2511 dlist->dev_hard_addr.hard_addr)) != 0) { 2512 (void) free(dev_list); 2513 (void) close(fd); 2514 g_dev_map_fini(impl_map); 2515 *l_err = err; 2516 return (NULL); 2517 } 2518 if (i == 0) { 2519 mdl_start = mdl_end = impl_dev; 2520 } else { 2521 mdl_end->next = impl_dev; 2522 mdl_end = impl_dev; 2523 } 2524 if ((flag & MAP_XPORT_PROP_ONLY) != 2525 MAP_XPORT_PROP_ONLY) { 2526 if (((hba_port_top == FC_TOP_PUBLIC_LOOP) || 2527 (hba_port_top == FC_TOP_FABRIC)) && 2528 (memcmp(fp_hba_port.dev_pwwn.raw_wwn, 2529 dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) { 2530 (void) memset(&fcio, 0, sizeof (fcio_t)); 2531 fcio.fcio_cmd = FCIO_GET_STATE; 2532 fcio.fcio_ilen = sizeof (dlist->dev_pwwn); 2533 fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn; 2534 fcio.fcio_xfer = FCIO_XFER_READ | 2535 FCIO_XFER_WRITE; 2536 fcio.fcio_olen = sizeof (uint32_t); 2537 fcio.fcio_obuf = (caddr_t)&state; 2538 fcio.fcio_alen = 0; 2539 fcio.fcio_abuf = NULL; 2540 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) { 2541 I_DPRINTF( 2542 " FCIO_GET_STATE ioctl failed.\n"); 2543 if ((err = update_map_dev_FCP_prop( 2544 &impl_dev->prop_list, NULL, 2545 L_FCIO_GET_STATE_FAIL, 2546 PROP_NOEXIST)) != 0) { 2547 (void) free(dev_list); 2548 (void) close(fd); 2549 g_dev_map_fini(impl_map); 2550 *l_err = err; 2551 return (NULL); 2552 } 2553 } 2554 if (state != PORT_DEVICE_LOGGED_IN) { 2555 (void) close(fd); 2556 if ((fd = g_object_open(drvr_path, 2557 O_NDELAY | O_RDONLY | O_EXCL)) == 2558 -1) { 2559 (void) free(dev_list); 2560 g_dev_map_fini(impl_map); 2561 *l_err = L_OPEN_PATH_FAIL; 2562 return (NULL); 2563 } 2564 (void) memset(&fcio, 0, 2565 sizeof (fcio_t)); 2566 fcio.fcio_cmd = FCIO_DEV_LOGIN; 2567 fcio.fcio_ilen = 2568 sizeof (dlist->dev_pwwn); 2569 fcio.fcio_ibuf = 2570 (caddr_t)&dlist->dev_pwwn; 2571 fcio.fcio_xfer = FCIO_XFER_WRITE; 2572 fcio.fcio_olen = fcio.fcio_alen = 0; 2573 fcio.fcio_obuf = fcio.fcio_abuf = NULL; 2574 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 2575 0) { 2576 2577 /* Code refactorization is needed for C style */ 2578 I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n"); 2579 2580 if ((err = update_map_dev_FCP_prop( 2581 &impl_dev->prop_list, NULL, 2582 L_FCIO_DEV_LOGIN_FAIL, 2583 PROP_NOEXIST)) != 0) { 2584 (void) free(dev_list); 2585 (void) close(fd); 2586 g_dev_map_fini(impl_map); 2587 *l_err = err; 2588 return (NULL); 2589 } 2590 2591 /* 2592 * plogi failed continue 2593 * to next dev 2594 */ 2595 continue; 2596 } 2597 } 2598 } 2599 /* sbuf should be set from hba_port handling. */ 2600 if ((err = handle_map_dev_FCP_prop( 2601 minor(sbuf.st_rdev), 2602 dlist->dev_pwwn, &impl_dev->prop_list)) != 2603 0) { 2604 (void) free(dev_list); 2605 (void) close(fd); 2606 g_dev_map_fini(impl_map); 2607 *l_err = err; 2608 return (NULL); 2609 } 2610 } 2611 } 2612 /* connect the children to to map. */ 2613 impl_map->child = mdl_start; 2614 S_FREE(dev_list); 2615 2616 } else { /* sf and fc4/pci devices */ 2617 /* initialize map */ 2618 (void) memset(&sf_map, 0, sizeof (struct sf_al_map)); 2619 if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) { 2620 I_DPRINTF(" SFIOCGMAP ioctl failed.\n"); 2621 (void) close(fd); 2622 *l_err = L_SFIOCGMAP_IOCTL_FAIL; 2623 return (NULL); 2624 } 2625 /* Check for reasonableness. */ 2626 if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) { 2627 (void) close(fd); 2628 *l_err = L_INVALID_LOOP_MAP; 2629 return (NULL); 2630 } 2631 2632 if (sf_map.sf_count == 0) { 2633 (void) close(fd); 2634 *l_err = L_NO_DEVICES_FOUND; 2635 return (NULL); 2636 } 2637 2638 if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) { 2639 (void) close(fd); 2640 *l_err = err; 2641 return (NULL); 2642 } 2643 2644 if ((nexus_fd = 2645 g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) { 2646 (void) close(fd); 2647 S_FREE(nexus_path); 2648 *l_err = errno; 2649 return (NULL); 2650 } 2651 2652 /* get limited map to get hba param info */ 2653 if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) { 2654 I_DPRINTF(" FCIO_GETMAP ioctl failed\n"); 2655 (void) close(fd); 2656 (void) close(nexus_fd); 2657 S_FREE(nexus_path); 2658 *l_err = L_FCIO_GETMAP_IOCTL_FAIL; 2659 return (NULL); 2660 } 2661 (void) close(nexus_fd); 2662 S_FREE(nexus_path); 2663 2664 for (i = 0; i < sf_map.sf_count; i++) { 2665 if (sf_map.sf_addr_pair[i].sf_al_pa == 2666 limited_map.lilp_myalpa) { 2667 sf_map.sf_hba_addr = sf_map.sf_addr_pair[i]; 2668 hba_alpa_found = 1; 2669 } 2670 } 2671 2672 if (!(hba_alpa_found)) { 2673 (void) close(fd); 2674 *l_err = L_INVALID_LOOP_MAP; 2675 return (NULL); 2676 } 2677 2678 /* We have dev list info and host param info. */ 2679 /* Now constructs map tree with these info. */ 2680 /* First consturct the root of the map tree */ 2681 /* with host param. */ 2682 if ((impl_map = (impl_map_dev_t *)calloc( 2683 1, sizeof (impl_map_dev_t))) == NULL) { 2684 (void) close(fd); 2685 *l_err = L_MALLOC_FAILED; 2686 return (NULL); 2687 } 2688 impl_map->flag = flag; 2689 impl_map->topo = hba_port_top; 2690 2691 /* consturct hba property list. */ 2692 if ((err = update_map_dev_fc_prop(&impl_map->prop_list, 2693 hba_port_top, sf_map.sf_hba_addr.sf_port_wwn, 2694 sf_map.sf_hba_addr.sf_node_wwn, 2695 (int)sf_map.sf_hba_addr.sf_al_pa, 2696 (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) { 2697 (void) close(fd); 2698 g_dev_map_fini(impl_map); 2699 *l_err = err; 2700 return (NULL); 2701 } 2702 2703 if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) { 2704 if ((err = update_map_dev_FCP_prop(&impl_map->prop_list, 2705 &sf_map.sf_hba_addr.sf_inq_dtype, 0, 2706 PROP_NOEXIST)) != 0) { 2707 (void) close(fd); 2708 g_dev_map_fini(impl_map); 2709 *l_err = err; 2710 return (NULL); 2711 } 2712 } 2713 2714 for (i = 0; i < sf_map.sf_count; i++) { 2715 if ((impl_dev = (impl_map_dev_t *)calloc( 2716 1, sizeof (impl_map_dev_t))) == NULL) { 2717 (void) close(fd); 2718 g_dev_map_fini(impl_map); 2719 *l_err = L_MALLOC_FAILED; 2720 return (NULL); 2721 } 2722 /* set the map as parent */ 2723 impl_dev->parent = impl_map; 2724 if ((err = update_map_dev_fc_prop(&impl_dev->prop_list, 2725 hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn, 2726 sf_map.sf_addr_pair[i].sf_node_wwn, 2727 (int)(sf_map.sf_addr_pair[i].sf_al_pa), 2728 (int)(sf_map.sf_addr_pair[i].sf_hard_address))) != 2729 0) { 2730 (void) close(fd); 2731 g_dev_map_fini(impl_map); 2732 *l_err = err; 2733 return (NULL); 2734 } 2735 if (i == 0) { 2736 mdl_start = mdl_end = impl_dev; 2737 } else { 2738 mdl_end->next = impl_dev; 2739 mdl_end = impl_dev; 2740 } 2741 if ((flag & MAP_XPORT_PROP_ONLY) != 2742 MAP_XPORT_PROP_ONLY) { 2743 if ((err = update_map_dev_FCP_prop( 2744 &impl_dev->prop_list, 2745 &sf_map.sf_addr_pair[i].sf_inq_dtype, 0, 2746 PROP_NOEXIST)) != 0) { 2747 (void) close(fd); 2748 g_dev_map_fini(impl_map); 2749 *l_err = err; 2750 return (NULL); 2751 } 2752 } 2753 } /* end of for loop */ 2754 2755 impl_map->child = mdl_start; 2756 } /* end of else */ 2757 2758 close(fd); 2759 return ((gfc_dev_t)(impl_map)); 2760 } 2761 2762 /* 2763 * This function deallocates memory for propery list. 2764 */ 2765 static void 2766 free_prop_list(impl_map_dev_prop_t **prop_list) 2767 { 2768 impl_map_dev_prop_t *lp, *olp; 2769 2770 lp = *prop_list; 2771 while (lp != NULL) { 2772 switch (lp->prop_type) { 2773 case GFC_PROP_TYPE_BYTES: 2774 free((uchar_t *)(lp->prop_data)); 2775 break; 2776 case GFC_PROP_TYPE_INT: 2777 free((int *)(lp->prop_data)); 2778 break; 2779 case GFC_PROP_TYPE_STRING: 2780 free((char *)(lp->prop_data)); 2781 break; 2782 default: 2783 break; 2784 } 2785 lp->prop_data = NULL; 2786 olp = lp; 2787 lp = olp->next; 2788 S_FREE(olp); 2789 } 2790 2791 *prop_list = NULL; 2792 } 2793 2794 /* 2795 * This function deallocates memory for children list. 2796 */ 2797 static void 2798 free_child_list(impl_map_dev_t **dev_list) 2799 { 2800 impl_map_dev_t *lp, *olp; 2801 2802 lp = *dev_list; 2803 while (lp != NULL) { 2804 free_prop_list(&lp->prop_list); 2805 olp = lp; 2806 lp = olp->next; 2807 S_FREE(olp); 2808 } 2809 2810 *dev_list = NULL; 2811 } 2812 2813 /* 2814 * This function deallocates memory for the whole map. 2815 */ 2816 void 2817 g_dev_map_fini(gfc_dev_t map) 2818 { 2819 impl_map_dev_t *impl_map; 2820 2821 impl_map = (impl_map_dev_t *)map; 2822 2823 if (impl_map != NULL) { 2824 free_prop_list(&impl_map->prop_list); 2825 free_child_list(&impl_map->child); 2826 S_FREE(impl_map); 2827 } 2828 } 2829 2830 /* 2831 * This function passes back topology of the input map. 2832 * input should be a handle form g_dev_map_init(). 2833 * 2834 * return 0 if OK. 2835 * return error code otherwise. 2836 */ 2837 int 2838 g_get_map_topology(gfc_dev_t map, uint_t *topology) 2839 { 2840 impl_map_dev_t *impl_map; 2841 2842 if (map == NULL) { 2843 return (L_INVALID_MAP_DEV_ADDR); 2844 } 2845 2846 if (topology == NULL) { 2847 return (L_INVALID_ARG); 2848 } 2849 2850 impl_map = (impl_map_dev_t *)map; 2851 2852 *topology = impl_map->topo; 2853 2854 return (0); 2855 } 2856 2857 /* 2858 * This function returns the first device handle of the input map. 2859 * map input should be a handle form g_dev_map_init(). 2860 * 2861 * l_err set to 0 if OK. 2862 * l_err set to error code otherwise. 2863 */ 2864 gfc_dev_t 2865 g_get_first_dev(gfc_dev_t map, int *l_err) 2866 { 2867 impl_map_dev_t *impl_map; 2868 2869 if (l_err == NULL) { 2870 return (NULL); 2871 } 2872 2873 *l_err = 0; 2874 2875 if (map == NULL) { 2876 *l_err = L_INVALID_MAP_DEV_ADDR; 2877 return (NULL); 2878 } 2879 2880 impl_map = (impl_map_dev_t *)map; 2881 2882 if (impl_map->child == NULL) { 2883 *l_err = L_NO_SUCH_DEV_FOUND; 2884 } 2885 2886 return ((gfc_dev_t)(impl_map->child)); 2887 } 2888 2889 /* 2890 * This function returns the next device handle of the input map. 2891 * map_dev input should be a handle for device. 2892 * 2893 * l_err set to 0 if OK. 2894 * l_err set to error code otherwise. 2895 */ 2896 gfc_dev_t 2897 g_get_next_dev(gfc_dev_t map_dev, int *l_err) 2898 { 2899 impl_map_dev_t *impl_dev; 2900 2901 if (l_err == NULL) { 2902 return (NULL); 2903 } 2904 2905 *l_err = 0; 2906 2907 if (map_dev == NULL) { 2908 *l_err = L_INVALID_MAP_DEV_ADDR; 2909 return (NULL); 2910 } 2911 2912 impl_dev = (impl_map_dev_t *)map_dev; 2913 2914 if (impl_dev->next == NULL) { 2915 *l_err = L_NO_SUCH_DEV_FOUND; 2916 } 2917 2918 return ((gfc_dev_t)(impl_dev->next)); 2919 } 2920 2921 /* 2922 * This function passes back uchar_t type property and its count. 2923 * map_dev input should be a handle for device. 2924 * 2925 * return 0 if OK. 2926 * return error code otherwise. 2927 */ 2928 int 2929 g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name, 2930 int *prop_data_count, uchar_t **prop_data) 2931 { 2932 impl_map_dev_t *impl_dev; 2933 impl_map_dev_prop_t *impl_prop; 2934 int err; 2935 2936 if (map_dev == NULL) { 2937 return (L_INVALID_MAP_DEV_ADDR); 2938 } 2939 2940 if ((prop_name == NULL) || (prop_data == NULL) || 2941 (prop_data_count == NULL)) { 2942 return (L_INVALID_ARG); 2943 } 2944 2945 impl_dev = (impl_map_dev_t *)map_dev; 2946 impl_prop = impl_dev->prop_list; 2947 2948 err = L_INVALID_MAP_DEV_PROP_NAME; 2949 2950 while (impl_prop) { 2951 if (strncmp(impl_prop->prop_name, prop_name, 2952 strlen(prop_name)) == 0) { 2953 if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) { 2954 err = L_INVALID_MAP_DEV_PROP_TYPE; 2955 break; 2956 } 2957 if (impl_prop->prop_data) { 2958 *prop_data = (uchar_t *)(impl_prop->prop_data); 2959 *prop_data_count = impl_prop->prop_size; 2960 return (0); 2961 } else { 2962 err = impl_prop->prop_error; 2963 } 2964 break; 2965 } 2966 impl_prop = impl_prop->next; 2967 } 2968 2969 return (err); 2970 } 2971 2972 /* 2973 * This function passes back int type property. 2974 * map_dev input should be a handle for device. 2975 * 2976 * return 0 if OK. 2977 * return error code otherwise. 2978 */ 2979 int 2980 g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name, 2981 int **prop_data) 2982 { 2983 impl_map_dev_t *impl_dev; 2984 impl_map_dev_prop_t *impl_prop; 2985 int err; 2986 2987 if (map_dev == NULL) { 2988 return (L_INVALID_MAP_DEV_ADDR); 2989 } 2990 2991 if ((prop_name == NULL) || (prop_data == NULL)) { 2992 return (L_INVALID_ARG); 2993 } 2994 2995 impl_dev = (impl_map_dev_t *)map_dev; 2996 impl_prop = impl_dev->prop_list; 2997 2998 err = L_INVALID_MAP_DEV_PROP_NAME; 2999 3000 while (impl_prop) { 3001 if (strncmp(impl_prop->prop_name, prop_name, 3002 strlen(prop_name)) == 0) { 3003 if (impl_prop->prop_type != GFC_PROP_TYPE_INT) { 3004 err = L_INVALID_MAP_DEV_PROP_TYPE; 3005 break; 3006 } 3007 if (impl_prop->prop_data) { 3008 *prop_data = (int *)(impl_prop->prop_data); 3009 return (0); 3010 } else { 3011 err = impl_prop->prop_error; 3012 } 3013 break; 3014 } 3015 impl_prop = impl_prop->next; 3016 } 3017 3018 return (err); 3019 } 3020 3021 /* 3022 * This function passes back int type property. 3023 * map_dev input should be a handle for device. 3024 * 3025 * return 0 if OK. 3026 * return error code otherwise. 3027 */ 3028 int 3029 g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name, 3030 char **prop_data) 3031 { 3032 impl_map_dev_t *impl_dev; 3033 impl_map_dev_prop_t *impl_prop; 3034 int err; 3035 3036 if (map_dev == NULL) { 3037 return (L_INVALID_MAP_DEV_ADDR); 3038 } 3039 3040 if ((prop_name == NULL) || (prop_data == NULL)) { 3041 return (L_INVALID_ARG); 3042 } 3043 3044 impl_dev = (impl_map_dev_t *)map_dev; 3045 impl_prop = impl_dev->prop_list; 3046 3047 err = L_INVALID_MAP_DEV_PROP_NAME; 3048 3049 while (impl_prop) { 3050 if (strncmp(impl_prop->prop_name, prop_name, 3051 strlen(prop_name)) == 0) { 3052 if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) { 3053 err = L_INVALID_MAP_DEV_PROP_TYPE; 3054 break; 3055 } 3056 if (impl_prop->prop_data) { 3057 *prop_data = (char *)(impl_prop->prop_data); 3058 return (0); 3059 } else { 3060 err = impl_prop->prop_error; 3061 } 3062 break; 3063 } 3064 impl_prop = impl_prop->next; 3065 } 3066 3067 return (err); 3068 } 3069 3070 /* 3071 * This function returns the handle for the first property of the input device. 3072 * map_dev input should be a handle form a device. 3073 * 3074 * l_err set to 0 if OK. 3075 * l_err set to error code otherwise. 3076 */ 3077 gfc_prop_t 3078 g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err) 3079 { 3080 impl_map_dev_t *impl_dev; 3081 3082 if (l_err == NULL) { 3083 return (NULL); 3084 } 3085 3086 *l_err = 0; 3087 3088 if (map_dev == NULL) { 3089 *l_err = L_INVALID_MAP_DEV_ADDR; 3090 return (NULL); 3091 } 3092 3093 impl_dev = (impl_map_dev_t *)map_dev; 3094 3095 if (impl_dev->prop_list == NULL) { 3096 *l_err = L_NO_SUCH_PROP_FOUND; 3097 } 3098 3099 return ((gfc_prop_t)(impl_dev->prop_list)); 3100 } 3101 3102 /* 3103 * This function returns the handle for next property handle of the input prop. 3104 * map_prop input should be a handle for property. 3105 * 3106 * l_err set to 0 if OK. 3107 * l_err set to error code otherwise. 3108 */ 3109 gfc_prop_t 3110 g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err) 3111 { 3112 impl_map_dev_prop_t *impl_prop; 3113 3114 if (l_err == NULL) { 3115 return (NULL); 3116 } 3117 3118 *l_err = 0; 3119 3120 if (map_prop == NULL) { 3121 *l_err = L_INVALID_MAP_DEV_PROP; 3122 return (NULL); 3123 } 3124 3125 impl_prop = (impl_map_dev_prop_t *)map_prop; 3126 3127 if (impl_prop->next == NULL) { 3128 *l_err = L_NO_SUCH_PROP_FOUND; 3129 } 3130 3131 return ((gfc_prop_t)(impl_prop->next)); 3132 } 3133 3134 /* 3135 * This function returns the name of the property of the input prop. 3136 * map_prop input should be a handle for property. 3137 * 3138 * return name string if OK. 3139 * returns NULL and l_err set to error code otherwise. 3140 */ 3141 char * 3142 g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err) 3143 { 3144 impl_map_dev_prop_t *impl_prop; 3145 3146 if (l_err == NULL) { 3147 return (NULL); 3148 } 3149 3150 *l_err = 0; 3151 3152 if (map_prop == NULL) { 3153 *l_err = L_INVALID_MAP_DEV_PROP; 3154 return (NULL); 3155 } 3156 3157 impl_prop = (impl_map_dev_prop_t *)map_prop; 3158 3159 return (impl_prop->prop_name); 3160 } 3161 3162 /* 3163 * This function returns the type of the property of the input prop. 3164 * map_prop input should be a handle for property. 3165 * 3166 * return type if OK. 3167 * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise. 3168 */ 3169 int 3170 g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err) 3171 { 3172 impl_map_dev_prop_t *impl_prop; 3173 3174 if (l_err != NULL) { 3175 *l_err = 0; 3176 } else { 3177 return (L_INVALID_ARG); 3178 } 3179 3180 if (map_prop == NULL) { 3181 *l_err = L_INVALID_MAP_DEV_PROP; 3182 return (GFC_PROP_TYPE_UNKNOWN); 3183 } 3184 3185 impl_prop = (impl_map_dev_prop_t *)map_prop; 3186 3187 return (impl_prop->prop_type); 3188 } 3189 3190 /* 3191 * This function passes back uchar_t type property and its count. 3192 * map_prop input should be a handle for property. 3193 * 3194 * return 0 if OK. 3195 * return error code otherwise. 3196 */ 3197 int 3198 g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count, 3199 uchar_t **prop_data) 3200 { 3201 impl_map_dev_prop_t *impl_prop; 3202 3203 if (map_prop == NULL) { 3204 return (L_INVALID_MAP_DEV_ADDR); 3205 } 3206 3207 if ((prop_data == NULL) || (prop_data_count == NULL)) { 3208 return (L_INVALID_ARG); 3209 } 3210 3211 impl_prop = (impl_map_dev_prop_t *)map_prop; 3212 3213 if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) { 3214 return (L_INVALID_MAP_DEV_PROP_TYPE); 3215 } 3216 if (impl_prop->prop_data) { 3217 *prop_data = (uchar_t *)(impl_prop->prop_data); 3218 *prop_data_count = impl_prop->prop_size; 3219 } else { 3220 return (impl_prop->prop_error); 3221 } 3222 3223 return (0); 3224 } 3225 3226 /* 3227 * This function passes back int type property. 3228 * map_prop input should be a handle for property. 3229 * 3230 * return 0 if OK. 3231 * return error code otherwise. 3232 */ 3233 int 3234 g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data) 3235 { 3236 impl_map_dev_prop_t *impl_prop; 3237 3238 if (map_prop == NULL) { 3239 return (L_INVALID_MAP_DEV_ADDR); 3240 } 3241 3242 if (prop_data == NULL) { 3243 return (L_INVALID_ARG); 3244 } 3245 3246 impl_prop = (impl_map_dev_prop_t *)map_prop; 3247 3248 if (impl_prop->prop_type != GFC_PROP_TYPE_INT) { 3249 return (L_INVALID_MAP_DEV_PROP_TYPE); 3250 } 3251 if (impl_prop->prop_data) { 3252 *prop_data = (int *)(impl_prop->prop_data); 3253 } else { 3254 return (impl_prop->prop_error); 3255 } 3256 3257 return (0); 3258 } 3259 3260 /* 3261 * This function passes back string type property. 3262 * map_prop input should be a handle for property. 3263 * 3264 * return 0 if OK. 3265 * return error code otherwise. 3266 */ 3267 int 3268 g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data) 3269 { 3270 impl_map_dev_prop_t *impl_prop; 3271 3272 if (map_prop == NULL) { 3273 return (L_INVALID_MAP_DEV_ADDR); 3274 } 3275 3276 if (prop_data == NULL) { 3277 return (L_INVALID_ARG); 3278 } 3279 3280 impl_prop = (impl_map_dev_prop_t *)map_prop; 3281 3282 if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) { 3283 return (L_INVALID_MAP_DEV_PROP_TYPE); 3284 } 3285 if (impl_prop->prop_data) { 3286 *prop_data = (char *)(impl_prop->prop_data); 3287 } else { 3288 return (impl_prop->prop_error); 3289 } 3290 3291 return (0); 3292 } 3293 3294 /* 3295 * Free the linked list allocated by g_rdls() 3296 */ 3297 static void 3298 g_free_rls(AL_rls *rlsptr) 3299 { 3300 AL_rls *trlsptr; 3301 3302 while (rlsptr != NULL) { 3303 trlsptr = rlsptr->next; 3304 free(rlsptr); 3305 rlsptr = trlsptr; 3306 } 3307 } 3308 3309 /* 3310 * Read the extended link error status block 3311 * from the specified device and Host Adapter. 3312 * 3313 * PARAMS: 3314 * path_phys - physical path to an FC device 3315 * rls_ptr - pointer to read link state structure 3316 * 3317 * RETURNS: 3318 * 0 : if OK 3319 * non-zero: otherwise 3320 */ 3321 int 3322 g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose) 3323 { 3324 char nexus_path[MAXPATHLEN], *nexus_path_ptr; 3325 int fd, fp_fd, err, length, exp_map_flag = 0, *port_addr; 3326 struct lilpmap map; 3327 AL_rls *rls, *c1 = NULL, *c2 = NULL; 3328 uchar_t i, *port_wwn_byte; 3329 la_wwn_t port_wwn; 3330 sf_al_map_t exp_map; 3331 char *charPtr, fp_path[MAXPATHLEN]; 3332 uint_t dev_type; 3333 struct stat stbuf; 3334 fcio_t fcio; 3335 fc_portid_t rls_req; 3336 fc_rls_acc_t rls_payload; 3337 gfc_dev_t map_root, map_dev; 3338 uint32_t hba_port_top, state; 3339 int pathcnt = 1, count; 3340 mp_pathlist_t pathlist; 3341 int p_on = 0, p_st = 0; 3342 3343 /* return invalid path if path_phys is NULL */ 3344 if (path_phys == NULL) { 3345 return (L_INVALID_PATH); 3346 } 3347 /* return invalid arg if rls_ptr is NULL */ 3348 if (rls_ptr == NULL) { 3349 return (L_INVALID_ARG); 3350 } 3351 3352 *rls_ptr = rls = NULL; 3353 3354 if (strstr(path_phys, SCSI_VHCI) != NULL) { 3355 (void) strcpy(fp_path, path_phys); 3356 if (g_get_pathlist(fp_path, &pathlist)) { 3357 return (L_INVALID_PATH); 3358 } 3359 pathcnt = pathlist.path_count; 3360 p_on = p_st = 0; 3361 for (i = 0; i < pathcnt; i++) { 3362 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 3363 if (pathlist.path_info[i].path_state == 3364 MDI_PATHINFO_STATE_ONLINE) { 3365 p_on = i; 3366 break; 3367 } else if (pathlist.path_info[i].path_state == 3368 MDI_PATHINFO_STATE_STANDBY) { 3369 p_st = i; 3370 } 3371 } 3372 } 3373 if (pathlist.path_info[p_on].path_state == 3374 MDI_PATHINFO_STATE_ONLINE) { 3375 /* on_line path */ 3376 (void) strcpy(fp_path, 3377 pathlist.path_info[p_on].path_hba); 3378 } else { 3379 /* standby or path0 */ 3380 (void) strcpy(fp_path, 3381 pathlist.path_info[p_st].path_hba); 3382 } 3383 free(pathlist.path_info); 3384 } else { 3385 (void) strcpy(fp_path, path_phys); 3386 } 3387 3388 /* Get map of devices on this loop. */ 3389 if ((dev_type = g_get_path_type(fp_path)) == 0) { 3390 return (L_INVALID_PATH); 3391 } 3392 if (dev_type & FC_FCA_MASK) { 3393 if (strstr(path_phys, SCSI_VHCI) != NULL) { 3394 (void) strcat(fp_path, FC_CTLR); 3395 } else if (strstr(fp_path, DRV_NAME_SSD) || 3396 strstr(fp_path, DRV_NAME_ST) || 3397 strstr(fp_path, SES_NAME)) { 3398 if ((charPtr = strrchr(fp_path, '/')) == NULL) { 3399 return (L_INVALID_PATH); 3400 } 3401 *charPtr = '\0'; 3402 /* append devctl to the path */ 3403 (void) strcat(fp_path, FC_CTLR); 3404 } else { 3405 if (stat(fp_path, &stbuf) < 0) { 3406 return (L_LSTAT_ERROR); 3407 } 3408 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3409 /* append devctl to the path */ 3410 (void) strcat(fp_path, FC_CTLR); 3411 } 3412 } 3413 3414 if ((map_root = g_dev_map_init(fp_path, &err, 3415 MAP_XPORT_PROP_ONLY)) == NULL) { 3416 return (err); 3417 } 3418 3419 } else { /* FC4_FCA_MASK type path */ 3420 (void) memset(&map, 0, sizeof (struct lilpmap)); 3421 3422 if ((err = g_get_nexus_path(path_phys, 3423 &nexus_path_ptr)) != 0) { 3424 return (err); 3425 } 3426 (void) strcpy(nexus_path, nexus_path_ptr); 3427 g_destroy_data(nexus_path_ptr); 3428 3429 /* open driver */ 3430 if ((fd = g_object_open(nexus_path, 3431 O_NDELAY | O_RDONLY)) == -1) 3432 return (errno); 3433 3434 /* 3435 * First try using the socal version of the map. 3436 * If that fails get the expanded vesion. 3437 */ 3438 if (ioctl(fd, FCIO_GETMAP, &map) != 0) { 3439 I_DPRINTF(" FCIO_GETMAP ioctl failed.\n"); 3440 if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) { 3441 I_DPRINTF(" SFIOCGMAP ioctl failed.\n"); 3442 (void) close(fd); 3443 return (L_SFIOCGMAP_IOCTL_FAIL); 3444 } 3445 /* Check for reasonableness. */ 3446 if ((exp_map.sf_count > 126) || 3447 (exp_map.sf_count < 0)) { 3448 (void) close(fd); 3449 return (L_INVALID_LOOP_MAP); 3450 } 3451 for (i = 0; i < exp_map.sf_count; i++) { 3452 if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) { 3453 (void) close(fd); 3454 return (L_INVALID_LOOP_MAP); 3455 } 3456 } 3457 length = exp_map.sf_count; 3458 exp_map_flag++; 3459 } else { 3460 I_DPRINTF(" g_rdls:" 3461 " FCIO_GETMAP ioctl returned %d entries.\n", 3462 map.lilp_length); 3463 /* Check for reasonableness. */ 3464 if (map.lilp_length > sizeof (map.lilp_list)) { 3465 (void) close(fd); 3466 return (L_FCIOGETMAP_INVLD_LEN); 3467 } 3468 length = map.lilp_length; 3469 } 3470 for (i = 0; i < length; i++) { 3471 if ((c2 = (struct al_rls *) 3472 g_zalloc(sizeof (struct al_rls))) == NULL) { 3473 close(fd); 3474 return (L_MALLOC_FAILED); 3475 } 3476 if (rls == NULL) { 3477 c1 = rls = c2; 3478 } else { 3479 for (c1 = rls; c1->next; c1 = c1->next) {}; 3480 c1 = c1->next = c2; 3481 } 3482 (void) strcpy(c1->driver_path, nexus_path); 3483 if (exp_map_flag) { 3484 c1->payload.rls_portno = c1->al_ha = 3485 exp_map.sf_addr_pair[i].sf_al_pa; 3486 } else { 3487 c1->payload.rls_portno = c1->al_ha = 3488 map.lilp_list[i]; 3489 } 3490 c1->payload.rls_linkfail = 3491 (uint_t)0xff000000; /* get LESB for this port */ 3492 I_DPRINTF(" g_rdls:" 3493 " al_pa 0x%x\n", c1->payload.rls_portno); 3494 3495 if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) { 3496 /* 3497 * The ifp driver will return ENXIO when rls 3498 * is issued for same initiator on loop when 3499 * there is more than one on the loop. 3500 * Rather than completely fail, continue on. 3501 * Set values in the payload struct to -1 as 3502 * this is what socal is currently doing for 3503 * the case of same initiator rls. 3504 */ 3505 if ((dev_type & FC4_PCI_FCA) && 3506 (errno == ENXIO)) { 3507 c1->payload.rls_linkfail = 3508 c1->payload.rls_syncfail = 3509 c1->payload.rls_sigfail = 3510 c1->payload.rls_primitiverr = 3511 c1->payload.rls_invalidword = 3512 c1->payload.rls_invalidcrc = 3513 (uint_t)0xffffffff; 3514 } else { 3515 I_DPRINTF(" FCIO_LINKSTATUS ioctl" 3516 " failed with errno %d.\n", errno); 3517 g_free_rls(rls); 3518 (void) close(fd); 3519 return (L_FCIO_LINKSTATUS_FAILED); 3520 } 3521 } 3522 I_DPRINTF(" g_rdls: al_pa returned by ioctl 0x%x\n", 3523 c1->payload.rls_portno); 3524 } 3525 *rls_ptr = rls; /* Pass back pointer */ 3526 3527 (void) close(fd); 3528 return (0); 3529 } 3530 3531 /* Now we need to take care of FC_FCA_MASK case. */ 3532 /* we have map created already via g_dev_map_init. */ 3533 if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) { 3534 g_dev_map_fini(map_root); 3535 return (err); 3536 } 3537 3538 if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) { 3539 g_dev_map_fini(map_root); 3540 if (err != L_NO_SUCH_DEV_FOUND) { 3541 return (err); 3542 } else { 3543 return (L_NO_DEVICES_FOUND); 3544 } 3545 } 3546 3547 while (map_dev) { 3548 if ((err = g_dev_prop_lookup_ints( 3549 map_dev, PORT_ADDR_PROP, &port_addr)) != 0) { 3550 g_dev_map_fini(map_root); 3551 g_free_rls(rls); 3552 return (err); 3553 } 3554 3555 if ((c2 = (struct al_rls *) 3556 g_zalloc(sizeof (struct al_rls))) == NULL) { 3557 g_dev_map_fini(map_root); 3558 g_free_rls(rls); 3559 close(fd); 3560 return (L_MALLOC_FAILED); 3561 } 3562 if (rls == NULL) { 3563 c1 = rls = c2; 3564 } else { 3565 for (c1 = rls; c1->next; c1 = c1->next) {}; 3566 c1 = c1->next = c2; 3567 } 3568 /* Set the al_ha here */ 3569 c1->al_ha = rls_req.port_id = *port_addr; 3570 3571 /* 3572 * fp uses different input/output structures for 3573 * rls. Load the values returned for the fp ioctl 3574 * into the structure passed back to the caller 3575 * Note: There is no reason for the path 3576 * to be loaded into AL_rls as is done for socal/ifp 3577 * above. 3578 */ 3579 if ((hba_port_top == FC_TOP_FABRIC) || 3580 (hba_port_top == FC_TOP_PUBLIC_LOOP)) { 3581 if ((err = g_dev_prop_lookup_bytes( 3582 map_dev, PORT_WWN_PROP, &count, 3583 &port_wwn_byte)) != 0) { 3584 g_dev_map_fini(map_root); 3585 g_free_rls(rls); 3586 return (err); 3587 } 3588 memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE); 3589 if ((err = g_get_dev_port_state( 3590 fp_path, port_wwn, &state)) == 0) { 3591 if (state != PORT_DEVICE_LOGGED_IN) { 3592 if ((err = g_dev_login(fp_path, 3593 port_wwn)) != 0) { 3594 3595 c1->payload.rls_linkfail = 3596 c1->payload.rls_syncfail = 3597 c1->payload.rls_sigfail = 3598 c1->payload.rls_primitiverr = 3599 c1->payload.rls_invalidword = 3600 c1->payload.rls_invalidcrc = 3601 (uint_t)0xffffffff; 3602 if (((map_dev = 3603 g_get_next_dev(map_dev, 3604 &err)) 3605 == NULL) && 3606 (err != 3607 L_NO_SUCH_DEV_FOUND)) { 3608 g_dev_map_fini( 3609 map_root); 3610 g_free_rls(rls); 3611 return (err); 3612 } 3613 continue; 3614 } 3615 } 3616 } /* if g_get_dev_port_state fails proceed. */ 3617 } 3618 3619 fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT; 3620 if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) { 3621 g_dev_map_fini(map_root); 3622 g_free_rls(rls); 3623 return (L_OPEN_PATH_FAIL); 3624 } 3625 fcio.fcio_cmd = FCIO_LINK_STATUS; 3626 fcio.fcio_ibuf = (caddr_t)&rls_req; 3627 fcio.fcio_ilen = sizeof (rls_req); 3628 fcio.fcio_xfer = FCIO_XFER_RW; 3629 fcio.fcio_flags = 0; 3630 fcio.fcio_obuf = (caddr_t)&rls_payload; 3631 fcio.fcio_olen = sizeof (rls_payload); 3632 if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) { 3633 c1->payload.rls_linkfail = 3634 c1->payload.rls_syncfail = 3635 c1->payload.rls_sigfail = 3636 c1->payload.rls_primitiverr = 3637 c1->payload.rls_invalidword = 3638 c1->payload.rls_invalidcrc = (uint_t)0xffffffff; 3639 } else { 3640 /* 3641 * Load the values into the struct passed 3642 * back to the caller 3643 */ 3644 c1->payload.rls_linkfail = rls_payload.rls_link_fail; 3645 c1->payload.rls_syncfail = rls_payload.rls_sync_loss; 3646 c1->payload.rls_sigfail = rls_payload.rls_sig_loss; 3647 c1->payload.rls_primitiverr = 3648 rls_payload.rls_prim_seq_err; 3649 c1->payload.rls_invalidword = 3650 rls_payload.rls_invalid_word; 3651 c1->payload.rls_invalidcrc = 3652 rls_payload.rls_invalid_crc; 3653 } 3654 (void) close(fp_fd); 3655 3656 if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) && 3657 (err != L_NO_SUCH_DEV_FOUND)) { 3658 g_dev_map_fini(map_root); 3659 g_free_rls(rls); 3660 return (err); 3661 } 3662 } 3663 3664 /* for Leadville issue a final call for the initiator */ 3665 3666 if ((err = g_dev_prop_lookup_ints( 3667 map_root, PORT_ADDR_PROP, &port_addr)) != 0) { 3668 g_dev_map_fini(map_root); 3669 g_free_rls(rls); 3670 return (err); 3671 } 3672 3673 if ((c2 = (struct al_rls *) 3674 g_zalloc(sizeof (struct al_rls))) == NULL) { 3675 g_dev_map_fini(map_root); 3676 g_free_rls(rls); 3677 return (L_MALLOC_FAILED); 3678 } 3679 if (rls == NULL) { 3680 c1 = rls = c2; 3681 } else { 3682 for (c1 = rls; c1->next; c1 = c1->next) {}; 3683 c1 = c1->next = c2; 3684 } 3685 3686 c1->al_ha = rls_req.port_id = *port_addr; 3687 3688 if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) { 3689 g_dev_map_fini(map_root); 3690 g_free_rls(rls); 3691 return (L_OPEN_PATH_FAIL); 3692 } 3693 3694 fcio.fcio_cmd = FCIO_LINK_STATUS; 3695 fcio.fcio_ibuf = (caddr_t)&rls_req; 3696 fcio.fcio_ilen = sizeof (rls_req); 3697 fcio.fcio_xfer = FCIO_XFER_RW; 3698 fcio.fcio_flags = 0; 3699 fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT; 3700 fcio.fcio_obuf = (caddr_t)&rls_payload; 3701 fcio.fcio_olen = sizeof (rls_payload); 3702 3703 if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) { 3704 c1->payload.rls_linkfail = 3705 c1->payload.rls_syncfail = 3706 c1->payload.rls_sigfail = 3707 c1->payload.rls_primitiverr = 3708 c1->payload.rls_invalidword = 3709 c1->payload.rls_invalidcrc = (uint_t)0xffffffff; 3710 } else { 3711 /* 3712 * Load the values into the struct passed 3713 * back to the caller 3714 */ 3715 c1->payload.rls_linkfail = rls_payload.rls_link_fail; 3716 c1->payload.rls_syncfail = rls_payload.rls_sync_loss; 3717 c1->payload.rls_sigfail = rls_payload.rls_sig_loss; 3718 c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err; 3719 c1->payload.rls_invalidword = rls_payload.rls_invalid_word; 3720 c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc; 3721 (void) close(fp_fd); 3722 } 3723 (void) close(fp_fd); 3724 3725 *rls_ptr = rls; /* Pass back pointer */ 3726 3727 g_dev_map_fini(map_root); 3728 return (0); 3729 } 3730 3731 static u_longlong_t wwnConversion(uchar_t *wwn) 3732 { 3733 u_longlong_t tmp; 3734 memcpy(&tmp, wwn, sizeof (u_longlong_t)); 3735 return (tmp); 3736 } 3737 3738 /* 3739 * Get device World Wide Name (port and node) for device at path 3740 * and add all WWNs to the wwn_list_found list. 3741 * 3742 * RETURN: 0 O.K. 3743 * 3744 * INPUTS: 3745 * - path_phys must be of a device, either an IB or disk. 3746 */ 3747 static int 3748 get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa, 3749 struct wwn_list_found_struct **wwn_list_found) 3750 { 3751 uint32_t hba_port_top; 3752 int i, err, count; 3753 char *char_ptr, *ptr; 3754 int found = 0, pathcnt, *port_addr; 3755 unsigned long long pwwn; 3756 uchar_t *port_wwn_byte, *node_wwn_byte; 3757 char drvr_path[MAXPATHLEN]; 3758 int p_on = 0, p_st = 0; 3759 mp_pathlist_t pathlist; 3760 char pwwn1[WWN_S_LEN]; 3761 gfc_dev_t map_root, map_dev; 3762 hrtime_t start_time, end_time; 3763 char *env = NULL; 3764 3765 P_DPRINTF(" g_get_wwn: Getting device WWN" 3766 " and al_pa for device: %s\n", 3767 path_phys); 3768 3769 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 3770 start_time = gethrtime(); 3771 } 3772 3773 /* 3774 * Get the loop identifier (switch setting) from the path. 3775 * 3776 * This assumes the path looks something like this: 3777 * /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0 3778 * or 3779 * /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0 3780 */ 3781 if ((char_ptr = strrchr(path_phys, '@')) == NULL) { 3782 return (L_INVLD_PATH_NO_ATSIGN_FND); 3783 } 3784 char_ptr++; /* point to the loop identifier or WWN */ 3785 3786 (void) strcpy(drvr_path, path_phys); 3787 /* This function allocs mem for map.dev_addr on success */ 3788 if (strstr(drvr_path, SCSI_VHCI)) { 3789 if (g_get_pathlist(drvr_path, &pathlist)) { 3790 return (L_INVALID_PATH); 3791 } 3792 pathcnt = pathlist.path_count; 3793 p_on = p_st = 0; 3794 for (i = 0; i < pathcnt; i++) { 3795 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 3796 if (pathlist.path_info[i].path_state == 3797 MDI_PATHINFO_STATE_ONLINE) { 3798 p_on = i; 3799 break; 3800 } else if (pathlist.path_info[i].path_state == 3801 MDI_PATHINFO_STATE_STANDBY) { 3802 p_st = i; 3803 } 3804 } 3805 } 3806 if (p_on == i) { 3807 /* on_line path */ 3808 (void) strcpy(drvr_path, 3809 pathlist.path_info[p_on].path_hba); 3810 (void) strncpy(pwwn1, 3811 pathlist.path_info[p_on].path_addr, 3812 WWN_S_LEN - 1); 3813 pwwn1[WWN_S_LEN - 1] = '\0'; 3814 } else { 3815 /* standby or path0 */ 3816 (void) strcpy(drvr_path, 3817 pathlist.path_info[p_st].path_hba); 3818 (void) strncpy(pwwn1, 3819 pathlist.path_info[p_st].path_addr, 3820 WWN_S_LEN - 1); 3821 pwwn1[WWN_S_LEN - 1] = '\0'; 3822 } 3823 free(pathlist.path_info); 3824 (void) strcat(drvr_path, FC_CTLR); 3825 } 3826 if ((map_root = g_dev_map_init(drvr_path, &err, 3827 MAP_XPORT_PROP_ONLY)) == NULL) { 3828 return (err); 3829 } 3830 3831 if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) { 3832 g_dev_map_fini(map_root); 3833 return (err); 3834 } 3835 3836 if (strstr(path_phys, SCSI_VHCI)) { 3837 char_ptr = pwwn1; 3838 } else { 3839 /* 3840 * Format of WWN is 3841 * ssd@w2200002037000f96,0:a,raw 3842 */ 3843 if (*char_ptr != 'w') { 3844 g_dev_map_fini(map_root); 3845 return (L_INVLD_WWN_FORMAT); 3846 } 3847 char_ptr++; 3848 } 3849 pwwn = strtoull(char_ptr, &ptr, 16); 3850 if (ptr == char_ptr) { 3851 g_dev_map_fini(map_root); 3852 return (L_NO_WWN_FOUND_IN_PATH); 3853 } 3854 P_DPRINTF(" g_get_wwn: Looking for WWN " 3855 "0x%llx\n", pwwn); 3856 3857 if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) && 3858 (err != L_NO_SUCH_DEV_FOUND)) { 3859 g_dev_map_fini(map_root); 3860 return (err); 3861 } 3862 3863 while (map_dev) { 3864 if ((err = g_dev_prop_lookup_bytes(map_dev, 3865 PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) { 3866 g_dev_map_fini(map_root); 3867 return (err); 3868 } 3869 if ((err = g_dev_prop_lookup_bytes(map_dev, 3870 NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) { 3871 g_dev_map_fini(map_root); 3872 return (err); 3873 } 3874 3875 if (pwwn == wwnConversion(port_wwn_byte) && found != 1) { 3876 found = 1; 3877 memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE); 3878 memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE); 3879 if ((err = g_dev_prop_lookup_ints( 3880 map_dev, PORT_ADDR_PROP, &port_addr)) != 0) { 3881 g_dev_map_fini(map_root); 3882 return (err); 3883 } 3884 *al_pa = *port_addr; 3885 } 3886 add_wwn_entry(wwn_list_found, port_wwn_byte, 3887 node_wwn_byte); 3888 3889 if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) && 3890 (err != L_NO_SUCH_DEV_FOUND)) { 3891 g_dev_map_fini(map_root); 3892 return (err); 3893 } 3894 } 3895 if (!found) { 3896 g_dev_map_fini(map_root); 3897 return (L_NO_LOOP_ADDRS_FOUND); 3898 } 3899 3900 g_dev_map_fini(map_root); 3901 if (env != NULL) { 3902 end_time = gethrtime(); 3903 fprintf(stdout, " get_wwns: " 3904 "\t\tTime = %lld millisec\n", 3905 (end_time - start_time)/1000000); 3906 } 3907 return (0); 3908 } 3909 3910 /* 3911 * Get device World Wide Name and AL_PA for device at path 3912 * 3913 * RETURN: 0 O.K. 3914 * 3915 * INPUTS: 3916 * - path_phys must be of a device, either an IB or disk. 3917 */ 3918 int 3919 g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], 3920 int *al_pa, int verbose) 3921 { 3922 struct wwn_list_found_struct *wwn_list_found = NULL; 3923 int ret; 3924 3925 /* return invalid path if the argument is NULL */ 3926 if (path_phys == NULL) { 3927 return (L_INVALID_PATH); 3928 } 3929 /* return invalid arg if the argument is NULL */ 3930 if ((port_wwn == NULL) || (node_wwn == NULL) || (al_pa == NULL)) { 3931 return (L_INVALID_ARG); 3932 } 3933 3934 ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found); 3935 g_free_wwn_list_found(&wwn_list_found); 3936 return (ret); 3937 } 3938 3939 int 3940 g_get_serial_number(char *path, uchar_t *serial_number, 3941 size_t *serial_number_len) 3942 { 3943 int fd, status = 0; 3944 L_inquiry80 inq80; 3945 3946 /* return invalid path if path is NULL */ 3947 if (path == NULL) { 3948 return (L_INVALID_PATH); 3949 } 3950 /* return invalid arg if serial_number is NULL */ 3951 if (serial_number == NULL) { 3952 return (L_INVALID_ARG); 3953 } 3954 3955 P_DPRINTF(" g_get_serial_number: path: %s\n", path); 3956 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) { 3957 return (L_OPEN_PATH_FAIL); 3958 } 3959 /* 3960 * Call the inquiry cmd on page 0x80 only if the vendor 3961 * supports page 0x80. 3962 */ 3963 if ((g_find_supported_inq_page(fd, 0x80))) { 3964 /* 3965 * Let's retrieve the serial number from page 0x80 3966 * and store it in the inquiry structure 3967 */ 3968 status = g_scsi_inquiry_cmd80(fd, 3969 (uchar_t *)&inq80, 3970 sizeof (struct l_inquiry80_struct)); 3971 if (status == 0) { 3972 if (*serial_number_len > inq80.inq_page_len) 3973 *serial_number_len = inq80.inq_page_len; 3974 strncpy((char *)serial_number, (char *)inq80.inq_serial, 3975 *serial_number_len); 3976 } else { 3977 char unavail[] = "Unavailable"; 3978 status = 0; 3979 if (*serial_number_len > strlen(unavail)) 3980 *serial_number_len = strlen(unavail); 3981 strncpy((char *)serial_number, unavail, 3982 *serial_number_len); 3983 } 3984 } else { 3985 /* 3986 * page 0x80 is not supported, so print the 3987 * appropriate message. 3988 */ 3989 char unsupp[] = "Unsupported"; 3990 if (*serial_number_len > strlen(unsupp)) 3991 *serial_number_len = strlen(unsupp); 3992 strncpy((char *)serial_number, unsupp, 3993 *serial_number_len); 3994 } 3995 (void) close(fd); 3996 return (status); 3997 } 3998 3999 int 4000 g_get_inquiry(char *path, L_inquiry *l_inquiry) 4001 { 4002 int fd, status; 4003 4004 /* return invalid path if path is NULL */ 4005 if (path == NULL) { 4006 return (L_INVALID_PATH); 4007 } 4008 /* return invalid arg if l_inquiry is NULL */ 4009 if (l_inquiry == NULL) { 4010 return (L_INVALID_ARG); 4011 } 4012 4013 P_DPRINTF(" g_get_inquiry: path: %s\n", path); 4014 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4015 return (L_OPEN_PATH_FAIL); 4016 status = g_scsi_inquiry_cmd(fd, 4017 (uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct)); 4018 4019 (void) close(fd); 4020 return (status); 4021 } 4022 4023 /* 4024 * Function to retrieve inquiry page 0x80 from the device 4025 */ 4026 static int 4027 g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len) 4028 { 4029 struct uscsi_cmd ucmd; 4030 my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0}; 4031 struct scsi_extended_sense sense; 4032 4033 (void) memset(buf_ptr, 0, buf_len); 4034 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 4035 cdb.count = (uchar_t)buf_len; 4036 ucmd.uscsi_cdb = (caddr_t)&cdb; 4037 ucmd.uscsi_cdblen = CDB_GROUP0; 4038 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 4039 ucmd.uscsi_buflen = buf_len; 4040 ucmd.uscsi_rqbuf = (caddr_t)&sense; 4041 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 4042 ucmd.uscsi_timeout = 60; 4043 return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT)); 4044 } 4045 4046 /* 4047 * Function to determine if the given page is supported by vendor. 4048 */ 4049 static int 4050 g_find_supported_inq_page(int fd, int page_num) 4051 { 4052 struct uscsi_cmd ucmd; 4053 my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0}; 4054 struct scsi_extended_sense sense; 4055 L_inquiry00 inq00; 4056 uchar_t *data; 4057 int status = 0; 4058 int index; 4059 4060 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 4061 cdb.count = (uchar_t)(sizeof (L_inquiry00)); 4062 ucmd.uscsi_cdb = (caddr_t)&cdb; 4063 ucmd.uscsi_cdblen = CDB_GROUP0; 4064 ucmd.uscsi_bufaddr = (caddr_t)&inq00; 4065 ucmd.uscsi_buflen = sizeof (inq00); 4066 ucmd.uscsi_rqbuf = (caddr_t)&sense; 4067 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 4068 ucmd.uscsi_timeout = 60; 4069 status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT); 4070 if (status) { 4071 return (0); 4072 } 4073 data = (uchar_t *)&inq00; 4074 for (index = 4; (index <= inq00.len+3)&& 4075 (data[index] <= page_num); index ++) { 4076 if (data[index] == page_num) { 4077 return (1); 4078 } 4079 } 4080 return (0); 4081 } 4082 4083 int 4084 g_get_perf_statistics(char *path, uchar_t *perf_ptr) 4085 { 4086 int fd; 4087 4088 P_DPRINTF(" g_get_perf_statistics: Get Performance Statistics:" 4089 "\n Path:%s\n", 4090 path); 4091 4092 /* initialize tables */ 4093 (void) memset(perf_ptr, 0, sizeof (int)); 4094 4095 /* open controller */ 4096 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4097 return (L_OPEN_PATH_FAIL); 4098 4099 4100 /* update parameters in the performance table */ 4101 4102 /* get the period in seconds */ 4103 4104 4105 (void) close(fd); 4106 4107 return (0); 4108 } 4109 4110 4111 int 4112 g_start(char *path) 4113 { 4114 int status; 4115 int fd; 4116 4117 P_DPRINTF(" g_start: Start: Path %s\n", path); 4118 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4119 return (L_OPEN_PATH_FAIL); 4120 status = g_scsi_start_cmd(fd); 4121 (void) close(fd); 4122 return (status); 4123 } 4124 4125 int 4126 g_stop(char *path, int immediate_flag) 4127 { 4128 int status, fd; 4129 4130 P_DPRINTF(" g_stop: Stop: Path %s\n", path); 4131 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4132 return (errno); 4133 status = g_scsi_stop_cmd(fd, immediate_flag); 4134 (void) close(fd); 4135 return (status); 4136 } 4137 4138 int 4139 g_reserve(char *path) 4140 { 4141 int fd, status; 4142 4143 P_DPRINTF(" g_reserve: Reserve: Path %s\n", path); 4144 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4145 return (L_OPEN_PATH_FAIL); 4146 status = g_scsi_reserve_cmd(fd); 4147 (void) close(fd); 4148 return (status); 4149 } 4150 4151 int 4152 g_release(char *path) 4153 { 4154 int fd, status; 4155 4156 P_DPRINTF(" g_release: Release: Path %s\n", path); 4157 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) 4158 return (L_OPEN_PATH_FAIL); 4159 status = g_scsi_release_cmd(fd); 4160 (void) close(fd); 4161 return (status); 4162 } 4163 4164 static char 4165 ctoi(char c) 4166 { 4167 if ((c >= '0') && (c <= '9')) 4168 c -= '0'; 4169 else if ((c >= 'A') && (c <= 'F')) 4170 c = c - 'A' + 10; 4171 else if ((c >= 'a') && (c <= 'f')) 4172 c = c - 'a' + 10; 4173 else 4174 c = -1; 4175 return (c); 4176 } 4177 4178 int 4179 g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp) 4180 { 4181 int i; 4182 char c, c1; 4183 4184 *wwnp++ = 0; 4185 *wwnp++ = 0; 4186 for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) { 4187 c = ctoi(*wwn++); 4188 c1 = ctoi(*wwn++); 4189 if (c == -1 || c1 == -1) 4190 return (-1); 4191 *wwnp = ((c << 4) + c1); 4192 } 4193 4194 return (0); 4195 4196 } 4197 4198 /* 4199 * Converts a string of WWN ASCII characters to a 4200 * binary representation. 4201 * 4202 * Input: string - pointer to uchar_t array 4203 * WWN in ASCII 4204 * length: 16 bytes 4205 * Output: wwn - pointer to uchar_t array 4206 * containing WWN result 4207 * length: 8 bytes 4208 * Returns: 4209 * non-zero on error 4210 * zero on success 4211 */ 4212 int 4213 string_to_wwn(uchar_t *string, uchar_t *wwn) 4214 { 4215 int i; 4216 char c, c1; 4217 uchar_t *wwnp; 4218 4219 wwnp = wwn; 4220 4221 for (i = 0; i < WWN_SIZE; i++, wwnp++) { 4222 4223 c = ctoi(*string++); 4224 c1 = ctoi(*string++); 4225 if (c == -1 || c1 == -1) 4226 return (-1); 4227 *wwnp = ((c << 4) + c1); 4228 } 4229 4230 return (0); 4231 4232 } 4233 4234 4235 /* 4236 * Get multiple paths to a given device port. 4237 * INPUTS: 4238 * port WWN string. 4239 */ 4240 int 4241 g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose) 4242 { 4243 int err; 4244 WWN_list *wwn_list, *wwn_list_ptr; 4245 struct dlist *dlt, *dl; 4246 4247 4248 /* Initialize list structures. */ 4249 dl = *dlh = dlt = (struct dlist *)NULL; 4250 wwn_list = wwn_list_ptr = NULL; 4251 4252 H_DPRINTF(" g_get_port_multipath: Looking for multiple paths for" 4253 " device with\n port WWW:" 4254 "%s\n", port_wwn_s); 4255 4256 if (err = g_get_wwn_list(&wwn_list, verbose)) { 4257 return (err); 4258 } 4259 4260 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; 4261 wwn_list_ptr = wwn_list_ptr->wwn_next) { 4262 if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) { 4263 if ((dl = (struct dlist *) 4264 g_zalloc(sizeof (struct dlist))) == NULL) { 4265 while (*dlh != NULL) { 4266 dl = (*dlh)->next; 4267 (void) g_destroy_data(*dlh); 4268 *dlh = dl; 4269 } 4270 (void) g_free_wwn_list(&wwn_list); 4271 return (L_MALLOC_FAILED); 4272 } 4273 H_DPRINTF(" g_get_port_multipath:" 4274 " Found multipath:\n %s\n", 4275 wwn_list_ptr->physical_path); 4276 dl->dev_path = strdup(wwn_list_ptr->physical_path); 4277 dl->logical_path = strdup(wwn_list_ptr->logical_path); 4278 if (*dlh == NULL) { 4279 *dlh = dlt = dl; 4280 } else { 4281 dlt->next = dl; 4282 dl->prev = dlt; 4283 dlt = dl; 4284 } 4285 } 4286 } 4287 (void) g_free_wwn_list(&wwn_list); 4288 return (0); 4289 } 4290 4291 4292 4293 /* 4294 * Get multiple paths to a given disk/tape device. 4295 * The arg: devpath should be the physical path to device. 4296 * 4297 * OUTPUT: 4298 * multipath_list points to a list of multiple paths to the device. 4299 * NOTE: The caller must free the allocated list (dlist). 4300 * 4301 * RETURNS: 4302 * 0 if O.K. 4303 * non-zero otherwise 4304 */ 4305 int 4306 g_get_multipath(char *devpath, struct dlist **multipath_list, 4307 struct wwn_list_struct *wwn_list, int verbose) 4308 { 4309 int err; 4310 4311 H_DPRINTF(" g_get_multipath: Looking for multiple paths for" 4312 " device at path: %s\n", devpath); 4313 4314 /* return invalid path if devpath is NULL */ 4315 if (devpath == NULL) { 4316 return (L_INVALID_PATH); 4317 } 4318 /* return invalid arg if argument is NULL */ 4319 if ((multipath_list == NULL) || (wwn_list == NULL)) { 4320 return (L_INVALID_ARG); 4321 } 4322 4323 if (strstr(devpath, DRV_NAME_SSD) != NULL) { 4324 err = get_multipath_disk(devpath, multipath_list, wwn_list); 4325 } else { 4326 err = get_multipath(devpath, multipath_list, wwn_list); 4327 } 4328 4329 return (err); 4330 } 4331 4332 4333 /* 4334 * Returns multipath information for a ssd device. 4335 * Inputs: 4336 * devpath: device path to for requested multipath info 4337 * wwn_list: returned from g_get_wwn_list or devices_get_all 4338 * Output: 4339 * multipath_list: dlist list of paths 4340 * Returns: 4341 * 0 on success 4342 * non-zero on failure 4343 */ 4344 int 4345 get_multipath_disk(char *devpath, struct dlist **multipath_list, 4346 struct wwn_list_struct *wwn_list) 4347 { 4348 WWN_list *wwn_list_ptr; 4349 struct dlist *dl = NULL, *dlt = NULL; 4350 ddi_devid_t devid = NULL; 4351 int err; 4352 di_node_t root; 4353 struct mplist_struct *mplistp = NULL, *mplisth = NULL; 4354 4355 if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) { 4356 return (L_NULL_WWN_LIST); 4357 } 4358 4359 if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 4360 return (L_DEV_SNAPSHOT_FAILED); 4361 } 4362 4363 if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) { 4364 di_fini(root); 4365 return (err); 4366 } 4367 4368 *multipath_list = (struct dlist *)NULL; 4369 if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) { 4370 di_fini(root); 4371 return (err); 4372 } 4373 4374 if (mplisth == NULL) { 4375 di_fini(root); 4376 return (L_NULL_WWN_LIST); 4377 } 4378 4379 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; 4380 wwn_list_ptr = wwn_list_ptr->wwn_next) { 4381 /* 4382 * When a path is found from the list, load the logical 4383 * and physical dev path 4384 */ 4385 for (mplistp = mplisth; mplistp != NULL; 4386 mplistp = mplistp->next) { 4387 if (strncmp(mplistp->devpath, 4388 wwn_list_ptr->physical_path, 4389 strlen(mplistp->devpath)) == 0) { 4390 4391 /* Load multipath list */ 4392 if ((dl = (struct dlist *) 4393 calloc(1, sizeof (struct dlist))) == NULL) { 4394 while (*multipath_list != NULL) { 4395 dl = dlt->next; 4396 g_destroy_data(dlt); 4397 dlt = dl; 4398 } 4399 di_fini(root); 4400 return (L_MALLOC_FAILED); 4401 } 4402 H_DPRINTF( 4403 " g_get_multipath: Found multipath=%s\n", 4404 wwn_list_ptr->physical_path); 4405 dl->logical_path = 4406 strdup(wwn_list_ptr->logical_path); 4407 dl->dev_path = 4408 strdup(wwn_list_ptr->physical_path); 4409 if (*multipath_list == NULL) { 4410 *multipath_list = dlt = dl; 4411 } else { 4412 dlt->next = dl; 4413 dl->prev = dlt; 4414 dlt = dl; 4415 } 4416 } 4417 } 4418 } 4419 di_fini(root); 4420 mplist_free(mplisth); 4421 return (0); 4422 } 4423 4424 int 4425 get_multipath(char *devpath, struct dlist **multipath_list, 4426 struct wwn_list_struct *wwn_list) 4427 { 4428 WWN_list *wwn_list_ptr; 4429 struct dlist *dl, *dlt; 4430 char path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr; 4431 int len; 4432 int lun_a = -1; 4433 char node_wwn_s[WWN_S_LEN]; 4434 4435 if (devpath == NULL) { 4436 return (L_INVALID_PATH); 4437 } 4438 4439 /* Strip partition information. */ 4440 if ((ptr = strrchr(devpath, ':')) != NULL) { 4441 len = strlen(devpath) - strlen(ptr); 4442 (void) strncpy(path, devpath, len); 4443 path[len] = '\0'; 4444 } else { 4445 (void) strcpy(path, devpath); 4446 } 4447 4448 *multipath_list = dl = dlt = (struct dlist *)NULL; 4449 4450 4451 if (wwn_list == NULL) { 4452 return (L_NULL_WWN_LIST); 4453 } 4454 4455 for (*node_wwn_s = NULL, wwn_list_ptr = wwn_list; 4456 wwn_list_ptr != NULL; 4457 wwn_list_ptr = wwn_list_ptr->wwn_next) { 4458 4459 if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) { 4460 len = strlen(wwn_list_ptr->physical_path) - strlen(ptr); 4461 (void) strncpy(m_phys_path, wwn_list_ptr->physical_path, 4462 len); 4463 m_phys_path[len] = '\0'; 4464 } else { 4465 (void) strcpy(m_phys_path, wwn_list_ptr->physical_path); 4466 } 4467 4468 if (strcasecmp(m_phys_path, path) == 0) { 4469 (void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s); 4470 break; 4471 } 4472 } 4473 4474 if (*node_wwn_s == NULL) { 4475 H_DPRINTF("node_wwn_s is NULL!\n"); 4476 return (L_NO_NODE_WWN_IN_WWNLIST); 4477 } 4478 4479 lun_a = g_get_lun_number(wwn_list_ptr->physical_path); 4480 4481 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; 4482 wwn_list_ptr = wwn_list_ptr->wwn_next) { 4483 if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) && 4484 ((lun_a < 0) || (lun_a == 4485 g_get_lun_number(wwn_list_ptr->physical_path)))) { 4486 4487 if ((dl = (struct dlist *) 4488 g_zalloc(sizeof (struct dlist))) == NULL) { 4489 while (*multipath_list != NULL) { 4490 dl = dlt->next; 4491 (void) g_destroy_data(dlt); 4492 dlt = dl; 4493 } 4494 return (L_MALLOC_FAILED); 4495 } 4496 H_DPRINTF(" g_get_multipath: Found multipath=%s\n", 4497 wwn_list_ptr->physical_path); 4498 dl->dev_path = strdup(wwn_list_ptr->physical_path); 4499 dl->logical_path = strdup(wwn_list_ptr->logical_path); 4500 if (*multipath_list == NULL) { 4501 *multipath_list = dlt = dl; 4502 } else { 4503 dlt->next = dl; 4504 dl->prev = dlt; 4505 dlt = dl; 4506 } 4507 } 4508 } 4509 return (0); 4510 } 4511 4512 /* 4513 * Free a multipath list 4514 * 4515 */ 4516 void 4517 g_free_multipath(struct dlist *dlh) 4518 { 4519 struct dlist *dl; 4520 4521 while (dlh != NULL) { 4522 dl = dlh->next; 4523 if (dlh->dev_path != NULL) 4524 (void) g_destroy_data(dlh->dev_path); 4525 if (dlh->logical_path != NULL) 4526 (void) g_destroy_data(dlh->logical_path); 4527 (void) g_destroy_data(dlh); 4528 dlh = dl; 4529 } 4530 } 4531 4532 4533 4534 /* 4535 * Get the path to the nexus (HBA) driver. 4536 * This assumes the path looks something like this: 4537 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 4538 * or maybe this 4539 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0 4540 * or 4541 * /devices/sbus@1f,0/SUNW,socal@1,0 4542 * or 4543 * /devices/sbus@1f,0/SUNW,socal@1,0:1 4544 * or 4545 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 4546 * (or "qlc" instead of "socal" and "fp" for "sf") 4547 * 4548 * Which should resolve to a path like this: 4549 * /devices/sbus@1f,0/SUNW,socal@1,0:1 4550 * or 4551 * /devices/pci@6,2000/pci@2/SUNW,qlc@5 4552 * 4553 * or 4554 * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0 4555 * which should resolve to 4556 * /devices/pci@4,2000/scsi@1:devctl 4557 */ 4558 int 4559 g_get_nexus_path(char *path_phys, char **nexus_path) 4560 { 4561 uchar_t port = 0; 4562 int port_flag = 0, i = 0, pathcnt = 1; 4563 char *char_ptr; 4564 char drvr_path[MAXPATHLEN]; 4565 char buf[MAXPATHLEN]; 4566 char temp_buf[MAXPATHLEN]; 4567 struct stat stbuf; 4568 uint_t path_type; 4569 mp_pathlist_t pathlist; 4570 int p_on = 0, p_st = 0; 4571 4572 /* return invalid path if the path_phys is NULL */ 4573 if (path_phys == NULL) { 4574 return (L_INVALID_PATH); 4575 } 4576 4577 *nexus_path = NULL; 4578 (void) strcpy(drvr_path, path_phys); 4579 4580 if (strstr(path_phys, SCSI_VHCI)) { 4581 if (g_get_pathlist(drvr_path, &pathlist)) { 4582 return (L_INVALID_PATH); 4583 } 4584 pathcnt = pathlist.path_count; 4585 p_on = p_st = 0; 4586 for (i = 0; i < pathcnt; i++) { 4587 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 4588 if (pathlist.path_info[i].path_state == 4589 MDI_PATHINFO_STATE_ONLINE) { 4590 p_on = i; 4591 break; 4592 } else if (pathlist.path_info[i].path_state == 4593 MDI_PATHINFO_STATE_STANDBY) { 4594 p_st = i; 4595 } 4596 } 4597 } 4598 if (pathlist.path_info[p_on].path_state == 4599 MDI_PATHINFO_STATE_ONLINE) { 4600 /* on_line path */ 4601 (void) strcpy(drvr_path, 4602 pathlist.path_info[p_on].path_hba); 4603 } else { 4604 /* standby or path0 */ 4605 (void) strcpy(drvr_path, 4606 pathlist.path_info[p_st].path_hba); 4607 } 4608 free(pathlist.path_info); 4609 (void) strcat(drvr_path, FC_CTLR); 4610 } else { 4611 if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path, 4612 DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) { 4613 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { 4614 return (L_INVALID_PATH); 4615 } 4616 *char_ptr = '\0'; /* Terminate string */ 4617 } 4618 4619 path_type = g_get_path_type(drvr_path); 4620 4621 if (path_type & FC4_SF_XPORT) { 4622 4623 /* sf driver in path so capture the port # */ 4624 if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) { 4625 return (L_INVALID_PATH); 4626 } 4627 port = atoi(char_ptr + 3); 4628 if (port > 1) { 4629 return (L_INVLD_PORT_IN_PATH); 4630 } 4631 4632 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { 4633 return (L_INVALID_PATH); 4634 } 4635 *char_ptr = '\0'; /* Terminate string */ 4636 port_flag++; 4637 4638 L_DPRINTF(" g_get_nexus_path:" 4639 " sf driver in path so use port #%d.\n", 4640 port); 4641 } else if (path_type & FC_GEN_XPORT) { 4642 /* 4643 * check to see if it 3rd party vendor FCA. 4644 * if it is return error for this operation since 4645 * we don't know how they creates FCA port related minor node. 4646 * 4647 * As of now there is no supported operation on FCA node so 4648 * this should be okay. 4649 */ 4650 if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) { 4651 return (L_INVALID_PATH_TYPE); 4652 } 4653 /* 4654 * For current Sun FCA driver, appending 4655 * port # doesn't work. Just remove transport layer from 4656 * input path. 4657 */ 4658 if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) { 4659 return (L_INVALID_PATH); 4660 } 4661 *char_ptr = '\0'; /* Terminate string */ 4662 } 4663 4664 if (stat(drvr_path, &stbuf) != 0) { 4665 return (L_LSTAT_ERROR); 4666 } 4667 4668 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 4669 /* 4670 * Found a directory. 4671 * Now append a port number or devctl to the path. 4672 */ 4673 if (port_flag) { 4674 /* append port */ 4675 (void) sprintf(buf, ":%d", port); 4676 } else { 4677 /* Try adding port 0 and see if node exists. */ 4678 (void) sprintf(temp_buf, "%s:0", drvr_path); 4679 if (stat(temp_buf, &stbuf) != 0) { 4680 /* 4681 * Path we guessed at does not 4682 * exist so it may be a driver 4683 * that ends in :devctl. 4684 */ 4685 (void) sprintf(buf, ":devctl"); 4686 } else { 4687 /* 4688 * The path that was entered 4689 * did not include a port number 4690 * so the port was set to zero, and 4691 * then checked. The default path 4692 * did exist. 4693 */ 4694 ER_DPRINTF("Since a complete path" 4695 " was not supplied " 4696 "a default path is being" 4697 " used:\n %s\n", 4698 temp_buf); 4699 (void) sprintf(buf, ":0"); 4700 } 4701 } 4702 4703 (void) strcat(drvr_path, buf); 4704 } 4705 4706 } 4707 *nexus_path = g_alloc_string(drvr_path); 4708 L_DPRINTF(" g_get_nexus_path: Nexus path = %s\n", drvr_path); 4709 return (0); 4710 } 4711 4712 4713 /* 4714 * Get the FC topology for the input device or nexus(HBA) path. 4715 * 4716 * The routine calls g_get_path_type to determine the stack of 4717 * the input path. 4718 * 4719 * If it a socal path 4720 * it returns FC_TOP_PRIVATE_LOOP 4721 * else 4722 * calls fc_get_topology ioctl to 4723 * get the fp topolgy from the driver. 4724 * 4725 * INPUTS: 4726 * path - a string of device path, transport path. 4727 * NOTE: "path" SHOULD NOT BE OPEN BEFORE CALLING 4728 * THIS FUNCTION BECAUSE THIS FUNCTION DOES 4729 * AN "O_EXCL" OPEN. 4730 * port_top - a pointer to the toplogy type. 4731 * 4732 * RETURNS: 4733 * 0 if there is no error. 4734 * error code. 4735 * 4736 * The input path is expected to be something like below: 4737 * 1) 4738 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 4739 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@.. 4740 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0 4741 * /devices/sbus@1f,0/SUNW,socal@1,0 4742 * /devices/sbus@1f,0/SUNW,socal@1,0:1 4743 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 4744 * (or "qlc" instead of "socal" and "fp" for "sf") 4745 * 4746 * Which should resolve to a path like this: 4747 * /devices/sbus@1f,0/SUNW,socal@1,0:1 4748 * /devices/pci@6,2000/pci@2/SUNW,qlc@5 4749 * 4750 * 2) 4751 * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0 4752 * which should resolve to 4753 * /devices/pci@4,2000/scsi@1:devctl 4754 * 4755 * 3) The nexus(hba or nexus) path will get an error only for qlc 4756 * since the routine need to open fp :devctl node for fcio ioctl. 4757 * /devices/sbus@1f,0/SUNW,socal@1,0 4758 * /devices/sbus@1f,0/SUNW,socal@1,0:1 4759 * /devices/pci@6,2000/pci@2/SUNW,qlc@5 => error 4760 */ 4761 int 4762 g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose) 4763 { 4764 fcio_t fcio; 4765 int fd, i = 0, pathcnt = 1; 4766 char drvr_path[MAXPATHLEN]; 4767 char *char_ptr; 4768 struct stat stbuf; 4769 uint_t dev_type; 4770 mp_pathlist_t pathlist; 4771 int p_on = 0, p_st = 0; 4772 4773 /* return invalid path if the path is NULL */ 4774 if (path == NULL) { 4775 return (L_INVALID_PATH); 4776 } 4777 /* return invalid arg if the argument is NULL */ 4778 if (port_top == NULL) { 4779 return (L_INVALID_ARG); 4780 } 4781 4782 (void) strcpy(drvr_path, path); 4783 if (strstr(path, SCSI_VHCI)) { 4784 if (g_get_pathlist(drvr_path, &pathlist)) { 4785 return (L_INVALID_PATH); 4786 } 4787 pathcnt = pathlist.path_count; 4788 p_on = p_st = 0; 4789 for (i = 0; i < pathcnt; i++) { 4790 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 4791 if (pathlist.path_info[i].path_state == 4792 MDI_PATHINFO_STATE_ONLINE) { 4793 p_on = i; 4794 break; 4795 } else if (pathlist.path_info[i].path_state == 4796 MDI_PATHINFO_STATE_STANDBY) { 4797 p_st = i; 4798 } 4799 } 4800 } 4801 if (pathlist.path_info[p_on].path_state == 4802 MDI_PATHINFO_STATE_ONLINE) { 4803 /* on_line path */ 4804 (void) strcpy(drvr_path, 4805 pathlist.path_info[p_on].path_hba); 4806 } else { 4807 /* standby or path0 */ 4808 (void) strcpy(drvr_path, 4809 pathlist.path_info[p_st].path_hba); 4810 } 4811 free(pathlist.path_info); 4812 (void) strcat(drvr_path, FC_CTLR); 4813 } else { 4814 /* 4815 * Get the path to the :devctl driver 4816 * 4817 * This assumes the path looks something like this: 4818 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 4819 * or 4820 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0 4821 * or 4822 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl 4823 * or 4824 * a 1 level PCI type driver but still :devctl 4825 * (or "qlc" in the place of "socal" and "fp" for "sf") 4826 * 4827 * The dir below doesn't have corresponding :devctl node. 4828 * /devices/pci@6,2000/pci@2/SUNW,qlc@5 4829 * /devices/sbus@2,0/SUNW,socal@1,0 4830 * 4831 */ 4832 if ((strstr(drvr_path, DRV_NAME_SSD) || 4833 strstr(drvr_path, SES_NAME)) || 4834 strstr(drvr_path, DRV_NAME_ST)) { 4835 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { 4836 return (L_INVALID_PATH); 4837 } 4838 *char_ptr = '\0'; /* Terminate sting */ 4839 /* append controller */ 4840 (void) strcat(drvr_path, FC_CTLR); 4841 } else { 4842 if (stat(drvr_path, &stbuf) < 0) { 4843 return (L_LSTAT_ERROR); 4844 } 4845 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 4846 /* append controller */ 4847 (void) strcat(drvr_path, FC_CTLR); 4848 } 4849 } 4850 } 4851 4852 if ((dev_type = g_get_path_type(drvr_path)) == 0) { 4853 return (L_INVALID_PATH); 4854 } 4855 4856 if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) { 4857 *port_top = FC_TOP_PRIVATE_LOOP; 4858 return (0); 4859 } 4860 4861 /* To contiue the path type should be fp :devctl node */ 4862 if (!(dev_type & FC_XPORT_MASK)) { 4863 return (L_INVALID_PATH); 4864 } 4865 4866 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) 4867 return (errno); 4868 4869 P_DPRINTF(" g_get_fca_port_topology: Geting topology from:" 4870 " %s\n", drvr_path); 4871 4872 fcio.fcio_cmd = FCIO_GET_TOPOLOGY; 4873 fcio.fcio_olen = sizeof (uint32_t); 4874 fcio.fcio_xfer = FCIO_XFER_READ; 4875 fcio.fcio_obuf = (caddr_t)port_top; 4876 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) { 4877 I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n"); 4878 close(fd); 4879 return (L_FCIO_GET_TOPOLOGY_FAIL); 4880 } 4881 close(fd); 4882 return (0); 4883 } 4884 4885 4886 /* 4887 * This functions enables or disables a FCA port depending on the 4888 * argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function 4889 * tries to disable the port specified by the argument 'phys_path'. If 4890 * cmd is PORT_ONLINE, the function tries to enable the port specified 4891 * by the argument 'phys_path'. 4892 * INPUTS : 4893 * nexus_port_ptr - Pointer to the nexus path of the FCA port to 4894 * operate on 4895 * cmd - PORT_OFFLINE or PORT_ONLINE 4896 * RETURNS : 4897 * 0 on success and non-zero otherwise 4898 */ 4899 static int 4900 g_set_port_state(char *nexus_port_ptr, int cmd) 4901 { 4902 int path_type, fd; 4903 4904 if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) { 4905 return (L_INVALID_PATH); 4906 } 4907 4908 if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) { 4909 return (L_OPEN_PATH_FAIL); 4910 } 4911 4912 switch (cmd) { 4913 case PORT_OFFLINE: 4914 if (path_type & FC4_SOCAL_FCA) { 4915 /* 4916 * Socal/sf drivers - 4917 * The socal driver currently returns EFAULT 4918 * even if the ioctl has completed successfully. 4919 */ 4920 if (ioctl(fd, FCIO_LOOPBACK_INTERNAL, 4921 NULL) == -1) { 4922 close(fd); 4923 return (L_PORT_OFFLINE_FAIL); 4924 } 4925 } else { 4926 /* 4927 * QLogic card - 4928 * Can't do much here since the driver currently 4929 * doesn't support this feature. We'll just fail 4930 * for now. Support can be added when the driver 4931 * is enabled with the feature at a later date. 4932 */ 4933 close(fd); 4934 return (L_PORT_OFFLINE_UNSUPPORTED); 4935 } 4936 break; 4937 case PORT_ONLINE: 4938 if (path_type & FC4_SOCAL_FCA) { 4939 /* 4940 * Socal/sf drivers 4941 * The socal driver currently returns EFAULT 4942 * even if the ioctl has completed successfully. 4943 */ 4944 if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) { 4945 close(fd); 4946 return (L_PORT_ONLINE_FAIL); 4947 } 4948 } else { 4949 /* 4950 * QLogic card - 4951 * Can't do much here since the driver currently 4952 * doesn't support this feature. We'll just fail 4953 * for now. Support can be added when the driver 4954 * is enabled with the feature at a later date. 4955 */ 4956 close(fd); 4957 return (L_PORT_ONLINE_UNSUPPORTED); 4958 } 4959 break; 4960 default: 4961 close(fd); 4962 return (-1); 4963 } 4964 close(fd); 4965 return (0); 4966 } 4967 4968 /* 4969 * The interfaces defined below (g_port_offline() and g_port_online()) 4970 * are what will be exposed to applications. We will hide g_set_port_state(). 4971 * They have to be functions (as against macros) because making them 4972 * macros will mean exposing g_set_port_state() and we dont want to do that 4973 */ 4974 4975 int 4976 g_port_offline(char *path) 4977 { 4978 return (g_set_port_state(path, PORT_OFFLINE)); 4979 } 4980 4981 int 4982 g_port_online(char *path) 4983 { 4984 return (g_set_port_state(path, PORT_ONLINE)); 4985 } 4986 4987 /* 4988 * This function sets the loopback mode for a port on a HBA 4989 * INPUTS : 4990 * portpath - Pointer to the path of the FCA port on which to 4991 * set the loopback mode 4992 * cmd - EXT_LPBACK 4993 * INT_LPBACK 4994 * NO_LPBACK 4995 * RETURNS : 4996 * 0 on success and non-zero otherwise 4997 */ 4998 int 4999 g_loopback_mode(char *portpath, int cmd) 5000 { 5001 int path_type, fd; 5002 5003 if ((path_type = g_get_path_type(portpath)) == 0) { 5004 return (L_INVALID_PATH); 5005 } 5006 5007 if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) { 5008 return (L_OPEN_PATH_FAIL); 5009 } 5010 5011 /* 5012 * The loopback calls are currently not fully supported 5013 * via fp. 5014 * 5015 * A fp based general solution is required to support Leadville FCAs 5016 * including Qlgc and 3rd party FCA. As of now qlgc provides 5017 * some diag functions like echo through qlc private ioctl 5018 * which is not supproted by luxadm and libraries. 5019 */ 5020 switch (cmd) { 5021 case EXT_LPBACK: 5022 if (path_type & FC4_SOCAL_FCA) { 5023 if (ioctl(fd, FCIO_LOOPBACK_MANUAL, 5024 NULL) == -1) { 5025 /* Check for previous mode set */ 5026 if (errno != EALREADY) { 5027 close(fd); 5028 return (L_LOOPBACK_FAILED); 5029 } 5030 } 5031 } else { 5032 /* 5033 * Well, it wasn't one of the above cards so.. 5034 */ 5035 close(fd); 5036 return (L_LOOPBACK_UNSUPPORTED); 5037 } 5038 break; 5039 case NO_LPBACK: 5040 if (path_type & FC4_SOCAL_FCA) { 5041 if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) { 5042 close(fd); 5043 return (L_LOOPBACK_FAILED); 5044 } 5045 } else { 5046 /* 5047 * Well, it wasn't one of the above cards so.. 5048 */ 5049 close(fd); 5050 return (L_LOOPBACK_UNSUPPORTED); 5051 } 5052 break; 5053 case INT_LPBACK: 5054 if (path_type & FC4_SOCAL_FCA) { 5055 if (ioctl(fd, FCIO_LOOPBACK_INTERNAL, 5056 NULL) == -1) { 5057 /* Check for previous mode set */ 5058 if (errno != EALREADY) { 5059 close(fd); 5060 return (L_LOOPBACK_FAILED); 5061 } 5062 } 5063 } else { 5064 /* 5065 * Well, it wasn't one of the above cards so.. 5066 */ 5067 close(fd); 5068 return (L_LOOPBACK_UNSUPPORTED); 5069 } 5070 break; 5071 default: 5072 close(fd); 5073 return (L_LOOPBACK_UNSUPPORTED); 5074 } 5075 close(fd); 5076 return (0); 5077 } 5078 5079 /* 5080 * g_get_port_state(char *portpath, int port_state) 5081 * Purpose: Get port state for a path 5082 * Input: portpath 5083 * set to path of port 5084 * Output: port_state 5085 * Set to one of the following: 5086 * PORT_CONNECTED 5087 * PORT_NOTCONNECTED 5088 * Returns: 0 on success 5089 * non-zero on failure 5090 */ 5091 int 5092 g_get_port_state(char *portpath, int *portstate, int verbose) 5093 { 5094 int fd, err, num_devices = 0; 5095 struct lilpmap map; 5096 uint_t dev_type; 5097 gfc_dev_t map_root; 5098 5099 5100 (void) memset(&map, 0, sizeof (struct lilpmap)); 5101 5102 /* return invalid path if portpath is NULL */ 5103 if (portpath == NULL) { 5104 return (L_INVALID_PATH); 5105 } 5106 /* return invalid arg if argument is NULL */ 5107 if ((portpath == NULL) || (portstate == NULL)) { 5108 return (L_INVALID_ARG); 5109 } 5110 5111 if ((dev_type = g_get_path_type(portpath)) == 0) { 5112 return (L_INVALID_PATH); 5113 } 5114 5115 /* 5116 * FCIO_GETMAP returns error when there are * no devices attached. 5117 * ENOMEM is returned when no devices are attached. 5118 * g_get_first_dev returns NULL without error when there is no 5119 * devices are attached. 5120 */ 5121 if (dev_type & FC_FCA_MASK) { 5122 if ((map_root = g_dev_map_init(portpath, &err, 5123 MAP_XPORT_PROP_ONLY)) == NULL) { 5124 return (err); 5125 } 5126 5127 if (g_get_first_dev(map_root, &err) == NULL) { 5128 /* no device is found if err == 0 */ 5129 if (err == L_NO_SUCH_DEV_FOUND) { 5130 *portstate = PORT_NOTCONNECTED; 5131 } 5132 g_dev_map_fini(map_root); 5133 return (0); 5134 } else { 5135 /* Device found okay */ 5136 *portstate = PORT_CONNECTED; 5137 g_dev_map_fini(map_root); 5138 } 5139 5140 } else { 5141 /* open controller */ 5142 if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) { 5143 return (errno); 5144 } 5145 5146 /* 5147 * Note: There is only one error returned by this ioctl. ENOMEM. 5148 * Hence the lack of return on error. 5149 */ 5150 if (ioctl(fd, FCIO_GETMAP, &map) != 0) { 5151 map.lilp_length = 0; 5152 } 5153 num_devices = map.lilp_length; 5154 5155 /* Non-Leadville stacks report the FCA in the count */ 5156 *portstate = (num_devices > 1) ? PORT_CONNECTED : 5157 PORT_NOTCONNECTED; 5158 (void) close(fd); 5159 } 5160 return (0); 5161 } 5162 5163 /* 5164 * g_dev_login(char *port_path, la_wwn_t port_wwn) 5165 * Purpose: port login via g_dev_log_in_out() 5166 * Input: port_path 5167 * fc transport port with fabric/public loop topology 5168 * port_wwn 5169 * port wwn of device node to login 5170 * 5171 * Returns: return code from g_dev_log_in_out() 5172 */ 5173 int 5174 g_dev_login(char *port_path, la_wwn_t port_wwn) 5175 { 5176 return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN)); 5177 } 5178 5179 5180 /* 5181 * g_dev_logout(char *port_path, la_wwn_t port_wwn) 5182 * Purpose: port login via g_dev_log_in_out() 5183 * Input: port_path 5184 * fc transport port with fabric/public loop topology 5185 * port_wwn 5186 * port wwn of device node to logout 5187 * 5188 * Returns: return code from g_dev_log_in_out() 5189 */ 5190 int 5191 g_dev_logout(char *port_path, la_wwn_t port_wwn) 5192 { 5193 return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT)); 5194 } 5195 5196 5197 /* 5198 * g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd) 5199 * Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT 5200 * IOCTL requires EXCLUSIVE open. 5201 * Input: port_path 5202 * fc transport port with fabric/public loop topology 5203 * port_wwn 5204 * port wwn of device node to logout 5205 * cmd 5206 * FCIO_DEV_LOGON or FCIO_DEV_LOGOUT 5207 * 5208 * Returns: 0 on success 5209 * non-zero on failure 5210 */ 5211 static int 5212 g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd) 5213 { 5214 int fd, err; 5215 uint32_t hba_port_top; 5216 fcio_t fcio; 5217 int verbose = 0; 5218 5219 if ((err = g_get_fca_port_topology(port_path, 5220 &hba_port_top, verbose)) != 0) { 5221 return (err); 5222 } 5223 5224 if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) || 5225 (hba_port_top == FC_TOP_FABRIC))) { 5226 return (L_OPNOSUPP_ON_TOPOLOGY); 5227 } 5228 5229 /* open controller */ 5230 if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1) 5231 return (L_OPEN_PATH_FAIL); 5232 5233 /* 5234 * stores port_wwn to la_wwn_t raw_wwn field 5235 * and construct fcio structures for FCIO_DEV_LOGIN. 5236 */ 5237 fcio.fcio_cmd = cmd; 5238 fcio.fcio_ilen = sizeof (port_wwn); 5239 fcio.fcio_ibuf = (caddr_t)&port_wwn; 5240 fcio.fcio_xfer = FCIO_XFER_WRITE; 5241 fcio.fcio_olen = fcio.fcio_alen = 0; 5242 fcio.fcio_obuf = fcio.fcio_abuf = NULL; 5243 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) { 5244 I_DPRINTF((cmd == FCIO_DEV_LOGIN) ? 5245 " FCIO_DEV_LOGIN ioctl failed.\n" 5246 : " FCIO_DEV_LOGOUT ioctl failed.\n"); 5247 (void) close(fd); 5248 return ((cmd == FCIO_DEV_LOGIN) ? 5249 L_FCIO_DEV_LOGIN_FAIL 5250 : L_FCIO_DEV_LOGOUT_FAIL); 5251 } else { 5252 (void) close(fd); 5253 return (0); 5254 } 5255 } 5256 5257 /* 5258 * This function will verify if a FC device (represented by input WWN 5259 * is connected on a FCA port by searching the device list from 5260 * g_get_dev_list() for a WWN match. 5261 * 5262 * input: 5263 * fca_path: pointer to the physical path string, path to a fp node. 5264 * possible forms are 5265 * /devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl 5266 * dev_wwn: WWN string 5267 * flag: indicate that the input WWN is node or port 5268 * 5269 * returned values 5270 * 0: if a match is found. 5271 * L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found 5272 * L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error 5273 * from the topology checking of the input fca path. 5274 * L_MALLOC_FAILED: existing error code for allocation eror from the 5275 * g_get_dev_list(). 5276 * L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the 5277 * FCIO ioctl called by the g_get_dev_list() 5278 * -1: other failure 5279 * 5280 */ 5281 int 5282 g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag) 5283 { 5284 uint_t dev_type; 5285 int i, err; 5286 fc_port_dev_t *dev_list; 5287 fc_port_dev_t *dev_list_save; 5288 int num_devices = 0; 5289 5290 if ((dev_type = g_get_path_type(fca_path)) == 0) { 5291 return (L_INVALID_PATH); 5292 } 5293 5294 if (!(dev_type & FC_XPORT_MASK)) { 5295 return (L_INVALID_PATH_TYPE); 5296 } 5297 5298 if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices)) 5299 != 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) { 5300 return (err); 5301 } 5302 5303 dev_list_save = dev_list; 5304 5305 switch (flag) { 5306 case MATCH_NODE_WWN: 5307 for (i = 0; i < num_devices; i++, dev_list++) { 5308 if (memcmp(dev_list->dev_nwwn.raw_wwn, 5309 dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) { 5310 (void) free(dev_list_save); 5311 return (0); 5312 } 5313 } 5314 (void) free(dev_list_save); 5315 /* consider a new error code for not found. */ 5316 return (L_WWN_NOT_FOUND_IN_DEV_LIST); 5317 5318 case MATCH_PORT_WWN: 5319 for (i = 0; i < num_devices; i++, dev_list++) { 5320 if (memcmp(dev_list->dev_pwwn.raw_wwn, 5321 dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) { 5322 (void) free(dev_list_save); 5323 return (0); 5324 } 5325 } 5326 (void) free(dev_list_save); 5327 /* consider a new error code for not found. */ 5328 return (L_WWN_NOT_FOUND_IN_DEV_LIST); 5329 } 5330 (void) free(dev_list_save); 5331 return (-1); 5332 } 5333 5334 5335 /* 5336 * g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state) 5337 * Purpose: get the state of device port login via FCIO_GET_STATE ioctl. 5338 * 5339 * Input: fca_path 5340 * fc transport port with fabric/public loop topology 5341 * port_wwn 5342 * port wwn of device node to logout 5343 * state 5344 * port login or not 5345 * 5346 * Returns: 0 on success 5347 * non-zero on failure 5348 */ 5349 static int 5350 g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state) 5351 { 5352 int fd; 5353 int dev_type; 5354 fcio_t fcio; 5355 int verbose = 0; 5356 5357 if ((dev_type = g_get_path_type(fca_path)) == 0) { 5358 return (L_INVALID_PATH); 5359 } 5360 5361 if (!(dev_type & FC_XPORT_MASK)) { 5362 return (L_INVALID_PATH_TYPE); 5363 } 5364 5365 /* open controller */ 5366 if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1) 5367 return (L_OPEN_PATH_FAIL); 5368 5369 /* 5370 * stores port_wwn to la_wwn_t raw_wwn field 5371 * and construct fcio structures for FCIO_DEV_LOGIN. 5372 */ 5373 fcio.fcio_cmd = FCIO_GET_STATE; 5374 fcio.fcio_ilen = sizeof (port_wwn); 5375 fcio.fcio_ibuf = (caddr_t)&port_wwn; 5376 fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE; 5377 fcio.fcio_olen = sizeof (uint32_t); 5378 fcio.fcio_obuf = (caddr_t)state; 5379 fcio.fcio_alen = 0; 5380 fcio.fcio_abuf = NULL; 5381 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) { 5382 I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n"); 5383 (void) close(fd); 5384 return (L_FCIO_GET_STATE_FAIL); 5385 } else { 5386 (void) close(fd); 5387 return (0); 5388 } 5389 } 5390 5391 /* 5392 * Name: lilp_map_cmp 5393 * 5394 * Description: This function is used to compare the physical location 5395 * of to fc devices in a gfc_map_t.dev_addr arrary. 5396 * 5397 * Params: 5398 * First device to compare 5399 * Second device to compare 5400 * 5401 * Return: 5402 * 0 = Devices at equal phyiscal location, How did this happen? 5403 * >0 = First device have a higher physical location than second 5404 * <0 = Second device have a higher physical location than first 5405 */ 5406 static int lilp_map_cmp(const void* dev1, const void* dev2) { 5407 int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit; 5408 int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit; 5409 5410 if (i_dev1 > i_dev2) 5411 return (1); 5412 if (i_dev1 < i_dev2) 5413 return (-1); 5414 return (0); 5415 } 5416 5417 /* 5418 * Description: 5419 * Retrieves multiple paths to a device based on devid 5420 * Caller must use mplist_free to free mplist structure 5421 * This currently only supports ssd devices. 5422 * The st driver does not register a device id. 5423 * 5424 * Input Values: 5425 * 5426 * devid: ptr to valid ddi_devid_t struct 5427 * root: root handle to device tree snapshot 5428 * drvr_name: driver name to start the node tree search 5429 * 5430 * Return Value: 5431 * 0 on success 5432 * non-zero on failure 5433 */ 5434 5435 static int 5436 devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name, 5437 struct mplist_struct **mplistp) 5438 { 5439 ddi_devid_t mydevid; 5440 di_node_t node; 5441 char *devfs_path = NULL; 5442 struct mplist_struct *mpl, *mpln; 5443 5444 if (devid == NULL || root == NULL || drvr_name == NULL || 5445 mplistp == NULL || 5446 (strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME)) 5447 != 0)) { 5448 return (EINVAL); 5449 } 5450 5451 *mplistp = mpl = mpln = (struct mplist_struct *)NULL; 5452 5453 /* point to first node which matches portdrvr */ 5454 node = di_drv_first_node(drvr_name, root); 5455 if (node == DI_NODE_NIL) { 5456 return (L_NO_DRIVER_NODES_FOUND); 5457 } 5458 5459 while (node != DI_NODE_NIL) { 5460 if ((mydevid = di_devid(node)) != NULL) { 5461 if (((devid_compare(mydevid, devid)) == 0)) { 5462 /* Load multipath list */ 5463 if ((mpl = (struct mplist_struct *) 5464 calloc(1, sizeof (struct mplist_struct))) 5465 == NULL) { 5466 mplist_free(*mplistp); 5467 return (L_MALLOC_FAILED); 5468 } 5469 if ((devfs_path = my_devfs_path(node)) == 5470 NULL) { 5471 node = di_drv_next_node(node); 5472 S_FREE(mpl); 5473 continue; 5474 } 5475 mpl->devpath = (char *)calloc(1, 5476 strlen(devfs_path) + 5477 strlen(SSD_MINOR_NAME) + 1); 5478 if (mpl->devpath == NULL) { 5479 S_FREE(mpl); 5480 mplist_free(*mplistp); 5481 my_devfs_path_free(devfs_path); 5482 return (L_MALLOC_FAILED); 5483 } 5484 sprintf(mpl->devpath, "%s%s", devfs_path, 5485 SSD_MINOR_NAME); 5486 if (*mplistp == NULL) { 5487 *mplistp = mpln = mpl; 5488 } else { 5489 mpln->next = mpl; 5490 mpln = mpl; 5491 } 5492 my_devfs_path_free(devfs_path); 5493 } 5494 } 5495 node = di_drv_next_node(node); 5496 } 5497 return (0); 5498 } 5499 5500 /* 5501 * Frees a previously allocated mplist_struct 5502 */ 5503 static void 5504 mplist_free(struct mplist_struct *mplistp) 5505 { 5506 struct mplist_struct *mplistn; 5507 5508 while (mplistp != NULL) { 5509 mplistn = mplistp->next; 5510 if (mplistp->devpath != NULL) { 5511 free(mplistp->devpath); 5512 mplistp->devpath = NULL; 5513 } 5514 free(mplistp); 5515 mplistp = mplistn; 5516 } 5517 } 5518 5519 /* 5520 * Description 5521 * Retrieves all device nodes based on drvr_name 5522 * Currently supports SSD_DRVR_NAME, ST_DRVR_NAME 5523 * There will be a device node in the libdevinfo 5524 * snapshot only if there is at least one node bound. 5525 * 5526 * Input values: 5527 * root valid snapshot handle from di_init(3DEVINFO) 5528 * drvr_name name of driver to start node search 5529 * wwn_list_ptr ptr to ptr to WWN_list struct 5530 * 5531 * 5532 */ 5533 static int 5534 devices_get_all(di_node_t root, char *drvr_name, char *minor_name, 5535 struct wwn_list_struct **wwn_list_ptr) 5536 { 5537 di_node_t node; 5538 char *devfs_path; 5539 char devicepath[MAXPATHLEN]; 5540 uchar_t *nwwn = NULL, *pwwn = NULL; 5541 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 5542 WWN_list *wwn_list, *l1, *l2; 5543 int scsi_vhci = 0; 5544 int err, devtype; 5545 5546 if (root == DI_NODE_NIL || drvr_name == NULL || 5547 wwn_list_ptr == NULL) { 5548 return (EINVAL); 5549 } 5550 5551 wwn_list = *wwn_list_ptr = NULL; 5552 5553 memset(port_wwn, 0, sizeof (port_wwn)); 5554 memset(node_wwn, 0, sizeof (node_wwn)); 5555 5556 if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) { 5557 devtype = DTYPE_DIRECT; 5558 } else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) { 5559 devtype = DTYPE_SEQUENTIAL; 5560 } else { 5561 /* 5562 * An unsupported driver name was passed in 5563 */ 5564 return (L_DRIVER_NOTSUPP); 5565 } 5566 5567 /* point to first node which matches portdrvr */ 5568 node = di_drv_first_node(drvr_name, root); 5569 if (node == DI_NODE_NIL) { 5570 return (L_NO_DEVICES_FOUND); 5571 } 5572 5573 while (node != DI_NODE_NIL) { 5574 5575 if ((devfs_path = my_devfs_path(node)) != NULL) { 5576 5577 /* 5578 * Check for offline state 5579 */ 5580 if ((di_state(node) & 5581 DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) { 5582 my_devfs_path_free(devfs_path); 5583 node = di_drv_next_node(node); 5584 continue; 5585 } 5586 5587 /* 5588 * Only support st, ssd nodes 5589 */ 5590 if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) && 5591 !strstr(devfs_path, SLSH_DRV_NAME_ST)) { 5592 my_devfs_path_free(devfs_path); 5593 node = di_drv_next_node(node); 5594 continue; 5595 } 5596 5597 devicepath[0] = '\0'; 5598 5599 /* 5600 * form device path 5601 */ 5602 sprintf(devicepath, "%s%s", devfs_path, minor_name); 5603 5604 if ((strstr(devicepath, SCSI_VHCI) == NULL)) { 5605 if ((err = get_wwn_data(node, &nwwn, &pwwn)) != 5606 0) { 5607 my_devfs_path_free(devfs_path); 5608 return (err); 5609 } else { 5610 memcpy(node_wwn, nwwn, 5611 sizeof (node_wwn)); 5612 memcpy(port_wwn, pwwn, 5613 sizeof (port_wwn)); 5614 } 5615 } else { 5616 /* 5617 * Clear values for SCSI VHCI devices. 5618 * node wwn, port wwn are irrevelant at 5619 * the SCSI VHCI level 5620 */ 5621 scsi_vhci++; 5622 memset(port_wwn, 0, sizeof (port_wwn)); 5623 memset(node_wwn, 0, sizeof (node_wwn)); 5624 } 5625 5626 /* Got wwns, load data in list */ 5627 if ((l2 = (struct wwn_list_struct *) 5628 calloc(1, sizeof (struct wwn_list_struct))) == 5629 NULL) { 5630 my_devfs_path_free(devfs_path); 5631 return (L_MALLOC_FAILED); 5632 } 5633 if ((l2->physical_path = (char *) 5634 calloc(1, strlen(devicepath) +1)) == NULL) { 5635 my_devfs_path_free(devfs_path); 5636 return (L_MALLOC_FAILED); 5637 } 5638 5639 memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE); 5640 5641 if (scsi_vhci) { 5642 strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A")); 5643 } else { 5644 copy_wwn_data_to_str(l2->node_wwn_s, node_wwn); 5645 copy_wwn_data_to_str(l2->port_wwn_s, port_wwn); 5646 } 5647 5648 strcpy(l2->physical_path, devicepath); 5649 5650 l2->device_type = devtype; 5651 if (wwn_list == NULL) { 5652 l1 = wwn_list = l2; 5653 } else { 5654 l2->wwn_prev = l1; 5655 l1 = l1->wwn_next = l2; 5656 } 5657 my_devfs_path_free(devfs_path); 5658 scsi_vhci = 0; 5659 } 5660 node = di_drv_next_node(node); 5661 } 5662 5663 *wwn_list_ptr = wwn_list; /* pass back ptr to list */ 5664 5665 if (*wwn_list_ptr == NULL) { 5666 return (L_NO_DEVICES_FOUND); 5667 } else { 5668 /* 5669 * Now load the /dev/ paths 5670 */ 5671 if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) { 5672 if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR, 5673 DIR_MATCH_SSD)) != 0) { 5674 g_free_wwn_list(wwn_list_ptr); 5675 return (err); 5676 } 5677 } else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) { 5678 if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR, 5679 DIR_MATCH_ST)) != 0) { 5680 g_free_wwn_list(wwn_list_ptr); 5681 return (err); 5682 } 5683 } 5684 return (0); 5685 } 5686 } 5687 5688 5689 /* 5690 * Access the properties for the node to get the node-wwn, port-wwn property 5691 * On error, contents of nwwn, pwwn are unspecified. 5692 * On successful return nwwn and pwwn are WWN_SIZE bytes. 5693 */ 5694 static int 5695 get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn) 5696 { 5697 if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP, 5698 nwwn) != WWN_SIZE) { 5699 /* If we didn't get back the right count, return error */ 5700 return (L_NO_WWN_PROP_FOUND); 5701 } 5702 if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP, 5703 pwwn) != WWN_SIZE) { 5704 /* If we didn't get back the right count, return error */ 5705 return (L_NO_WWN_PROP_FOUND); 5706 } 5707 return (0); 5708 } 5709 5710 /* 5711 * Description 5712 * retrieves the /dev logical path for a WWN_list of devices. 5713 * Input values 5714 * wwn_list_ptr ptr to list returned by devices_get_all 5715 * dir_name /dev/ directory to search 5716 * 5717 */ 5718 static int 5719 get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name, 5720 char *pattern_match) 5721 { 5722 DIR *dirp; 5723 struct dirent *entp; 5724 char namebuf[MAXPATHLEN]; 5725 char *result = NULL; 5726 WWN_list *wwn_list, *wwn_list_save; 5727 char *env; 5728 hrtime_t start_time, end_time; 5729 5730 if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL || 5731 dir_name == NULL || pattern_match == NULL) { 5732 return (EINVAL); 5733 } 5734 5735 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 5736 start_time = gethrtime(); 5737 } 5738 5739 wwn_list = *wwn_list_ptr; 5740 5741 if ((dirp = opendir(dir_name)) == NULL) { 5742 P_DPRINTF(" get_dev_path: No devices found\n"); 5743 return (L_NO_DEVICES_FOUND); 5744 } 5745 5746 while ((entp = readdir(dirp)) != NULL) { 5747 /* 5748 * Ignore current directory and parent directory 5749 * entries. 5750 */ 5751 if ((strcmp(entp->d_name, ".") == 0) || 5752 (strcmp(entp->d_name, "..") == 0) || 5753 (fnmatch(pattern_match, entp->d_name, 0) != 0)) 5754 continue; 5755 5756 memset(namebuf, 0, sizeof (namebuf)); 5757 sprintf(namebuf, "%s/%s", dir_name, entp->d_name); 5758 5759 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) { 5760 ER_DPRINTF(" Warning: Get physical name from" 5761 " link failed. Link=%s\n", namebuf); 5762 continue; 5763 } 5764 for (wwn_list = *wwn_list_ptr; wwn_list != NULL; 5765 wwn_list = wwn_list->wwn_next) { 5766 if (strcmp(wwn_list->physical_path, result) == 0) { 5767 /* 5768 * Add information to the list. 5769 */ 5770 if ((wwn_list->logical_path = (char *) 5771 calloc(1, strlen(namebuf) + 1)) == NULL) { 5772 free(result); 5773 return (L_MALLOC_FAILED); 5774 } 5775 strcpy(wwn_list->logical_path, namebuf); 5776 break; 5777 } 5778 } 5779 free(result); 5780 } 5781 closedir(dirp); 5782 5783 /* 5784 * Did we load all of the paths? 5785 * Note: if there is a missing entry in /dev then 5786 * the user probably did a cleanup of /dev. 5787 * Whatever the case, remove the entry as it 5788 * is invalid. 5789 */ 5790 wwn_list = *wwn_list_ptr; 5791 while (wwn_list != NULL) { 5792 if (wwn_list->logical_path == NULL) { 5793 free(wwn_list->physical_path); 5794 wwn_list_save = wwn_list; 5795 if (wwn_list->wwn_prev != NULL) { 5796 wwn_list->wwn_prev->wwn_next = 5797 wwn_list->wwn_next; 5798 } else { 5799 /* 5800 * No previous entries 5801 */ 5802 *wwn_list_ptr = wwn_list->wwn_next; 5803 } 5804 if (wwn_list->wwn_next != NULL) { 5805 wwn_list->wwn_next->wwn_prev = 5806 wwn_list->wwn_prev; 5807 } 5808 wwn_list = wwn_list->wwn_next; 5809 free(wwn_list_save); 5810 } else { 5811 wwn_list = wwn_list->wwn_next; 5812 } 5813 } 5814 5815 if (env != NULL) { 5816 end_time = gethrtime(); 5817 fprintf(stdout, 5818 " get_dev_path %s: " 5819 "\t\tTime = %lld millisec\n", 5820 dir_name, (end_time - start_time)/1000000); 5821 } 5822 5823 if (*wwn_list_ptr == NULL) { 5824 return (L_NO_DEVICES_FOUND); 5825 } else { 5826 return (0); 5827 } 5828 } 5829 5830 /* 5831 * This functions calls di_devfs_path and gets the path associated with a 5832 * given devinfo node. If the path returned does not have a '@' in it, it 5833 * checks if the driver is detached and creates a path after looking at the 5834 * driver properties. 5835 * 5836 * di_devfs_path_free is called internally. 5837 * 5838 * The argument 'path' points to the final value upon return. 5839 * Caller must use my_devfs_path_free on returned char * 5840 * Note: Only support FC/SCSI_VHCI devices, 5841 * for FC check for initiator-interconnect-type prop 5842 * 5843 */ 5844 static char * 5845 my_devfs_path(di_node_t node) 5846 { 5847 uchar_t *pwwn = NULL; 5848 char *interconnect = NULL; 5849 char pwwns[WWN_SIZE*2+1]; 5850 char *mypath; 5851 int scsi_vhci = 0; 5852 int rval; 5853 char *tptr = NULL, *lun_guid = NULL; 5854 int *lunnump = NULL; 5855 di_node_t parentnode; 5856 5857 /* sanity check */ 5858 if (node == DI_NODE_NIL) { 5859 return (NULL); 5860 } 5861 5862 /* Now go get the path for this node */ 5863 if ((tptr = di_devfs_path(node)) == NULL) { 5864 return (NULL); 5865 } 5866 5867 parentnode = di_parent_node(node); 5868 5869 if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) { 5870 di_devfs_path_free(tptr); 5871 return (NULL); 5872 } 5873 5874 /* Prepend "/devices" to libdevinfo-returned paths */ 5875 sprintf(mypath, "%s%s", DEVICES_DIR, tptr); 5876 5877 di_devfs_path_free(tptr); 5878 5879 /* 5880 * Is this a FC device? 5881 * Check initiator-interconnect-type property 5882 */ 5883 if (strstr(mypath, SCSI_VHCI) == NULL) { 5884 rval = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode, 5885 "initiator-interconnect-type", &interconnect); 5886 /* Check for INTERCONNECT_FABRIC_STR & INTERCONNECT_FIBRE_STR */ 5887 if ((rval <= 0) || 5888 ((strcmp(interconnect, "FABRIC") != 0) && 5889 (strcmp(interconnect, "FIBRE") != 0))) { 5890 /* Not a FC device. Free path and return */ 5891 free(mypath); 5892 return (NULL); 5893 } 5894 } else { 5895 scsi_vhci++; 5896 } 5897 5898 if ((tptr = strrchr(mypath, '/')) == NULL) { 5899 free(mypath); 5900 return (NULL); 5901 } 5902 5903 if (strchr(tptr, '@') != NULL) { 5904 return (mypath); 5905 } 5906 5907 /* 5908 * No '@' in path. This can happen when driver is detached. 5909 * We'll check if the state is detached and if it is, we'll construct 5910 * the path by looking at the properties. 5911 */ 5912 5913 if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { 5914 /* 5915 * Driver is not detached and no '@' in path. 5916 * Can't handle it. 5917 */ 5918 free(mypath); 5919 return (NULL); 5920 } 5921 5922 if (!scsi_vhci) { 5923 copy_wwn_data_to_str(pwwns, pwwn); 5924 di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump); 5925 sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump); 5926 } else { 5927 di_prop_lookup_strings(DDI_DEV_T_ANY, node, 5928 LUN_GUID_PROP, &lun_guid); 5929 sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid); 5930 } 5931 return (mypath); 5932 } 5933 5934 static void 5935 my_devfs_path_free(char *path) 5936 { 5937 if (path != NULL) { 5938 free(path); 5939 } 5940 } 5941 5942 /* 5943 * from_ptr: ptr to uchar_t array of size WWN_SIZE 5944 * to_ptr: char ptr to string of size WWN_SIZE*2+1 5945 */ 5946 static void 5947 copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr) 5948 { 5949 if ((to_ptr == NULL) || (from_ptr == NULL)) 5950 return; 5951 5952 sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 5953 from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3], 5954 from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]); 5955 } 5956 5957 /* 5958 * Open the requested directory and get one valid open. 5959 * If a device is busy, return. 5960 * Only need to open one device since 5961 * that implies there will be a node returned from 5962 * di_drv_first_node() 5963 * dir_name: logical device name directory 5964 * (DEV_TAPE_DIR, DEV_RDIR) 5965 * pattern_match: used by fnmatch on directory entry 5966 * (DIR_MATCH_SSD, DIR_MATCH_ST) 5967 * drvr_path: path type to verify ("/ssd@", "/st@") 5968 * (SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD) 5969 * 5970 * Returns: None 5971 */ 5972 static void 5973 init_drv(char *dir_name, char *pattern_match, char *drvr_path) 5974 { 5975 DIR *dirp; 5976 struct dirent *entp; 5977 char namebuf[MAXPATHLEN]; 5978 char *result = NULL; 5979 int fd; 5980 5981 if ((dirp = opendir(dir_name)) == NULL) { 5982 return; 5983 } 5984 5985 while ((entp = readdir(dirp)) != NULL) { 5986 /* 5987 * Ignore current directory and parent directory 5988 * entries. 5989 */ 5990 if ((strcmp(entp->d_name, ".") == 0) || 5991 (strcmp(entp->d_name, "..") == 0) || 5992 (fnmatch(pattern_match, entp->d_name, 0) != 0)) { 5993 continue; 5994 } 5995 5996 memset(namebuf, 0, sizeof (namebuf)); 5997 sprintf(namebuf, "%s/%s", dir_name, entp->d_name); 5998 5999 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) { 6000 ER_DPRINTF(" Warning: Get physical name from" 6001 " link failed. Link=%s\n", namebuf); 6002 continue; 6003 } 6004 6005 if (strstr(result, drvr_path) == NULL) { 6006 free(result); 6007 result = NULL; 6008 continue; 6009 } 6010 6011 if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) { 6012 close(fd); 6013 break; 6014 } else if (errno != EBUSY) { 6015 free(result); 6016 result = NULL; 6017 continue; 6018 } else { 6019 break; 6020 } 6021 } 6022 free(result); 6023 closedir(dirp); 6024 } 6025