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