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, int verbose) 523 { 524 gfc_map_t map; 525 char ses_path[MAXPATHLEN]; 526 uchar_t *page_buf; 527 int err, write, fd, front_index, rear_index, offset; 528 unsigned short page_len; 529 struct device_element *elem; 530 L_state *l_state; 531 int enc_type; 532 533 if ((path_struct == NULL) || (status == NULL)) { 534 return (L_INVALID_PATH_FORMAT); 535 } 536 537 /* 538 * Need to get a valid location, front/rear & slot. 539 * 540 * The path_struct will return a valid slot 541 * and the IB path or a disk path. 542 */ 543 544 map.dev_addr = (gfc_port_dev_info_t *)NULL; 545 if (!path_struct->ib_path_flag) { 546 if ((err = g_get_dev_map(path_struct->p_physical_path, 547 &map, verbose)) != 0) 548 return (err); 549 if ((err = l_get_ses_path(path_struct->p_physical_path, 550 ses_path, &map, verbose)) != 0) { 551 free((void *)map.dev_addr); 552 return (err); 553 } 554 } else { 555 (void) strcpy(ses_path, path_struct->p_physical_path); 556 } 557 558 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 559 free((void *)map.dev_addr); 560 return (L_MALLOC_FAILED); 561 } 562 563 if (!path_struct->slot_valid) { 564 if ((map.dev_addr != NULL) && 565 (err = g_get_dev_map(path_struct->p_physical_path, 566 &map, verbose)) != 0) { 567 (void) l_free_lstate(&l_state); 568 return (err); 569 } 570 if ((err = l_get_ses_path(path_struct->p_physical_path, 571 ses_path, &map, verbose)) != 0) { 572 (void) l_free_lstate(&l_state); 573 free((void *)map.dev_addr); 574 return (err); 575 } 576 if ((err = l_get_status(ses_path, l_state, verbose)) != 0) { 577 (void) l_free_lstate(&l_state); 578 free((void *)map.dev_addr); 579 return (err); 580 } 581 582 /* We are passing the disks path */ 583 if (err = l_get_slot(path_struct, l_state, verbose)) { 584 (void) l_free_lstate(&l_state); 585 free((void *)map.dev_addr); 586 return (err); 587 } 588 } 589 if (map.dev_addr != NULL) 590 free((void *)map.dev_addr); /* Not used anymore */ 591 592 if ((page_buf = (uchar_t *)calloc(1, 593 MAX_REC_DIAG_LENGTH)) == NULL) { 594 (void) l_free_lstate(&l_state); 595 return (L_MALLOC_FAILED); 596 } 597 598 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 599 (void) l_free_lstate(&l_state); 600 (void) g_destroy_data(page_buf); 601 return (L_OPEN_PATH_FAIL); 602 } 603 604 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 605 L_PAGE_2, verbose)) { 606 (void) l_free_lstate(&l_state); 607 (void) close(fd); 608 (void) g_destroy_data(page_buf); 609 return (err); 610 } 611 612 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 613 614 /* Get index to the disk we are interested in */ 615 if (err = l_get_status(ses_path, l_state, verbose)) { 616 (void) l_free_lstate(&l_state); 617 (void) close(fd); 618 (void) g_destroy_data(page_buf); 619 return (err); 620 } 621 622 /* find enclosure type */ 623 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 624 strlen(DAK_OFF_NAME)) == 0) || 625 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 626 strlen(DAK_PROD_STR)) == 0)) { 627 enc_type = DAK_ENC_TYPE; 628 } else { 629 enc_type = SENA_ENC_TYPE; 630 } 631 632 /* Double check slot. */ 633 if (path_struct->slot >= l_state->total_num_drv/2) { 634 (void) l_free_lstate(&l_state); 635 return (L_INVALID_SLOT); 636 } 637 638 if (err = l_get_disk_element_index(l_state, &front_index, 639 &rear_index)) { 640 (void) l_free_lstate(&l_state); 641 return (err); 642 } 643 644 /* Skip global element */ 645 front_index++; 646 if (enc_type == DAK_ENC_TYPE) { 647 rear_index += l_state->total_num_drv/2 + 1; 648 } else { 649 rear_index++; 650 } 651 652 if (path_struct->f_flag) { 653 offset = (8 + (front_index + path_struct->slot)*4); 654 } else { 655 offset = (8 + (rear_index + path_struct->slot)*4); 656 } 657 658 elem = (struct device_element *)(page_buf + offset); 659 /* 660 * now do requested action. 661 */ 662 bcopy((const void *)elem, (void *)status, 663 sizeof (struct device_element)); /* save status */ 664 bzero(elem, sizeof (struct device_element)); 665 elem->select = 1; 666 elem->dev_off = status->dev_off; 667 elem->en_bypass_a = status->en_bypass_a; 668 elem->en_bypass_b = status->en_bypass_b; 669 write = 1; 670 671 switch (led_action) { 672 case L_LED_STATUS: 673 write = 0; 674 break; 675 case L_LED_RQST_IDENTIFY: 676 elem->ident = 1; 677 if (verbose) { 678 if (enc_type == DAK_ENC_TYPE) { 679 (void) fprintf(stdout, 680 MSGSTR(9043, " Blinking LED for slot %d in enclosure" 681 " %s\n"), path_struct->f_flag ? path_struct->slot : 682 path_struct->slot + (MAX_DRIVES_DAK/2), 683 l_state->ib_tbl.enclosure_name); 684 } else { 685 (void) fprintf(stdout, 686 MSGSTR(9043, " Blinking LED for slot %d in enclosure" 687 " %s\n"), path_struct->slot, 688 l_state->ib_tbl.enclosure_name); 689 } 690 } 691 break; 692 case L_LED_OFF: 693 if (verbose) { 694 if (enc_type == DAK_ENC_TYPE) { 695 (void) fprintf(stdout, 696 MSGSTR(9044, 697 " Turning off LED for slot %d in enclosure" 698 " %s\n"), path_struct->f_flag ? path_struct->slot 699 : path_struct->slot + (MAX_DRIVES_DAK/2), 700 l_state->ib_tbl.enclosure_name); 701 } else { 702 (void) fprintf(stdout, 703 MSGSTR(9044, 704 " Turning off LED for slot %d in enclosure" 705 " %s\n"), path_struct->slot, 706 l_state->ib_tbl.enclosure_name); 707 } 708 } 709 break; 710 default: 711 (void) l_free_lstate(&l_state); 712 return (L_INVALID_LED_RQST); 713 } /* End of switch */ 714 715 if (write) { 716 if (getenv("_LUX_D_DEBUG") != NULL) { 717 g_dump(" l_led: Updating led state: " 718 "Device Status Element ", 719 (uchar_t *)elem, sizeof (struct device_element), 720 HEX_ONLY); 721 } 722 if (err = g_scsi_send_diag_cmd(fd, 723 (uchar_t *)page_buf, page_len)) { 724 (void) close(fd); 725 (void) g_destroy_data(page_buf); 726 (void) l_free_lstate(&l_state); 727 return (err); 728 } 729 730 bzero(page_buf, MAX_REC_DIAG_LENGTH); 731 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 732 L_PAGE_2, verbose)) { 733 (void) g_destroy_data(page_buf); 734 (void) close(fd); 735 (void) l_free_lstate(&l_state); 736 return (err); 737 } 738 elem = (struct device_element *)(page_buf + offset); 739 bcopy((const void *)elem, (void *)status, 740 sizeof (struct device_element)); 741 } 742 if (getenv("_LUX_D_DEBUG") != NULL) { 743 g_dump(" l_led: Device Status Element ", 744 (uchar_t *)status, sizeof (struct device_element), 745 HEX_ONLY); 746 } 747 748 (void) l_free_lstate(&l_state); 749 (void) close(fd); 750 (void) g_destroy_data(page_buf); 751 return (0); 752 } 753 754 755 /* 756 * frees the previously alloced l_state 757 * structure. 758 * 759 * RETURNS: 760 * 0 O.K. 761 * non-zero otherwise 762 */ 763 int 764 l_free_lstate(L_state **l_state) 765 { 766 int i; 767 768 if ((l_state == NULL) || (*l_state == NULL)) 769 return (0); 770 771 for (i = 0; i < (int)(*l_state)->total_num_drv/2; i++) { 772 if ((*l_state)->drv_front[i].g_disk_state.multipath_list != NULL) 773 (void) g_free_multipath( 774 (*l_state)->drv_front[i].g_disk_state.multipath_list); 775 if ((*l_state)->drv_rear[i].g_disk_state.multipath_list != NULL) 776 (void) g_free_multipath( 777 (*l_state)->drv_rear[i].g_disk_state.multipath_list); 778 } 779 (void) g_destroy_data (*l_state); 780 l_state = NULL; 781 782 return (0); 783 } 784 785 786 787 /* 788 * Set the state of an individual disk 789 * in the Photon enclosure the powered 790 * up/down mode. The path must point to 791 * a disk or the ib_path_flag must be set. 792 * 793 * RETURNS: 794 * 0 O.K. 795 * non-zero otherwise 796 */ 797 int 798 l_dev_pwr_up_down(char *path_phys, struct path_struct *path_struct, 799 int power_off_flag, int verbose, int force_flag) 800 /*ARGSUSED*/ 801 { 802 gfc_map_t map; 803 char ses_path[MAXPATHLEN], dev_path[MAXPATHLEN]; 804 int slot, err = 0; 805 L_state *l_state = NULL; 806 struct l_disk_state_struct *drive; 807 struct dlist *dl, *dl1; 808 devctl_hdl_t devhdl; 809 WWN_list *wwn_list = NULL; 810 L_inquiry inq; 811 812 if (path_struct == NULL) { 813 return (L_INVALID_PATH_FORMAT); 814 } 815 816 dl = (struct dlist *)NULL; 817 map.dev_addr = (gfc_port_dev_info_t *)NULL; 818 819 if (err = g_get_dev_map(path_struct->p_physical_path, 820 &map, verbose)) 821 return (err); 822 823 if (err = l_get_ses_path(path_struct->p_physical_path, 824 ses_path, &map, verbose)) { 825 free((void *)map.dev_addr); 826 return (err); 827 } 828 free((void *)map.dev_addr); /* Not used anymore */ 829 830 /* 831 * Check to see if we have a photon, and if not, don't allow 832 * this operation 833 */ 834 if (err = g_get_inquiry(ses_path, &inq)) { 835 return (err); 836 } 837 if (l_get_enc_type(inq) != SENA_ENC_TYPE) { 838 return (L_ENCL_INVALID_PATH); 839 } 840 /* 841 * OK, so we have a photon... we can continue 842 */ 843 844 845 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 846 return (L_MALLOC_FAILED); 847 } 848 849 if (err = l_get_status(ses_path, l_state, verbose)) { 850 (void) l_free_lstate(&l_state); 851 return (err); 852 } 853 854 if (!path_struct->slot_valid) { 855 /* We are passing the disks path */ 856 if (err = l_get_slot(path_struct, l_state, verbose)) { 857 (void) l_free_lstate(&l_state); 858 return (err); 859 } 860 } 861 862 slot = path_struct->slot; 863 (void) strcpy(dev_path, path_struct->p_physical_path); 864 865 /* 866 * Either front or rear drive 867 */ 868 if (path_struct->f_flag) { 869 drive = &l_state->drv_front[slot]; 870 } else { 871 drive = &l_state->drv_rear[slot]; 872 } 873 874 /* 875 * Check for drive presence always 876 */ 877 if (drive->ib_status.code == S_NOT_INSTALLED) { 878 (void) l_free_lstate(&l_state); 879 return (L_SLOT_EMPTY); 880 } 881 882 /* 883 * Check disk state 884 * before the power off. 885 * 886 */ 887 if (power_off_flag && !force_flag) { 888 goto pre_pwr_dwn; 889 } else { 890 goto pwr_up_dwn; 891 } 892 893 pre_pwr_dwn: 894 895 /* 896 * Check whether disk 897 * is reserved by another 898 * host 899 */ 900 if ((drive->g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || 901 (drive->g_disk_state.d_state_flags[PORT_B] & 902 L_RESERVED)) { 903 (void) l_free_lstate(&l_state); 904 return (L_DEVICE_RESERVED); 905 } 906 907 908 if ((dl = (struct dlist *)g_zalloc(sizeof (struct dlist))) == NULL) { 909 (void) l_free_lstate(&l_state); 910 return (L_MALLOC_FAILED); 911 } 912 913 /* 914 * NOTE: It is not necessary to get the multipath list here as ------ 915 * we alread have it after getting the status earlier. 916 * - REWRITE - 917 */ 918 919 /* 920 * Get path to all the FC disk and tape devices. 921 * 922 * I get this now and pass down for performance 923 * reasons. 924 * If for some reason the list can become invalid, 925 * i.e. device being offlined, then the list 926 * must be re-gotten. 927 */ 928 if (err = g_get_wwn_list(&wwn_list, verbose)) { 929 (void) g_destroy_data(dl); 930 (void) l_free_lstate(&l_state); 931 return (err); /* Failure */ 932 } 933 934 dl->dev_path = dev_path; 935 if ((err = g_get_multipath(dev_path, 936 &(dl->multipath), wwn_list, verbose)) != 0) { 937 (void) g_destroy_data(dl); 938 (void) g_free_wwn_list(&wwn_list); 939 (void) l_free_lstate(&l_state); 940 return (err); 941 } 942 943 for (dl1 = dl->multipath; dl1 != NULL; dl1 = dl1->next) { 944 if ((devhdl = devctl_device_acquire(dl1->dev_path, 945 DC_EXCL)) == NULL) { 946 if (errno != EBUSY) { 947 ER_DPRINTF("%s could not acquire" 948 " the device: %s\n\n", 949 strerror(errno), dl1->dev_path); 950 continue; 951 } 952 } 953 if (devctl_device_offline(devhdl) != 0) { 954 (void) devctl_release(devhdl); 955 (void) g_free_multipath(dl->multipath); 956 (void) g_destroy_data(dl); 957 (void) g_free_wwn_list(&wwn_list); 958 (void) l_free_lstate(&l_state); 959 return (L_POWER_OFF_FAIL_BUSY); 960 } 961 (void) devctl_release(devhdl); 962 } 963 964 pwr_up_dwn: 965 err = pwr_up_down(ses_path, l_state, path_struct->f_flag, 966 path_struct->slot, power_off_flag, verbose); 967 968 if (dl != NULL) { 969 (void) g_free_multipath(dl->multipath); 970 (void) g_destroy_data(dl); 971 } 972 (void) g_free_wwn_list(&wwn_list); 973 (void) l_free_lstate(&l_state); 974 if (err) { 975 return (err); 976 } 977 return (0); 978 } 979 980 981 982 /* 983 * l_pho_pwr_up_down() Set the state of the Photon enclosure 984 * the powered up/down mode. 985 * The path must point to an IB. 986 * 987 * RETURNS: 988 * 0 O.K. 989 * non-zero otherwise 990 */ 991 int 992 l_pho_pwr_up_down(char *dev_name, char *path_phys, int power_off_flag, 993 int verbose, int force_flag) 994 { 995 L_state *l_state = NULL; 996 int i, err = 0; 997 struct dlist *dl, *dl1; 998 char dev_path[MAXPATHLEN]; 999 devctl_hdl_t devhdl; 1000 WWN_list *wwn_list = NULL; 1001 1002 if (path_phys == NULL) { 1003 return (L_INVALID_PATH_FORMAT); 1004 } 1005 1006 dl = (struct dlist *)NULL; 1007 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 1008 return (L_MALLOC_FAILED); 1009 } 1010 if (err = l_get_status(path_phys, l_state, verbose)) { 1011 (void) l_free_lstate(&l_state); 1012 return (err); 1013 } 1014 if (power_off_flag && !force_flag) { 1015 goto pre_pwr_dwn; 1016 } else { 1017 goto pwr_up_dwn; 1018 } 1019 1020 pre_pwr_dwn: 1021 1022 /* 1023 * Check if any disk in this enclosure 1024 * is reserved by another host before 1025 * the power off. 1026 */ 1027 for (i = 0; i < l_state->total_num_drv/2; i++) { 1028 if ((l_state->drv_front[i].g_disk_state.d_state_flags[PORT_A] & 1029 L_RESERVED) || 1030 (l_state->drv_front[i].g_disk_state.d_state_flags[PORT_B] & 1031 L_RESERVED) || 1032 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_A] & 1033 L_RESERVED) || 1034 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_B] & 1035 L_RESERVED)) { 1036 return (L_DISKS_RESERVED); 1037 } 1038 } 1039 1040 /* 1041 * Check if any disk in this enclosure 1042 * Get path to all the FC disk and tape devices. 1043 * 1044 * I get this now and pass down for performance 1045 * reasons. 1046 * If for some reason the list can become invalid, 1047 * i.e. device being offlined, then the list 1048 * must be re-gotten. 1049 */ 1050 if (err = g_get_wwn_list(&wwn_list, verbose)) { 1051 (void) l_free_lstate(&l_state); 1052 return (err); /* Failure */ 1053 } 1054 for (i = 0; i < l_state->total_num_drv/2; i++) { 1055 if (*l_state->drv_front[i].g_disk_state.physical_path) { 1056 (void) memset(dev_path, 0, MAXPATHLEN); 1057 (void) strcpy(dev_path, 1058 (char *)&l_state->drv_front[i].g_disk_state.physical_path); 1059 1060 if ((dl = (struct dlist *) 1061 g_zalloc(sizeof (struct dlist))) == NULL) { 1062 (void) g_free_wwn_list(&wwn_list); 1063 (void) l_free_lstate(&l_state); 1064 return (L_MALLOC_FAILED); 1065 } 1066 dl->dev_path = dev_path; 1067 if (g_get_multipath(dev_path, &(dl->multipath), 1068 wwn_list, verbose) != 0) { 1069 (void) g_destroy_data(dl); 1070 continue; 1071 } 1072 1073 for (dl1 = dl->multipath; 1074 dl1 != NULL; 1075 dl1 = dl1->next) { 1076 1077 /* attempt to acquire the device */ 1078 if ((devhdl = devctl_device_acquire( 1079 dl1->dev_path, DC_EXCL)) == NULL) { 1080 if (errno != EBUSY) { 1081 ER_DPRINTF("%s: Could not " 1082 "acquire the device: %s\n\n", 1083 strerror(errno), 1084 dl1->dev_path); 1085 continue; 1086 } 1087 } 1088 1089 /* attempt to offline the device */ 1090 if (devctl_device_offline(devhdl) != 0) { 1091 (void) devctl_release(devhdl); 1092 (void) g_free_multipath( 1093 dl->multipath); 1094 (void) g_destroy_data(dl); 1095 (void) g_free_wwn_list(&wwn_list); 1096 (void) l_free_lstate(&l_state); 1097 return (L_POWER_OFF_FAIL_BUSY); 1098 } 1099 1100 /* release handle acquired above */ 1101 (void) devctl_release(devhdl); 1102 } 1103 (void) g_free_multipath(dl->multipath); 1104 (void) g_destroy_data(dl); 1105 1106 } 1107 if (*l_state->drv_rear[i].g_disk_state.physical_path) { 1108 (void) memset(dev_path, 0, MAXPATHLEN); 1109 (void) strcpy(dev_path, 1110 (char *)&l_state->drv_rear[i].g_disk_state.physical_path); 1111 1112 if ((dl = (struct dlist *) 1113 g_zalloc(sizeof (struct dlist))) == NULL) { 1114 (void) g_free_wwn_list(&wwn_list); 1115 (void) l_free_lstate(&l_state); 1116 return (L_MALLOC_FAILED); 1117 } 1118 dl->dev_path = dev_path; 1119 if (g_get_multipath(dev_path, &(dl->multipath), 1120 wwn_list, verbose) != 0) { 1121 (void) g_destroy_data(dl); 1122 continue; 1123 } 1124 1125 1126 for (dl1 = dl->multipath; 1127 dl1 != NULL; 1128 dl1 = dl1->next) { 1129 1130 /* attempt to acquire the device */ 1131 if ((devhdl = devctl_device_acquire( 1132 dl1->dev_path, DC_EXCL)) == NULL) { 1133 if (errno != EBUSY) { 1134 ER_DPRINTF("%s: Could not " 1135 "acquire the device: %s\n\n", 1136 strerror(errno), 1137 dl1->dev_path); 1138 continue; 1139 } 1140 } 1141 /* attempt to offline the device */ 1142 if (devctl_device_offline(devhdl) != 0) { 1143 (void) devctl_release(devhdl); 1144 (void) g_free_multipath( 1145 dl->multipath); 1146 (void) g_destroy_data(dl); 1147 (void) g_free_wwn_list(&wwn_list); 1148 (void) l_free_lstate(&l_state); 1149 return (L_POWER_OFF_FAIL_BUSY); 1150 } 1151 1152 /* release handle acquired above */ 1153 (void) devctl_release(devhdl); 1154 } 1155 (void) g_free_multipath(dl->multipath); 1156 (void) g_destroy_data(dl); 1157 1158 } 1159 } 1160 1161 pwr_up_dwn: 1162 1163 (void) g_free_wwn_list(&wwn_list); 1164 if ((err = pwr_up_down(path_phys, l_state, 0, -1, 1165 power_off_flag, verbose)) != 0) { 1166 (void) l_free_lstate(&l_state); 1167 return (err); 1168 } 1169 (void) l_free_lstate(&l_state); 1170 return (0); 1171 } 1172 1173 1174 /* 1175 * Set the state of the Photon enclosure or disk 1176 * powered up/down mode. 1177 * The path must point to an IB. 1178 * slot == -1 implies entire enclosure. 1179 * 1180 * RETURNS: 1181 * 0 O.K. 1182 * non-zero otherwise 1183 */ 1184 static int 1185 pwr_up_down(char *path_phys, L_state *l_state, int front, int slot, 1186 int power_off_flag, int verbose) 1187 { 1188 L_inquiry inq; 1189 int fd, status, err; 1190 uchar_t *page_buf; 1191 int front_index, rear_index, front_offset; 1192 int 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)) != 0) { 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] = '\0'; 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 == '\0')) { 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 = '\0'; /* 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)) != 0) { 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)) != 0) { 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 = '\0'; 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 != 0) { 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 (void) strcpy(path, 3721 seslist->dev_path); 3722 if (err = 3723 l_get_node_status(path, 3724 state, &found_flag, 3725 wwn_list, verbose)) { 3726 goto done; 3727 } 3728 } 3729 seslist = seslist->next; 3730 } 3731 } 3732 } else { 3733 if ((state->ib_status.bypass_b_en && 3734 !(state->ib_status.bypass_a_en)) || 3735 !(state->ib_status.bypass_a_en)) { 3736 while (seslist != NULL && !found_flag) { 3737 if (err = l_get_port( 3738 seslist->dev_path, 3739 &port_a_flag, verbose)) { 3740 goto done; 3741 } 3742 if ((strcmp(seslist->dev_path, 3743 path) != 0) && port_a_flag) { 3744 (void) strcpy(path, 3745 seslist->dev_path); 3746 if (err = 3747 l_get_node_status(path, 3748 state, &found_flag, 3749 wwn_list, verbose)) { 3750 goto done; 3751 } 3752 } 3753 seslist = seslist->next; 3754 } 3755 } 3756 } 3757 if (!found_flag) { 3758 state->l_state_flag = L_INVALID_MAP; 3759 G_DPRINTF(" l_get_individual_state: " 3760 "Disk state was " 3761 "Not in map.\n"); 3762 } else { 3763 G_DPRINTF(" l_get_individual_state: " 3764 "Disk was found in the map.\n"); 3765 } 3766 3767 if (seslist != NULL) 3768 (void) g_free_multipath(seslist); 3769 3770 } 3771 3772 } else { 3773 G_DPRINTF(" l_get_individual_state: Disk state was %s.\n", 3774 (state->ib_status.code == S_NOT_INSTALLED) ? 3775 "Not Installed" : "Not Available"); 3776 } 3777 3778 if (getenv("_LUX_T_DEBUG") != NULL) { 3779 end_time = gethrtime(); 3780 (void) fprintf(stdout, " l_get_individual_state:" 3781 "\tTime = %lld millisec\n", 3782 (end_time - start_time)/1000000); 3783 } 3784 3785 return (0); 3786 done: 3787 (void) g_free_multipath(seslist); 3788 return (err); 3789 } 3790 3791 3792 3793 /* 3794 * Get the global state of the photon. 3795 * 3796 * INPUT: 3797 * path and verbose flag 3798 * 3799 * "path" must be of the ses driver. 3800 * e.g. 3801 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0 3802 * or 3803 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0 3804 * 3805 * OUTPUT: 3806 * The struct l_state (which was passed in) has the status info 3807 * 3808 * RETURNS: 3809 * 0 O.K. 3810 * non-zero otherwise 3811 */ 3812 int 3813 l_get_status(char *path, struct l_state_struct *l_state, int verbose) 3814 { 3815 int err = 0, i, count; 3816 L_inquiry inq; 3817 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 3818 int al_pa, found_front, found_rear, front_flag, enc_type; 3819 char ses_path_front[MAXPATHLEN]; 3820 char ses_path_rear[MAXPATHLEN]; 3821 Box_list *b_list = NULL; 3822 Box_list *o_list = NULL; 3823 char node_wwn_s[(WWN_SIZE*2)+1]; 3824 uint_t select_id; 3825 hrtime_t start_time, end_time; 3826 WWN_list *wwn_list = NULL; 3827 3828 if ((path == NULL) || (l_state == NULL)) { 3829 return (L_INVALID_PATH_FORMAT); 3830 } 3831 3832 start_time = gethrtime(); 3833 3834 G_DPRINTF(" l_get_status: Get Status for enclosure at: " 3835 " %s\n", path); 3836 3837 /* initialization */ 3838 (void) memset(l_state, 0, sizeof (struct l_state_struct)); 3839 3840 if (err = g_get_inquiry(path, &inq)) { 3841 return (err); 3842 } 3843 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 3844 (!(strncmp((char *)inq.inq_vid, "SUN ", 3845 sizeof (inq.inq_vid)) && 3846 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 3847 return (L_ENCL_INVALID_PATH); 3848 } 3849 3850 (void) strncpy((char *)l_state->ib_tbl.enclosure_name, 3851 (char *)inq.inq_box_name, sizeof (inq.inq_box_name)); 3852 3853 /* 3854 * Get all of the IB Receive Diagnostic pages. 3855 */ 3856 if (err = l_get_ib_status(path, l_state, verbose)) { 3857 return (err); 3858 } 3859 3860 /* 3861 * Now get the individual devices information from 3862 * the device itself. 3863 * 3864 * May need to use multiple paths to get to the 3865 * front and rear drives in the box. 3866 * If the loop is split some drives may not even be available 3867 * from this host. 3868 * 3869 * The way this works is in the select ID the front disks 3870 * are accessed via the IB with the bit 4 = 0 3871 * and the rear disks by the IB with bit 4 = 1. 3872 * 3873 * First get device map from fc nexus driver for this loop. 3874 */ 3875 /* 3876 * Get the boxes node WWN & al_pa for this path. 3877 */ 3878 if (err = g_get_wwn(path, port_wwn, node_wwn, &al_pa, verbose)) { 3879 return (err); 3880 } 3881 if (err = l_get_box_list(&o_list, verbose)) { 3882 (void) l_free_box_list(&o_list); 3883 return (err); /* Failure */ 3884 } 3885 3886 found_front = found_rear = 0; 3887 for (i = 0; i < WWN_SIZE; i++) { 3888 (void) sprintf(&node_wwn_s[i << 1], "%02x", node_wwn[i]); 3889 } 3890 3891 /* 3892 * The al_pa (or pa) can be 24 bits in size for fabric loops. 3893 * But we will take only the low order byte to get the select_id. 3894 * Private loops have al_pa which is only a byte in size. 3895 */ 3896 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3897 l_state->ib_tbl.box_id = (select_id & BOX_ID_MASK) >> 5; 3898 3899 G_DPRINTF(" l_get_status: Using this select_id 0x%x " 3900 "and node WWN %s\n", 3901 select_id, node_wwn_s); 3902 3903 if (strstr(path, SCSI_VHCI) != NULL) { 3904 /* there is no way to obtain all the al_pa with */ 3905 /* current implementation. assume both front */ 3906 /* and rear. need changes later on. */ 3907 found_rear = 1; 3908 found_front = 1; 3909 (void) strcpy(ses_path_rear, path); 3910 (void) strcpy(ses_path_front, path); 3911 } else { 3912 3913 if (select_id & ALT_BOX_ID) { 3914 found_rear = 1; 3915 (void) strcpy(ses_path_rear, path); 3916 b_list = o_list; 3917 while (b_list) { 3918 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) { 3919 if (err = g_get_wwn(b_list->b_physical_path, 3920 port_wwn, node_wwn, 3921 &al_pa, verbose)) { 3922 (void) l_free_box_list(&o_list); 3923 return (err); 3924 } 3925 3926 /* Take the low order byte of al_pa */ 3927 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3928 if (!(select_id & ALT_BOX_ID)) { 3929 (void) strcpy(ses_path_front, 3930 b_list->b_physical_path); 3931 found_front = 1; 3932 break; 3933 } 3934 } 3935 b_list = b_list->box_next; 3936 } 3937 } else { 3938 (void) strcpy(ses_path_front, path); 3939 found_front = 1; 3940 b_list = o_list; 3941 while (b_list) { 3942 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) { 3943 if (err = g_get_wwn(b_list->b_physical_path, 3944 port_wwn, node_wwn, 3945 &al_pa, verbose)) { 3946 (void) l_free_box_list(&o_list); 3947 return (err); 3948 } 3949 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 3950 if (select_id & ALT_BOX_ID) { 3951 (void) strcpy(ses_path_rear, 3952 b_list->b_physical_path); 3953 found_rear = 1; 3954 break; 3955 } 3956 } 3957 b_list = b_list->box_next; 3958 } 3959 } 3960 } 3961 3962 if (getenv("_LUX_G_DEBUG") != NULL) { 3963 if (!found_front) { 3964 (void) printf("l_get_status: Loop to front disks not found.\n"); 3965 } 3966 if (!found_rear) { 3967 (void) printf("l_get_status: Loop to rear disks not found.\n"); 3968 } 3969 } 3970 3971 /* 3972 * Get path to all the FC disk and tape devices. 3973 * 3974 * I get this now and pass down for performance 3975 * reasons. 3976 * If for some reason the list can become invalid, 3977 * i.e. device being offlined, then the list 3978 * must be re-gotten. 3979 */ 3980 if (err = g_get_wwn_list(&wwn_list, verbose)) { 3981 return (err); /* Failure */ 3982 } 3983 3984 enc_type = l_get_enc_type(inq); 3985 if (found_front) { 3986 front_flag = 1; 3987 for (i = 0, count = 0; i < l_state->total_num_drv/2; 3988 count++, i++) { 3989 if (enc_type == DAK_ENC_TYPE) { 3990 G_DPRINTF(" l_get_status: Getting individual" 3991 " State for disk in slot %d\n", count); 3992 } else { 3993 G_DPRINTF(" l_get_status: Getting individual" 3994 " State for front disk in slot %d\n", i); 3995 } 3996 if (err = l_get_individual_state(ses_path_front, 3997 (struct l_disk_state_struct *)&l_state->drv_front[i], 3998 &l_state->ib_tbl, front_flag, o_list, 3999 wwn_list, verbose)) { 4000 (void) l_free_box_list(&o_list); 4001 (void) g_free_wwn_list(&wwn_list); 4002 return (err); 4003 } 4004 } 4005 } else { 4006 /* Set to loop not accessable. */ 4007 for (i = 0; i < l_state->total_num_drv/2; i++) { 4008 l_state->drv_front[i].l_state_flag = L_NO_LOOP; 4009 } 4010 } 4011 /* 4012 * For Daktari's, disk 0-5 information are located in the 4013 * l_state->drv_front array 4014 * For Daktari's, disk 6-11 information are located in the 4015 * l_state->drv_rear array 4016 * 4017 * For this reason, on daktari's, I ignore the found_front and 4018 * found_rear flags and check both the drv_front and drv_rear 4019 */ 4020 4021 if (enc_type == DAK_ENC_TYPE && found_front) { 4022 front_flag = 1; 4023 for (i = 0; i < l_state->total_num_drv/2; i++, count++) { 4024 G_DPRINTF(" l_get_status: Getting individual" 4025 " State for disk in slot %d\n", count); 4026 if (err = l_get_individual_state(ses_path_front, 4027 (struct l_disk_state_struct *)&l_state->drv_rear[i], 4028 &l_state->ib_tbl, front_flag, o_list, 4029 wwn_list, verbose)) { 4030 (void) l_free_box_list(&o_list); 4031 (void) g_free_wwn_list(&wwn_list); 4032 return (err); 4033 } 4034 } 4035 } else if (enc_type != DAK_ENC_TYPE && found_rear) { 4036 for (i = 0; i < l_state->total_num_drv/2; i++, count++) { 4037 G_DPRINTF(" l_get_status: Getting individual" 4038 " State for rear disk in slot %d\n", i); 4039 if (err = l_get_individual_state(ses_path_rear, 4040 (struct l_disk_state_struct *)&l_state->drv_rear[i], 4041 &l_state->ib_tbl, front_flag, o_list, 4042 wwn_list, verbose)) { 4043 (void) l_free_box_list(&o_list); 4044 (void) g_free_wwn_list(&wwn_list); 4045 return (err); 4046 } 4047 } 4048 } else if (enc_type != DAK_ENC_TYPE) { 4049 /* Set to loop not accessable. */ 4050 for (i = 0; i < l_state->total_num_drv/2; i++) { 4051 l_state->drv_rear[i].l_state_flag = L_NO_LOOP; 4052 } 4053 } 4054 4055 (void) l_free_box_list(&o_list); 4056 (void) g_free_wwn_list(&wwn_list); 4057 if (getenv("_LUX_T_DEBUG") != NULL) { 4058 end_time = gethrtime(); 4059 (void) fprintf(stdout, " l_get_status: " 4060 "Time = %lld millisec\n", 4061 (end_time - start_time)/1000000); 4062 } 4063 4064 return (0); 4065 } 4066 4067 4068 4069 /* 4070 * Check the SENA file for validity: 4071 * - verify the size is that of 3 proms worth of text. 4072 * - verify PROM_MAGIC. 4073 * - verify (and print) the date. 4074 * - verify the checksum. 4075 * - verify the WWN == 0. 4076 * Since this requires reading the entire file, do it now and pass a pointer 4077 * to the allocated buffer back to the calling routine (which is responsible 4078 * for freeing it). If the buffer is not allocated it will be NULL. 4079 * 4080 * RETURNS: 4081 * 0 O.K. 4082 * non-zero otherwise 4083 */ 4084 4085 static int 4086 check_file(int fd, int verbose, uchar_t **buf_ptr, int dl_info_offset) 4087 { 4088 struct exec the_exec; 4089 int temp, i, j, *p, size, *start; 4090 uchar_t *buf; 4091 char *date_str; 4092 struct dl_info *dl_info; 4093 4094 *buf_ptr = NULL; 4095 4096 /* read exec header */ 4097 if (lseek(fd, 0, SEEK_SET) == -1) 4098 return (errno); 4099 if ((temp = read(fd, (char *)&the_exec, sizeof (the_exec))) == -1) { 4100 return (L_DWNLD_READ_HEADER_FAIL); 4101 } 4102 if (temp != sizeof (the_exec)) { 4103 return (L_DWNLD_READ_INCORRECT_BYTES); 4104 } 4105 4106 if (the_exec.a_text != PROMSIZE) { 4107 return (L_DWNLD_INVALID_TEXT_SIZE); 4108 } 4109 4110 if (!(buf = (uchar_t *)g_zalloc(PROMSIZE))) 4111 return (L_MALLOC_FAILED); 4112 4113 if ((temp = read(fd, buf, PROMSIZE)) == -1) { 4114 return (L_DWNLD_READ_ERROR); 4115 } 4116 4117 if (temp != PROMSIZE) { 4118 return (L_DWNLD_READ_INCORRECT_BYTES); 4119 } 4120 4121 4122 4123 /* check the IB firmware MAGIC */ 4124 dl_info = (struct dl_info *)(unsigned long)(buf + dl_info_offset); 4125 if (dl_info->magic != PROM_MAGIC) { 4126 return (L_DWNLD_BAD_FRMWARE); 4127 } 4128 4129 /* 4130 * Get the date 4131 */ 4132 4133 date_str = ctime(&dl_info->datecode); 4134 4135 if (verbose) { 4136 (void) fprintf(stdout, 4137 MSGSTR(9050, " IB Prom Date: %s"), 4138 date_str); 4139 } 4140 4141 /* 4142 * verify checksum 4143 */ 4144 4145 if (dl_info_offset == FPM_DL_INFO) { 4146 start = (int *)(long)(buf + FPM_OFFSET); 4147 size = FPM_SZ; 4148 } else { 4149 start = (int *)(long)buf; 4150 size = TEXT_SZ + IDATA_SZ; 4151 } 4152 4153 for (j = 0, p = start, i = 0; i < (size/ 4); i++, j ^= *p++); 4154 4155 if (j != 0) { 4156 return (L_DWNLD_CHKSUM_FAILED); 4157 } 4158 4159 /* file verified */ 4160 *buf_ptr = buf; 4161 4162 return (0); 4163 } 4164 4165 /* 4166 * Check the DPM file for validity: 4167 * 4168 * RETURNS: 4169 * 0 O.K. 4170 * non-zero otherwise 4171 */ 4172 #define dakstring "64616B74617269" 4173 #define dakoffs "BFC00000" 4174 4175 static int 4176 check_dpm_file(int fd) 4177 { 4178 struct s3hdr { 4179 char rtype[2]; 4180 char rlen[2]; 4181 char data[255]; 4182 } theRec; 4183 int nread; 4184 int reclen; 4185 4186 if (fd < 0) { 4187 return (L_DWNLD_READ_ERROR); 4188 } 4189 lseek(fd, 0, SEEK_SET); 4190 4191 /* First record */ 4192 memset((void*)&theRec, 0, sizeof (struct s3hdr)); 4193 nread = read(fd, (void *)&theRec, 4); 4194 if (nread != 4) { 4195 /* error reading first record/length */ 4196 return (L_DWNLD_READ_ERROR); 4197 } 4198 if (strncmp((char *)&theRec.rtype[0], "S0", 2) != 0) { 4199 /* error in first record type */ 4200 return (L_DWNLD_READ_HEADER_FAIL); 4201 } 4202 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16); 4203 if (reclen == 0) { 4204 /* error in length == 0 */ 4205 return (L_DWNLD_READ_HEADER_FAIL); 4206 } 4207 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1)); 4208 if (nread != ((reclen*2) +1)) { 4209 /* error in trying to read data */ 4210 return (L_DWNLD_READ_HEADER_FAIL); 4211 } 4212 if (strncmp(&theRec.data[4], dakstring, 14) != 0) { 4213 /* error in compiled file name */ 4214 return (L_DWNLD_READ_HEADER_FAIL); 4215 } 4216 4217 /* Second record */ 4218 memset((void*)&theRec, 0, sizeof (struct s3hdr)); 4219 nread = read(fd, (void *)&theRec, 4); 4220 if (nread != 4) { 4221 /* error reading second record/length */ 4222 return (L_DWNLD_READ_ERROR); 4223 } 4224 if (strncmp((char *)&theRec.rtype[0], "S3", 2) != 0) { 4225 /* error in second record type */ 4226 return (L_DWNLD_READ_HEADER_FAIL); 4227 } 4228 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16); 4229 if (reclen == 0) { 4230 /* error in length == 0 */ 4231 return (L_DWNLD_READ_HEADER_FAIL); 4232 } 4233 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1)); 4234 if (nread != ((reclen*2) +1)) { 4235 /* error in trying to read data */ 4236 return (L_DWNLD_READ_HEADER_FAIL); 4237 } 4238 if (strncmp(&theRec.data[0], dakoffs, 8) != 0) { 4239 /* error in SSC100 offset pointer */ 4240 return (L_DWNLD_READ_HEADER_FAIL); 4241 } 4242 lseek(fd, 0, SEEK_SET); 4243 return (0); 4244 } 4245 4246 4247 4248 int 4249 l_check_file(char *file, int verbose) 4250 { 4251 int file_fd; 4252 int err; 4253 uchar_t *buf; 4254 4255 if ((file_fd = g_object_open(file, O_RDONLY)) == -1) { 4256 return (L_OPEN_PATH_FAIL); 4257 } 4258 err = check_file(file_fd, verbose, &buf, FW_DL_INFO); 4259 if (buf) 4260 (void) g_destroy_data((char *)buf); 4261 return (err); 4262 } 4263 4264 4265 4266 /* 4267 * Write buffer command set up to download 4268 * firmware to the Photon IB. 4269 * 4270 * RETURNS: 4271 * status 4272 */ 4273 static int 4274 ib_download_code_cmd(int fd, int promid, int off, uchar_t *buf_ptr, 4275 int buf_len, int sp) 4276 { 4277 int status, sz; 4278 4279 while (buf_len) { 4280 sz = MIN(256, buf_len); 4281 buf_len -= sz; 4282 status = g_scsi_writebuffer_cmd(fd, off, buf_ptr, sz, 4283 (sp) ? 3 : 2, promid); 4284 if (status) 4285 return (status); 4286 buf_ptr += sz; 4287 off += sz; 4288 } 4289 4290 return (status); 4291 } 4292 4293 /* 4294 * 4295 * Downloads the code to the DAKTARI/DPM with the hdr set correctly 4296 * 4297 * 4298 * Inputs: 4299 * fd - int for the file descriptor 4300 * buf_ptr - uchar_t pointer to the firmware itself 4301 * buf_len - int for the length of the data 4302 * 4303 * Returns: 4304 * status: 0 indicates success, != 0 failure, returned from writebuffer 4305 * 4306 */ 4307 4308 static int 4309 dak_download_code_cmd(int fd, uchar_t *buf_ptr, int buf_len) 4310 { 4311 int status = 0; 4312 int sz = 0; 4313 int offs = 0; 4314 4315 while (buf_len > 0) { 4316 sz = MIN(256, buf_len); 4317 buf_len -= sz; 4318 status = g_scsi_writebuffer_cmd(fd, offs, buf_ptr, sz, 0x07, 0); 4319 if (status != 0) { 4320 return (status); 4321 } 4322 buf_ptr += sz; 4323 offs += sz; 4324 } 4325 return (status); 4326 } 4327 4328 4329 4330 4331 /* 4332 * Downloads the new prom image to IB. 4333 * 4334 * INPUTS: 4335 * path - physical path of Photon SES card 4336 * file - input file for new code (may be NULL) 4337 * ps - whether the "save" bit should be set 4338 * verbose - to be verbose or not 4339 * 4340 * RETURNS: 4341 * 0 O.K. 4342 * non-zero otherwise 4343 */ 4344 int 4345 l_download(char *path_phys, char *file, int ps, int verbose) 4346 { 4347 int file_fd, controller_fd; 4348 int err, status; 4349 uchar_t *buf_ptr; 4350 char printbuf[MAXPATHLEN]; 4351 int retry; 4352 char file_path[MAXPATHLEN]; 4353 struct stat statbuf; 4354 int enc_type; 4355 L_inquiry inq; 4356 4357 if (path_phys == NULL) { 4358 return (L_INVALID_PATH_FORMAT); 4359 } 4360 4361 if (!file) { 4362 (void) strcpy(file_path, IBFIRMWARE_FILE); 4363 } else { 4364 (void) strncpy(file_path, file, sizeof (file_path)); 4365 } 4366 if (verbose) 4367 (void) fprintf(stdout, "%s\n", 4368 MSGSTR(9051, " Opening the IB for I/O.")); 4369 4370 if ((controller_fd = g_object_open(path_phys, O_NDELAY | O_RDWR)) == -1) 4371 return (L_OPEN_PATH_FAIL); 4372 4373 (void) sprintf(printbuf, MSGSTR(9052, " Doing download to:" 4374 "\n\t%s.\n From file: %s."), path_phys, file_path); 4375 4376 if (verbose) 4377 (void) fprintf(stdout, "%s\n", printbuf); 4378 P_DPRINTF(" Doing download to:" 4379 "\n\t%s\n From file: %s\n", path_phys, file_path); 4380 4381 if ((file_fd = g_object_open(file_path, O_NDELAY | O_RDONLY)) == -1) { 4382 /* 4383 * Return a different error code here to differentiate between 4384 * this failure in g_object_open() and the one above. 4385 */ 4386 return (L_INVALID_PATH); 4387 } 4388 4389 if (g_scsi_inquiry_cmd(controller_fd, (uchar_t *)&inq, sizeof (inq))) { 4390 return (L_SCSI_ERROR); 4391 } 4392 enc_type = l_get_enc_type(inq); 4393 switch (enc_type) { 4394 case DAK_ENC_TYPE: 4395 /* 4396 * We don't have a default daktari file location, so 4397 * the user must specify the firmware file on the command line 4398 */ 4399 if (!file) { 4400 return (L_REQUIRE_FILE); 4401 } 4402 /* Validate the file */ 4403 if ((err = check_dpm_file(file_fd))) { 4404 return (err); 4405 } 4406 /* Now go ahead and load up the data */ 4407 if (fstat(file_fd, &statbuf) == -1) { 4408 err = errno; 4409 (void) fprintf(stdout, "%s %s\n", 4410 MSGSTR(9101, " Stat'ing the F/W file:"), strerror(err)); 4411 return (L_OPEN_PATH_FAIL); 4412 } 4413 buf_ptr = (uchar_t *)g_zalloc(statbuf.st_size); 4414 if (buf_ptr == NULL) { 4415 err = errno; 4416 (void) fprintf(stdout, "%s %s\n", 4417 MSGSTR(9102, " Cannot alloc mem to read F/W file:"), 4418 strerror(err)); 4419 return (L_MALLOC_FAILED); 4420 } 4421 if (read(file_fd, buf_ptr, statbuf.st_size) == -1) { 4422 err = errno; 4423 (void) fprintf(stdout, "%s %s\n", 4424 MSGSTR(9103, " Reading F/W file:"), strerror(err)); 4425 g_destroy_data((char *)buf_ptr); 4426 return (L_DWNLD_READ_ERROR); 4427 } 4428 break; 4429 default: 4430 if (err = check_file(file_fd, verbose, &buf_ptr, FW_DL_INFO)) { 4431 if (buf_ptr) { 4432 (void) g_destroy_data((char *)buf_ptr); 4433 return (err); 4434 } 4435 } 4436 break; 4437 } 4438 4439 if (verbose) { 4440 (void) fprintf(stdout, " "); 4441 (void) fprintf(stdout, MSGSTR(127, "Checkfile O.K.")); 4442 (void) fprintf(stdout, "\n"); 4443 } 4444 P_DPRINTF(" Checkfile OK.\n"); 4445 (void) close(file_fd); 4446 4447 if (verbose) { 4448 (void) fprintf(stdout, MSGSTR(9053, 4449 " Verifying the IB is available.\n")); 4450 } 4451 4452 retry = DOWNLOAD_RETRIES; 4453 while (retry) { 4454 if ((status = g_scsi_tur(controller_fd)) == 0) { 4455 break; 4456 } else { 4457 if ((retry % 30) == 0) { 4458 ER_DPRINTF(" Waiting for the IB to be" 4459 " available.\n"); 4460 } 4461 (void) sleep(1); 4462 } 4463 } 4464 if (!retry) { 4465 if (buf_ptr) 4466 (void) g_destroy_data((char *)buf_ptr); 4467 (void) close(controller_fd); 4468 return (status); 4469 } 4470 4471 if (verbose) 4472 (void) fprintf(stdout, "%s\n", 4473 MSGSTR(9054, " Writing new text image to IB.")); 4474 P_DPRINTF(" Writing new image to IB\n"); 4475 switch (enc_type) { 4476 case DAK_ENC_TYPE: 4477 status = dak_download_code_cmd(controller_fd, buf_ptr, 4478 statbuf.st_size); 4479 if (status != 0) { 4480 if (buf_ptr != NULL) { 4481 g_destroy_data((char *)buf_ptr); 4482 } 4483 (void) close(controller_fd); 4484 return (status); 4485 } 4486 break; 4487 default: 4488 status = ib_download_code_cmd(controller_fd, IBEEPROM, TEXT_OFFSET, 4489 (uchar_t *)(buf_ptr + TEXT_OFFSET), TEXT_SZ, ps); 4490 if (status) { 4491 (void) close(controller_fd); 4492 (void) g_destroy_data((char *)buf_ptr); 4493 return (status); 4494 } 4495 if (verbose) { 4496 (void) fprintf(stdout, "%s\n", 4497 MSGSTR(9055, " Writing new data image to IB.")); 4498 } 4499 status = ib_download_code_cmd(controller_fd, IBEEPROM, IDATA_OFFSET, 4500 (uchar_t *)(buf_ptr + IDATA_OFFSET), IDATA_SZ, ps); 4501 if (status) { 4502 (void) close(controller_fd); 4503 (void) g_destroy_data((char *)buf_ptr); 4504 return (status); 4505 } 4506 break; 4507 } 4508 4509 4510 if (verbose) { 4511 (void) fprintf(stdout, MSGSTR(9056, 4512 " Re-verifying the IB is available.\n")); 4513 } 4514 4515 retry = DOWNLOAD_RETRIES; 4516 while (retry) { 4517 if ((status = g_scsi_tur(controller_fd)) == 0) { 4518 break; 4519 } else { 4520 if ((retry % 30) == 0) { 4521 ER_DPRINTF(" Waiting for the IB to be" 4522 " available.\n"); 4523 } 4524 (void) sleep(1); 4525 } 4526 retry--; 4527 } 4528 if (!retry) { 4529 (void) close(controller_fd); 4530 (void) g_destroy_data((char *)buf_ptr); 4531 return (L_DWNLD_TIMED_OUT); 4532 } 4533 4534 switch (enc_type) { 4535 case DAK_ENC_TYPE: 4536 break; 4537 default: 4538 if (verbose) { 4539 (void) fprintf(stdout, "%s\n", 4540 MSGSTR(9057, " Writing new image to FPM.")); 4541 } 4542 status = ib_download_code_cmd(controller_fd, MBEEPROM, FPM_OFFSET, 4543 (uchar_t *)(buf_ptr + FPM_OFFSET), FPM_SZ, ps); 4544 break; 4545 } 4546 4547 if ((!status) && ps) { 4548 /* 4549 * Reset the IB 4550 */ 4551 status = g_scsi_reset(controller_fd); 4552 } 4553 4554 (void) close(controller_fd); 4555 return (status); 4556 } 4557 4558 /* 4559 * Set the World Wide Name 4560 * in page 4 of the Send Diagnostic command. 4561 * 4562 * Is it allowed to change the wwn ??? 4563 * The path must point to an IB. 4564 * 4565 */ 4566 int 4567 l_set_wwn(char *path_phys, char *wwn) 4568 { 4569 Page4_name page4; 4570 L_inquiry inq; 4571 int fd, status; 4572 char wwnp[WWN_SIZE]; 4573 4574 (void) memset(&inq, 0, sizeof (inq)); 4575 (void) memset(&page4, 0, sizeof (page4)); 4576 4577 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) { 4578 return (L_OPEN_PATH_FAIL); 4579 } 4580 /* Verify it is a Photon */ 4581 if (status = g_scsi_inquiry_cmd(fd, 4582 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) { 4583 (void) close(fd); 4584 return (status); 4585 } 4586 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && 4587 (!(strncmp((char *)inq.inq_vid, "SUN ", 4588 sizeof (inq.inq_vid)) && 4589 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { 4590 (void) close(fd); 4591 return (L_ENCL_INVALID_PATH); 4592 } 4593 4594 page4.page_code = L_PAGE_4; 4595 page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4)); 4596 page4.string_code = L_WWN; 4597 page4.enable = 1; 4598 if (g_string_to_wwn((uchar_t *)wwn, (uchar_t *)&page4.name)) { 4599 close(fd); 4600 return (EINVAL); 4601 } 4602 bcopy((void *)wwnp, (void *)page4.name, (size_t)WWN_SIZE); 4603 4604 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4, 4605 sizeof (page4))) { 4606 (void) close(fd); 4607 return (status); 4608 } 4609 4610 /* 4611 * Check the wwn really changed. 4612 */ 4613 bzero((char *)page4.name, 32); 4614 if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&page4, 4615 sizeof (page4), L_PAGE_4)) { 4616 (void) close(fd); 4617 return (status); 4618 } 4619 if (bcmp((char *)page4.name, wwnp, WWN_SIZE)) { 4620 (void) close(fd); 4621 return (L_WARNING); 4622 } 4623 4624 (void) close(fd); 4625 return (0); 4626 } 4627 4628 4629 4630 /* 4631 * Use a physical path to a disk in a Photon box 4632 * as the base to genererate a path to a SES 4633 * card in this box. 4634 * 4635 * path_phys: Physical path to a Photon disk. 4636 * ses_path: This must be a pointer to an already allocated path string. 4637 * 4638 * RETURNS: 4639 * 0 O.K. 4640 * non-zero otherwise 4641 */ 4642 int 4643 l_get_ses_path(char *path_phys, char *ses_path, gfc_map_t *map, 4644 int verbose) 4645 { 4646 char *char_ptr, id_buf[MAXPATHLEN], wwn[20]; 4647 uchar_t t_wwn[20], *ses_wwn, *ses_wwn1, *ses_nwwn; 4648 int j, al_pa, al_pa1, box_id, fd, disk_flag = 0; 4649 int err, found = 0; 4650 gfc_port_dev_info_t *dev_addr_ptr; 4651 4652 if ((path_phys == NULL) || (ses_path == NULL) || (map == NULL)) { 4653 return (L_NO_SES_PATH); 4654 } 4655 4656 (void) strcpy(ses_path, path_phys); 4657 if ((char_ptr = strrchr(ses_path, '/')) == NULL) { 4658 return (L_INVLD_PATH_NO_SLASH_FND); 4659 } 4660 disk_flag++; 4661 *char_ptr = '\0'; /* Terminate sting */ 4662 (void) strcat(ses_path, SLSH_SES_NAME); 4663 4664 /* 4665 * Figure out and create the boxes pathname. 4666 * 4667 * NOTE: This uses the fact that the disks's 4668 * AL_PA and the boxes AL_PA must match 4669 * the assigned hard address in the current 4670 * implementations. This may not be true in the 4671 * future. 4672 */ 4673 if ((char_ptr = strrchr(path_phys, '@')) == NULL) { 4674 return (L_INVLD_PATH_NO_ATSIGN_FND); 4675 } 4676 char_ptr++; /* point to the loop identifier */ 4677 4678 if ((err = g_get_wwn(path_phys, t_wwn, t_wwn, 4679 &al_pa, verbose)) != 0) { 4680 return (err); 4681 } 4682 box_id = g_sf_alpa_to_switch[al_pa & 0xFF] & BOX_ID_MASK; 4683 4684 switch (map->hba_addr.port_topology) { 4685 case FC_TOP_PRIVATE_LOOP: 4686 for (j = 0, dev_addr_ptr = map->dev_addr; 4687 j < map->count; j++, dev_addr_ptr++) { 4688 if (dev_addr_ptr->gfc_port_dev.priv_port. 4689 sf_inq_dtype == DTYPE_ESI) { 4690 al_pa1 = dev_addr_ptr->gfc_port_dev. 4691 priv_port.sf_al_pa; 4692 if (box_id == (g_sf_alpa_to_switch[al_pa1] & 4693 BOX_ID_MASK)) { 4694 if (!found) { 4695 ses_wwn = dev_addr_ptr-> 4696 gfc_port_dev.priv_port.sf_port_wwn; 4697 ses_nwwn = dev_addr_ptr-> 4698 gfc_port_dev.priv_port.sf_node_wwn; 4699 if (getenv("_LUX_P_DEBUG")) { 4700 (void) g_ll_to_str(ses_wwn, 4701 (char *)t_wwn); 4702 (void) printf( 4703 " l_get_ses_path: " 4704 "Found ses wwn = %s " 4705 "al_pa 0x%x\n", t_wwn, al_pa1); 4706 } 4707 } else { 4708 ses_wwn1 = dev_addr_ptr-> 4709 gfc_port_dev.priv_port.sf_port_wwn; 4710 if (getenv("_LUX_P_DEBUG")) { 4711 (void) g_ll_to_str(ses_wwn1, 4712 (char *)t_wwn); 4713 (void) printf( 4714 " l_get_ses_path: " 4715 "Found second ses " "wwn = %s " 4716 "al_pa 0x%x\n", t_wwn, al_pa1); 4717 } 4718 } 4719 found++; 4720 } 4721 } 4722 } 4723 break; 4724 case FC_TOP_FABRIC: 4725 case FC_TOP_PUBLIC_LOOP: 4726 for (j = 0, dev_addr_ptr = map->dev_addr; 4727 j < map->count; j++, dev_addr_ptr++) { 4728 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype == 4729 DTYPE_ESI) { 4730 /* 4731 * We found an enclosure, lets match the 4732 * area and domain codes for this enclosure with 4733 * that of the ses path since there may be 4734 * multiple enclosures with same box id on a 4735 * fabric 4736 */ 4737 al_pa1 = dev_addr_ptr->gfc_port_dev. 4738 pub_port.dev_did.port_id; 4739 if ((al_pa & AREA_DOMAIN_ID) == 4740 (al_pa1 & AREA_DOMAIN_ID)) { 4741 /* 4742 * The area and domain matched. Now, we 4743 * match the box id of the disk with 4744 * this enclosure 4745 */ 4746 if (box_id == 4747 (g_sf_alpa_to_switch[al_pa1 & 4748 0xFF] & BOX_ID_MASK)) { 4749 if (!found) { 4750 ses_wwn = dev_addr_ptr-> 4751 gfc_port_dev.pub_port. 4752 dev_pwwn.raw_wwn; 4753 ses_nwwn = dev_addr_ptr-> 4754 gfc_port_dev.pub_port. 4755 dev_nwwn.raw_wwn; 4756 if (getenv("_LUX_P_DEBUG")) { 4757 (void) g_ll_to_str(ses_wwn, 4758 (char *)t_wwn); 4759 (void) printf( 4760 " l_get_ses_path: " 4761 "Found ses wwn = %s " 4762 "al_pa 0x%x\n", t_wwn, 4763 al_pa1); 4764 } 4765 } else { 4766 ses_wwn1 = dev_addr_ptr-> 4767 gfc_port_dev.pub_port. 4768 dev_pwwn.raw_wwn; 4769 if (getenv("_LUX_P_DEBUG")) { 4770 (void) g_ll_to_str(ses_wwn1, 4771 (char *)t_wwn); 4772 (void) printf( 4773 " l_get_ses_path: " 4774 "Found second ses " 4775 "wwn = %s " 4776 "al_pa 0x%x\n", t_wwn, 4777 al_pa1); 4778 } 4779 } 4780 found++; 4781 } 4782 } 4783 } 4784 } 4785 break; 4786 case FC_TOP_PT_PT: 4787 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 4788 default: 4789 return (L_UNEXPECTED_FC_TOPOLOGY); 4790 } /* End of switch on port_topology */ 4791 4792 if (!found) { 4793 return (L_NO_SES_PATH); 4794 } 4795 4796 if (strstr(path_phys, SCSI_VHCI) != NULL) { 4797 (void) g_ll_to_str(ses_nwwn, wwn); 4798 (void) sprintf(id_buf, "g%s:0", wwn); 4799 } else { 4800 (void) g_ll_to_str(ses_wwn, wwn); 4801 (void) sprintf(id_buf, "w%s,0:0", wwn); 4802 } 4803 (void) strcat(ses_path, id_buf); 4804 if (verbose) { 4805 (void) fprintf(stdout, 4806 MSGSTR(9058, " Creating enclosure path:\n %s\n"), 4807 ses_path); 4808 } 4809 4810 /* 4811 * see if these paths exist. 4812 */ 4813 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDONLY)) == -1) { 4814 4815 if (strstr(path_phys, SCSI_VHCI) != NULL) { 4816 return (L_INVALID_PATH); 4817 } 4818 4819 char_ptr = strrchr(ses_path, '/'); 4820 *char_ptr = '\0'; 4821 (void) strcat(ses_path, SLSH_SES_NAME); 4822 if (found > 1) { 4823 (void) g_ll_to_str(ses_wwn1, wwn); 4824 P_DPRINTF(" l_get_ses_path: " 4825 "Using second path, ses wwn1 = %s\n", 4826 wwn); 4827 (void) sprintf(id_buf, "w%s,0:0", wwn); 4828 strcat(ses_path, id_buf); 4829 return (0); 4830 } else { 4831 return (L_NO_SES_PATH); 4832 } 4833 } 4834 close(fd); 4835 return (0); 4836 } 4837 4838 4839 4840 /* 4841 * Get a valid location, front/rear & slot. 4842 * 4843 * path_struct->p_physical_path must be of a disk. 4844 * 4845 * OUTPUT: path_struct->slot_valid 4846 * path_struct->slot 4847 * path_struct->f_flag 4848 * 4849 * RETURN: 4850 * 0 O.K. 4851 * non-zero otherwise 4852 */ 4853 int 4854 l_get_slot(struct path_struct *path_struct, L_state *l_state, int verbose) 4855 { 4856 int err, al_pa, slot, found = 0; 4857 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; 4858 uint_t select_id; 4859 4860 if ((path_struct == NULL) || (l_state == NULL)) { 4861 return (L_INVALID_PATH_FORMAT); 4862 } 4863 4864 /* Double check to see if we need to calculate. */ 4865 if (path_struct->slot_valid) 4866 return (0); 4867 4868 /* Programming error if this occures */ 4869 assert(path_struct->ib_path_flag == 0); 4870 4871 if (strstr(path_struct->p_physical_path, "ssd") == NULL) { 4872 return (L_INVLD_PHYS_PATH_TO_DISK); 4873 } 4874 if (err = g_get_wwn(path_struct->p_physical_path, port_wwn, node_wwn, 4875 &al_pa, verbose)) { 4876 return (err); 4877 } 4878 4879 /* 4880 * Find the slot by searching for the matching hard address. 4881 * Take only the low order byte ignoring area and domain code in 4882 * fabric devices' 24 bit al_pa 4883 */ 4884 select_id = g_sf_alpa_to_switch[al_pa & 0xFF]; 4885 P_DPRINTF(" l_get_slot: Searching Receive Diagnostic page 2, " 4886 "to find the slot number with this ID:0x%x\n", 4887 select_id); 4888 4889 for (slot = 0; slot < l_state->total_num_drv/2; slot++) { 4890 if (l_state->drv_front[slot].ib_status.sel_id == 4891 select_id) { 4892 path_struct->f_flag = 1; 4893 found = 1; 4894 break; 4895 } else if (l_state->drv_rear[slot].ib_status.sel_id == 4896 select_id) { 4897 path_struct->f_flag = 0; 4898 found = 1; 4899 break; 4900 } 4901 } 4902 if (!found) { 4903 return (L_INVALID_SLOT); /* Failure */ 4904 } 4905 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 4906 strlen(DAK_OFF_NAME)) == 0) || 4907 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 4908 strlen(DAK_OFF_NAME)) == 0)) { 4909 P_DPRINTF(" l_get_slot: Found slot %d.\n", 4910 path_struct->f_flag ? slot : slot + (MAX_DRIVES_DAK/2)); 4911 } else { 4912 P_DPRINTF(" l_get_slot: Found slot %d %s.\n", slot, 4913 path_struct->f_flag ? "Front" : "Rear"); 4914 } 4915 path_struct->slot = slot; 4916 path_struct->slot_valid = 1; 4917 return (0); 4918 } 4919 4920 4921 void 4922 l_element_msg_string(uchar_t code, char *es) 4923 { 4924 if (code == S_OK) { 4925 (void) sprintf(es, MSGSTR(29, "O.K.")); 4926 } else if (code == S_NOT_AVAILABLE) { 4927 (void) sprintf(es, MSGSTR(34, "Disabled")); 4928 } else if (code == S_NOT_INSTALLED) { 4929 (void) sprintf(es, MSGSTR(30, "Not Installed")); 4930 } else if (code == S_NONCRITICAL) { 4931 (void) sprintf(es, MSGSTR(9059, "Noncritical failure")); 4932 } else if (code == S_CRITICAL) { 4933 (void) sprintf(es, MSGSTR(122, "Critical failure")); 4934 } else { 4935 (void) sprintf(es, MSGSTR(4, "Unknown status")); 4936 } 4937 } 4938 4939 4940 /* 4941 * Get all ses paths paths to a given box. 4942 * The arg should be the physical path to one of the box's IB. 4943 * NOTE: The caller must free the allocated lists. 4944 * 4945 * OUTPUT: 4946 * a pointer to a list of ses paths if found 4947 * NULL on error. 4948 * 4949 * RETURNS: 4950 * 0 if O.K. 4951 * non-zero otherwise 4952 */ 4953 int 4954 l_get_allses(char *path, struct box_list_struct *box_list, 4955 struct dlist **ses_list, int verbose) 4956 { 4957 struct box_list_struct *box_list_ptr; 4958 char node_wwn_s[WWN_S_LEN]; 4959 struct dlist *dlt, *dl; 4960 4961 if ((path == NULL) || (box_list == NULL) || (ses_list == NULL)) { 4962 return (L_INVALID_PATH_FORMAT); 4963 } 4964 4965 /* Initialize lists/arrays */ 4966 *ses_list = dlt = dl = (struct dlist *)NULL; 4967 node_wwn_s[0] = '\0'; 4968 4969 H_DPRINTF(" l_get_allses: Looking for all ses paths for" 4970 " box at path: %s\n", path); 4971 4972 for (box_list_ptr = box_list; box_list_ptr != NULL; 4973 box_list_ptr = box_list_ptr->box_next) { 4974 H_DPRINTF(" l_get_allses: physical_path= %s\n", 4975 box_list_ptr->b_physical_path); 4976 if (strcmp(path, box_list_ptr->b_physical_path) == 0) { 4977 (void) strcpy(node_wwn_s, box_list_ptr->b_node_wwn_s); 4978 break; 4979 } 4980 } 4981 if (node_wwn_s[0] == '\0') { 4982 H_DPRINTF("node_wwn_s is NULL!\n"); 4983 return (L_NO_NODE_WWN_IN_BOXLIST); 4984 } 4985 H_DPRINTF(" l_get_allses: node_wwn=%s\n", node_wwn_s); 4986 for (box_list_ptr = box_list; box_list_ptr != NULL; 4987 box_list_ptr = box_list_ptr->box_next) { 4988 if (strcmp(node_wwn_s, box_list_ptr->b_node_wwn_s) == 0) { 4989 if ((dl = (struct dlist *) 4990 g_zalloc(sizeof (struct dlist))) == NULL) { 4991 while (*ses_list != NULL) { 4992 dl = dlt->next; 4993 (void) g_destroy_data(dlt); 4994 dlt = dl; 4995 } 4996 return (L_MALLOC_FAILED); 4997 } 4998 H_DPRINTF(" l_get_allses: Found ses=%s\n", 4999 box_list_ptr->b_physical_path); 5000 dl->dev_path = strdup(box_list_ptr->b_physical_path); 5001 dl->logical_path = strdup(box_list_ptr->logical_path); 5002 if (*ses_list == NULL) { 5003 *ses_list = dlt = dl; 5004 } else { 5005 dlt->next = dl; 5006 dl->prev = dlt; 5007 dlt = dl; 5008 } 5009 } 5010 } 5011 5012 return (0); 5013 } 5014 5015 /* 5016 * Routine to return the enclosure type pointed to by the path. 5017 * Inputs: The inquiry data for the device in question 5018 * 5019 * Return: >= 0 is the type: 5020 * 5021 * Types are defined in storage/libg_fc/common/hdrs/g_state.h: 5022 * 5023 * 0 -> default (SENA) 5024 * 1 -> Daktari 5025 * 2 -> Other Enclosures 5026 * 5027 */ 5028 int 5029 l_get_enc_type(L_inquiry inq) 5030 { 5031 if (strncmp((char *)&inq.inq_pid[0], ENCLOSURE_PROD_ID, 5032 strlen(ENCLOSURE_PROD_ID)) == 0) { 5033 return (SENA_ENC_TYPE); 5034 } 5035 if (strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME, 5036 strlen(DAK_OFF_NAME)) == 0) { 5037 return (DAK_ENC_TYPE); 5038 } 5039 if (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR, 5040 strlen(DAK_PROD_STR)) == 0) { 5041 return (DAK_ENC_TYPE); 5042 } 5043 /* 5044 * ADD OTHERS here if ever needed/wanted, and add to def's 5045 * as noted above 5046 */ 5047 return (UNDEF_ENC_TYPE); 5048 } 5049 5050 void 5051 free_mp_dev_map(gfc_map_mp_t **map_mp_ptr) { 5052 gfc_map_mp_t *next = NULL; 5053 5054 for (; *map_mp_ptr != NULL; *map_mp_ptr = next) { 5055 next = (*map_mp_ptr)->map_next; 5056 (void) g_destroy_data((*map_mp_ptr)->map.dev_addr); 5057 (void) g_destroy_data(*map_mp_ptr); 5058 } 5059 *map_mp_ptr = NULL; 5060 } 5061 /* 5062 * This function will return a linked list of device maps 5063 * An example of when this will be used is when we want to return the device 5064 * map of a vhci path. 5065 */ 5066 5067 int 5068 get_mp_dev_map(char *path, gfc_map_mp_t **map_mp_ptr, int verbose) { 5069 5070 int pathcnt, i, err; 5071 mp_pathlist_t pathlist; 5072 gfc_map_mp_t *new_map_mp_ptr; 5073 char drvr_path[MAXPATHLEN]; 5074 if (strstr(path, SCSI_VHCI)) { 5075 if (g_get_pathlist(path, &pathlist)) { 5076 return (L_INVALID_PATH); 5077 } 5078 pathcnt = pathlist.path_count; 5079 for (i = 0; i < pathcnt; i++) { 5080 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 5081 /* 5082 * only pay attention to paths that are either 5083 * ONLINE or STANDBY 5084 */ 5085 if ((pathlist.path_info[i].path_state == 5086 MDI_PATHINFO_STATE_ONLINE) || 5087 (pathlist.path_info[i].path_state == 5088 MDI_PATHINFO_STATE_STANDBY)) { 5089 if ((new_map_mp_ptr = (gfc_map_mp_t *) 5090 g_zalloc(sizeof (gfc_map_mp_t))) 5091 == NULL) { 5092 free(pathlist.path_info); 5093 free_mp_dev_map(map_mp_ptr); 5094 return (L_MALLOC_FAILED); 5095 } 5096 (void) strcpy(drvr_path, 5097 pathlist.path_info[i].path_hba); 5098 (void) strcat(drvr_path, FC_CTLR); 5099 if (err = g_get_dev_map(drvr_path, 5100 &(new_map_mp_ptr->map), 5101 verbose)) { 5102 free(pathlist.path_info); 5103 free_mp_dev_map(map_mp_ptr); 5104 return (err); 5105 } 5106 /* add newly created map onto list */ 5107 if (*map_mp_ptr == NULL) { 5108 new_map_mp_ptr->map_next = NULL; 5109 *map_mp_ptr = new_map_mp_ptr; 5110 } else { 5111 new_map_mp_ptr->map_next = 5112 *map_mp_ptr; 5113 *map_mp_ptr = new_map_mp_ptr; 5114 } 5115 } 5116 } 5117 } 5118 free(pathlist.path_info); 5119 } else { 5120 if ((new_map_mp_ptr = (gfc_map_mp_t *)g_zalloc 5121 (sizeof (gfc_map_mp_t))) == NULL) { 5122 return (L_MALLOC_FAILED); 5123 } 5124 g_get_dev_map(path, &(new_map_mp_ptr->map), verbose); 5125 *map_mp_ptr = new_map_mp_ptr; 5126 } 5127 return (0); 5128 } 5129