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