1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 */ 26 27 28 /*LINTLIBRARY*/ 29 30 /* 31 * I18N message number ranges 32 * This file: 9000 - 9499 33 * Shared common messages: 1 - 1999 34 */ 35 36 /* 37 * This module is part of the photon library 38 */ 39 /* Includes */ 40 #include <stdlib.h> 41 #include <stdio.h> 42 #include <sys/file.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/param.h> 46 #include <fcntl.h> 47 #include <unistd.h> 48 #include <errno.h> 49 #include <string.h> 50 #include <assert.h> 51 #include <sys/scsi/scsi.h> 52 #include <dirent.h> /* for DIR */ 53 #include <sys/vtoc.h> 54 #include <sys/dkio.h> 55 #include <nl_types.h> 56 #include <strings.h> 57 #include <sys/ddi.h> /* for max */ 58 #include <l_common.h> 59 #include <stgcom.h> 60 #include <l_error.h> 61 #include <rom.h> 62 #include <exec.h> 63 #include <a_state.h> 64 #include <a5k.h> 65 66 67 /* Defines */ 68 #define PLNDEF "SUNW,pln" /* check if box name starts with 'c' */ 69 #define DOWNLOAD_RETRIES 60*5 /* 5 minutes */ 70 #define IBFIRMWARE_FILE "/usr/lib/locale/C/LC_MESSAGES/ibfirmware" 71 72 /* Global variables */ 73 extern uchar_t g_switch_to_alpa[]; 74 extern uchar_t g_sf_alpa_to_switch[]; 75 76 /* Forward declarations */ 77 static int pwr_up_down(char *, L_state *, int, int, int, int); 78 static int load_flds_if_enc_disk(char *, struct path_struct **); 79 static int copy_config_page(struct l_state_struct *, uchar_t *); 80 static void copy_page_7(struct l_state_struct *, uchar_t *); 81 static int l_get_node_status(char *, struct l_disk_state_struct *, 82 int *, WWN_list *, int); 83 static int check_file(int, int, uchar_t **, int); 84 static int check_dpm_file(int); 85 static int ib_download_code_cmd(int, int, int, uchar_t *, int, int); 86 static int dak_download_code_cmd(int, uchar_t *, int); 87 static void free_mp_dev_map(struct gfc_map_mp **); 88 static int get_mp_dev_map(char *, struct gfc_map_mp **, int); 89 90 /* 91 * l_get_mode_pg() - Read all mode pages. 92 * 93 * RETURNS: 94 * 0 O.K. 95 * non-zero otherwise 96 * 97 * INPUTS: 98 * path pointer to device path 99 * pg_buf ptr to mode pages 100 * 101 */ 102 /*ARGSUSED*/ 103 int 104 l_get_mode_pg(char *path, uchar_t **pg_buf, int verbose) 105 { 106 Mode_header_10 *mode_header_ptr; 107 int status, size, fd; 108 109 P_DPRINTF(" l_get_mode_pg: Reading Mode Sense pages.\n"); 110 111 /* do not do mode sense if this is a tape device */ 112 /* mode sense will rewind the tape */ 113 if (strstr(path, SLSH_DRV_NAME_ST)) { 114 return (-1); 115 } 116 117 /* open controller */ 118 if ((fd = g_object_open(path, O_NDELAY | O_RDWR)) == -1) 119 return (L_OPEN_PATH_FAIL); 120 121 /* 122 * Read the first part of the page to get the page size 123 */ 124 size = 20; 125 if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) { 126 (void) close(fd); 127 return (L_MALLOC_FAILED); 128 } 129 /* read page */ 130 if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size, 131 0, MODEPAGE_ALLPAGES)) { 132 (void) close(fd); 133 (void) g_destroy_data((char *)*pg_buf); 134 return (status); 135 } 136 /* Now get the size for all pages */ 137 mode_header_ptr = (struct mode_header_10_struct *)(void *)*pg_buf; 138 size = mode_header_ptr->length + sizeof (mode_header_ptr->length); 139 (void) g_destroy_data((char *)*pg_buf); 140 if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) { 141 (void) close(fd); 142 return (L_MALLOC_FAILED); 143 } 144 /* read all pages */ 145 if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size, 146 0, MODEPAGE_ALLPAGES)) { 147 (void) close(fd); 148 (void) g_destroy_data((char *)*pg_buf); 149 return (status); 150 } 151 (void) close(fd); 152 return (0); 153 } 154 155 156 157 /* 158 * Format QLA21xx status 159 * 160 * INPUTS: message buffer 161 * Count 162 * status 163 * 164 * OUTPUT: Message of this format in message buffer 165 * "status type: 0xstatus count" 166 */ 167 int 168 l_format_ifp_status_msg(char *status_msg_buf, int count, int status) 169 { 170 if (status_msg_buf == NULL) { 171 return (0); 172 } 173 174 switch (status) { 175 case IFP_CMD_CMPLT: 176 (void) sprintf(status_msg_buf, 177 MSGSTR(9000, "O.K. 0x%-2x" 178 " %d"), status, count); 179 break; 180 case IFP_CMD_INCOMPLETE: 181 (void) sprintf(status_msg_buf, 182 MSGSTR(9001, "Cmd incomplete 0x%-2x" 183 " %d"), status, count); 184 break; 185 case IFP_CMD_DMA_DERR: 186 (void) sprintf(status_msg_buf, 187 MSGSTR(9002, "DMA direction error 0x%-2x" 188 " %d"), status, count); 189 break; 190 case IFP_CMD_TRAN_ERR: 191 (void) sprintf(status_msg_buf, 192 MSGSTR(9003, "Unspecified transport error 0x%-2x" 193 " %d"), status, count); 194 break; 195 case IFP_CMD_RESET: 196 (void) sprintf(status_msg_buf, 197 MSGSTR(9004, "Reset aborted transport 0x%-2x" 198 " %d"), status, count); 199 break; 200 case IFP_CMD_ABORTED: 201 (void) sprintf(status_msg_buf, 202 MSGSTR(9005, "Cmd aborted 0x%-2x" 203 " %d"), status, count); 204 break; 205 case IFP_CMD_TIMEOUT: 206 (void) sprintf(status_msg_buf, 207 MSGSTR(9006, "Cmd Timeout 0x%-2x" 208 " %d"), status, count); 209 break; 210 case IFP_CMD_DATA_OVR: 211 (void) sprintf(status_msg_buf, 212 MSGSTR(9007, "Data Overrun 0x%-2x" 213 " %d"), status, count); 214 break; 215 case IFP_CMD_ABORT_REJECTED: 216 (void) sprintf(status_msg_buf, 217 MSGSTR(9008, "Target rejected abort msg 0x%-2x" 218 " %d"), status, count); 219 break; 220 case IFP_CMD_RESET_REJECTED: 221 (void) sprintf(status_msg_buf, 222 MSGSTR(9009, "Target rejected reset msg 0x%-2x" 223 " %d"), status, count); 224 break; 225 case IFP_CMD_DATA_UNDER: 226 (void) sprintf(status_msg_buf, 227 MSGSTR(9010, "Data underrun 0x%-2x" 228 " %d"), status, count); 229 break; 230 case IFP_CMD_QUEUE_FULL: 231 (void) sprintf(status_msg_buf, 232 MSGSTR(9011, "Queue full SCSI status 0x%-2x" 233 " %d"), status, count); 234 break; 235 case IFP_CMD_PORT_UNAVAIL: 236 (void) sprintf(status_msg_buf, 237 MSGSTR(9012, "Port unavailable 0x%-2x" 238 " %d"), status, count); 239 break; 240 case IFP_CMD_PORT_LOGGED_OUT: 241 (void) sprintf(status_msg_buf, 242 MSGSTR(9013, "Port loged out 0x%-2x" 243 " %d"), status, count); 244 break; 245 case IFP_CMD_PORT_CONFIG_CHANGED: 246 /* Not enough packets for given request */ 247 (void) sprintf(status_msg_buf, 248 MSGSTR(9014, "Port name changed 0x%-2x" 249 " %d"), status, count); 250 break; 251 default: 252 (void) sprintf(status_msg_buf, 253 "%s 0x%-2x" 254 " %d", MSGSTR(4, "Unknown status"), 255 status, count); 256 257 } /* End of switch() */ 258 259 return (0); 260 261 } 262 263 264 265 /* 266 * Format Fibre Channel status 267 * 268 * INPUTS: message buffer 269 * Count 270 * status 271 * 272 * OUTPUT: Message of this format in message buffer 273 * "status type: 0xstatus count" 274 */ 275 int 276 l_format_fc_status_msg(char *status_msg_buf, int count, int status) 277 { 278 if (status_msg_buf == NULL) { 279 return (0); 280 } 281 282 switch (status) { 283 case FCAL_STATUS_OK: 284 (void) sprintf(status_msg_buf, 285 MSGSTR(9015, "O.K. 0x%-2x" 286 " %d"), status, count); 287 break; 288 case FCAL_STATUS_P_RJT: 289 (void) sprintf(status_msg_buf, 290 MSGSTR(9016, "P_RJT (Frame Rejected) 0x%-2x" 291 " %d"), status, count); 292 break; 293 case FCAL_STATUS_F_RJT: 294 (void) sprintf(status_msg_buf, 295 MSGSTR(9017, "F_RJT (Frame Rejected) 0x%-2x" 296 " %d"), status, count); 297 break; 298 case FCAL_STATUS_P_BSY: 299 (void) sprintf(status_msg_buf, 300 MSGSTR(9018, "P_BSY (Port Busy) 0x%-2x" 301 " %d"), status, count); 302 break; 303 case FCAL_STATUS_F_BSY: 304 (void) sprintf(status_msg_buf, 305 MSGSTR(9019, "F_BSY (Port Busy) 0x%-2x" 306 " %d"), status, count); 307 break; 308 case FCAL_STATUS_OLDPORT_ONLINE: 309 /* Should not happen. */ 310 (void) sprintf(status_msg_buf, 311 MSGSTR(9020, "Old port Online 0x%-2x" 312 " %d"), status, count); 313 break; 314 case FCAL_STATUS_ERR_OFFLINE: 315 (void) sprintf(status_msg_buf, 316 MSGSTR(9021, "Link Offline 0x%-2x" 317 " %d"), status, count); 318 break; 319 case FCAL_STATUS_TIMEOUT: 320 /* Should not happen. */ 321 (void) sprintf(status_msg_buf, 322 MSGSTR(9022, "Sequence Timeout 0x%-2x" 323 " %d"), status, count); 324 break; 325 case FCAL_STATUS_ERR_OVERRUN: 326 (void) sprintf(status_msg_buf, 327 MSGSTR(9023, "Sequence Payload Overrun 0x%-2x" 328 " %d"), status, count); 329 break; 330 case FCAL_STATUS_LOOP_ONLINE: 331 (void) sprintf(status_msg_buf, 332 MSGSTR(9060, "Loop Online 0x%-2x" 333 " %d"), status, count); 334 break; 335 case FCAL_STATUS_OLD_PORT: 336 (void) sprintf(status_msg_buf, 337 MSGSTR(9061, "Old port 0x%-2x" 338 " %d"), status, count); 339 break; 340 case FCAL_STATUS_AL_PORT: 341 (void) sprintf(status_msg_buf, 342 MSGSTR(9062, "AL port 0x%-2x" 343 " %d"), status, count); 344 break; 345 case FCAL_STATUS_UNKNOWN_CQ_TYPE: 346 (void) sprintf(status_msg_buf, 347 MSGSTR(9024, "Unknown request type 0x%-2x" 348 " %d"), status, count); 349 break; 350 case FCAL_STATUS_BAD_SEG_CNT: 351 (void) sprintf(status_msg_buf, 352 MSGSTR(9025, "Bad segment count 0x%-2x" 353 " %d"), status, count); 354 break; 355 case FCAL_STATUS_MAX_XCHG_EXCEEDED: 356 (void) sprintf(status_msg_buf, 357 MSGSTR(9026, "Maximum exchanges exceeded 0x%-2x" 358 " %d"), status, count); 359 break; 360 case FCAL_STATUS_BAD_XID: 361 (void) sprintf(status_msg_buf, 362 MSGSTR(9027, "Bad exchange identifier 0x%-2x" 363 " %d"), status, count); 364 break; 365 case FCAL_STATUS_XCHG_BUSY: 366 (void) sprintf(status_msg_buf, 367 MSGSTR(9028, "Duplicate exchange request 0x%-2x" 368 " %d"), status, count); 369 break; 370 case FCAL_STATUS_BAD_POOL_ID: 371 (void) sprintf(status_msg_buf, 372 MSGSTR(9029, "Bad memory pool ID 0x%-2x" 373 " %d"), status, count); 374 break; 375 case FCAL_STATUS_INSUFFICIENT_CQES: 376 /* Not enough packets for given request */ 377 (void) sprintf(status_msg_buf, 378 MSGSTR(9030, "Invalid # of segments for req 0x%-2x" 379 " %d"), status, count); 380 break; 381 case FCAL_STATUS_ALLOC_FAIL: 382 (void) sprintf(status_msg_buf, 383 MSGSTR(9031, "Resource allocation failure 0x%-2x" 384 " %d"), status, count); 385 break; 386 case FCAL_STATUS_BAD_SID: 387 (void) sprintf(status_msg_buf, 388 MSGSTR(9032, "Bad Source Identifier(S_ID) 0x%-2x" 389 " %d"), status, count); 390 break; 391 case FCAL_STATUS_NO_SEQ_INIT: 392 (void) sprintf(status_msg_buf, 393 MSGSTR(9033, "No sequence initiative 0x%-2x" 394 " %d"), status, count); 395 break; 396 case FCAL_STATUS_BAD_DID: 397 (void) sprintf(status_msg_buf, 398 MSGSTR(9034, "Bad Destination ID(D_ID) 0x%-2x" 399 " %d"), status, count); 400 break; 401 case FCAL_STATUS_ABORTED: 402 (void) sprintf(status_msg_buf, 403 MSGSTR(9035, "Received BA_ACC from abort 0x%-2x" 404 " %d"), status, count); 405 break; 406 case FCAL_STATUS_ABORT_FAILED: 407 (void) sprintf(status_msg_buf, 408 MSGSTR(9036, "Received BA_RJT from abort 0x%-2x" 409 " %d"), status, count); 410 break; 411 case FCAL_STATUS_DIAG_BUSY: 412 (void) sprintf(status_msg_buf, 413 MSGSTR(9037, "Diagnostics currently busy 0x%-2x" 414 " %d"), status, count); 415 break; 416 case FCAL_STATUS_DIAG_INVALID: 417 (void) sprintf(status_msg_buf, 418 MSGSTR(9038, "Diagnostics illegal request 0x%-2x" 419 " %d"), status, count); 420 break; 421 case FCAL_STATUS_INCOMPLETE_DMA_ERR: 422 (void) sprintf(status_msg_buf, 423 MSGSTR(9039, "SBus DMA did not complete 0x%-2x" 424 " %d"), status, count); 425 break; 426 case FCAL_STATUS_CRC_ERR: 427 (void) sprintf(status_msg_buf, 428 MSGSTR(9040, "CRC error detected 0x%-2x" 429 " %d"), status, count); 430 break; 431 case FCAL_STATUS_OPEN_FAIL: 432 (void) sprintf(status_msg_buf, 433 MSGSTR(9063, "Open failure 0x%-2x" 434 " %d"), status, count); 435 break; 436 case FCAL_STATUS_ERROR: 437 (void) sprintf(status_msg_buf, 438 MSGSTR(9041, "Invalid status error 0x%-2x" 439 " %d"), status, count); 440 break; 441 case FCAL_STATUS_ONLINE_TIMEOUT: 442 (void) sprintf(status_msg_buf, 443 MSGSTR(9042, "Timed out before ONLINE 0x%-2x" 444 " %d"), status, count); 445 break; 446 default: 447 (void) sprintf(status_msg_buf, 448 "%s 0x%-2x" 449 " %d", MSGSTR(4, "Unknown status"), 450 status, count); 451 452 } /* End of switch() */ 453 454 return (0); 455 456 } 457 458 459 460 /* 461 * Get the indexes to the disk device elements in page 2, 462 * based on the locations found in page 1. 463 * 464 * RETURNS: 465 * 0 O.K. 466 * non-zero otherwise 467 */ 468 int 469 l_get_disk_element_index(struct l_state_struct *l_state, int *front_index, 470 int *rear_index) 471 { 472 int index = 0, front_flag = 0, local_front = 0, local_rear = 0; 473 int i, rear_flag = 0; 474 475 if ((l_state == NULL) || (front_index == NULL) || 476 (rear_index == NULL)) { 477 return (L_INVALID_PATH_FORMAT); 478 } 479 480 *front_index = *rear_index = 0; 481 /* Get the indexes to the disk device elements */ 482 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { 483 if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) { 484 if (front_flag) { 485 local_rear = index; 486 rear_flag = 1; 487 break; 488 } else { 489 local_front = index; 490 front_flag = 1; 491 } 492 } 493 index += l_state->ib_tbl.config.type_hdr[i].num; 494 index++; /* for global element */ 495 } 496 497 D_DPRINTF(" l_get_disk_element_index:" 498 " Index to front disk elements 0x%x\n" 499 " l_get_disk_element_index:" 500 " Index to rear disk elements 0x%x\n", 501 local_front, local_rear); 502 503 if (!front_flag && !rear_flag) { /* neither is found */ 504 return (L_RD_NO_DISK_ELEM); 505 } 506 *front_index = local_front; 507 *rear_index = local_rear; 508 return (0); 509 } 510 511 512 513 /* 514 * l_led() manage the device led's 515 * 516 * RETURNS: 517 * 0 O.K. 518 * non-zero otherwise 519 */ 520 int 521 l_led(struct path_struct *path_struct, int led_action, 522 struct device_element *status, 523 int verbose) 524 { 525 gfc_map_t map; 526 char ses_path[MAXPATHLEN]; 527 uchar_t *page_buf; 528 int err, write, fd, front_index, rear_index, offset; 529 unsigned short page_len; 530 struct device_element *elem; 531 L_state *l_state; 532 int enc_type; 533 534 if ((path_struct == NULL) || (status == NULL)) { 535 return (L_INVALID_PATH_FORMAT); 536 } 537 538 /* 539 * Need to get a valid location, front/rear & slot. 540 * 541 * The path_struct will return a valid slot 542 * and the IB path or a disk path. 543 */ 544 545 map.dev_addr = (gfc_port_dev_info_t *)NULL; 546 if (!path_struct->ib_path_flag) { 547 if ((err = g_get_dev_map(path_struct->p_physical_path, 548 &map, verbose)) != 0) 549 return (err); 550 if ((err = l_get_ses_path(path_struct->p_physical_path, 551 ses_path, &map, verbose)) != 0) { 552 free((void *)map.dev_addr); 553 return (err); 554 } 555 } else { 556 (void) strcpy(ses_path, path_struct->p_physical_path); 557 } 558 559 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 560 free((void *)map.dev_addr); 561 return (L_MALLOC_FAILED); 562 } 563 564 if (!path_struct->slot_valid) { 565 if ((map.dev_addr != NULL) && 566 (err = g_get_dev_map(path_struct->p_physical_path, 567 &map, verbose)) != 0) { 568 (void) l_free_lstate(&l_state); 569 return (err); 570 } 571 if ((err = l_get_ses_path(path_struct->p_physical_path, 572 ses_path, &map, verbose)) != 0) { 573 (void) l_free_lstate(&l_state); 574 free((void *)map.dev_addr); 575 return (err); 576 } 577 if ((err = l_get_status(ses_path, l_state, verbose)) != 0) { 578 (void) l_free_lstate(&l_state); 579 free((void *)map.dev_addr); 580 return (err); 581 } 582 583 /* We are passing the disks path */ 584 if (err = l_get_slot(path_struct, l_state, verbose)) { 585 (void) l_free_lstate(&l_state); 586 free((void *)map.dev_addr); 587 return (err); 588 } 589 } 590 if (map.dev_addr != NULL) 591 free((void *)map.dev_addr); /* Not used anymore */ 592 593 if ((page_buf = (uchar_t *)calloc(1, 594 MAX_REC_DIAG_LENGTH)) == NULL) { 595 (void) l_free_lstate(&l_state); 596 return (L_MALLOC_FAILED); 597 } 598 599 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 600 (void) l_free_lstate(&l_state); 601 (void) g_destroy_data(page_buf); 602 return (L_OPEN_PATH_FAIL); 603 } 604 605 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 606 L_PAGE_2, verbose)) { 607 (void) l_free_lstate(&l_state); 608 (void) close(fd); 609 (void) g_destroy_data(page_buf); 610 return (err); 611 } 612 613 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 614 615 /* Get index to the disk we are interested in */ 616 if (err = l_get_status(ses_path, l_state, verbose)) { 617 (void) l_free_lstate(&l_state); 618 (void) close(fd); 619 (void) g_destroy_data(page_buf); 620 return (err); 621 } 622 623 /* find enclosure type */ 624 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 625 strlen(DAK_OFF_NAME)) == 0) || 626 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 627 strlen(DAK_PROD_STR)) == 0)) { 628 enc_type = DAK_ENC_TYPE; 629 } else { 630 enc_type = SENA_ENC_TYPE; 631 } 632 633 /* Double check slot. */ 634 if (path_struct->slot >= l_state->total_num_drv/2) { 635 (void) l_free_lstate(&l_state); 636 return (L_INVALID_SLOT); 637 } 638 639 if (err = l_get_disk_element_index(l_state, &front_index, 640 &rear_index)) { 641 (void) l_free_lstate(&l_state); 642 return (err); 643 } 644 645 /* Skip global element */ 646 front_index++; 647 if (enc_type == DAK_ENC_TYPE) { 648 rear_index += l_state->total_num_drv/2 + 1; 649 } else { 650 rear_index++; 651 } 652 653 if (path_struct->f_flag) { 654 offset = (8 + (front_index + path_struct->slot)*4); 655 } else { 656 offset = (8 + (rear_index + path_struct->slot)*4); 657 } 658 659 elem = (struct device_element *)(page_buf + offset); 660 /* 661 * now do requested action. 662 */ 663 bcopy((const void *)elem, (void *)status, 664 sizeof (struct device_element)); /* save status */ 665 bzero(elem, sizeof (struct device_element)); 666 elem->select = 1; 667 elem->dev_off = status->dev_off; 668 elem->en_bypass_a = status->en_bypass_a; 669 elem->en_bypass_b = status->en_bypass_b; 670 write = 1; 671 672 switch (led_action) { 673 case L_LED_STATUS: 674 write = 0; 675 break; 676 case L_LED_RQST_IDENTIFY: 677 elem->ident = 1; 678 if (verbose) { 679 if (enc_type == DAK_ENC_TYPE) { 680 (void) fprintf(stdout, 681 MSGSTR(9043, " Blinking LED for slot %d in enclosure" 682 " %s\n"), path_struct->f_flag ? path_struct->slot : 683 path_struct->slot + (MAX_DRIVES_DAK/2), 684 l_state->ib_tbl.enclosure_name); 685 } else { 686 (void) fprintf(stdout, 687 MSGSTR(9043, " Blinking LED for slot %d in enclosure" 688 " %s\n"), path_struct->slot, 689 l_state->ib_tbl.enclosure_name); 690 } 691 } 692 break; 693 case L_LED_OFF: 694 if (verbose) { 695 if (enc_type == DAK_ENC_TYPE) { 696 (void) fprintf(stdout, 697 MSGSTR(9044, 698 " Turning off LED for slot %d in enclosure" 699 " %s\n"), path_struct->f_flag ? path_struct->slot 700 : path_struct->slot + (MAX_DRIVES_DAK/2), 701 l_state->ib_tbl.enclosure_name); 702 } else { 703 (void) fprintf(stdout, 704 MSGSTR(9044, 705 " Turning off LED for slot %d in enclosure" 706 " %s\n"), path_struct->slot, 707 l_state->ib_tbl.enclosure_name); 708 } 709 } 710 break; 711 default: 712 (void) l_free_lstate(&l_state); 713 return (L_INVALID_LED_RQST); 714 } /* End of switch */ 715 716 if (write) { 717 if (getenv("_LUX_D_DEBUG") != NULL) { 718 g_dump(" l_led: Updating led state: " 719 "Device Status Element ", 720 (uchar_t *)elem, sizeof (struct device_element), 721 HEX_ONLY); 722 } 723 if (err = g_scsi_send_diag_cmd(fd, 724 (uchar_t *)page_buf, page_len)) { 725 (void) close(fd); 726 (void) g_destroy_data(page_buf); 727 (void) l_free_lstate(&l_state); 728 return (err); 729 } 730 731 bzero(page_buf, MAX_REC_DIAG_LENGTH); 732 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 733 L_PAGE_2, verbose)) { 734 (void) g_destroy_data(page_buf); 735 (void) close(fd); 736 (void) l_free_lstate(&l_state); 737 return (err); 738 } 739 elem = (struct device_element *)(page_buf + offset); 740 bcopy((const void *)elem, (void *)status, 741 sizeof (struct device_element)); 742 } 743 if (getenv("_LUX_D_DEBUG") != NULL) { 744 g_dump(" l_led: Device Status Element ", 745 (uchar_t *)status, sizeof (struct device_element), 746 HEX_ONLY); 747 } 748 749 (void) l_free_lstate(&l_state); 750 (void) close(fd); 751 (void) g_destroy_data(page_buf); 752 return (0); 753 } 754 755 756 /* 757 * frees the previously alloced l_state 758 * structure. 759 * 760 * RETURNS: 761 * 0 O.K. 762 * non-zero otherwise 763 */ 764 int 765 l_free_lstate(L_state **l_state) 766 { 767 int i; 768 769 if ((l_state == NULL) || (*l_state == NULL)) 770 return (0); 771 772 for (i = 0; i < (int)(*l_state)->total_num_drv/2; i++) { 773 if ((*l_state)->drv_front[i].g_disk_state.multipath_list != NULL) 774 (void) g_free_multipath( 775 (*l_state)->drv_front[i].g_disk_state.multipath_list); 776 if ((*l_state)->drv_rear[i].g_disk_state.multipath_list != NULL) 777 (void) g_free_multipath( 778 (*l_state)->drv_rear[i].g_disk_state.multipath_list); 779 } 780 (void) g_destroy_data (*l_state); 781 l_state = NULL; 782 783 return (0); 784 } 785 786 787 788 /* 789 * Set the state of an individual disk 790 * in the Photon enclosure the powered 791 * up/down mode. The path must point to 792 * a disk or the ib_path_flag must be set. 793 * 794 * RETURNS: 795 * 0 O.K. 796 * non-zero otherwise 797 */ 798 int 799 l_dev_pwr_up_down(char *path_phys, struct path_struct *path_struct, 800 int power_off_flag, int verbose, int force_flag) 801 /*ARGSUSED*/ 802 { 803 gfc_map_t map; 804 char ses_path[MAXPATHLEN], dev_path[MAXPATHLEN]; 805 int slot, err = 0; 806 L_state *l_state = NULL; 807 struct l_disk_state_struct *drive; 808 struct dlist *dl, *dl1; 809 devctl_hdl_t devhdl; 810 WWN_list *wwn_list = NULL; 811 L_inquiry inq; 812 813 if (path_struct == NULL) { 814 return (L_INVALID_PATH_FORMAT); 815 } 816 817 dl = (struct dlist *)NULL; 818 map.dev_addr = (gfc_port_dev_info_t *)NULL; 819 820 if (err = g_get_dev_map(path_struct->p_physical_path, 821 &map, verbose)) 822 return (err); 823 824 if (err = l_get_ses_path(path_struct->p_physical_path, 825 ses_path, &map, verbose)) { 826 free((void *)map.dev_addr); 827 return (err); 828 } 829 free((void *)map.dev_addr); /* Not used anymore */ 830 831 /* 832 * Check to see if we have a photon, and if not, don't allow 833 * this operation 834 */ 835 if (err = g_get_inquiry(ses_path, &inq)) { 836 return (err); 837 } 838 if (l_get_enc_type(inq) != SENA_ENC_TYPE) { 839 return (L_ENCL_INVALID_PATH); 840 } 841 /* 842 * OK, so we have a photon... we can continue 843 */ 844 845 846 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 847 return (L_MALLOC_FAILED); 848 } 849 850 if (err = l_get_status(ses_path, l_state, verbose)) { 851 (void) l_free_lstate(&l_state); 852 return (err); 853 } 854 855 if (!path_struct->slot_valid) { 856 /* We are passing the disks path */ 857 if (err = l_get_slot(path_struct, l_state, verbose)) { 858 (void) l_free_lstate(&l_state); 859 return (err); 860 } 861 } 862 863 slot = path_struct->slot; 864 (void) strcpy(dev_path, path_struct->p_physical_path); 865 866 /* 867 * Either front or rear drive 868 */ 869 if (path_struct->f_flag) { 870 drive = &l_state->drv_front[slot]; 871 } else { 872 drive = &l_state->drv_rear[slot]; 873 } 874 875 /* 876 * Check for drive presence always 877 */ 878 if (drive->ib_status.code == S_NOT_INSTALLED) { 879 (void) l_free_lstate(&l_state); 880 return (L_SLOT_EMPTY); 881 } 882 883 /* 884 * Check disk state 885 * before the power off. 886 * 887 */ 888 if (power_off_flag && !force_flag) { 889 goto pre_pwr_dwn; 890 } else { 891 goto pwr_up_dwn; 892 } 893 894 pre_pwr_dwn: 895 896 /* 897 * Check whether disk 898 * is reserved by another 899 * host 900 */ 901 if ((drive->g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || 902 (drive->g_disk_state.d_state_flags[PORT_B] & 903 L_RESERVED)) { 904 (void) l_free_lstate(&l_state); 905 return (L_DEVICE_RESERVED); 906 } 907 908 909 if ((dl = (struct dlist *)g_zalloc(sizeof (struct dlist))) == NULL) { 910 (void) l_free_lstate(&l_state); 911 return (L_MALLOC_FAILED); 912 } 913 914 /* 915 * NOTE: It is not necessary to get the multipath list here as ------ 916 * we alread have it after getting the status earlier. 917 * - REWRITE - 918 */ 919 920 /* 921 * Get path to all the FC disk and tape devices. 922 * 923 * I get this now and pass down for performance 924 * reasons. 925 * If for some reason the list can become invalid, 926 * i.e. device being offlined, then the list 927 * must be re-gotten. 928 */ 929 if (err = g_get_wwn_list(&wwn_list, verbose)) { 930 (void) g_destroy_data(dl); 931 (void) l_free_lstate(&l_state); 932 return (err); /* Failure */ 933 } 934 935 dl->dev_path = dev_path; 936 if ((err = g_get_multipath(dev_path, 937 &(dl->multipath), wwn_list, verbose)) != 0) { 938 (void) g_destroy_data(dl); 939 (void) g_free_wwn_list(&wwn_list); 940 (void) l_free_lstate(&l_state); 941 return (err); 942 } 943 944 for (dl1 = dl->multipath; dl1 != NULL; dl1 = dl1->next) { 945 if ((devhdl = devctl_device_acquire(dl1->dev_path, 946 DC_EXCL)) == NULL) { 947 if (errno != EBUSY) { 948 ER_DPRINTF("%s could not acquire" 949 " the device: %s\n\n", 950 strerror(errno), dl1->dev_path); 951 continue; 952 } 953 } 954 if (devctl_device_offline(devhdl) != 0) { 955 (void) devctl_release(devhdl); 956 (void) g_free_multipath(dl->multipath); 957 (void) g_destroy_data(dl); 958 (void) g_free_wwn_list(&wwn_list); 959 (void) l_free_lstate(&l_state); 960 return (L_POWER_OFF_FAIL_BUSY); 961 } 962 (void) devctl_release(devhdl); 963 } 964 965 pwr_up_dwn: 966 err = pwr_up_down(ses_path, l_state, path_struct->f_flag, 967 path_struct->slot, power_off_flag, verbose); 968 969 if (dl != NULL) { 970 (void) g_free_multipath(dl->multipath); 971 (void) g_destroy_data(dl); 972 } 973 (void) g_free_wwn_list(&wwn_list); 974 (void) l_free_lstate(&l_state); 975 if (err) { 976 return (err); 977 } 978 return (0); 979 } 980 981 982 983 /* 984 * l_pho_pwr_up_down() Set the state of the Photon enclosure 985 * the powered up/down mode. 986 * The path must point to an IB. 987 * 988 * RETURNS: 989 * 0 O.K. 990 * non-zero otherwise 991 */ 992 int 993 l_pho_pwr_up_down(char *dev_name, char *path_phys, int power_off_flag, 994 int verbose, int force_flag) 995 { 996 L_state *l_state = NULL; 997 int i, err = 0; 998 struct dlist *dl, *dl1; 999 char dev_path[MAXPATHLEN]; 1000 devctl_hdl_t devhdl; 1001 WWN_list *wwn_list = NULL; 1002 1003 if (path_phys == NULL) { 1004 return (L_INVALID_PATH_FORMAT); 1005 } 1006 1007 dl = (struct dlist *)NULL; 1008 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 1009 return (L_MALLOC_FAILED); 1010 } 1011 if (err = l_get_status(path_phys, l_state, verbose)) { 1012 (void) l_free_lstate(&l_state); 1013 return (err); 1014 } 1015 if (power_off_flag && !force_flag) { 1016 goto pre_pwr_dwn; 1017 } else { 1018 goto pwr_up_dwn; 1019 } 1020 1021 pre_pwr_dwn: 1022 1023 /* 1024 * Check if any disk in this enclosure 1025 * is reserved by another host before 1026 * the power off. 1027 */ 1028 for (i = 0; i < l_state->total_num_drv/2; i++) { 1029 if ((l_state->drv_front[i].g_disk_state.d_state_flags[PORT_A] & 1030 L_RESERVED) || 1031 (l_state->drv_front[i].g_disk_state.d_state_flags[PORT_B] & 1032 L_RESERVED) || 1033 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_A] & 1034 L_RESERVED) || 1035 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_B] & 1036 L_RESERVED)) { 1037 return (L_DISKS_RESERVED); 1038 } 1039 } 1040 1041 /* 1042 * Check if any disk in this enclosure 1043 * Get path to all the FC disk and tape devices. 1044 * 1045 * I get this now and pass down for performance 1046 * reasons. 1047 * If for some reason the list can become invalid, 1048 * i.e. device being offlined, then the list 1049 * must be re-gotten. 1050 */ 1051 if (err = g_get_wwn_list(&wwn_list, verbose)) { 1052 (void) l_free_lstate(&l_state); 1053 return (err); /* Failure */ 1054 } 1055 for (i = 0; i < l_state->total_num_drv/2; i++) { 1056 if (*l_state->drv_front[i].g_disk_state.physical_path) { 1057 (void) memset(dev_path, 0, MAXPATHLEN); 1058 (void) strcpy(dev_path, 1059 (char *)&l_state->drv_front[i].g_disk_state.physical_path); 1060 1061 if ((dl = (struct dlist *) 1062 g_zalloc(sizeof (struct dlist))) == NULL) { 1063 (void) g_free_wwn_list(&wwn_list); 1064 (void) l_free_lstate(&l_state); 1065 return (L_MALLOC_FAILED); 1066 } 1067 dl->dev_path = dev_path; 1068 if (g_get_multipath(dev_path, &(dl->multipath), 1069 wwn_list, verbose) != 0) { 1070 (void) g_destroy_data(dl); 1071 continue; 1072 } 1073 1074 for (dl1 = dl->multipath; 1075 dl1 != NULL; 1076 dl1 = dl1->next) { 1077 1078 /* attempt to acquire the device */ 1079 if ((devhdl = devctl_device_acquire( 1080 dl1->dev_path, DC_EXCL)) == NULL) { 1081 if (errno != EBUSY) { 1082 ER_DPRINTF("%s: Could not " 1083 "acquire the device: %s\n\n", 1084 strerror(errno), 1085 dl1->dev_path); 1086 continue; 1087 } 1088 } 1089 1090 /* attempt to offline the device */ 1091 if (devctl_device_offline(devhdl) != 0) { 1092 (void) devctl_release(devhdl); 1093 (void) g_free_multipath( 1094 dl->multipath); 1095 (void) g_destroy_data(dl); 1096 (void) g_free_wwn_list(&wwn_list); 1097 (void) l_free_lstate(&l_state); 1098 return (L_POWER_OFF_FAIL_BUSY); 1099 } 1100 1101 /* release handle acquired above */ 1102 (void) devctl_release(devhdl); 1103 } 1104 (void) g_free_multipath(dl->multipath); 1105 (void) g_destroy_data(dl); 1106 1107 } 1108 if (*l_state->drv_rear[i].g_disk_state.physical_path) { 1109 (void) memset(dev_path, 0, MAXPATHLEN); 1110 (void) strcpy(dev_path, 1111 (char *)&l_state->drv_rear[i].g_disk_state.physical_path); 1112 1113 if ((dl = (struct dlist *) 1114 g_zalloc(sizeof (struct dlist))) == NULL) { 1115 (void) g_free_wwn_list(&wwn_list); 1116 (void) l_free_lstate(&l_state); 1117 return (L_MALLOC_FAILED); 1118 } 1119 dl->dev_path = dev_path; 1120 if (g_get_multipath(dev_path, &(dl->multipath), 1121 wwn_list, verbose) != 0) { 1122 (void) g_destroy_data(dl); 1123 continue; 1124 } 1125 1126 1127 for (dl1 = dl->multipath; 1128 dl1 != NULL; 1129 dl1 = dl1->next) { 1130 1131 /* attempt to acquire the device */ 1132 if ((devhdl = devctl_device_acquire( 1133 dl1->dev_path, DC_EXCL)) == NULL) { 1134 if (errno != EBUSY) { 1135 ER_DPRINTF("%s: Could not " 1136 "acquire the device: %s\n\n", 1137 strerror(errno), 1138 dl1->dev_path); 1139 continue; 1140 } 1141 } 1142 /* attempt to offline the device */ 1143 if (devctl_device_offline(devhdl) != 0) { 1144 (void) devctl_release(devhdl); 1145 (void) g_free_multipath( 1146 dl->multipath); 1147 (void) g_destroy_data(dl); 1148 (void) g_free_wwn_list(&wwn_list); 1149 (void) l_free_lstate(&l_state); 1150 return (L_POWER_OFF_FAIL_BUSY); 1151 } 1152 1153 /* release handle acquired above */ 1154 (void) devctl_release(devhdl); 1155 } 1156 (void) g_free_multipath(dl->multipath); 1157 (void) g_destroy_data(dl); 1158 1159 } 1160 } 1161 1162 pwr_up_dwn: 1163 1164 (void) g_free_wwn_list(&wwn_list); 1165 if ((err = pwr_up_down(path_phys, l_state, 0, -1, 1166 power_off_flag, verbose)) != 0) { 1167 (void) l_free_lstate(&l_state); 1168 return (err); 1169 } 1170 (void) l_free_lstate(&l_state); 1171 return (0); 1172 } 1173 1174 1175 /* 1176 * Set the state of the Photon enclosure or disk 1177 * powered up/down mode. 1178 * The path must point to an IB. 1179 * slot == -1 implies entire enclosure. 1180 * 1181 * RETURNS: 1182 * 0 O.K. 1183 * non-zero otherwise 1184 */ 1185 static int 1186 pwr_up_down(char *path_phys, L_state *l_state, int front, int slot, 1187 int power_off_flag, int verbose) 1188 { 1189 L_inquiry inq; 1190 int fd, status, err; 1191 uchar_t *page_buf; 1192 int front_index, rear_index, front_offset, rear_offset; 1193 unsigned short page_len; 1194 struct device_element *front_elem, *rear_elem; 1195 1196 (void) memset(&inq, 0, sizeof (inq)); 1197 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) { 1198 return (L_OPEN_PATH_FAIL); 1199 } 1200 /* Verify it is a Photon */ 1201 if (status = g_scsi_inquiry_cmd(fd, 1202 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 1203 (void) close(fd); 1204 return (status); 1205 } 1206 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 1207 (!(strncmp((char *)inq.inq_vid, "SUN ", 1208 sizeof (inq.inq_vid)) && 1209 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 1210 (void) close(fd); 1211 return (L_ENCL_INVALID_PATH); 1212 } 1213 1214 /* 1215 * To power up/down a Photon we use the Driver Off 1216 * bit in the global device control element. 1217 */ 1218 if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) { 1219 return (L_MALLOC_FAILED); 1220 } 1221 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 1222 L_PAGE_2, verbose)) { 1223 (void) close(fd); 1224 (void) g_destroy_data(page_buf); 1225 return (err); 1226 } 1227 1228 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 1229 1230 /* Double check slot as convert_name only does gross check */ 1231 if (slot >= l_state->total_num_drv/2) { 1232 (void) close(fd); 1233 (void) g_destroy_data(page_buf); 1234 return (L_INVALID_SLOT); 1235 } 1236 1237 if (err = l_get_disk_element_index(l_state, &front_index, 1238 &rear_index)) { 1239 (void) close(fd); 1240 (void) g_destroy_data(page_buf); 1241 return (err); 1242 } 1243 /* Skip global element */ 1244 front_index++; 1245 rear_index++; 1246 1247 front_offset = (8 + (front_index + slot)*4); 1248 rear_offset = (8 + (rear_index + slot)*4); 1249 1250 front_elem = (struct device_element *)(page_buf + front_offset); 1251 rear_elem = (struct device_element *)(page_buf + rear_offset); 1252 1253 if (front || slot == -1) { 1254 /* 1255 * now do requested action. 1256 */ 1257 bzero(front_elem, sizeof (struct device_element)); 1258 /* Set/reset power off bit */ 1259 front_elem->dev_off = power_off_flag; 1260 front_elem->select = 1; 1261 } 1262 if (!front || slot == -1) { 1263 /* Now do rear */ 1264 bzero(rear_elem, sizeof (struct device_element)); 1265 /* Set/reset power off bit */ 1266 rear_elem->dev_off = power_off_flag; 1267 rear_elem->select = 1; 1268 } 1269 1270 if (getenv("_LUX_D_DEBUG") != NULL) { 1271 if (front || slot == -1) { 1272 g_dump(" pwr_up_down: " 1273 "Front Device Status Element ", 1274 (uchar_t *)front_elem, 1275 sizeof (struct device_element), 1276 HEX_ONLY); 1277 } 1278 if (!front || slot == -1) { 1279 g_dump(" pwr_up_down: " 1280 "Rear Device Status Element ", 1281 (uchar_t *)rear_elem, 1282 sizeof (struct device_element), 1283 HEX_ONLY); 1284 } 1285 } 1286 if (err = g_scsi_send_diag_cmd(fd, 1287 (uchar_t *)page_buf, page_len)) { 1288 (void) close(fd); 1289 (void) g_destroy_data(page_buf); 1290 return (err); 1291 } 1292 (void) close(fd); 1293 (void) g_destroy_data(page_buf); 1294 return (0); 1295 } 1296 1297 /* 1298 * Set the password of the FPM by sending the password 1299 * in page 4 of the Send Diagnostic command. 1300 * 1301 * The path must point to an IB. 1302 * 1303 * The size of the password string must be <= 8 bytes. 1304 * The string can also be NULL. This is the way the user 1305 * chooses to not have a password. 1306 * 1307 * I then tell the photon by giving it 4 NULL bytes. 1308 * 1309 * RETURNS: 1310 * 0 O.K. 1311 * non-zero otherwise 1312 */ 1313 int 1314 l_new_password(char *path_phys, char *password) 1315 { 1316 Page4_name page4; 1317 L_inquiry inq; 1318 int fd, status; 1319 1320 (void) memset(&inq, 0, sizeof (inq)); 1321 (void) memset(&page4, 0, sizeof (page4)); 1322 1323 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) { 1324 return (L_OPEN_PATH_FAIL); 1325 } 1326 /* Verify it is a Photon */ 1327 if (status = g_scsi_inquiry_cmd(fd, 1328 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 1329 (void) close(fd); 1330 return (status); 1331 } 1332 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 1333 (!(strncmp((char *)inq.inq_vid, "SUN ", 1334 sizeof (inq.inq_vid)) && 1335 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 1336 (void) close(fd); 1337 return (L_ENCL_INVALID_PATH); 1338 } 1339 1340 page4.page_code = L_PAGE_4; 1341 page4.page_len = (ushort_t)max((strlen(password) + 4), 8); 1342 /* Double check */ 1343 if (strlen(password) > 8) { 1344 return (L_INVALID_PASSWORD_LEN); 1345 } 1346 page4.string_code = L_PASSWORD; 1347 page4.enable = 1; 1348 (void) strcpy((char *)page4.name, password); 1349 1350 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4, 1351 page4.page_len + HEADER_LEN)) { 1352 (void) close(fd); 1353 return (status); 1354 } 1355 1356 (void) close(fd); 1357 return (0); 1358 } 1359 1360 1361 1362 /* 1363 * Set the name of the enclosure by sending the name 1364 * in page 4 of the Send Diagnostic command. 1365 * 1366 * The path must point to an IB. 1367 * 1368 * RETURNS: 1369 * 0 O.K. 1370 * non-zero otherwise 1371 */ 1372 int 1373 l_new_name(char *path_phys, char *name) 1374 { 1375 Page4_name page4; 1376 L_inquiry inq; 1377 int fd, status; 1378 1379 if ((path_phys == NULL) || (name == NULL)) { 1380 return (L_INVALID_PATH_FORMAT); 1381 } 1382 1383 (void) memset(&inq, 0, sizeof (inq)); 1384 (void) memset(&page4, 0, sizeof (page4)); 1385 1386 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) { 1387 return (L_OPEN_PATH_FAIL); 1388 } 1389 /* Verify it is a Photon */ 1390 if (status = g_scsi_inquiry_cmd(fd, 1391 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 1392 (void) close(fd); 1393 return (status); 1394 } 1395 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 1396 (!(strncmp((char *)inq.inq_vid, "SUN ", 1397 sizeof (inq.inq_vid)) && 1398 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 1399 (void) close(fd); 1400 return (L_ENCL_INVALID_PATH); 1401 } 1402 1403 page4.page_code = L_PAGE_4; 1404 page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4)); 1405 page4.string_code = L_ENCL_NAME; 1406 page4.enable = 1; 1407 strncpy((char *)page4.name, name, sizeof (page4.name)); 1408 1409 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4, 1410 sizeof (page4))) { 1411 (void) close(fd); 1412 return (status); 1413 } 1414 1415 /* 1416 * Check the name really changed. 1417 */ 1418 if (status = g_scsi_inquiry_cmd(fd, 1419 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 1420 (void) close(fd); 1421 return (status); 1422 } 1423 if (strncmp((char *)inq.inq_box_name, name, sizeof (page4.name)) != 0) { 1424 char name_buf[MAXNAMELEN]; 1425 (void) close(fd); 1426 strncpy((char *)name_buf, (char *)inq.inq_box_name, 1427 sizeof (inq.inq_box_name)); 1428 return (L_ENCL_NAME_CHANGE_FAIL); 1429 } 1430 1431 (void) close(fd); 1432 return (0); 1433 } 1434 1435 1436 1437 /* 1438 * Issue a Loop Port enable Primitive sequence 1439 * to the device specified by the pathname. 1440 */ 1441 int 1442 l_enable(char *path, int verbose) 1443 /*ARGSUSED*/ 1444 { 1445 1446 return (0); 1447 } 1448 1449 /* 1450 * Issue a Loop Port Bypass Primitive sequence 1451 * to the device specified by the pathname. This requests the 1452 * device to set its L_Port into the bypass mode. 1453 */ 1454 int 1455 l_bypass(char *path, int verbose) 1456 /*ARGSUSED*/ 1457 { 1458 1459 return (0); 1460 } 1461 1462 1463 1464 /* 1465 * Create a linked list of all the Photon enclosures that 1466 * are attached to this host. 1467 * 1468 * RETURN VALUES: 0 O.K. 1469 * 1470 * box_list pointer: 1471 * NULL: No enclosures found. 1472 * !NULL: Enclosures found 1473 * box_list points to a linked list of boxes. 1474 */ 1475 int 1476 l_get_box_list(struct box_list_struct **box_list_ptr, int verbose) 1477 { 1478 char *dev_name; 1479 DIR *dirp; 1480 struct dirent *entp; 1481 char namebuf[MAXPATHLEN]; 1482 struct stat sb; 1483 char *result = NULL; 1484 int fd, status; 1485 L_inquiry inq; 1486 Box_list *box_list, *l1, *l2; 1487 IB_page_config page1; 1488 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 1489 int al_pa; 1490 1491 if (box_list_ptr == NULL) { 1492 return (L_INVALID_PATH_FORMAT); 1493 } 1494 1495 box_list = *box_list_ptr = NULL; 1496 if ((dev_name = (char *)g_zalloc(sizeof ("/dev/es"))) == NULL) { 1497 return (L_MALLOC_FAILED); 1498 } 1499 (void) sprintf((char *)dev_name, "/dev/es"); 1500 1501 if (verbose) { 1502 (void) fprintf(stdout, 1503 MSGSTR(9045, 1504 " Searching directory %s for links to enclosures\n"), 1505 dev_name); 1506 } 1507 1508 if ((dirp = opendir(dev_name)) == NULL) { 1509 (void) g_destroy_data(dev_name); 1510 /* No Photons found */ 1511 B_DPRINTF(" l_get_box_list: No Photons found\n"); 1512 return (0); 1513 } 1514 1515 1516 while ((entp = readdir(dirp)) != NULL) { 1517 if (strcmp(entp->d_name, ".") == 0 || 1518 strcmp(entp->d_name, "..") == 0) 1519 continue; 1520 1521 (void) sprintf(namebuf, "%s/%s", dev_name, entp->d_name); 1522 1523 if ((lstat(namebuf, &sb)) < 0) { 1524 ER_DPRINTF("Warning: Cannot stat %s\n", 1525 namebuf); 1526 continue; 1527 } 1528 1529 if (!S_ISLNK(sb.st_mode)) { 1530 ER_DPRINTF("Warning: %s is not a symbolic link\n", 1531 namebuf); 1532 continue; 1533 } 1534 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) { 1535 ER_DPRINTF(" Warning: Get physical name from" 1536 " link failed. Link=%s\n", namebuf); 1537 continue; 1538 } 1539 1540 /* Found a SES card. */ 1541 B_DPRINTF(" l_get_box_list: Link to SES Card found: %s/%s\n", 1542 dev_name, entp->d_name); 1543 if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) == -1) { 1544 g_destroy_data(result); 1545 continue; /* Ignore errors */ 1546 } 1547 /* Get the box name */ 1548 if (status = g_scsi_inquiry_cmd(fd, 1549 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 1550 (void) close(fd); 1551 g_destroy_data(result); 1552 continue; /* Ignore errors */ 1553 } 1554 1555 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) || 1556 (((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI) && 1557 (l_get_enc_type(inq) == DAK_ENC_TYPE))) { 1558 /* 1559 * Found Photon/Daktari 1560 */ 1561 1562 /* Get the port WWN from the IB, page 1 */ 1563 if ((status = l_get_envsen_page(fd, (uchar_t *)&page1, 1564 sizeof (page1), 1, 0)) != NULL) { 1565 (void) close(fd); 1566 g_destroy_data(result); 1567 (void) g_destroy_data(dev_name); 1568 closedir(dirp); 1569 return (status); 1570 } 1571 1572 /* 1573 * Build list of names. 1574 */ 1575 if ((l2 = (struct box_list_struct *) 1576 g_zalloc(sizeof (struct box_list_struct))) 1577 == NULL) { 1578 (void) close(fd); 1579 g_destroy_data(result); 1580 g_destroy_data(dev_name); 1581 closedir(dirp); 1582 return (L_MALLOC_FAILED); 1583 } 1584 1585 /* Fill in structure */ 1586 (void) strcpy((char *)l2->b_physical_path, 1587 (char *)result); 1588 (void) strcpy((char *)l2->logical_path, 1589 (char *)namebuf); 1590 bcopy((void *)page1.enc_node_wwn, 1591 (void *)l2->b_node_wwn, WWN_SIZE); 1592 (void) sprintf(l2->b_node_wwn_s, 1593 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 1594 page1.enc_node_wwn[0], 1595 page1.enc_node_wwn[1], 1596 page1.enc_node_wwn[2], 1597 page1.enc_node_wwn[3], 1598 page1.enc_node_wwn[4], 1599 page1.enc_node_wwn[5], 1600 page1.enc_node_wwn[6], 1601 page1.enc_node_wwn[7]); 1602 strncpy((char *)l2->prod_id_s, 1603 (char *)inq.inq_pid, 1604 sizeof (inq.inq_pid)); 1605 strncpy((char *)l2->b_name, 1606 (char *)inq.inq_box_name, 1607 sizeof (inq.inq_box_name)); 1608 /* make sure null terminated */ 1609 l2->b_name[sizeof (l2->b_name) - 1] = NULL; 1610 1611 /* 1612 * Now get the port WWN for the port 1613 * we are connected to. 1614 */ 1615 status = g_get_wwn(result, port_wwn, node_wwn, 1616 &al_pa, verbose); 1617 if (status == 0) { 1618 (void) sprintf(l2->b_port_wwn_s, 1619 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 1620 port_wwn[0], port_wwn[1], port_wwn[2], 1621 port_wwn[3], port_wwn[4], port_wwn[5], 1622 port_wwn[6], port_wwn[7]); 1623 bcopy((void *)port_wwn, 1624 (void *)l2->b_port_wwn, WWN_SIZE); 1625 1626 B_DPRINTF(" l_get_box_list:" 1627 " Found enclosure named:%s\n", l2->b_name); 1628 1629 if (box_list == NULL) { 1630 l1 = box_list = l2; 1631 } else { 1632 l2->box_prev = l1; 1633 l1 = l1->box_next = l2; 1634 } 1635 } else { 1636 (void) close(fd); 1637 g_destroy_data(result); 1638 (void) g_destroy_data(dev_name); 1639 (void) g_destroy_data(l2); 1640 closedir(dirp); 1641 return (status); 1642 } 1643 1644 } 1645 g_destroy_data(result); 1646 (void) close(fd); 1647 *box_list_ptr = box_list; /* pass back ptr to list */ 1648 } 1649 (void) g_destroy_data(dev_name); 1650 closedir(dirp); 1651 return (0); 1652 } 1653 1654 void 1655 l_free_box_list(struct box_list_struct **box_list) 1656 { 1657 Box_list *next = NULL; 1658 1659 if (box_list == NULL) { 1660 return; 1661 } 1662 1663 for (; *box_list != NULL; *box_list = next) { 1664 next = (*box_list)->box_next; 1665 (void) g_destroy_data(*box_list); 1666 } 1667 1668 *box_list = NULL; 1669 } 1670 1671 1672 1673 /* 1674 * Finds out if there are any other boxes 1675 * with the same name as "name". 1676 * 1677 * RETURNS: 1678 * 0 There are no other boxes with the same name. 1679 * >0 if duplicate names found 1680 */ 1681 /*ARGSUSED*/ 1682 int 1683 l_duplicate_names(Box_list *b_list, char wwn[], char *name, int verbose) 1684 { 1685 int dup_flag = 0; 1686 Box_list *box_list_ptr = NULL; 1687 1688 if ((name == NULL) || (wwn == NULL)) 1689 return (0); 1690 1691 box_list_ptr = b_list; 1692 while (box_list_ptr != NULL) { 1693 if ((strcmp(name, (const char *)box_list_ptr->b_name) == 0) && 1694 (strcmp(box_list_ptr->b_node_wwn_s, wwn) != 0)) { 1695 dup_flag++; 1696 break; 1697 } 1698 box_list_ptr = box_list_ptr->box_next; 1699 } 1700 return (dup_flag); 1701 } 1702 1703 1704 1705 /* 1706 * Checks for a name conflict with an SSA cN type name. 1707 */ 1708 int 1709 l_get_conflict(char *name, char **result, int verbose) 1710 { 1711 char s[MAXPATHLEN]; 1712 char *p = NULL; 1713 char *pp = NULL; 1714 Box_list *box_list = NULL; 1715 int found_box = 0, err = 0; 1716 1717 (void) strcpy(s, name); 1718 if ((*result = g_get_physical_name(s)) == NULL) { 1719 return (0); 1720 } 1721 if ((strstr((const char *)*result, PLNDEF)) == NULL) { 1722 (void) g_destroy_data(*result); 1723 *result = NULL; 1724 return (0); 1725 } 1726 P_DPRINTF(" l_get_conflict: Found " 1727 "SSA path using %s\n", s); 1728 /* Find path to IB */ 1729 if ((err = l_get_box_list(&box_list, verbose)) != 0) { 1730 return (err); /* Failure */ 1731 } 1732 /* 1733 * Valid cN type name found. 1734 */ 1735 while (box_list != NULL) { 1736 if ((strcmp((char *)s, 1737 (char *)box_list->b_name)) == 0) { 1738 found_box = 1; 1739 if (p == NULL) { 1740 if ((p = g_zalloc(strlen( 1741 box_list->b_physical_path) 1742 + 2)) == NULL) { 1743 (void) l_free_box_list(&box_list); 1744 return (errno); 1745 } 1746 } else { 1747 if ((pp = g_zalloc(strlen( 1748 box_list->b_physical_path) 1749 + strlen(p) 1750 + 2)) == NULL) { 1751 (void) l_free_box_list(&box_list); 1752 return (errno); 1753 } 1754 (void) strcpy(pp, p); 1755 (void) g_destroy_data(p); 1756 p = pp; 1757 } 1758 (void) strcat(p, box_list->b_physical_path); 1759 (void) strcat(p, "\n"); 1760 } 1761 box_list = box_list->box_next; 1762 } 1763 if (found_box) { 1764 D_DPRINTF("There is a conflict between the " 1765 "enclosure\nwith this name, %s, " 1766 "and a SSA name of the same form.\n" 1767 "Please use one of the following physical " 1768 "pathnames:\n%s\n%s\n", 1769 s, *result, p); 1770 1771 (void) l_free_box_list(&box_list); 1772 (void) g_destroy_data(p); 1773 return (L_SSA_CONFLICT); /* failure */ 1774 } 1775 (void) l_free_box_list(&box_list); 1776 return (0); 1777 } 1778 1779 /* 1780 * This function sets the "slot", "slot_valid" and "f_flag" fields of the 1781 * path_struct that is passed in IFF the device path passed in ("phys_path") 1782 * is a disk in an A5K or a Daktari. This is achieved by calling l_get_slot(). 1783 * 1784 * INPUT : 1785 * phys_path - physical path to a device 1786 * path_sturct - Pointer to pointer to a path_struct data structure 1787 * 1788 * OUTPUT : 1789 * if phys_path is that of an A5K/Daktari disk 1790 * path_struct->slot is set to the slot position in enclosure 1791 * path_struct->slot_valid is set to 1 1792 * path_struct->f_flag is set to 1 if in the front of an A5k 1793 * or if among the first 6 disks on a Daktari 1794 * else 1795 * they are left as they were 1796 * RETURNS: 1797 * 0 on SUCCESS 1798 * non-zero otherwise 1799 */ 1800 static int 1801 load_flds_if_enc_disk(char *phys_path, struct path_struct **path_struct) 1802 { 1803 int err = 0, verbose = 0; 1804 char ses_path[MAXPATHLEN]; 1805 gfc_map_t map; 1806 L_inquiry inq; 1807 L_state *l_state = NULL; 1808 1809 if ((path_struct == NULL) || (*path_struct == NULL) || 1810 (phys_path == NULL) || (*phys_path == NULL)) { 1811 return (L_INVALID_PATH_FORMAT); 1812 } 1813 1814 if ((strstr(phys_path, SLSH_DRV_NAME_SSD) == NULL) || 1815 (g_get_path_type(phys_path) == 0)) { 1816 /* 1817 * Don't proceed when not a disk device or if it is not a 1818 * valid FC device on which g_get_dev_map() can be done 1819 * (for example, g_get_dev_map() will fail on SSAs). 1820 * 1821 * Just return success 1822 */ 1823 return (0); 1824 } 1825 1826 if ((*path_struct)->ib_path_flag) { 1827 /* 1828 * If this flag is set, l_get_slot() should not be called 1829 * So, no point in proceeding. Just return success. 1830 */ 1831 return (0); 1832 } 1833 1834 if ((err = g_get_dev_map(phys_path, &map, verbose)) != 0) { 1835 return (err); 1836 } 1837 1838 if ((err = l_get_ses_path(phys_path, ses_path, &map, verbose)) != 0) { 1839 (void) free(map.dev_addr); 1840 if (err == L_NO_SES_PATH) { 1841 /* 1842 * This is not an error since this could be a device 1843 * which does not have SES nodes 1844 */ 1845 return (0); 1846 } 1847 return (err); 1848 } 1849 1850 /* 1851 * There is a SES path on the same FCA as the given disk. But if the 1852 * SES node is not of a photon/Daktari, we dont proceed 1853 */ 1854 if ((err = g_get_inquiry(ses_path, &inq)) != 0) { 1855 (void) free(map.dev_addr); 1856 return (err); 1857 } 1858 1859 /* 1860 * only want to continue if this is a photon or a Daktari 1861 * 1862 * if product ID is not SENA or VID is not "SUN" (checks for photon) 1863 * and if enclosure type is not a Daktari, then I return 1864 */ 1865 if (((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) || 1866 (strncmp((char *)inq.inq_vid, "SUN ", 1867 sizeof (inq.inq_vid)) != 0)) && 1868 ((l_get_enc_type(inq) != DAK_ENC_TYPE))) { 1869 /* Not a photon/Daktari */ 1870 (void) free(map.dev_addr); 1871 return (0); 1872 } 1873 1874 /* Now, set some fields that l_get_slot() uses and then call it */ 1875 if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) { 1876 (void) free(map.dev_addr); 1877 return (L_MALLOC_FAILED); 1878 } 1879 1880 if ((err = l_get_ib_status(ses_path, l_state, verbose)) != 0) { 1881 (void) free(map.dev_addr); 1882 (void) l_free_lstate(&l_state); 1883 return (err); 1884 } 1885 1886 if ((err = l_get_slot(*path_struct, l_state, verbose)) != 0) { 1887 (void) free(map.dev_addr); 1888 (void) l_free_lstate(&l_state); 1889 return (err); 1890 } 1891 1892 (void) free(map.dev_addr); 1893 (void) l_free_lstate(&l_state); 1894 return (0); 1895 } 1896 1897 /* 1898 * convert box name or WWN or logical path to physical path. 1899 * 1900 * OUTPUT: 1901 * path_struct: 1902 * - This structure is used to return more detailed 1903 * information about the path. 1904 * - *p_physical_path 1905 * Normally this is the requested physical path. 1906 * If the requested path is not found then iff the 1907 * ib_path_flag is set this is the IB path. 1908 * - *argv 1909 * This is the argument variable input. e.g. Bob,f1 1910 * - slot_valid 1911 * - slot 1912 * This is the slot number that was entered when using 1913 * the box,[fr]slot format. It is only valid if the 1914 * slot_valid flag is set. 1915 * - f_flag 1916 * Front flag - If set, the requested device is located in the 1917 * front of the enclosure. 1918 * - ib_path_flag 1919 * If this flag is set it means a devices path was requested 1920 * but could not be found but an IB's path was found and 1921 * the p_physical_path points to that path. 1922 * - **phys_path 1923 * physical path to the device. 1924 * RETURNS: 1925 * - 0 if O.K. 1926 * - error otherwise. 1927 */ 1928 int 1929 l_convert_name(char *name, char **phys_path, 1930 struct path_struct **path_struct, int verbose) 1931 { 1932 char tmp_name[MAXPATHLEN], ses_path[MAXPATHLEN]; 1933 char *char_ptr, *ptr = NULL; 1934 char *result = NULL; 1935 char *env = NULL; 1936 char save_frd; /* which designator was it? */ 1937 int slot = 0, slot_flag = 0, found_box = 0, found_comma = 0; 1938 int err = 0, enc_type = 0; 1939 hrtime_t start_time, end_time; 1940 Box_list *box_list = NULL, *box_list_ptr = NULL; 1941 L_inquiry inq; 1942 L_state *l_state = NULL; 1943 Path_struct *path_ptr = NULL; 1944 WWN_list *wwn_list, *wwn_list_ptr; 1945 1946 if ((name == NULL) || (phys_path == NULL) || 1947 (path_struct == NULL)) { 1948 return (L_INVALID_PATH_FORMAT); 1949 } 1950 1951 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 1952 start_time = gethrtime(); 1953 } 1954 1955 if ((*path_struct = path_ptr = (struct path_struct *) 1956 g_zalloc(sizeof (struct path_struct))) == NULL) { 1957 return (L_MALLOC_FAILED); 1958 } 1959 1960 *phys_path = NULL; 1961 /* 1962 * If the path contains a "/" then assume 1963 * it is a logical or physical path as the 1964 * box name or wwn can not contain "/"s. 1965 */ 1966 if (strchr(name, '/') != NULL) { 1967 if ((result = g_get_physical_name(name)) == NULL) { 1968 return (L_NO_PHYS_PATH); 1969 } 1970 1971 path_ptr->p_physical_path = result; 1972 /* 1973 * Make sure it's a disk or tape path 1974 */ 1975 if (strstr(name, DEV_RDIR) || strstr(name, SLSH_DRV_NAME_SSD) || 1976 strstr(name, DEV_TAPE_DIR) || 1977 strstr(name, SLSH_DRV_NAME_ST)) { 1978 if ((err = g_get_inquiry(result, &inq)) != 0) { 1979 (void) free(result); 1980 return (L_SCSI_ERROR); 1981 } 1982 /* 1983 * Check to see if it is not a 1984 * A5K/v880/v890 disk 1985 * 1986 */ 1987 if (!g_enclDiskChk((char *)inq.inq_vid, 1988 (char *)inq.inq_pid)) { 1989 path_ptr->argv = name; 1990 *phys_path = result; 1991 return (0); 1992 } 1993 } 1994 1995 if (err = load_flds_if_enc_disk(result, path_struct)) { 1996 (void) free(result); 1997 return (err); 1998 } 1999 goto done; 2000 } 2001 2002 (void) strcpy(tmp_name, name); 2003 if ((tmp_name[0] == 'c') && 2004 ((int)strlen(tmp_name) > 1) && ((int)strlen(tmp_name) < 5)) { 2005 if ((err = l_get_conflict(tmp_name, &result, verbose)) != 0) { 2006 if (result != NULL) { 2007 (void) g_destroy_data(result); 2008 } 2009 return (err); 2010 } 2011 if (result != NULL) { 2012 path_ptr->p_physical_path = result; 2013 if ((err = g_get_inquiry(result, &inq)) != 0) { 2014 (void) free(result); 2015 return (L_SCSI_ERROR); 2016 } 2017 /* 2018 * Check to see if it is a supported 2019 * A5K/v880/v890 storage subsystem disk 2020 */ 2021 if (g_enclDiskChk((char *)inq.inq_vid, 2022 (char *)inq.inq_pid)) { 2023 if (err = load_flds_if_enc_disk( 2024 result, path_struct)) { 2025 (void) free(result); 2026 return (err); 2027 } 2028 } 2029 goto done; 2030 } 2031 } 2032 2033 /* 2034 * Check to see if we have a box or WWN name. 2035 * 2036 * If it contains a , then the format must be 2037 * box_name,f1 where f is front and 1 is the slot number 2038 * or it is a format like 2039 * ssd@w2200002037049adf,0:h,raw 2040 * or 2041 * SUNW,pln@a0000000,77791d:ctlr 2042 */ 2043 if (((char_ptr = strstr(tmp_name, ",")) != NULL) && 2044 ((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') || 2045 (*(char_ptr + 1) == 's'))) { 2046 char_ptr++; /* point to f/r */ 2047 if ((*char_ptr == 'f') || (*char_ptr == 's')) { 2048 path_ptr->f_flag = 1; 2049 } else if (*char_ptr != 'r') { 2050 return (L_INVALID_PATH_FORMAT); 2051 } 2052 save_frd = (char)*char_ptr; /* save it */ 2053 char_ptr++; 2054 slot = strtol(char_ptr, &ptr, 10); 2055 /* 2056 * NOTE: Need to double check the slot when we get 2057 * the number of the devices actually in the box. 2058 */ 2059 if ((slot < 0) || (ptr == char_ptr) || 2060 ((save_frd == 's' && slot >= MAX_DRIVES_DAK) || 2061 ((save_frd != 's' && slot >= (MAX_DRIVES_PER_BOX/2))))) { 2062 return (L_INVALID_SLOT); 2063 } 2064 /* Say slot valid. */ 2065 slot_flag = path_ptr->slot_valid = 1; 2066 if (save_frd == 's' && slot >= (MAX_DRIVES_DAK/2)) { 2067 path_ptr->slot = slot = slot % (MAX_DRIVES_DAK/2); 2068 path_ptr->f_flag = 0; 2069 } else 2070 path_ptr->slot = slot; 2071 } 2072 2073 if (((char_ptr = strstr(tmp_name, ",")) != NULL) && 2074 ((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') || 2075 (*(char_ptr + 1) == 's'))) { 2076 *char_ptr = NULL; /* make just box name */ 2077 found_comma = 1; 2078 } 2079 /* Find path to IB */ 2080 if ((err = l_get_box_list(&box_list, verbose)) != 0) { 2081 (void) l_free_box_list(&box_list); 2082 return (err); 2083 } 2084 box_list_ptr = box_list; 2085 /* Look for box name. */ 2086 while (box_list != NULL) { 2087 if ((strcmp((char *)tmp_name, (char *)box_list->b_name)) == 0) { 2088 result = 2089 g_alloc_string(box_list->b_physical_path); 2090 L_DPRINTF(" l_convert_name:" 2091 " Found subsystem: name %s WWN %s\n", 2092 box_list->b_name, box_list->b_node_wwn_s); 2093 /* 2094 * Check for another box with this name. 2095 */ 2096 if (l_duplicate_names(box_list_ptr, 2097 box_list->b_node_wwn_s, 2098 (char *)box_list->b_name, 2099 verbose)) { 2100 (void) l_free_box_list(&box_list_ptr); 2101 (void) g_destroy_data(result); 2102 return (L_DUPLICATE_ENCLOSURES); 2103 } 2104 found_box = 1; 2105 break; 2106 } 2107 box_list = box_list->box_next; 2108 } 2109 /* 2110 * Check to see if we must get individual disks path. 2111 */ 2112 2113 if (found_box && slot_flag) { 2114 if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) { 2115 (void) g_destroy_data(result); 2116 (void) l_free_box_list(&box_list_ptr); 2117 return (L_MALLOC_FAILED); 2118 } 2119 (void) strcpy(ses_path, result); 2120 if ((err = l_get_status(ses_path, l_state, 2121 verbose)) != 0) { 2122 (void) g_destroy_data(result); 2123 (void) g_destroy_data(l_state); 2124 (void) l_free_box_list(&box_list_ptr); 2125 return (err); 2126 } 2127 /* 2128 * Now double check the slot number. 2129 */ 2130 if (slot >= l_state->total_num_drv/2) { 2131 path_ptr->slot_valid = 0; 2132 (void) g_destroy_data(result); 2133 (void) l_free_box_list(&box_list_ptr); 2134 (void) l_free_lstate(&l_state); 2135 return (L_INVALID_SLOT); 2136 } 2137 2138 /* Only allow the single slot version for Daktari */ 2139 if (g_get_inquiry(ses_path, &inq)) { 2140 return (L_SCSI_ERROR); 2141 } 2142 enc_type = l_get_enc_type(inq); 2143 if (((enc_type == DAK_ENC_TYPE) && (save_frd != 's')) || 2144 ((enc_type != DAK_ENC_TYPE) && (save_frd == 's'))) { 2145 path_ptr->slot_valid = 0; 2146 (void) g_destroy_data(result); 2147 (void) l_free_box_list(&box_list_ptr); 2148 (void) l_free_lstate(&l_state); 2149 return (L_INVALID_SLOT); 2150 } 2151 2152 if (path_ptr->f_flag) { 2153 if (*l_state->drv_front[slot].g_disk_state.physical_path) { 2154 result = 2155 g_alloc_string(l_state->drv_front[slot].g_disk_state.physical_path); 2156 } else { 2157 /* Result is the IB path */ 2158 path_ptr->ib_path_flag = 1; 2159 path_ptr->p_physical_path = 2160 g_alloc_string(result); 2161 (void) g_destroy_data(result); 2162 result = NULL; 2163 } 2164 } else { 2165 if (*l_state->drv_rear[slot].g_disk_state.physical_path) { 2166 result = 2167 g_alloc_string(l_state->drv_rear[slot].g_disk_state.physical_path); 2168 } else { 2169 /* Result is the IB path */ 2170 path_ptr->ib_path_flag = 1; 2171 path_ptr->p_physical_path = 2172 g_alloc_string(result); 2173 (void) g_destroy_data(result); 2174 result = NULL; 2175 } 2176 } 2177 (void) l_free_lstate(&l_state); 2178 goto done; 2179 } 2180 if (found_box || found_comma) { 2181 goto done; 2182 } 2183 /* 2184 * No luck with the box name. 2185 * 2186 * Try WWN's 2187 */ 2188 /* Look for the SES's WWN */ 2189 box_list = box_list_ptr; 2190 while (box_list != NULL) { 2191 if (((strcasecmp((char *)tmp_name, 2192 (char *)box_list->b_port_wwn_s)) == 0) || 2193 ((strcasecmp((char *)tmp_name, 2194 (char *)box_list->b_node_wwn_s)) == 0)) { 2195 result = 2196 g_alloc_string(box_list->b_physical_path); 2197 L_DPRINTF(" l_convert_name:" 2198 " Found subsystem using the WWN" 2199 ": name %s WWN %s\n", 2200 box_list->b_name, box_list->b_node_wwn_s); 2201 goto done; 2202 } 2203 box_list = box_list->box_next; 2204 } 2205 /* Look for a device's WWN */ 2206 if (strlen(tmp_name) <= L_WWN_LENGTH) { 2207 if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) { 2208 (void) l_free_box_list(&box_list_ptr); 2209 return (err); 2210 } 2211 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; 2212 wwn_list_ptr = wwn_list_ptr->wwn_next) { 2213 if (((strcasecmp((char *)tmp_name, 2214 (char *)wwn_list_ptr->node_wwn_s)) == 0) || 2215 ((strcasecmp((char *)tmp_name, 2216 (char *)wwn_list_ptr->port_wwn_s)) == 0)) { 2217 /* 2218 * Found the device's WWN in the global WWN list. 2219 * It MAY be in a photon/Daktari. If it is, we'll set 2220 * additional fields in path_struct. 2221 */ 2222 result = g_alloc_string(wwn_list_ptr->physical_path); 2223 L_DPRINTF(" l_convert_name:" 2224 " Found device: WWN %s Path %s\n", 2225 tmp_name, wwn_list_ptr->logical_path); 2226 2227 (void) g_free_wwn_list(&wwn_list); 2228 2229 /* 2230 * Now check if it is a disk in an A5K and set 2231 * path_struct fields 2232 */ 2233 path_ptr->p_physical_path = result; 2234 if ((err = g_get_inquiry(result, &inq)) != 0) { 2235 (void) free(result); 2236 return (L_SCSI_ERROR); 2237 } 2238 /* 2239 * Check to see if it is a supported 2240 * A5K/v880/v890 storage subsystem disk 2241 */ 2242 if (g_enclDiskChk((char *)inq.inq_vid, 2243 (char *)inq.inq_pid)) { 2244 if (err = load_flds_if_enc_disk( 2245 result, path_struct)) { 2246 (void) free(result); 2247 return (err); 2248 } 2249 } 2250 goto done; 2251 } 2252 } 2253 } 2254 2255 /* 2256 * Try again in case we were in the /dev 2257 * or /devices directory. 2258 */ 2259 result = g_get_physical_name(name); 2260 2261 done: 2262 (void) l_free_box_list(&box_list_ptr); 2263 path_ptr->argv = name; 2264 if (result == NULL) { 2265 if (!path_ptr->ib_path_flag) 2266 return (-1); 2267 } else { 2268 path_ptr->p_physical_path = result; 2269 } 2270 2271 L_DPRINTF(" l_convert_name: path_struct:\n\tphysical_path:\n\t %s\n" 2272 "\targv:\t\t%s" 2273 "\n\tslot_valid\t%d" 2274 "\n\tslot\t\t%d" 2275 "\n\tf_flag\t\t%d" 2276 "\n\tib_path_flag\t%d\n", 2277 path_ptr->p_physical_path, 2278 path_ptr->argv, 2279 path_ptr->slot_valid, 2280 path_ptr->slot, 2281 path_ptr->f_flag, 2282 path_ptr->ib_path_flag); 2283 if (env != NULL) { 2284 end_time = gethrtime(); 2285 (void) fprintf(stdout, " l_convert_name: " 2286 "Time = %lld millisec\n", 2287 (end_time - start_time)/1000000); 2288 } 2289 2290 if (path_ptr->ib_path_flag) 2291 return (-1); 2292 *phys_path = result; 2293 return (0); 2294 } 2295 2296 2297 /* 2298 * Gets envsen information of an enclosure from IB 2299 * 2300 * RETURNS: 2301 * 0 O.K. 2302 * non-zero otherwise 2303 */ 2304 int 2305 l_get_envsen_page(int fd, uchar_t *buf, int buf_size, uchar_t page_code, 2306 int verbose) 2307 { 2308 Rec_diag_hdr hdr; 2309 uchar_t *pg; 2310 int size, new_size, status; 2311 2312 if (buf == NULL) { 2313 return (L_INVALID_BUF_LEN); 2314 } 2315 2316 if (verbose) { 2317 (void) fprintf(stdout, 2318 MSGSTR(9046, " Reading SES page %x\n"), page_code); 2319 } 2320 2321 (void) memset(&hdr, 0, sizeof (struct rec_diag_hdr)); 2322 if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&hdr, 2323 sizeof (struct rec_diag_hdr), page_code)) { 2324 return (status); 2325 } 2326 2327 /* Check */ 2328 if ((hdr.page_code != page_code) || (hdr.page_len == 0)) { 2329 return (L_RD_PG_INVLD_CODE); 2330 } 2331 size = HEADER_LEN + hdr.page_len; 2332 /* 2333 * Because of a hardware restriction in the soc+ chip 2334 * the transfers must be word aligned. 2335 */ 2336 while (size & 0x03) { 2337 size++; 2338 if (size > buf_size) { 2339 return (L_RD_PG_MIN_BUFF); 2340 } 2341 P_DPRINTF(" l_get_envsen_page: Adjusting size of the " 2342 "g_scsi_rec_diag_cmd buffer.\n"); 2343 } 2344 2345 if ((pg = (uchar_t *)g_zalloc(size)) == NULL) { 2346 return (L_MALLOC_FAILED); 2347 } 2348 2349 P_DPRINTF(" l_get_envsen_page: Reading page %x of size 0x%x\n", 2350 page_code, size); 2351 if (status = g_scsi_rec_diag_cmd(fd, pg, size, page_code)) { 2352 (void) g_destroy_data((char *)pg); 2353 return (status); 2354 } 2355 2356 new_size = MIN(size, buf_size); 2357 bcopy((const void *)pg, (void *)buf, (size_t)new_size); 2358 2359 (void) g_destroy_data(pg); 2360 return (0); 2361 } 2362 2363 2364 2365 /* 2366 * Get consolidated copy of all environmental information 2367 * into buf structure. 2368 * 2369 * RETURNS: 2370 * 0 O.K. 2371 * non-zero otherwise 2372 */ 2373 2374 int 2375 l_get_envsen(char *path_phys, uchar_t *buf, int size, int verbose) 2376 { 2377 int fd, rval; 2378 uchar_t *page_list_ptr, page_code, *local_buf_ptr = buf; 2379 Rec_diag_hdr *hdr = (struct rec_diag_hdr *)(void *)buf; 2380 ushort_t num_pages; 2381 2382 if ((path_phys == NULL) || (buf == NULL)) { 2383 return (L_INVALID_PATH_FORMAT); 2384 } 2385 2386 page_code = L_PAGE_PAGE_LIST; 2387 2388 /* open IB */ 2389 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) 2390 return (L_OPEN_PATH_FAIL); 2391 2392 P_DPRINTF(" l_get_envsen: Getting list of supported" 2393 " pages from IB\n"); 2394 if (verbose) { 2395 (void) fprintf(stdout, 2396 MSGSTR(9047, " Getting list of supported pages from IB\n")); 2397 } 2398 2399 /* Get page 0 */ 2400 if ((rval = l_get_envsen_page(fd, local_buf_ptr, 2401 size, page_code, verbose)) != NULL) { 2402 (void) close(fd); 2403 return (rval); 2404 } 2405 2406 page_list_ptr = buf + HEADER_LEN + 1; /* +1 to skip page 0 */ 2407 2408 num_pages = hdr->page_len - 1; 2409 2410 /* 2411 * check whether the number of pages received 2412 * from IB are valid. SENA enclosure 2413 * supports only 8 pages of sense information. 2414 * According to SES specification dpANS X3.xxx-1997 2415 * X3T10/Project 1212-D/Rev 8a, the enclosure supported 2416 * pages can go upto L_MAX_POSSIBLE_PAGES (0xFF). 2417 * Return an error if no. of pages exceeds L_MAX_POSSIBLE_PAGES. 2418 * See if (num_pages >= L_MAX_POSSIBLE_PAGES) since 1 page (page 0) 2419 * was already subtracted from the total number of pages before. 2420 */ 2421 if (num_pages < 1 || num_pages >= L_MAX_POSSIBLE_PAGES) { 2422 return (L_INVALID_NO_OF_ENVSEN_PAGES); 2423 } 2424 /* 2425 * Buffer size of MAX_REC_DIAG_LENGTH can be small if the 2426 * number of pages exceed more than L_MAX_SENAIB_PAGES 2427 * but less than L_MAX_POSSIBLE_PAGES. 2428 */ 2429 if (size == MAX_REC_DIAG_LENGTH && 2430 num_pages >= L_MAX_SENAIB_PAGES) { 2431 return (L_INVALID_BUF_LEN); 2432 } 2433 /* Align buffer */ 2434 while (hdr->page_len & 0x03) { 2435 hdr->page_len++; 2436 } 2437 local_buf_ptr += HEADER_LEN + hdr->page_len; 2438 2439 /* 2440 * Getting all pages and appending to buf 2441 */ 2442 for (; num_pages--; page_list_ptr++) { 2443 /* 2444 * The fifth byte of page 0 is the start 2445 * of the list of pages not including page 0. 2446 */ 2447 page_code = *page_list_ptr; 2448 2449 if ((rval = l_get_envsen_page(fd, local_buf_ptr, 2450 size, page_code, verbose)) != NULL) { 2451 (void) close(fd); 2452 return (rval); 2453 } 2454 hdr = (struct rec_diag_hdr *)(void *)local_buf_ptr; 2455 local_buf_ptr += HEADER_LEN + hdr->page_len; 2456 } 2457 2458 (void) close(fd); 2459 return (0); 2460 } 2461 2462 2463 2464 /* 2465 * Get the individual disk status. 2466 * Path must be physical and point to a disk. 2467 * 2468 * This function updates the d_state_flags, port WWN's 2469 * and num_blocks for all accessiable ports 2470 * in l_disk_state->g_disk_state structure. 2471 * 2472 * RETURNS: 2473 * 0 O.K. 2474 * non-zero otherwise 2475 */ 2476 int 2477 l_get_disk_status(char *path, struct l_disk_state_struct *l_disk_state, 2478 WWN_list *wwn_list, int verbose) 2479 { 2480 struct dlist *ml; 2481 char path_a[MAXPATHLEN], path_b[MAXPATHLEN], ses_path[MAXPATHLEN]; 2482 gfc_map_t map; 2483 int path_a_found = 0, path_b_found = 0, local_port_a_flag; 2484 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 2485 int al_pa, err, pathcnt = 1; 2486 int i = 0; 2487 char temppath[MAXPATHLEN]; 2488 mp_pathlist_t pathlist; 2489 char pwwn[WWN_S_LEN]; 2490 struct stat sbuf; 2491 2492 if ((path == NULL) || (l_disk_state == NULL)) { 2493 return (L_INVALID_PATH_FORMAT); 2494 } 2495 2496 /* Check device name */ 2497 if (stat(path, &sbuf) || (sbuf.st_rdev == NODEV)) { 2498 G_DPRINTF(" l_get_disk_status: invalid device %s\n", path); 2499 return (L_INVALID_PATH); 2500 } 2501 2502 /* Initialize */ 2503 *path_a = *path_b = NULL; 2504 l_disk_state->g_disk_state.num_blocks = 0; 2505 2506 /* Get paths. */ 2507 g_get_multipath(path, 2508 &(l_disk_state->g_disk_state.multipath_list), 2509 wwn_list, verbose); 2510 ml = l_disk_state->g_disk_state.multipath_list; 2511 if (ml == NULL) { 2512 l_disk_state->l_state_flag = L_NO_PATH_FOUND; 2513 G_DPRINTF(" l_get_disk_status: Error finding a " 2514 "multipath to the disk.\n"); 2515 return (0); 2516 } 2517 2518 if (strstr(path, SCSI_VHCI) != NULL) { 2519 /* 2520 * It is an MPXIO Path 2521 */ 2522 (void) strcpy(temppath, path); 2523 if (g_get_pathlist(temppath, &pathlist)) { 2524 return (0); 2525 } 2526 pathcnt = pathlist.path_count; 2527 for (i = 0; i < pathcnt; i++) { 2528 /* 2529 * Skip inactive paths. 2530 * A path that is not in either 2531 * MDI_PATHINFO_STATE_ONLINE or 2532 * MDI_PATHINFO_STATE_STANDBY state is not 2533 * an active path. 2534 * 2535 * When a disk port is bypassed and mpxio is 2536 * enabled, the path_state for that path goes to the 2537 * offline state 2538 */ 2539 if (pathlist.path_info[i].path_state != 2540 MDI_PATHINFO_STATE_ONLINE && 2541 pathlist.path_info[i].path_state != 2542 MDI_PATHINFO_STATE_STANDBY) { 2543 continue; 2544 } 2545 (void) strncpy(pwwn, pathlist.path_info[i].path_addr, 2546 L_WWN_LENGTH); 2547 pwwn[L_WWN_LENGTH] = '\0'; 2548 if (!(path_a_found || path_b_found)) { 2549 if (pwwn[1] == '1') { 2550 local_port_a_flag = 1; 2551 } else { 2552 local_port_a_flag = 0; 2553 } 2554 } else if (path_a_found && 2555 (strstr(l_disk_state->g_disk_state.port_a_wwn_s, 2556 pwwn) == NULL)) { 2557 /* do port b */ 2558 local_port_a_flag = 0; 2559 } else if (path_b_found && 2560 (strstr(l_disk_state->g_disk_state.port_b_wwn_s, 2561 pwwn) == NULL)) { 2562 /* do port a */ 2563 local_port_a_flag = 1; 2564 } 2565 2566 if (err = l_get_disk_port_status(path, 2567 l_disk_state, local_port_a_flag, verbose)) { 2568 return (err); 2569 } 2570 2571 if (local_port_a_flag && (!path_a_found)) { 2572 (void) strcpy(l_disk_state-> 2573 g_disk_state.port_a_wwn_s, pwwn); 2574 l_disk_state->g_disk_state.port_a_valid++; 2575 path_a_found++; 2576 } 2577 2578 if ((!local_port_a_flag) && (!path_b_found)) { 2579 (void) strcpy(l_disk_state-> 2580 g_disk_state.port_b_wwn_s, pwwn); 2581 l_disk_state->g_disk_state.port_b_valid++; 2582 path_b_found++; 2583 } 2584 } 2585 free(pathlist.path_info); 2586 return (0); 2587 } 2588 2589 while (ml && (!(path_a_found && path_b_found))) { 2590 if (err = g_get_dev_map(ml->dev_path, &map, verbose)) { 2591 (void) g_free_multipath(ml); 2592 return (err); 2593 } 2594 if ((err = l_get_ses_path(ml->dev_path, ses_path, 2595 &map, verbose)) != 0) { 2596 (void) g_free_multipath(ml); 2597 free((void *)map.dev_addr); 2598 return (err); 2599 } 2600 free((void *)map.dev_addr); /* Not used anymore */ 2601 2602 /* 2603 * Get the port, A or B, of the disk, 2604 * by passing the IB path. 2605 */ 2606 if (err = l_get_port(ses_path, &local_port_a_flag, verbose)) { 2607 (void) g_free_multipath(ml); 2608 return (err); 2609 } 2610 if (local_port_a_flag && (!path_a_found)) { 2611 G_DPRINTF(" l_get_disk_status: Path to Port A " 2612 "found: %s\n", ml->dev_path); 2613 if (err = l_get_disk_port_status(ml->dev_path, 2614 l_disk_state, local_port_a_flag, verbose)) { 2615 (void) g_free_multipath(ml); 2616 return (err); 2617 } 2618 if (err = g_get_wwn(ml->dev_path, 2619 port_wwn, node_wwn, 2620 &al_pa, verbose)) { 2621 (void) g_free_multipath(ml); 2622 return (err); 2623 } 2624 (void) sprintf(l_disk_state->g_disk_state.port_a_wwn_s, 2625 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 2626 port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3], 2627 port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]); 2628 2629 l_disk_state->g_disk_state.port_a_valid++; 2630 path_a_found++; 2631 } 2632 if ((!local_port_a_flag) && (!path_b_found)) { 2633 G_DPRINTF(" l_get_disk_status: Path to Port B " 2634 "found: %s\n", ml->dev_path); 2635 if (err = l_get_disk_port_status(ml->dev_path, 2636 l_disk_state, local_port_a_flag, verbose)) { 2637 return (err); 2638 } 2639 if (err = g_get_wwn(ml->dev_path, 2640 port_wwn, node_wwn, 2641 &al_pa, verbose)) { 2642 (void) g_free_multipath(ml); 2643 return (err); 2644 } 2645 (void) sprintf(l_disk_state->g_disk_state.port_b_wwn_s, 2646 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 2647 port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3], 2648 port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]); 2649 2650 l_disk_state->g_disk_state.port_b_valid++; 2651 path_b_found++; 2652 } 2653 ml = ml->next; 2654 } 2655 return (0); 2656 2657 2658 } 2659 2660 2661 2662 /* 2663 * Check for Persistent Reservations. 2664 */ 2665 int 2666 l_persistent_check(int fd, struct l_disk_state_struct *l_disk_state, 2667 int verbose) 2668 { 2669 int status; 2670 Read_keys read_key_buf; 2671 Read_reserv read_reserv_buf; 2672 2673 (void) memset(&read_key_buf, 0, sizeof (struct read_keys_struct)); 2674 if ((status = g_scsi_persistent_reserve_in_cmd(fd, 2675 (uchar_t *)&read_key_buf, sizeof (struct read_keys_struct), 2676 ACTION_READ_KEYS))) { 2677 return (status); 2678 } 2679 /* This means persistent reservations are supported by the disk. */ 2680 l_disk_state->g_disk_state.persistent_reserv_flag = 1; 2681 2682 if (read_key_buf.rk_length) { 2683 l_disk_state->g_disk_state.persistent_registered = 1; 2684 } 2685 2686 (void) memset(&read_reserv_buf, 0, 2687 sizeof (struct read_reserv_struct)); 2688 if ((status = g_scsi_persistent_reserve_in_cmd(fd, 2689 (uchar_t *)&read_reserv_buf, 2690 sizeof (struct read_reserv_struct), 2691 ACTION_READ_RESERV))) { 2692 return (status); 2693 } 2694 if (read_reserv_buf.rr_length) { 2695 l_disk_state->g_disk_state.persistent_active = 1; 2696 } 2697 if (verbose) { 2698 (void) fprintf(stdout, 2699 MSGSTR(9048, " Checking for Persistent " 2700 "Reservations:")); 2701 if (l_disk_state->g_disk_state.persistent_reserv_flag) { 2702 if (l_disk_state->g_disk_state.persistent_active != NULL) { 2703 (void) fprintf(stdout, MSGSTR(39, "Active")); 2704 } else { 2705 (void) fprintf(stdout, MSGSTR(9049, "Registered")); 2706 } 2707 } else { 2708 (void) fprintf(stdout, 2709 MSGSTR(87, 2710 "Not being used")); 2711 } 2712 (void) fprintf(stdout, "\n"); 2713 } 2714 return (0); 2715 } 2716 2717 2718 2719 /* 2720 * Gets the disk status and 2721 * updates the l_disk_state_struct structure. 2722 * Checks for open fail, Reservation Conflicts, 2723 * Not Ready and so on. 2724 * 2725 * RETURNS: 2726 * 0 O.K. 2727 * non-zero otherwise 2728 */ 2729 int 2730 l_get_disk_port_status(char *path, struct l_disk_state_struct *l_disk_state, 2731 int port_a_flag, int verbose) 2732 { 2733 int fd, status = 0, local_state = 0; 2734 Read_capacity_data capacity; /* local read capacity buffer */ 2735 struct vtoc vtoc; 2736 2737 if ((path == NULL) || (l_disk_state == NULL)) { 2738 return (L_INVALID_PATH_FORMAT); 2739 } 2740 2741 /* 2742 * Try to open drive. 2743 */ 2744 if ((fd = g_object_open(path, O_RDONLY)) == -1) { 2745 if ((fd = g_object_open(path, 2746 O_RDONLY | O_NDELAY)) == -1) { 2747 G_DPRINTF(" l_get_disk_port_status: Error " 2748 "opening drive %s\n", path); 2749 local_state = L_OPEN_FAIL; 2750 } else { 2751 /* See if drive ready */ 2752 if (status = g_scsi_tur(fd)) { 2753 if ((status & L_SCSI_ERROR) && 2754 ((status & ~L_SCSI_ERROR) == STATUS_CHECK)) { 2755 /* 2756 * TBD 2757 * This is where I should figure out 2758 * if the device is Not Ready or whatever. 2759 */ 2760 local_state = L_NOT_READY; 2761 } else if ((status & L_SCSI_ERROR) && 2762 ((status & ~L_SCSI_ERROR) == 2763 STATUS_RESERVATION_CONFLICT)) { 2764 /* mark reserved */ 2765 local_state = L_RESERVED; 2766 } else { 2767 local_state = L_SCSI_ERR; 2768 } 2769 2770 /* 2771 * There may not be a label on the drive - check 2772 */ 2773 } else if (ioctl(fd, DKIOCGVTOC, &vtoc) == 0) { 2774 /* 2775 * Sanity-check the vtoc 2776 */ 2777 if (vtoc.v_sanity != VTOC_SANE || 2778 vtoc.v_sectorsz != DEV_BSIZE) { 2779 local_state = L_NO_LABEL; 2780 G_DPRINTF(" l_get_disk_port_status: " 2781 "Checking vtoc - No Label found.\n"); 2782 } 2783 } else if (errno != ENOTSUP) { 2784 I_DPRINTF("\t- DKIOCGVTOC ioctl failed: " 2785 " invalid geometry\n"); 2786 local_state = L_NO_LABEL; 2787 } 2788 } 2789 } 2790 /* 2791 * Need an extra check for tape devices 2792 * read capacity should not be run on tape devices. 2793 * It will always return Not Readable 2794 */ 2795 if (((local_state == 0) || (local_state == L_NO_LABEL)) && 2796 ! (strstr(path, SLSH_DRV_NAME_ST))) { 2797 2798 if (status = g_scsi_read_capacity_cmd(fd, (uchar_t *)&capacity, 2799 sizeof (capacity))) { 2800 G_DPRINTF(" l_get_disk_port_status: " 2801 "Read Capacity failed.\n"); 2802 if (status & L_SCSI_ERROR) { 2803 if ((status & ~L_SCSI_ERROR) == 2804 STATUS_RESERVATION_CONFLICT) { 2805 /* mark reserved */ 2806 local_state |= L_RESERVED; 2807 } else 2808 /* mark bad */ 2809 local_state |= L_NOT_READABLE; 2810 } else { 2811 /* 2812 * TBD 2813 * Need a more complete state definition here. 2814 */ 2815 l_disk_state->g_disk_state.d_state_flags[port_a_flag] = 2816 L_SCSI_ERR; 2817 (void) close(fd); 2818 return (0); 2819 } 2820 } else { 2821 /* save capacity */ 2822 l_disk_state->g_disk_state.num_blocks = 2823 capacity.last_block_addr + 1; 2824 } 2825 2826 } 2827 (void) close(fd); 2828 2829 l_disk_state->g_disk_state.d_state_flags[port_a_flag] = local_state; 2830 G_DPRINTF(" l_get_disk_port_status: Individual Disk" 2831 " Status: 0x%x for" 2832 " port %s for path:" 2833 " %s\n", local_state, 2834 port_a_flag ? "A" : "B", path); 2835 2836 return (0); 2837 } 2838 2839 2840 2841 /* 2842 * Copy and format page 1 from big buffer to state structure. 2843 * 2844 * RETURNS: 2845 * 0 O.K. 2846 * non-zero otherwise 2847 */ 2848 2849 static int 2850 copy_config_page(struct l_state_struct *l_state, uchar_t *from_ptr) 2851 { 2852 IB_page_config *encl_ptr; 2853 int size, i; 2854 2855 2856 encl_ptr = (struct ib_page_config *)(void *)from_ptr; 2857 2858 /* Sanity check. */ 2859 if ((encl_ptr->enc_len > MAX_VEND_SPECIFIC_ENC) || 2860 (encl_ptr->enc_len == 0)) { 2861 return (L_REC_DIAG_PG1); 2862 } 2863 if ((encl_ptr->enc_num_elem > MAX_IB_ELEMENTS) || 2864 (encl_ptr->enc_num_elem == 0)) { 2865 return (L_REC_DIAG_PG1); 2866 } 2867 2868 size = HEADER_LEN + 4 + HEADER_LEN + encl_ptr->enc_len; 2869 bcopy((void *)(from_ptr), 2870 (void *)&l_state->ib_tbl.config, (size_t)size); 2871 /* 2872 * Copy Type Descriptors seperately to get aligned. 2873 */ 2874 from_ptr += size; 2875 size = (sizeof (struct type_desc_hdr))*encl_ptr->enc_num_elem; 2876 bcopy((void *)(from_ptr), 2877 (void *)&l_state->ib_tbl.config.type_hdr, (size_t)size); 2878 2879 /* 2880 * Copy Text Descriptors seperately to get aligned. 2881 * 2882 * Must use the text size from the Type Descriptors. 2883 */ 2884 from_ptr += size; 2885 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { 2886 size = l_state->ib_tbl.config.type_hdr[i].text_len; 2887 bcopy((void *)(from_ptr), 2888 (void *)&l_state->ib_tbl.config.text[i], (size_t)size); 2889 from_ptr += size; 2890 } 2891 return (0); 2892 } 2893 2894 2895 2896 /* 2897 * Copy page 7 (Element Descriptor page) to state structure. 2898 * Copy header then copy each element descriptor 2899 * seperately. 2900 * 2901 * RETURNS: 2902 * 0 O.K. 2903 * non-zero otherwise 2904 */ 2905 static void 2906 copy_page_7(struct l_state_struct *l_state, uchar_t *from_ptr) 2907 { 2908 uchar_t *my_from_ptr; 2909 int size, j, k, p7_index; 2910 2911 size = HEADER_LEN + 2912 sizeof (l_state->ib_tbl.p7_s.gen_code); 2913 bcopy((void *)(from_ptr), 2914 (void *)&l_state->ib_tbl.p7_s, (size_t)size); 2915 my_from_ptr = from_ptr + size; 2916 if (getenv("_LUX_D_DEBUG") != NULL) { 2917 g_dump(" copy_page_7: Page 7 header: ", 2918 (uchar_t *)&l_state->ib_tbl.p7_s, size, 2919 HEX_ASCII); 2920 (void) fprintf(stdout, 2921 " copy_page_7: Elements being stored " 2922 "in state table\n" 2923 " "); 2924 } 2925 /* I am assuming page 1 has been read. */ 2926 for (j = 0, p7_index = 0; 2927 j < (int)l_state->ib_tbl.config.enc_num_elem; j++) { 2928 /* Copy global element */ 2929 size = HEADER_LEN + 2930 ((*(my_from_ptr + 2) << 8) | *(my_from_ptr + 3)); 2931 bcopy((void *)(my_from_ptr), 2932 (void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++], 2933 (size_t)size); 2934 my_from_ptr += size; 2935 for (k = 0; k < (int)l_state->ib_tbl.config.type_hdr[j].num; 2936 k++) { 2937 /* Copy individual elements */ 2938 size = HEADER_LEN + 2939 ((*(my_from_ptr + 2) << 8) | 2940 *(my_from_ptr + 3)); 2941 bcopy((void *)(my_from_ptr), 2942 (void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++], 2943 (size_t)size); 2944 my_from_ptr += size; 2945 D_DPRINTF("."); 2946 } 2947 } 2948 D_DPRINTF("\n"); 2949 } 2950 2951 2952 /* 2953 * Gets IB diagnostic pages on a given pathname from l_get_envsen(). 2954 * It also fills up the individual device element of l_state_struct using 2955 * diagnostics pages. 2956 * Gets IB diagnostic pages on a given pathname from l_get_envsen(). 2957 * It also fills up the individual device element of l_state_struct using 2958 * diagnostics pages. 2959 * 2960 * The path must be of the ses driver. 2961 * e.g. 2962 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 2963 * or 2964 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0 2965 * 2966 * 2967 * RETURNS: 2968 * 0 O.K. 2969 * non-zero otherwise 2970 */ 2971 int 2972 l_get_ib_status(char *path, struct l_state_struct *l_state, 2973 int verbose) 2974 { 2975 L_inquiry inq; 2976 uchar_t *ib_buf, *from_ptr; 2977 int num_pages, i, size, err; 2978 IB_page_2 *encl_ptr; 2979 int front_index, rear_index; 2980 int enc_type = 0; 2981 2982 if ((path == NULL) || (l_state == NULL)) { 2983 return (L_INVALID_PATH_FORMAT); 2984 } 2985 2986 /* 2987 * get big buffer 2988 */ 2989 if ((ib_buf = (uchar_t *)calloc(1, 2990 MAX_REC_DIAG_LENGTH)) == NULL) { 2991 return (L_MALLOC_FAILED); 2992 } 2993 2994 /* 2995 * Get IB information 2996 * Even if there are 2 IB's in this box on this loop don't bother 2997 * talking to the other one as both IB's in a box 2998 * are supposed to report the same information. 2999 */ 3000 if (err = l_get_envsen(path, ib_buf, MAX_REC_DIAG_LENGTH, 3001 verbose)) { 3002 (void) g_destroy_data(ib_buf); 3003 return (err); 3004 } 3005 3006 /* 3007 * Set up state structure 3008 */ 3009 bcopy((void *)ib_buf, (void *)&l_state->ib_tbl.p0, 3010 (size_t)sizeof (struct ib_page_0)); 3011 3012 num_pages = l_state->ib_tbl.p0.page_len; 3013 from_ptr = ib_buf + HEADER_LEN + l_state->ib_tbl.p0.page_len; 3014 3015 for (i = 1; i < num_pages; i++) { 3016 if (l_state->ib_tbl.p0.sup_page_codes[i] == L_PAGE_1) { 3017 if (err = copy_config_page(l_state, from_ptr)) { 3018 return (err); 3019 } 3020 } else if (l_state->ib_tbl.p0.sup_page_codes[i] == 3021 L_PAGE_2) { 3022 encl_ptr = (struct ib_page_2 *)(void *)from_ptr; 3023 size = HEADER_LEN + encl_ptr->page_len; 3024 bcopy((void *)(from_ptr), 3025 (void *)&l_state->ib_tbl.p2_s, (size_t)size); 3026 if (getenv("_LUX_D_DEBUG") != NULL) { 3027 g_dump(" l_get_ib_status: Page 2: ", 3028 (uchar_t *)&l_state->ib_tbl.p2_s, size, 3029 HEX_ONLY); 3030 } 3031 3032 } else if (l_state->ib_tbl.p0.sup_page_codes[i] == 3033 L_PAGE_7) { 3034 (void) copy_page_7(l_state, from_ptr); 3035 } 3036 from_ptr += ((*(from_ptr + 2) << 8) | *(from_ptr + 3)); 3037 from_ptr += HEADER_LEN; 3038 } 3039 (void) g_destroy_data(ib_buf); 3040 G_DPRINTF(" l_get_ib_status: Read %d Receive Diagnostic pages " 3041 "from the IB.\n", num_pages); 3042 3043 if (err = g_get_inquiry(path, &inq)) { 3044 return (err); 3045 } 3046 enc_type = l_get_enc_type(inq); 3047 /* 3048 * Get the total number of drives per box. 3049 * This assumes front & rear are the same. 3050 */ 3051 l_state->total_num_drv = 0; /* default to use as a flag */ 3052 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { 3053 if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) { 3054 if (l_state->total_num_drv) { 3055 if (l_state->total_num_drv != 3056 (l_state->ib_tbl.config.type_hdr[i].num * 2)) { 3057 return (L_INVALID_NUM_DISKS_ENCL); 3058 } 3059 } else { 3060 if (enc_type == DAK_ENC_TYPE) { 3061 l_state->total_num_drv = 3062 l_state->ib_tbl.config.type_hdr[i].num; 3063 } else { 3064 l_state->total_num_drv = 3065 l_state->ib_tbl.config.type_hdr[i].num * 2; 3066 } 3067 } 3068 } 3069 } 3070 3071 /* 3072 * transfer the individual drive Device Element information 3073 * from IB state to drive state. 3074 */ 3075 if (err = l_get_disk_element_index(l_state, &front_index, 3076 &rear_index)) { 3077 return (err); 3078 } 3079 /* Skip global element */ 3080 front_index++; 3081 if (enc_type == DAK_ENC_TYPE) { 3082 rear_index += l_state->total_num_drv/2 + 1; 3083 } else { 3084 rear_index++; 3085 } 3086 3087 for (i = 0; i < l_state->total_num_drv/2; i++) { 3088 bcopy((void *)&l_state->ib_tbl.p2_s.element[front_index + i], 3089 (void *)&l_state->drv_front[i].ib_status, 3090 (size_t)sizeof (struct device_element)); 3091 bcopy((void *)&l_state->ib_tbl.p2_s.element[rear_index + i], 3092 (void *)&l_state->drv_rear[i].ib_status, 3093 (size_t)sizeof (struct device_element)); 3094 } 3095 if (getenv("_LUX_G_DEBUG") != NULL) { 3096 g_dump(" l_get_ib_status: disk elements: ", 3097 (uchar_t *)&l_state->ib_tbl.p2_s.element[front_index], 3098 ((sizeof (struct device_element)) * (l_state->total_num_drv)), 3099 HEX_ONLY); 3100 } 3101 3102 return (0); 3103 } 3104 3105 3106 3107 /* 3108 * Given an IB path get the port, A or B. 3109 * 3110 * OUTPUT: 3111 * port_a: sets to 1 for port A 3112 * and 0 for port B. 3113 * RETURNS: 3114 * err: 0 O.k. 3115 * non-zero otherwise 3116 */ 3117 int 3118 l_get_port(char *ses_path, int *port_a, int verbose) 3119 { 3120 L_state *ib_state = NULL; 3121 Ctlr_elem_st ctlr; 3122 int i, err, elem_index = 0; 3123 3124 if ((ses_path == NULL) || (port_a == NULL)) { 3125 return (L_NO_SES_PATH); 3126 } 3127 3128 if ((ib_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 3129 return (L_MALLOC_FAILED); 3130 } 3131 3132 bzero(&ctlr, sizeof (ctlr)); 3133 if (err = l_get_ib_status(ses_path, ib_state, verbose)) { 3134 (void) l_free_lstate(&ib_state); 3135 return (err); 3136 } 3137 3138 for (i = 0; i < (int)ib_state->ib_tbl.config.enc_num_elem; i++) { 3139 elem_index++; /* skip global */ 3140 if (ib_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) { 3141 bcopy((const void *) 3142 &ib_state->ib_tbl.p2_s.element[elem_index], 3143 (void *)&ctlr, sizeof (ctlr)); 3144 break; 3145 } 3146 elem_index += ib_state->ib_tbl.config.type_hdr[i].num; 3147 } 3148 *port_a = ctlr.report; 3149 G_DPRINTF(" l_get_port: Found ses is the %s card.\n", 3150 ctlr.report ? "A" : "B"); 3151 (void) l_free_lstate(&ib_state); 3152 return (0); 3153 } 3154 3155 /* 3156 * This function expects a pointer to a device path ending in the form 3157 * .../ses@w<NODEWWN>,<something> or .../ssd@w<NODEWWN>,<something> 3158 * 3159 * No validity checking of the path is done by the function. 3160 * 3161 * It gets the wwn (node wwn) out of the passed string, searches the passed 3162 * map for a match, gets the corresponding phys addr (port id) for that entry 3163 * and stores in the pointer the caller has passed as an argument (pid) 3164 * 3165 * This function is to be called only for public/fabric topologies 3166 * 3167 * If this interface is going to get exported, one point to be 3168 * considered is if a call to g_get_path_type() has to be made. 3169 * 3170 * INPUT: 3171 * path - pointer to the enclosure/disk device path 3172 * map - pointer to the map 3173 * 3174 * OUTPUT: 3175 * pid - the physical address associated for the node WWN that was found 3176 * in the map 3177 * 3178 * RETURNS: 3179 * 0 - on success 3180 * non-zero - otherwise 3181 */ 3182 int 3183 l_get_pid_from_path(const char *path, const gfc_map_t *map, int *pid) 3184 { 3185 int i; 3186 unsigned long long ll_wwn; 3187 char *char_ptr, wwn_str[WWN_SIZE * 2 + 1]; 3188 char *byte_ptr, *temp_ptr; 3189 gfc_port_dev_info_t *dev_addr_ptr; 3190 mp_pathlist_t pathlist; 3191 char path0[MAXPATHLEN], pwwn0[WWN_S_LEN]; 3192 3193 /* if mpxio device */ 3194 if (strstr(path, SCSI_VHCI) != NULL) { 3195 (void) strcpy(path0, path); 3196 if (g_get_pathlist(path0, &pathlist)) { 3197 return (L_INVALID_PATH); 3198 } else { 3199 (void) strncpy(pwwn0, pathlist.path_info[0]. 3200 path_addr, L_WWN_LENGTH); 3201 pwwn0[L_WWN_LENGTH] = '\0'; 3202 free(pathlist.path_info); 3203 char_ptr = pwwn0; 3204 } 3205 } else { 3206 /* First a quick check on the path */ 3207 if (((char_ptr = strrchr(path, '@')) == NULL) || 3208 (*++char_ptr != 'w')) { 3209 return (L_INVALID_PATH); 3210 } else { 3211 char_ptr++; 3212 } 3213 } 3214 3215 if (strlen(char_ptr) < (WWN_SIZE * 2)) { 3216 return (L_INVALID_PATH); 3217 } 3218 (void) strncpy(wwn_str, char_ptr, WWN_SIZE * 2); 3219 wwn_str[WWN_SIZE * 2] = '\0'; 3220 errno = 0; /* For error checking */ 3221 ll_wwn = strtoull(wwn_str, &temp_ptr, L_WWN_LENGTH); 3222 3223 if (errno || (temp_ptr != (wwn_str + (WWN_SIZE * 2)))) { 3224 return (L_INVALID_PATH); 3225 } 3226 3227 byte_ptr = (char *)&ll_wwn; 3228 3229 /* 3230 * Search for the ses's node wwn in map to get the area and 3231 * domain ids from the corresponding port id (phys address). 3232 */ 3233 for (dev_addr_ptr = map->dev_addr, i = 0; i < map->count; 3234 dev_addr_ptr++, i++) { 3235 if (bcmp((char *)dev_addr_ptr->gfc_port_dev. 3236 pub_port.dev_nwwn.raw_wwn, byte_ptr, WWN_SIZE) == 0) 3237 break; 3238 } 3239 if (i >= map->count) 3240 return (L_INVALID_PATH); 3241 *pid = dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id; 3242 return (0); 3243 } 3244 3245 3246 /* 3247 * Finds the disk's node wwn string, and 3248 * port A and B's WWNs and their port status. 3249 * 3250 * INPUT: 3251 * path - pointer to a ses path 3252 * wwn_list - pointer to the wwn_list 3253 * 3254 * OUTPUT: 3255 * state - node_wwn and wwn of ports A & B of disk, etc are inited 3256 * - by l_get_disk_status() 3257 * found_flag - incremented after each examined element in the map 3258 * 3259 * RETURNS: 3260 * 0 O.K. 3261 * non-zero otherwise. 3262 */ 3263 static int 3264 l_get_node_status(char *path, struct l_disk_state_struct *state, 3265 int *found_flag, WWN_list *wwn_list, int verbose) 3266 { 3267 int j, select_id, err; 3268 int path_pid; 3269 char temp_path[MAXPATHLEN]; 3270 char sbuf[MAXPATHLEN], *char_ptr; 3271 gfc_map_mp_t *map_mp, *map_ptr; 3272 struct stat stat_buf; 3273 WWN_list *wwnlp; 3274 char wwnp[WWN_S_LEN]; 3275 3276 /* 3277 * Get a new map. 3278 */ 3279 map_mp = NULL; 3280 if (err = get_mp_dev_map(path, &map_mp, verbose)) 3281 return (err); 3282 3283 for (map_ptr = map_mp; map_ptr != NULL; map_ptr = map_ptr->map_next) { 3284 switch (map_ptr->map.hba_addr.port_topology) { 3285 case FC_TOP_PRIVATE_LOOP: 3286 for (j = 0; j < map_ptr->map.count; j++) { 3287 /* 3288 * Get a generic path to a device 3289 * 3290 * This assumes the path looks something like this 3291 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/... 3292 * ...ses@x,0:0 3293 * then creates a path that looks like 3294 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@ 3295 */ 3296 (void) strcpy(temp_path, path); 3297 if ((char_ptr = strrchr(temp_path, '/')) == NULL) { 3298 free_mp_dev_map(&map_mp); 3299 return (L_INVALID_PATH); 3300 } 3301 *char_ptr = '\0'; /* Terminate sting */ 3302 (void) strcat(temp_path, SLSH_DRV_NAME_SSD); 3303 /* 3304 * Create complete path. 3305 * 3306 * Build entry ssd@xx,0:c,raw 3307 * where xx is the WWN. 3308 */ 3309 select_id = g_sf_alpa_to_switch[map_ptr->map. 3310 dev_addr[j].gfc_port_dev.priv_port.sf_al_pa]; 3311 G_DPRINTF(" l_get_node_status: Searching loop map " 3312 "to find disk: ID:0x%x" 3313 " AL_PA:0x%x\n", select_id, 3314 state->ib_status.sel_id); 3315 3316 if (strstr(path, SCSI_VHCI) == NULL) { 3317 3318 (void) sprintf(sbuf, 3319 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw", 3320 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3321 sf_port_wwn[0], 3322 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3323 sf_port_wwn[1], 3324 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3325 sf_port_wwn[2], 3326 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3327 sf_port_wwn[3], 3328 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3329 sf_port_wwn[4], 3330 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3331 sf_port_wwn[5], 3332 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3333 sf_port_wwn[6], 3334 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3335 sf_port_wwn[7]); 3336 (void) strcat(temp_path, sbuf); 3337 3338 } 3339 /* 3340 * If we find a device on this loop in this box 3341 * update its status. 3342 */ 3343 if (state->ib_status.sel_id == select_id) { 3344 /* 3345 * Found a device on this loop in this box. 3346 * 3347 * Update state. 3348 */ 3349 (void) sprintf(state->g_disk_state.node_wwn_s, 3350 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 3351 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3352 sf_node_wwn[0], 3353 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3354 sf_node_wwn[1], 3355 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3356 sf_node_wwn[2], 3357 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3358 sf_node_wwn[3], 3359 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3360 sf_node_wwn[4], 3361 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3362 sf_node_wwn[5], 3363 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3364 sf_node_wwn[6], 3365 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3366 sf_node_wwn[7]); 3367 3368 if (strstr(path, SCSI_VHCI) != NULL) { 3369 (void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev. 3370 priv_port.sf_node_wwn, wwnp); 3371 for (wwnlp = wwn_list; wwnlp != NULL; 3372 wwnlp = wwnlp->wwn_next) { 3373 if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) { 3374 (void) strcpy(temp_path, wwnlp->physical_path); 3375 break; 3376 } 3377 } 3378 if (wwnlp == NULL) { 3379 (void) sprintf(sbuf, 3380 "g%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x:c,raw", 3381 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3382 sf_node_wwn[0], 3383 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3384 sf_node_wwn[1], 3385 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3386 sf_node_wwn[2], 3387 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3388 sf_node_wwn[3], 3389 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3390 sf_node_wwn[4], 3391 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3392 sf_node_wwn[5], 3393 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3394 sf_node_wwn[6], 3395 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port. 3396 sf_node_wwn[7]); 3397 (void) strcat(temp_path, sbuf); 3398 /* 3399 * check to make sure this is a valid path. 3400 * Paths may not always be created on the 3401 * host. So, we make a quick check. 3402 */ 3403 if (stat(temp_path, &stat_buf) == -1) { 3404 free_mp_dev_map(&map_mp); 3405 return (errno); 3406 } 3407 3408 } 3409 } 3410 (void) strcpy(state->g_disk_state.physical_path, 3411 temp_path); 3412 3413 3414 /* Bad if WWN is all zeros. */ 3415 if (is_null_wwn(map_ptr->map.dev_addr[j]. 3416 gfc_port_dev.priv_port. 3417 sf_node_wwn)) { 3418 state->l_state_flag = L_INVALID_WWN; 3419 G_DPRINTF(" l_get_node_status: " 3420 "Disk state was " 3421 " Invalid WWN.\n"); 3422 (*found_flag)++; 3423 free_mp_dev_map(&map_mp); 3424 return (0); 3425 } 3426 3427 /* get device status */ 3428 if (err = l_get_disk_status(temp_path, state, 3429 wwn_list, verbose)) { 3430 free_mp_dev_map(&map_mp); 3431 return (err); 3432 } 3433 /* 3434 * found device in map. Don't need to look 3435 * any further 3436 */ 3437 (*found_flag)++; 3438 free_mp_dev_map(&map_mp); 3439 return (0); 3440 } 3441 } /* for loop */ 3442 break; 3443 case FC_TOP_PUBLIC_LOOP: 3444 case FC_TOP_FABRIC: 3445 /* 3446 * Get a generic path to a device 3447 * This assumes the path looks something like this 3448 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@wWWN,0:0 3449 * then creates a path that looks like 3450 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@ 3451 */ 3452 (void) strcpy(temp_path, path); 3453 if ((char_ptr = strrchr(temp_path, '/')) == NULL) { 3454 free_mp_dev_map(&map_mp); 3455 return (L_INVALID_PATH); 3456 } 3457 *char_ptr = '\0'; /* Terminate sting */ 3458 3459 if (err = l_get_pid_from_path(path, &map_ptr->map, &path_pid)) { 3460 free_mp_dev_map(&map_mp); 3461 return (err); 3462 } 3463 3464 /* Now append the ssd string */ 3465 (void) strcat(temp_path, SLSH_DRV_NAME_SSD); 3466 3467 /* 3468 * Create complete path. 3469 * 3470 * Build entry ssd@WWN,0:c,raw 3471 * 3472 * First, search the map for a device with the area code and 3473 * domain as in 'path_pid'. 3474 */ 3475 for (j = 0; j < map_ptr->map.count; j++) { 3476 if (map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3477 dev_dtype != DTYPE_ESI) { 3478 select_id = g_sf_alpa_to_switch[map_ptr->map. 3479 dev_addr[j].gfc_port_dev.pub_port.dev_did. 3480 port_id & 0xFF]; 3481 3482 if (((map_ptr->map.dev_addr[j].gfc_port_dev. 3483 pub_port.dev_did.port_id & 3484 AREA_DOMAIN_ID) == 3485 (path_pid & AREA_DOMAIN_ID)) && 3486 (state->ib_status.sel_id == select_id)) { 3487 /* 3488 * Found the device. Update state. 3489 */ 3490 if (strstr(temp_path, SCSI_VHCI) == NULL) { 3491 (void) sprintf(sbuf, 3492 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw", 3493 map_ptr->map.dev_addr[j].gfc_port_dev. 3494 pub_port.dev_pwwn.raw_wwn[0], 3495 map_ptr->map.dev_addr[j].gfc_port_dev. 3496 pub_port.dev_pwwn.raw_wwn[1], 3497 map_ptr->map.dev_addr[j].gfc_port_dev. 3498 pub_port.dev_pwwn.raw_wwn[2], 3499 map_ptr->map.dev_addr[j].gfc_port_dev. 3500 pub_port.dev_pwwn.raw_wwn[3], 3501 map_ptr->map.dev_addr[j].gfc_port_dev. 3502 pub_port.dev_pwwn.raw_wwn[4], 3503 map_ptr->map.dev_addr[j].gfc_port_dev. 3504 pub_port.dev_pwwn.raw_wwn[5], 3505 map_ptr->map.dev_addr[j].gfc_port_dev. 3506 pub_port.dev_pwwn.raw_wwn[6], 3507 map_ptr->map.dev_addr[j].gfc_port_dev. 3508 pub_port.dev_pwwn.raw_wwn[7]); 3509 (void) strcat(temp_path, sbuf); 3510 3511 /* 3512 * Paths for fabric cases may not always 3513 * be created on the host. So, we make a 3514 * quick check. 3515 */ 3516 if (stat(temp_path, &stat_buf) == -1) { 3517 free_mp_dev_map(&map_mp); 3518 return (errno); 3519 } 3520 3521 (void) sprintf(state-> 3522 g_disk_state.node_wwn_s, 3523 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", 3524 map_ptr->map.dev_addr[j].gfc_port_dev. 3525 pub_port.dev_nwwn.raw_wwn[0], 3526 map_ptr->map.dev_addr[j].gfc_port_dev. 3527 pub_port.dev_nwwn.raw_wwn[1], 3528 map_ptr->map.dev_addr[j].gfc_port_dev. 3529 pub_port.dev_nwwn.raw_wwn[2], 3530 map_ptr->map.dev_addr[j].gfc_port_dev. 3531 pub_port.dev_nwwn.raw_wwn[3], 3532 map_ptr->map.dev_addr[j].gfc_port_dev. 3533 pub_port.dev_nwwn.raw_wwn[4], 3534 map_ptr->map.dev_addr[j].gfc_port_dev. 3535 pub_port.dev_nwwn.raw_wwn[5], 3536 map_ptr->map.dev_addr[j].gfc_port_dev. 3537 pub_port.dev_nwwn.raw_wwn[6], 3538 map_ptr->map.dev_addr[j].gfc_port_dev. 3539 pub_port.dev_nwwn.raw_wwn[7]); 3540 3541 } else { 3542 (void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev. 3543 priv_port.sf_node_wwn, wwnp); 3544 for (wwnlp = wwn_list; wwnlp != NULL; 3545 wwnlp = wwnlp->wwn_next) { 3546 if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) { 3547 (void) strcpy(temp_path, wwnlp->physical_path); 3548 break; 3549 } 3550 } 3551 if (wwnlp == NULL) { 3552 (void) sprintf(sbuf, 3553 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw", 3554 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3555 dev_nwwn.raw_wwn[0], 3556 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3557 dev_nwwn.raw_wwn[1], 3558 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3559 dev_nwwn.raw_wwn[2], 3560 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3561 dev_nwwn.raw_wwn[3], 3562 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3563 dev_nwwn.raw_wwn[4], 3564 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3565 dev_nwwn.raw_wwn[5], 3566 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3567 dev_nwwn.raw_wwn[6], 3568 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port. 3569 dev_nwwn.raw_wwn[7]); 3570 (void) strcat(temp_path, sbuf); 3571 } 3572 } 3573 (void) strcpy(state->g_disk_state.physical_path, 3574 temp_path); 3575 3576 /* Bad if WWN is all zeros. */ 3577 if (is_null_wwn(map_ptr->map. 3578 dev_addr[j].gfc_port_dev. 3579 pub_port.dev_nwwn. 3580 raw_wwn)) { 3581 state->l_state_flag = 3582 L_INVALID_WWN; 3583 G_DPRINTF( 3584 " l_get_node_status: " 3585 "Disk state was " 3586 " Invalid WWN.\n"); 3587 (*found_flag)++; 3588 free_mp_dev_map(&map_mp); 3589 return (0); 3590 } 3591 3592 /* get device status */ 3593 if (err = l_get_disk_status(temp_path, 3594 state, wwn_list, verbose)) { 3595 free_mp_dev_map(&map_mp); 3596 return (err); 3597 } 3598 3599 (*found_flag)++; 3600 free_mp_dev_map(&map_mp); 3601 return (0); 3602 } /* if select_id match */ 3603 } /* if !DTYPE_ESI */ 3604 } /* for loop */ 3605 break; 3606 case FC_TOP_PT_PT: 3607 free_mp_dev_map(&map_mp); 3608 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 3609 default: 3610 free_mp_dev_map(&map_mp); 3611 return (L_UNEXPECTED_FC_TOPOLOGY); 3612 } /* End of switch on port_topology */ 3613 3614 } 3615 free_mp_dev_map(&map_mp); 3616 return (0); 3617 } 3618 3619 3620 /* 3621 * Get the individual drives status for the device specified by the index. 3622 * device at the path where the path is of the IB and updates the 3623 * g_disk_state_struct structure. 3624 * 3625 * If the disk's port is bypassed, it gets the 3626 * drive status such as node WWN from the second port. 3627 * 3628 * RETURNS: 3629 * 0 O.K. 3630 * non-zero otherwise 3631 */ 3632 int 3633 l_get_individual_state(char *path, 3634 struct l_disk_state_struct *state, Ib_state *ib_state, 3635 int front_flag, struct box_list_struct *box_list, 3636 struct wwn_list_struct *wwn_list, int verbose) 3637 { 3638 int found_flag = 0, elem_index = 0; 3639 int port_a_flag, err, j; 3640 struct dlist *seslist = NULL; 3641 Bp_elem_st bpf, bpr; 3642 hrtime_t start_time, end_time; 3643 3644 if ((path == NULL) || (state == NULL) || 3645 (ib_state == NULL) || (box_list == NULL)) { 3646 return (L_INVALID_PATH_FORMAT); 3647 } 3648 3649 start_time = gethrtime(); 3650 3651 3652 if ((state->ib_status.code != S_NOT_INSTALLED) && 3653 (state->ib_status.code != S_NOT_AVAILABLE)) { 3654 3655 /* 3656 * Disk could have been bypassed on this loop. 3657 * Check the port state before l_state_flag 3658 * is set to L_INVALID_MAP. 3659 */ 3660 for (j = 0; 3661 j < (int)ib_state->config.enc_num_elem; 3662 j++) { 3663 elem_index++; 3664 if (ib_state->config.type_hdr[j].type == 3665 ELM_TYP_BP) 3666 break; 3667 elem_index += 3668 ib_state->config.type_hdr[j].num; 3669 } 3670 3671 /* 3672 * check if port A & B of backplane are bypassed. 3673 * If so, do not bother. 3674 */ 3675 if (front_flag) { 3676 bcopy((const void *) 3677 &(ib_state->p2_s.element[elem_index]), 3678 (void *)&bpf, sizeof (bpf)); 3679 3680 if ((bpf.byp_a_enabled || bpf.en_bypass_a) && 3681 (bpf.byp_b_enabled || bpf.en_bypass_b)) 3682 return (0); 3683 } else { 3684 /* if disk is in rear slot */ 3685 bcopy((const void *) 3686 &(ib_state->p2_s.element[elem_index+1]), 3687 (void *)&bpr, sizeof (bpr)); 3688 3689 if ((bpr.byp_b_enabled || bpr.en_bypass_b) && 3690 (bpr.byp_a_enabled || bpr.en_bypass_a)) 3691 return (0); 3692 } 3693 3694 if ((err = l_get_node_status(path, state, 3695 &found_flag, wwn_list, verbose)) != 0) 3696 return (err); 3697 3698 if (!found_flag) { 3699 if ((err = l_get_allses(path, box_list, 3700 &seslist, 0)) != 0) { 3701 return (err); 3702 } 3703 3704 if (err = l_get_port(path, &port_a_flag, verbose)) 3705 goto done; 3706 3707 if (port_a_flag) { 3708 if ((state->ib_status.bypass_a_en && 3709 !(state->ib_status.bypass_b_en)) || 3710 !(state->ib_status.bypass_b_en)) { 3711 while (seslist != NULL && !found_flag) { 3712 if (err = l_get_port( 3713 seslist->dev_path, 3714 &port_a_flag, verbose)) { 3715 goto done; 3716 } 3717 if ((strcmp(seslist->dev_path, 3718 path) != 0) && 3719 !port_a_flag) { 3720 *path = NULL; 3721 (void) strcpy(path, 3722 seslist->dev_path); 3723 if (err = 3724 l_get_node_status(path, 3725 state, &found_flag, 3726 wwn_list, verbose)) { 3727 goto done; 3728 } 3729 } 3730 seslist = seslist->next; 3731 } 3732 } 3733 } else { 3734 if ((state->ib_status.bypass_b_en && 3735 !(state->ib_status.bypass_a_en)) || 3736 !(state->ib_status.bypass_a_en)) { 3737 while (seslist != NULL && !found_flag) { 3738 if (err = l_get_port( 3739 seslist->dev_path, 3740 &port_a_flag, verbose)) { 3741 goto done; 3742 } 3743 if ((strcmp(seslist->dev_path, 3744 path) != 0) && port_a_flag) { 3745 *path = NULL; 3746 (void) strcpy(path, 3747 seslist->dev_path); 3748 if (err = 3749 l_get_node_status(path, 3750 state, &found_flag, 3751 wwn_list, verbose)) { 3752 goto done; 3753 } 3754 } 3755 seslist = seslist->next; 3756 } 3757 } 3758 } 3759 if (!found_flag) { 3760 state->l_state_flag = L_INVALID_MAP; 3761 G_DPRINTF(" l_get_individual_state: " 3762 "Disk state was " 3763 "Not in map.\n"); 3764 } else { 3765 G_DPRINTF(" l_get_individual_state: " 3766 "Disk was found in the map.\n"); 3767 } 3768 3769 if (seslist != NULL) 3770 (void) g_free_multipath(seslist); 3771 3772 } 3773 3774 } else { 3775 G_DPRINTF(" l_get_individual_state: Disk state was %s.\n", 3776 (state->ib_status.code == S_NOT_INSTALLED) ? 3777 "Not Installed" : "Not Available"); 3778 } 3779 3780 if (getenv("_LUX_T_DEBUG") != NULL) { 3781 end_time = gethrtime(); 3782 (void) fprintf(stdout, " l_get_individual_state:" 3783 "\tTime = %lld millisec\n", 3784 (end_time - start_time)/1000000); 3785 } 3786 3787 return (0); 3788 done: 3789 (void) g_free_multipath(seslist); 3790 return (err); 3791 } 3792 3793 3794 3795 /* 3796 * Get the global state of the photon. 3797 * 3798 * INPUT: 3799 * path and verbose flag 3800 * 3801 * "path" must be of the ses driver. 3802 * e.g. 3803 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 3804 * or 3805 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0 3806 * 3807 * OUTPUT: 3808 * The struct l_state (which was passed in) has the status info 3809 * 3810 * RETURNS: 3811 * 0 O.K. 3812 * non-zero otherwise 3813 */ 3814 int 3815 l_get_status(char *path, struct l_state_struct *l_state, int verbose) 3816 { 3817 int err = 0, i, count; 3818 L_inquiry inq; 3819 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 3820 int al_pa, found_front, found_rear, front_flag, enc_type; 3821 char ses_path_front[MAXPATHLEN]; 3822 char ses_path_rear[MAXPATHLEN]; 3823 Box_list *b_list = NULL; 3824 Box_list *o_list = NULL; 3825 char node_wwn_s[(WWN_SIZE*2)+1]; 3826 uint_t select_id; 3827 hrtime_t start_time, end_time; 3828 WWN_list *wwn_list = NULL; 3829 3830 if ((path == NULL) || (l_state == NULL)) { 3831 return (L_INVALID_PATH_FORMAT); 3832 } 3833 3834 start_time = gethrtime(); 3835 3836 G_DPRINTF(" l_get_status: Get Status for enclosure at: " 3837 " %s\n", path); 3838 3839 /* initialization */ 3840 (void) memset(l_state, 0, sizeof (struct l_state_struct)); 3841 3842 if (err = g_get_inquiry(path, &inq)) { 3843 return (err); 3844 } 3845 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 3846 (!(strncmp((char *)inq.inq_vid, "SUN ", 3847 sizeof (inq.inq_vid)) && 3848 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 3849 return (L_ENCL_INVALID_PATH); 3850 } 3851 3852 (void) strncpy((char *)l_state->ib_tbl.enclosure_name, 3853 (char *)inq.inq_box_name, sizeof (inq.inq_box_name)); 3854 3855 /* 3856 * Get all of the IB Receive Diagnostic pages. 3857 */ 3858 if (err = l_get_ib_status(path, l_state, verbose)) { 3859 return (err); 3860 } 3861 3862 /* 3863 * Now get the individual devices information from 3864 * the device itself. 3865 * 3866 * May need to use multiple paths to get to the 3867 * front and rear drives in the box. 3868 * If the loop is split some drives may not even be available 3869 * from this host. 3870 * 3871 * The way this works is in the select ID the front disks 3872 * are accessed via the IB with the bit 4 = 0 3873 * and the rear disks by the IB with bit 4 = 1. 3874 * 3875 * First get device map from fc nexus driver for this loop. 3876 */ 3877 /* 3878 * Get the boxes node WWN & al_pa for this path. 3879 */ 3880 if (err = g_get_wwn(path, port_wwn, node_wwn, &al_pa, verbose)) { 3881 return (err); 3882 } 3883 if (err = l_get_box_list(&o_list, verbose)) { 3884 (void) l_free_box_list(&o_list); 3885 return (err); /* Failure */ 3886 } 3887 3888 found_front = found_rear = 0; 3889 for (i = 0; i < WWN_SIZE; i++) { 3890 (void) sprintf(&node_wwn_s[i << 1], "%02x", node_wwn[i]); 3891 } 3892 3893 /* 3894 * The al_pa (or pa) can be 24 bits in size for fabric loops. 3895 * But we will take only the low order byte to get the select_id. 3896 * Private loops have al_pa which is only a byte in size. 3897 */ 3898 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3899 l_state->ib_tbl.box_id = (select_id & BOX_ID_MASK) >> 5; 3900 3901 G_DPRINTF(" l_get_status: Using this select_id 0x%x " 3902 "and node WWN %s\n", 3903 select_id, node_wwn_s); 3904 3905 if (strstr(path, SCSI_VHCI) != NULL) { 3906 /* there is no way to obtain all the al_pa with */ 3907 /* current implementation. assume both front */ 3908 /* and rear. need changes later on. */ 3909 found_rear = 1; 3910 found_front = 1; 3911 (void) strcpy(ses_path_rear, path); 3912 (void) strcpy(ses_path_front, path); 3913 } else { 3914 3915 if (select_id & ALT_BOX_ID) { 3916 found_rear = 1; 3917 (void) strcpy(ses_path_rear, path); 3918 b_list = o_list; 3919 while (b_list) { 3920 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) { 3921 if (err = g_get_wwn(b_list->b_physical_path, 3922 port_wwn, node_wwn, 3923 &al_pa, verbose)) { 3924 (void) l_free_box_list(&o_list); 3925 return (err); 3926 } 3927 3928 /* Take the low order byte of al_pa */ 3929 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3930 if (!(select_id & ALT_BOX_ID)) { 3931 (void) strcpy(ses_path_front, 3932 b_list->b_physical_path); 3933 found_front = 1; 3934 break; 3935 } 3936 } 3937 b_list = b_list->box_next; 3938 } 3939 } else { 3940 (void) strcpy(ses_path_front, path); 3941 found_front = 1; 3942 b_list = o_list; 3943 while (b_list) { 3944 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) { 3945 if (err = g_get_wwn(b_list->b_physical_path, 3946 port_wwn, node_wwn, 3947 &al_pa, verbose)) { 3948 (void) l_free_box_list(&o_list); 3949 return (err); 3950 } 3951 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3952 if (select_id & ALT_BOX_ID) { 3953 (void) strcpy(ses_path_rear, 3954 b_list->b_physical_path); 3955 found_rear = 1; 3956 break; 3957 } 3958 } 3959 b_list = b_list->box_next; 3960 } 3961 } 3962 } 3963 3964 if (getenv("_LUX_G_DEBUG") != NULL) { 3965 if (!found_front) { 3966 (void) printf("l_get_status: Loop to front disks not found.\n"); 3967 } 3968 if (!found_rear) { 3969 (void) printf("l_get_status: Loop to rear disks not found.\n"); 3970 } 3971 } 3972 3973 /* 3974 * Get path to all the FC disk and tape devices. 3975 * 3976 * I get this now and pass down for performance 3977 * reasons. 3978 * If for some reason the list can become invalid, 3979 * i.e. device being offlined, then the list 3980 * must be re-gotten. 3981 */ 3982 if (err = g_get_wwn_list(&wwn_list, verbose)) { 3983 return (err); /* Failure */ 3984 } 3985 3986 enc_type = l_get_enc_type(inq); 3987 if (found_front) { 3988 front_flag = 1; 3989 for (i = 0, count = 0; i < l_state->total_num_drv/2; 3990 count++, i++) { 3991 if (enc_type == DAK_ENC_TYPE) { 3992 G_DPRINTF(" l_get_status: Getting individual" 3993 " State for disk in slot %d\n", count); 3994 } else { 3995 G_DPRINTF(" l_get_status: Getting individual" 3996 " State for front disk in slot %d\n", i); 3997 } 3998 if (err = l_get_individual_state(ses_path_front, 3999 (struct l_disk_state_struct *)&l_state->drv_front[i], 4000 &l_state->ib_tbl, front_flag, o_list, 4001 wwn_list, verbose)) { 4002 (void) l_free_box_list(&o_list); 4003 (void) g_free_wwn_list(&wwn_list); 4004 return (err); 4005 } 4006 } 4007 } else { 4008 /* Set to loop not accessable. */ 4009 for (i = 0; i < l_state->total_num_drv/2; i++) { 4010 l_state->drv_front[i].l_state_flag = L_NO_LOOP; 4011 } 4012 } 4013 /* 4014 * For Daktari's, disk 0-5 information are located in the 4015 * l_state->drv_front array 4016 * For Daktari's, disk 6-11 information are located in the 4017 * l_state->drv_rear array 4018 * 4019 * For this reason, on daktari's, I ignore the found_front and 4020 * found_rear flags and check both the drv_front and drv_rear 4021 */ 4022 4023 if (enc_type == DAK_ENC_TYPE && found_front) { 4024 front_flag = 1; 4025 for (i = 0; i < l_state->total_num_drv/2; i++, count++) { 4026 G_DPRINTF(" l_get_status: Getting individual" 4027 " State for disk in slot %d\n", count); 4028 if (err = l_get_individual_state(ses_path_front, 4029 (struct l_disk_state_struct *)&l_state->drv_rear[i], 4030 &l_state->ib_tbl, front_flag, o_list, 4031 wwn_list, verbose)) { 4032 (void) l_free_box_list(&o_list); 4033 (void) g_free_wwn_list(&wwn_list); 4034 return (err); 4035 } 4036 } 4037 } else if (enc_type != DAK_ENC_TYPE && found_rear) { 4038 for (i = 0; i < l_state->total_num_drv/2; i++, count++) { 4039 G_DPRINTF(" l_get_status: Getting individual" 4040 " State for rear disk in slot %d\n", i); 4041 if (err = l_get_individual_state(ses_path_rear, 4042 (struct l_disk_state_struct *)&l_state->drv_rear[i], 4043 &l_state->ib_tbl, front_flag, o_list, 4044 wwn_list, verbose)) { 4045 (void) l_free_box_list(&o_list); 4046 (void) g_free_wwn_list(&wwn_list); 4047 return (err); 4048 } 4049 } 4050 } else if (enc_type != DAK_ENC_TYPE) { 4051 /* Set to loop not accessable. */ 4052 for (i = 0; i < l_state->total_num_drv/2; i++) { 4053 l_state->drv_rear[i].l_state_flag = L_NO_LOOP; 4054 } 4055 } 4056 4057 (void) l_free_box_list(&o_list); 4058 (void) g_free_wwn_list(&wwn_list); 4059 if (getenv("_LUX_T_DEBUG") != NULL) { 4060 end_time = gethrtime(); 4061 (void) fprintf(stdout, " l_get_status: " 4062 "Time = %lld millisec\n", 4063 (end_time - start_time)/1000000); 4064 } 4065 4066 return (0); 4067 } 4068 4069 4070 4071 /* 4072 * Check the SENA file for validity: 4073 * - verify the size is that of 3 proms worth of text. 4074 * - verify PROM_MAGIC. 4075 * - verify (and print) the date. 4076 * - verify the checksum. 4077 * - verify the WWN == 0. 4078 * Since this requires reading the entire file, do it now and pass a pointer 4079 * to the allocated buffer back to the calling routine (which is responsible 4080 * for freeing it). If the buffer is not allocated it will be NULL. 4081 * 4082 * RETURNS: 4083 * 0 O.K. 4084 * non-zero otherwise 4085 */ 4086 4087 static int 4088 check_file(int fd, int verbose, uchar_t **buf_ptr, int dl_info_offset) 4089 { 4090 struct exec the_exec; 4091 int temp, i, j, *p, size, *start; 4092 uchar_t *buf; 4093 char *date_str; 4094 struct dl_info *dl_info; 4095 4096 *buf_ptr = NULL; 4097 4098 /* read exec header */ 4099 if (lseek(fd, 0, SEEK_SET) == -1) 4100 return (errno); 4101 if ((temp = read(fd, (char *)&the_exec, sizeof (the_exec))) == -1) { 4102 return (L_DWNLD_READ_HEADER_FAIL); 4103 } 4104 if (temp != sizeof (the_exec)) { 4105 return (L_DWNLD_READ_INCORRECT_BYTES); 4106 } 4107 4108 if (the_exec.a_text != PROMSIZE) { 4109 return (L_DWNLD_INVALID_TEXT_SIZE); 4110 } 4111 4112 if (!(buf = (uchar_t *)g_zalloc(PROMSIZE))) 4113 return (L_MALLOC_FAILED); 4114 4115 if ((temp = read(fd, buf, PROMSIZE)) == -1) { 4116 return (L_DWNLD_READ_ERROR); 4117 } 4118 4119 if (temp != PROMSIZE) { 4120 return (L_DWNLD_READ_INCORRECT_BYTES); 4121 } 4122 4123 4124 4125 /* check the IB firmware MAGIC */ 4126 dl_info = (struct dl_info *)(unsigned long)(buf + dl_info_offset); 4127 if (dl_info->magic != PROM_MAGIC) { 4128 return (L_DWNLD_BAD_FRMWARE); 4129 } 4130 4131 /* 4132 * Get the date 4133 */ 4134 4135 date_str = ctime(&dl_info->datecode); 4136 4137 if (verbose) { 4138 (void) fprintf(stdout, 4139 MSGSTR(9050, " IB Prom Date: %s"), 4140 date_str); 4141 } 4142 4143 /* 4144 * verify checksum 4145 */ 4146 4147 if (dl_info_offset == FPM_DL_INFO) { 4148 start = (int *)(long)(buf + FPM_OFFSET); 4149 size = FPM_SZ; 4150 } else { 4151 start = (int *)(long)buf; 4152 size = TEXT_SZ + IDATA_SZ; 4153 } 4154 4155 for (j = 0, p = start, i = 0; i < (size/ 4); i++, j ^= *p++); 4156 4157 if (j != 0) { 4158 return (L_DWNLD_CHKSUM_FAILED); 4159 } 4160 4161 /* file verified */ 4162 *buf_ptr = buf; 4163 4164 return (0); 4165 } 4166 4167 /* 4168 * Check the DPM file for validity: 4169 * 4170 * RETURNS: 4171 * 0 O.K. 4172 * non-zero otherwise 4173 */ 4174 #define dakstring "64616B74617269" 4175 #define dakoffs "BFC00000" 4176 4177 static int 4178 check_dpm_file(int fd) 4179 { 4180 struct s3hdr { 4181 char rtype[2]; 4182 char rlen[2]; 4183 char data[255]; 4184 } theRec; 4185 int nread; 4186 int reclen; 4187 4188 if (fd < 0) { 4189 return (L_DWNLD_READ_ERROR); 4190 } 4191 lseek(fd, 0, SEEK_SET); 4192 4193 /* First record */ 4194 memset((void*)&theRec, 0, sizeof (struct s3hdr)); 4195 nread = read(fd, (void *)&theRec, 4); 4196 if (nread != 4) { 4197 /* error reading first record/length */ 4198 return (L_DWNLD_READ_ERROR); 4199 } 4200 if (strncmp((char *)&theRec.rtype[0], "S0", 2) != 0) { 4201 /* error in first record type */ 4202 return (L_DWNLD_READ_HEADER_FAIL); 4203 } 4204 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16); 4205 if (reclen == 0) { 4206 /* error in length == 0 */ 4207 return (L_DWNLD_READ_HEADER_FAIL); 4208 } 4209 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1)); 4210 if (nread != ((reclen*2) +1)) { 4211 /* error in trying to read data */ 4212 return (L_DWNLD_READ_HEADER_FAIL); 4213 } 4214 if (strncmp(&theRec.data[4], dakstring, 14) != 0) { 4215 /* error in compiled file name */ 4216 return (L_DWNLD_READ_HEADER_FAIL); 4217 } 4218 4219 /* Second record */ 4220 memset((void*)&theRec, 0, sizeof (struct s3hdr)); 4221 nread = read(fd, (void *)&theRec, 4); 4222 if (nread != 4) { 4223 /* error reading second record/length */ 4224 return (L_DWNLD_READ_ERROR); 4225 } 4226 if (strncmp((char *)&theRec.rtype[0], "S3", 2) != 0) { 4227 /* error in second record type */ 4228 return (L_DWNLD_READ_HEADER_FAIL); 4229 } 4230 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16); 4231 if (reclen == 0) { 4232 /* error in length == 0 */ 4233 return (L_DWNLD_READ_HEADER_FAIL); 4234 } 4235 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1)); 4236 if (nread != ((reclen*2) +1)) { 4237 /* error in trying to read data */ 4238 return (L_DWNLD_READ_HEADER_FAIL); 4239 } 4240 if (strncmp(&theRec.data[0], dakoffs, 8) != 0) { 4241 /* error in SSC100 offset pointer */ 4242 return (L_DWNLD_READ_HEADER_FAIL); 4243 } 4244 lseek(fd, 0, SEEK_SET); 4245 return (0); 4246 } 4247 4248 4249 4250 int 4251 l_check_file(char *file, int verbose) 4252 { 4253 int file_fd; 4254 int err; 4255 uchar_t *buf; 4256 4257 if ((file_fd = g_object_open(file, O_RDONLY)) == -1) { 4258 return (L_OPEN_PATH_FAIL); 4259 } 4260 err = check_file(file_fd, verbose, &buf, FW_DL_INFO); 4261 if (buf) 4262 (void) g_destroy_data((char *)buf); 4263 return (err); 4264 } 4265 4266 4267 4268 /* 4269 * Write buffer command set up to download 4270 * firmware to the Photon IB. 4271 * 4272 * RETURNS: 4273 * status 4274 */ 4275 static int 4276 ib_download_code_cmd(int fd, int promid, int off, uchar_t *buf_ptr, 4277 int buf_len, int sp) 4278 { 4279 int status, sz; 4280 4281 while (buf_len) { 4282 sz = MIN(256, buf_len); 4283 buf_len -= sz; 4284 status = g_scsi_writebuffer_cmd(fd, off, buf_ptr, sz, 4285 (sp) ? 3 : 2, promid); 4286 if (status) 4287 return (status); 4288 buf_ptr += sz; 4289 off += sz; 4290 } 4291 4292 return (status); 4293 } 4294 4295 /* 4296 * 4297 * Downloads the code to the DAKTARI/DPM with the hdr set correctly 4298 * 4299 * 4300 * Inputs: 4301 * fd - int for the file descriptor 4302 * buf_ptr - uchar_t pointer to the firmware itself 4303 * buf_len - int for the length of the data 4304 * 4305 * Returns: 4306 * status: 0 indicates success, != 0 failure, returned from writebuffer 4307 * 4308 */ 4309 4310 static int 4311 dak_download_code_cmd(int fd, uchar_t *buf_ptr, int buf_len) 4312 { 4313 int status = 0; 4314 int sz = 0; 4315 int offs = 0; 4316 4317 while (buf_len > 0) { 4318 sz = MIN(256, buf_len); 4319 buf_len -= sz; 4320 status = g_scsi_writebuffer_cmd(fd, offs, buf_ptr, sz, 0x07, 0); 4321 if (status != 0) { 4322 return (status); 4323 } 4324 buf_ptr += sz; 4325 offs += sz; 4326 } 4327 return (status); 4328 } 4329 4330 4331 4332 4333 /* 4334 * Downloads the new prom image to IB. 4335 * 4336 * INPUTS: 4337 * path - physical path of Photon SES card 4338 * file - input file for new code (may be NULL) 4339 * ps - whether the "save" bit should be set 4340 * verbose - to be verbose or not 4341 * 4342 * RETURNS: 4343 * 0 O.K. 4344 * non-zero otherwise 4345 */ 4346 int 4347 l_download(char *path_phys, char *file, int ps, int verbose) 4348 { 4349 int file_fd, controller_fd; 4350 int err, status; 4351 uchar_t *buf_ptr; 4352 char printbuf[MAXPATHLEN]; 4353 int retry; 4354 char file_path[MAXPATHLEN]; 4355 struct stat statbuf; 4356 int enc_type; 4357 L_inquiry inq; 4358 4359 if (path_phys == NULL) { 4360 return (L_INVALID_PATH_FORMAT); 4361 } 4362 4363 if (!file) { 4364 (void) strcpy(file_path, IBFIRMWARE_FILE); 4365 } else { 4366 (void) strncpy(file_path, file, sizeof (file_path)); 4367 } 4368 if (verbose) 4369 (void) fprintf(stdout, "%s\n", 4370 MSGSTR(9051, " Opening the IB for I/O.")); 4371 4372 if ((controller_fd = g_object_open(path_phys, O_NDELAY | O_RDWR)) == -1) 4373 return (L_OPEN_PATH_FAIL); 4374 4375 (void) sprintf(printbuf, MSGSTR(9052, " Doing download to:" 4376 "\n\t%s.\n From file: %s."), path_phys, file_path); 4377 4378 if (verbose) 4379 (void) fprintf(stdout, "%s\n", printbuf); 4380 P_DPRINTF(" Doing download to:" 4381 "\n\t%s\n From file: %s\n", path_phys, file_path); 4382 4383 if ((file_fd = g_object_open(file_path, O_NDELAY | O_RDONLY)) == -1) { 4384 /* 4385 * Return a different error code here to differentiate between 4386 * this failure in g_object_open() and the one above. 4387 */ 4388 return (L_INVALID_PATH); 4389 } 4390 4391 if (g_scsi_inquiry_cmd(controller_fd, (uchar_t *)&inq, sizeof (inq))) { 4392 return (L_SCSI_ERROR); 4393 } 4394 enc_type = l_get_enc_type(inq); 4395 switch (enc_type) { 4396 case DAK_ENC_TYPE: 4397 /* 4398 * We don't have a default daktari file location, so 4399 * the user must specify the firmware file on the command line 4400 */ 4401 if (!file) { 4402 return (L_REQUIRE_FILE); 4403 } 4404 /* Validate the file */ 4405 if ((err = check_dpm_file(file_fd))) { 4406 return (err); 4407 } 4408 /* Now go ahead and load up the data */ 4409 if (fstat(file_fd, &statbuf) == -1) { 4410 err = errno; 4411 (void) fprintf(stdout, "%s %s\n", 4412 MSGSTR(9101, " Stat'ing the F/W file:"), strerror(err)); 4413 return (L_OPEN_PATH_FAIL); 4414 } 4415 buf_ptr = (uchar_t *)g_zalloc(statbuf.st_size); 4416 if (buf_ptr == NULL) { 4417 err = errno; 4418 (void) fprintf(stdout, "%s %s\n", 4419 MSGSTR(9102, " Cannot alloc mem to read F/W file:"), 4420 strerror(err)); 4421 return (L_MALLOC_FAILED); 4422 } 4423 if (read(file_fd, buf_ptr, statbuf.st_size) == -1) { 4424 err = errno; 4425 (void) fprintf(stdout, "%s %s\n", 4426 MSGSTR(9103, " Reading F/W file:"), strerror(err)); 4427 g_destroy_data((char *)buf_ptr); 4428 return (L_DWNLD_READ_ERROR); 4429 } 4430 break; 4431 default: 4432 if (err = check_file(file_fd, verbose, &buf_ptr, FW_DL_INFO)) { 4433 if (buf_ptr) { 4434 (void) g_destroy_data((char *)buf_ptr); 4435 return (err); 4436 } 4437 } 4438 break; 4439 } 4440 4441 if (verbose) { 4442 (void) fprintf(stdout, " "); 4443 (void) fprintf(stdout, MSGSTR(127, "Checkfile O.K.")); 4444 (void) fprintf(stdout, "\n"); 4445 } 4446 P_DPRINTF(" Checkfile OK.\n"); 4447 (void) close(file_fd); 4448 4449 if (verbose) { 4450 (void) fprintf(stdout, MSGSTR(9053, 4451 " Verifying the IB is available.\n")); 4452 } 4453 4454 retry = DOWNLOAD_RETRIES; 4455 while (retry) { 4456 if ((status = g_scsi_tur(controller_fd)) == 0) { 4457 break; 4458 } else { 4459 if ((retry % 30) == 0) { 4460 ER_DPRINTF(" Waiting for the IB to be" 4461 " available.\n"); 4462 } 4463 (void) sleep(1); 4464 } 4465 } 4466 if (!retry) { 4467 if (buf_ptr) 4468 (void) g_destroy_data((char *)buf_ptr); 4469 (void) close(controller_fd); 4470 return (status); 4471 } 4472 4473 if (verbose) 4474 (void) fprintf(stdout, "%s\n", 4475 MSGSTR(9054, " Writing new text image to IB.")); 4476 P_DPRINTF(" Writing new image to IB\n"); 4477 switch (enc_type) { 4478 case DAK_ENC_TYPE: 4479 status = dak_download_code_cmd(controller_fd, buf_ptr, 4480 statbuf.st_size); 4481 if (status != 0) { 4482 if (buf_ptr != NULL) { 4483 g_destroy_data((char *)buf_ptr); 4484 } 4485 (void) close(controller_fd); 4486 return (status); 4487 } 4488 break; 4489 default: 4490 status = ib_download_code_cmd(controller_fd, IBEEPROM, TEXT_OFFSET, 4491 (uchar_t *)(buf_ptr + TEXT_OFFSET), TEXT_SZ, ps); 4492 if (status) { 4493 (void) close(controller_fd); 4494 (void) g_destroy_data((char *)buf_ptr); 4495 return (status); 4496 } 4497 if (verbose) { 4498 (void) fprintf(stdout, "%s\n", 4499 MSGSTR(9055, " Writing new data image to IB.")); 4500 } 4501 status = ib_download_code_cmd(controller_fd, IBEEPROM, IDATA_OFFSET, 4502 (uchar_t *)(buf_ptr + IDATA_OFFSET), IDATA_SZ, ps); 4503 if (status) { 4504 (void) close(controller_fd); 4505 (void) g_destroy_data((char *)buf_ptr); 4506 return (status); 4507 } 4508 break; 4509 } 4510 4511 4512 if (verbose) { 4513 (void) fprintf(stdout, MSGSTR(9056, 4514 " Re-verifying the IB is available.\n")); 4515 } 4516 4517 retry = DOWNLOAD_RETRIES; 4518 while (retry) { 4519 if ((status = g_scsi_tur(controller_fd)) == 0) { 4520 break; 4521 } else { 4522 if ((retry % 30) == 0) { 4523 ER_DPRINTF(" Waiting for the IB to be" 4524 " available.\n"); 4525 } 4526 (void) sleep(1); 4527 } 4528 retry--; 4529 } 4530 if (!retry) { 4531 (void) close(controller_fd); 4532 (void) g_destroy_data((char *)buf_ptr); 4533 return (L_DWNLD_TIMED_OUT); 4534 } 4535 4536 switch (enc_type) { 4537 case DAK_ENC_TYPE: 4538 break; 4539 default: 4540 if (verbose) { 4541 (void) fprintf(stdout, "%s\n", 4542 MSGSTR(9057, " Writing new image to FPM.")); 4543 } 4544 status = ib_download_code_cmd(controller_fd, MBEEPROM, FPM_OFFSET, 4545 (uchar_t *)(buf_ptr + FPM_OFFSET), FPM_SZ, ps); 4546 break; 4547 } 4548 4549 if ((!status) && ps) { 4550 /* 4551 * Reset the IB 4552 */ 4553 status = g_scsi_reset(controller_fd); 4554 } 4555 4556 (void) close(controller_fd); 4557 return (status); 4558 } 4559 4560 /* 4561 * Set the World Wide Name 4562 * in page 4 of the Send Diagnostic command. 4563 * 4564 * Is it allowed to change the wwn ??? 4565 * The path must point to an IB. 4566 * 4567 */ 4568 int 4569 l_set_wwn(char *path_phys, char *wwn) 4570 { 4571 Page4_name page4; 4572 L_inquiry inq; 4573 int fd, status; 4574 char wwnp[WWN_SIZE]; 4575 4576 (void) memset(&inq, 0, sizeof (inq)); 4577 (void) memset(&page4, 0, sizeof (page4)); 4578 4579 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) { 4580 return (L_OPEN_PATH_FAIL); 4581 } 4582 /* Verify it is a Photon */ 4583 if (status = g_scsi_inquiry_cmd(fd, 4584 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 4585 (void) close(fd); 4586 return (status); 4587 } 4588 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 4589 (!(strncmp((char *)inq.inq_vid, "SUN ", 4590 sizeof (inq.inq_vid)) && 4591 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 4592 (void) close(fd); 4593 return (L_ENCL_INVALID_PATH); 4594 } 4595 4596 page4.page_code = L_PAGE_4; 4597 page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4)); 4598 page4.string_code = L_WWN; 4599 page4.enable = 1; 4600 if (g_string_to_wwn((uchar_t *)wwn, (uchar_t *)&page4.name)) { 4601 close(fd); 4602 return (EINVAL); 4603 } 4604 bcopy((void *)wwnp, (void *)page4.name, (size_t)WWN_SIZE); 4605 4606 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4, 4607 sizeof (page4))) { 4608 (void) close(fd); 4609 return (status); 4610 } 4611 4612 /* 4613 * Check the wwn really changed. 4614 */ 4615 bzero((char *)page4.name, 32); 4616 if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&page4, 4617 sizeof (page4), L_PAGE_4)) { 4618 (void) close(fd); 4619 return (status); 4620 } 4621 if (bcmp((char *)page4.name, wwnp, WWN_SIZE)) { 4622 (void) close(fd); 4623 return (L_WARNING); 4624 } 4625 4626 (void) close(fd); 4627 return (0); 4628 } 4629 4630 4631 4632 /* 4633 * Use a physical path to a disk in a Photon box 4634 * as the base to genererate a path to a SES 4635 * card in this box. 4636 * 4637 * path_phys: Physical path to a Photon disk. 4638 * ses_path: This must be a pointer to an already allocated path string. 4639 * 4640 * RETURNS: 4641 * 0 O.K. 4642 * non-zero otherwise 4643 */ 4644 int 4645 l_get_ses_path(char *path_phys, char *ses_path, gfc_map_t *map, 4646 int verbose) 4647 { 4648 char *char_ptr, id_buf[MAXPATHLEN], wwn[20]; 4649 uchar_t t_wwn[20], *ses_wwn, *ses_wwn1, *ses_nwwn; 4650 int j, al_pa, al_pa1, box_id, fd, disk_flag = 0; 4651 int err, found = 0; 4652 gfc_port_dev_info_t *dev_addr_ptr; 4653 4654 if ((path_phys == NULL) || (ses_path == NULL) || (map == NULL)) { 4655 return (L_NO_SES_PATH); 4656 } 4657 4658 (void) strcpy(ses_path, path_phys); 4659 if ((char_ptr = strrchr(ses_path, '/')) == NULL) { 4660 return (L_INVLD_PATH_NO_SLASH_FND); 4661 } 4662 disk_flag++; 4663 *char_ptr = '\0'; /* Terminate sting */ 4664 (void) strcat(ses_path, SLSH_SES_NAME); 4665 4666 /* 4667 * Figure out and create the boxes pathname. 4668 * 4669 * NOTE: This uses the fact that the disks's 4670 * AL_PA and the boxes AL_PA must match 4671 * the assigned hard address in the current 4672 * implementations. This may not be true in the 4673 * future. 4674 */ 4675 if ((char_ptr = strrchr(path_phys, '@')) == NULL) { 4676 return (L_INVLD_PATH_NO_ATSIGN_FND); 4677 } 4678 char_ptr++; /* point to the loop identifier */ 4679 4680 if ((err = g_get_wwn(path_phys, t_wwn, t_wwn, 4681 &al_pa, verbose)) != 0) { 4682 return (err); 4683 } 4684 box_id = g_sf_alpa_to_switch[al_pa & 0xFF] & BOX_ID_MASK; 4685 4686 switch (map->hba_addr.port_topology) { 4687 case FC_TOP_PRIVATE_LOOP: 4688 for (j = 0, dev_addr_ptr = map->dev_addr; 4689 j < map->count; j++, dev_addr_ptr++) { 4690 if (dev_addr_ptr->gfc_port_dev.priv_port. 4691 sf_inq_dtype == DTYPE_ESI) { 4692 al_pa1 = dev_addr_ptr->gfc_port_dev. 4693 priv_port.sf_al_pa; 4694 if (box_id == (g_sf_alpa_to_switch[al_pa1] & 4695 BOX_ID_MASK)) { 4696 if (!found) { 4697 ses_wwn = dev_addr_ptr-> 4698 gfc_port_dev.priv_port.sf_port_wwn; 4699 ses_nwwn = dev_addr_ptr-> 4700 gfc_port_dev.priv_port.sf_node_wwn; 4701 if (getenv("_LUX_P_DEBUG")) { 4702 (void) g_ll_to_str(ses_wwn, 4703 (char *)t_wwn); 4704 (void) printf( 4705 " l_get_ses_path: " 4706 "Found ses wwn = %s " 4707 "al_pa 0x%x\n", t_wwn, al_pa1); 4708 } 4709 } else { 4710 ses_wwn1 = dev_addr_ptr-> 4711 gfc_port_dev.priv_port.sf_port_wwn; 4712 if (getenv("_LUX_P_DEBUG")) { 4713 (void) g_ll_to_str(ses_wwn1, 4714 (char *)t_wwn); 4715 (void) printf( 4716 " l_get_ses_path: " 4717 "Found second ses " "wwn = %s " 4718 "al_pa 0x%x\n", t_wwn, al_pa1); 4719 } 4720 } 4721 found++; 4722 } 4723 } 4724 } 4725 break; 4726 case FC_TOP_FABRIC: 4727 case FC_TOP_PUBLIC_LOOP: 4728 for (j = 0, dev_addr_ptr = map->dev_addr; 4729 j < map->count; j++, dev_addr_ptr++) { 4730 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype == 4731 DTYPE_ESI) { 4732 /* 4733 * We found an enclosure, lets match the 4734 * area and domain codes for this enclosure with 4735 * that of the ses path since there may be 4736 * multiple enclosures with same box id on a 4737 * fabric 4738 */ 4739 al_pa1 = dev_addr_ptr->gfc_port_dev. 4740 pub_port.dev_did.port_id; 4741 if ((al_pa & AREA_DOMAIN_ID) == 4742 (al_pa1 & AREA_DOMAIN_ID)) { 4743 /* 4744 * The area and domain matched. Now, we 4745 * match the box id of the disk with 4746 * this enclosure 4747 */ 4748 if (box_id == 4749 (g_sf_alpa_to_switch[al_pa1 & 4750 0xFF] & BOX_ID_MASK)) { 4751 if (!found) { 4752 ses_wwn = dev_addr_ptr-> 4753 gfc_port_dev.pub_port. 4754 dev_pwwn.raw_wwn; 4755 ses_nwwn = dev_addr_ptr-> 4756 gfc_port_dev.pub_port. 4757 dev_nwwn.raw_wwn; 4758 if (getenv("_LUX_P_DEBUG")) { 4759 (void) g_ll_to_str(ses_wwn, 4760 (char *)t_wwn); 4761 (void) printf( 4762 " l_get_ses_path: " 4763 "Found ses wwn = %s " 4764 "al_pa 0x%x\n", t_wwn, 4765 al_pa1); 4766 } 4767 } else { 4768 ses_wwn1 = dev_addr_ptr-> 4769 gfc_port_dev.pub_port. 4770 dev_pwwn.raw_wwn; 4771 if (getenv("_LUX_P_DEBUG")) { 4772 (void) g_ll_to_str(ses_wwn1, 4773 (char *)t_wwn); 4774 (void) printf( 4775 " l_get_ses_path: " 4776 "Found second ses " 4777 "wwn = %s " 4778 "al_pa 0x%x\n", t_wwn, 4779 al_pa1); 4780 } 4781 } 4782 found++; 4783 } 4784 } 4785 } 4786 } 4787 break; 4788 case FC_TOP_PT_PT: 4789 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 4790 default: 4791 return (L_UNEXPECTED_FC_TOPOLOGY); 4792 } /* End of switch on port_topology */ 4793 4794 if (!found) { 4795 return (L_NO_SES_PATH); 4796 } 4797 4798 if (strstr(path_phys, SCSI_VHCI) != NULL) { 4799 (void) g_ll_to_str(ses_nwwn, wwn); 4800 (void) sprintf(id_buf, "g%s:0", wwn); 4801 } else { 4802 (void) g_ll_to_str(ses_wwn, wwn); 4803 (void) sprintf(id_buf, "w%s,0:0", wwn); 4804 } 4805 (void) strcat(ses_path, id_buf); 4806 if (verbose) { 4807 (void) fprintf(stdout, 4808 MSGSTR(9058, " Creating enclosure path:\n %s\n"), 4809 ses_path); 4810 } 4811 4812 /* 4813 * see if these paths exist. 4814 */ 4815 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDONLY)) == -1) { 4816 4817 if (strstr(path_phys, SCSI_VHCI) != NULL) { 4818 return (L_INVALID_PATH); 4819 } 4820 4821 char_ptr = strrchr(ses_path, '/'); 4822 *char_ptr = '\0'; 4823 (void) strcat(ses_path, SLSH_SES_NAME); 4824 if (found > 1) { 4825 (void) g_ll_to_str(ses_wwn1, wwn); 4826 P_DPRINTF(" l_get_ses_path: " 4827 "Using second path, ses wwn1 = %s\n", 4828 wwn); 4829 (void) sprintf(id_buf, "w%s,0:0", wwn); 4830 strcat(ses_path, id_buf); 4831 return (0); 4832 } else { 4833 return (L_NO_SES_PATH); 4834 } 4835 } 4836 close(fd); 4837 return (0); 4838 } 4839 4840 4841 4842 /* 4843 * Get a valid location, front/rear & slot. 4844 * 4845 * path_struct->p_physical_path must be of a disk. 4846 * 4847 * OUTPUT: path_struct->slot_valid 4848 * path_struct->slot 4849 * path_struct->f_flag 4850 * 4851 * RETURN: 4852 * 0 O.K. 4853 * non-zero otherwise 4854 */ 4855 int 4856 l_get_slot(struct path_struct *path_struct, L_state *l_state, int verbose) 4857 { 4858 int err, al_pa, slot, found = 0; 4859 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 4860 uint_t select_id; 4861 4862 if ((path_struct == NULL) || (l_state == NULL)) { 4863 return (L_INVALID_PATH_FORMAT); 4864 } 4865 4866 /* Double check to see if we need to calculate. */ 4867 if (path_struct->slot_valid) 4868 return (0); 4869 4870 /* Programming error if this occures */ 4871 assert(path_struct->ib_path_flag == 0); 4872 4873 if (strstr(path_struct->p_physical_path, "ssd") == NULL) { 4874 return (L_INVLD_PHYS_PATH_TO_DISK); 4875 } 4876 if (err = g_get_wwn(path_struct->p_physical_path, port_wwn, node_wwn, 4877 &al_pa, verbose)) { 4878 return (err); 4879 } 4880 4881 /* 4882 * Find the slot by searching for the matching hard address. 4883 * Take only the low order byte ignoring area and domain code in 4884 * fabric devices' 24 bit al_pa 4885 */ 4886 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 4887 P_DPRINTF(" l_get_slot: Searching Receive Diagnostic page 2, " 4888 "to find the slot number with this ID:0x%x\n", 4889 select_id); 4890 4891 for (slot = 0; slot < l_state->total_num_drv/2; slot++) { 4892 if (l_state->drv_front[slot].ib_status.sel_id == 4893 select_id) { 4894 path_struct->f_flag = 1; 4895 found = 1; 4896 break; 4897 } else if (l_state->drv_rear[slot].ib_status.sel_id == 4898 select_id) { 4899 path_struct->f_flag = 0; 4900 found = 1; 4901 break; 4902 } 4903 } 4904 if (!found) { 4905 return (L_INVALID_SLOT); /* Failure */ 4906 } 4907 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 4908 strlen(DAK_OFF_NAME)) == 0) || 4909 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 4910 strlen(DAK_OFF_NAME)) == 0)) { 4911 P_DPRINTF(" l_get_slot: Found slot %d.\n", 4912 path_struct->f_flag ? slot : slot + (MAX_DRIVES_DAK/2)); 4913 } else { 4914 P_DPRINTF(" l_get_slot: Found slot %d %s.\n", slot, 4915 path_struct->f_flag ? "Front" : "Rear"); 4916 } 4917 path_struct->slot = slot; 4918 path_struct->slot_valid = 1; 4919 return (0); 4920 } 4921 4922 4923 void 4924 l_element_msg_string(uchar_t code, char *es) 4925 { 4926 if (code == S_OK) { 4927 (void) sprintf(es, MSGSTR(29, "O.K.")); 4928 } else if (code == S_NOT_AVAILABLE) { 4929 (void) sprintf(es, MSGSTR(34, "Disabled")); 4930 } else if (code == S_NOT_INSTALLED) { 4931 (void) sprintf(es, MSGSTR(30, "Not Installed")); 4932 } else if (code == S_NONCRITICAL) { 4933 (void) sprintf(es, MSGSTR(9059, "Noncritical failure")); 4934 } else if (code == S_CRITICAL) { 4935 (void) sprintf(es, MSGSTR(122, "Critical failure")); 4936 } else { 4937 (void) sprintf(es, MSGSTR(4, "Unknown status")); 4938 } 4939 } 4940 4941 4942 /* 4943 * Get all ses paths paths to a given box. 4944 * The arg should be the physical path to one of the box's IB. 4945 * NOTE: The caller must free the allocated lists. 4946 * 4947 * OUTPUT: 4948 * a pointer to a list of ses paths if found 4949 * NULL on error. 4950 * 4951 * RETURNS: 4952 * 0 if O.K. 4953 * non-zero otherwise 4954 */ 4955 int 4956 l_get_allses(char *path, struct box_list_struct *box_list, 4957 struct dlist **ses_list, int verbose) 4958 { 4959 struct box_list_struct *box_list_ptr; 4960 char node_wwn_s[WWN_S_LEN]; 4961 struct dlist *dlt, *dl; 4962 4963 if ((path == NULL) || (box_list == NULL) || (ses_list == NULL)) { 4964 return (L_INVALID_PATH_FORMAT); 4965 } 4966 4967 /* Initialize lists/arrays */ 4968 *ses_list = dlt = dl = (struct dlist *)NULL; 4969 node_wwn_s[0] = '\0'; 4970 4971 H_DPRINTF(" l_get_allses: Looking for all ses paths for" 4972 " box at path: %s\n", path); 4973 4974 for (box_list_ptr = box_list; box_list_ptr != NULL; 4975 box_list_ptr = box_list_ptr->box_next) { 4976 H_DPRINTF(" l_get_allses: physical_path= %s\n", 4977 box_list_ptr->b_physical_path); 4978 if (strcmp(path, box_list_ptr->b_physical_path) == 0) { 4979 (void) strcpy(node_wwn_s, box_list_ptr->b_node_wwn_s); 4980 break; 4981 } 4982 } 4983 if (node_wwn_s[0] == '\0') { 4984 H_DPRINTF("node_wwn_s is NULL!\n"); 4985 return (L_NO_NODE_WWN_IN_BOXLIST); 4986 } 4987 H_DPRINTF(" l_get_allses: node_wwn=%s\n", node_wwn_s); 4988 for (box_list_ptr = box_list; box_list_ptr != NULL; 4989 box_list_ptr = box_list_ptr->box_next) { 4990 if (strcmp(node_wwn_s, box_list_ptr->b_node_wwn_s) == 0) { 4991 if ((dl = (struct dlist *) 4992 g_zalloc(sizeof (struct dlist))) == NULL) { 4993 while (*ses_list != NULL) { 4994 dl = dlt->next; 4995 (void) g_destroy_data(dlt); 4996 dlt = dl; 4997 } 4998 return (L_MALLOC_FAILED); 4999 } 5000 H_DPRINTF(" l_get_allses: Found ses=%s\n", 5001 box_list_ptr->b_physical_path); 5002 dl->dev_path = strdup(box_list_ptr->b_physical_path); 5003 dl->logical_path = strdup(box_list_ptr->logical_path); 5004 if (*ses_list == NULL) { 5005 *ses_list = dlt = dl; 5006 } else { 5007 dlt->next = dl; 5008 dl->prev = dlt; 5009 dlt = dl; 5010 } 5011 } 5012 } 5013 5014 return (0); 5015 } 5016 5017 /* 5018 * Routine to return the enclosure type pointed to by the path. 5019 * Inputs: The inquiry data for the device in question 5020 * 5021 * Return: >= 0 is the type: 5022 * 5023 * Types are defined in storage/libg_fc/common/hdrs/g_state.h: 5024 * 5025 * 0 -> default (SENA) 5026 * 1 -> Daktari 5027 * 2 -> Other Enclosures 5028 * 5029 */ 5030 int 5031 l_get_enc_type(L_inquiry inq) 5032 { 5033 if (strncmp((char *)&inq.inq_pid[0], ENCLOSURE_PROD_ID, 5034 strlen(ENCLOSURE_PROD_ID)) == 0) { 5035 return (SENA_ENC_TYPE); 5036 } 5037 if (strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME, 5038 strlen(DAK_OFF_NAME)) == 0) { 5039 return (DAK_ENC_TYPE); 5040 } 5041 if (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR, 5042 strlen(DAK_PROD_STR)) == 0) { 5043 return (DAK_ENC_TYPE); 5044 } 5045 /* 5046 * ADD OTHERS here if ever needed/wanted, and add to def's 5047 * as noted above 5048 */ 5049 return (UNDEF_ENC_TYPE); 5050 } 5051 5052 void 5053 free_mp_dev_map(gfc_map_mp_t **map_mp_ptr) { 5054 gfc_map_mp_t *next = NULL; 5055 5056 for (; *map_mp_ptr != NULL; *map_mp_ptr = next) { 5057 next = (*map_mp_ptr)->map_next; 5058 (void) g_destroy_data((*map_mp_ptr)->map.dev_addr); 5059 (void) g_destroy_data(*map_mp_ptr); 5060 } 5061 *map_mp_ptr = NULL; 5062 } 5063 /* 5064 * This function will return a linked list of device maps 5065 * An example of when this will be used is when we want to return the device 5066 * map of a vhci path. 5067 */ 5068 5069 int 5070 get_mp_dev_map(char *path, gfc_map_mp_t **map_mp_ptr, int verbose) { 5071 5072 int pathcnt, i, err; 5073 mp_pathlist_t pathlist; 5074 gfc_map_mp_t *new_map_mp_ptr; 5075 char drvr_path[MAXPATHLEN]; 5076 if (strstr(path, SCSI_VHCI)) { 5077 if (g_get_pathlist(path, &pathlist)) { 5078 return (L_INVALID_PATH); 5079 } 5080 pathcnt = pathlist.path_count; 5081 for (i = 0; i < pathcnt; i++) { 5082 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 5083 /* 5084 * only pay attention to paths that are either 5085 * ONLINE or STANDBY 5086 */ 5087 if ((pathlist.path_info[i].path_state == 5088 MDI_PATHINFO_STATE_ONLINE) || 5089 (pathlist.path_info[i].path_state == 5090 MDI_PATHINFO_STATE_STANDBY)) { 5091 if ((new_map_mp_ptr = (gfc_map_mp_t *) 5092 g_zalloc(sizeof (gfc_map_mp_t))) 5093 == NULL) { 5094 free(pathlist.path_info); 5095 free_mp_dev_map(map_mp_ptr); 5096 return (L_MALLOC_FAILED); 5097 } 5098 (void) strcpy(drvr_path, 5099 pathlist.path_info[i].path_hba); 5100 (void) strcat(drvr_path, FC_CTLR); 5101 if (err = g_get_dev_map(drvr_path, 5102 &(new_map_mp_ptr->map), 5103 verbose)) { 5104 free(pathlist.path_info); 5105 free_mp_dev_map(map_mp_ptr); 5106 return (err); 5107 } 5108 /* add newly created map onto list */ 5109 if (*map_mp_ptr == NULL) { 5110 new_map_mp_ptr->map_next = NULL; 5111 *map_mp_ptr = new_map_mp_ptr; 5112 } else { 5113 new_map_mp_ptr->map_next = 5114 *map_mp_ptr; 5115 *map_mp_ptr = new_map_mp_ptr; 5116 } 5117 } 5118 } 5119 } 5120 free(pathlist.path_info); 5121 } else { 5122 if ((new_map_mp_ptr = (gfc_map_mp_t *)g_zalloc 5123 (sizeof (gfc_map_mp_t))) == NULL) { 5124 return (L_MALLOC_FAILED); 5125 } 5126 g_get_dev_map(path, &(new_map_mp_ptr->map), verbose); 5127 *map_mp_ptr = new_map_mp_ptr; 5128 } 5129 return (0); 5130 } 5131