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