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 /* 31 * This module is part of the photon library 32 */ 33 34 /* 35 * I18N message number ranges 36 * This file: 8500 - 8999 37 * Shared common messages: 1 - 1999 38 */ 39 40 /* #define _POSIX_SOURCE 1 */ 41 42 /* Includes */ 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <sys/file.h> 46 #include <sys/types.h> 47 #include <sys/stat.h> 48 #include <sys/param.h> 49 #include <fcntl.h> 50 #include <unistd.h> 51 #include <errno.h> 52 #include <string.h> 53 #include <time.h> 54 #include <sys/scsi/scsi.h> 55 #include <sys/vtoc.h> 56 #include <nl_types.h> 57 #include <strings.h> 58 #include <sys/ddi.h> /* for max */ 59 #include <l_common.h> 60 #include <stgcom.h> 61 #include <l_error.h> 62 #include <rom.h> 63 #include <a_state.h> 64 #include <a5k.h> 65 66 67 /* Global variables */ 68 extern uchar_t g_switch_to_alpa[]; 69 extern uchar_t g_sf_alpa_to_switch[]; 70 71 72 /* 73 * This function checks if the passed char pointer has WWN_SIZE nulls (zeroes). 74 * 75 * This is only a convenience function. 76 * 77 * INPUT: 78 * wwn_ptr - pointer to a character string of length WWN_SIZE 79 * It is expected to be holding the WWN 80 * Ex: A WWN like 508002000000ddc1 is expected to be stored as 81 * the following 8 bytes - 82 * 0x50, 0x80, 0x00, 0x20, ... etc 83 * 84 * RETURNS: 85 * 0 - if there is atleast one of WWN_SIZE bytes is != '\0' 86 * non-zero - if all WWN_SIZE bytes are '\0' 87 */ 88 int 89 is_null_wwn(uchar_t *wwn_ptr) 90 { 91 int i; 92 93 for (i = 0; i < WWN_SIZE; i++) { 94 if (wwn_ptr[i] != '\0' || wwn_ptr[i] != '0') 95 return (0); 96 } 97 return (1); 98 } 99 100 101 /* 102 * This functions constructs a device path of the device/enclosure with the 103 * given tid and, for public/fabric cases, on the same area and domain as 104 * the given ses_path. 105 * 106 * INPUT: 107 * ses_path - pointer to the ses_path 108 * tid - tid of the device/enclosure whose path is to be constructed 109 * map - pointer to the map 110 * dtype - dtype of the device whose path is to be constructed 111 * 112 * OUTPUT: 113 * dev_path - pointer to the device path of type dtype and with tid 114 * - Caller has to free this after use 115 * 116 * RETURNS: 117 * 0 - on success 118 * non-zero - otherwise 119 */ 120 int 121 l_make_node(char *ses_path, int tid, char *dev_path, 122 gfc_map_t *map, int dtype) 123 { 124 int len, i, err; 125 int this_pid, ses_pid; 126 char ssd[40], wwn[20]; 127 gfc_port_dev_info_t *dev_addr_ptr; 128 struct stat stat_buf; 129 WWN_list *wwnlp, *wwn_list; 130 int found = 0; 131 132 if ((ses_path == NULL) || (dev_path == NULL) || (map == NULL)) { 133 return (L_INVALID_PATH_FORMAT); 134 } 135 136 switch (map->hba_addr.port_topology) { 137 case FC_TOP_PRIVATE_LOOP: 138 for (i = 0, dev_addr_ptr = map->dev_addr; 139 i < map->count; i++, dev_addr_ptr++) { 140 if (dev_addr_ptr->gfc_port_dev.priv_port. 141 sf_al_pa == g_switch_to_alpa[tid]) 142 break; 143 } 144 if (i >= map->count) { 145 *dev_path = '\0'; 146 return (L_INVALID_LOOP_MAP); 147 } 148 149 /* Make sure that the port WWN is valid */ 150 if (is_null_wwn(dev_addr_ptr->gfc_port_dev. 151 priv_port.sf_port_wwn)) { 152 *dev_path = '\0'; 153 return (L_INVLD_WWN_FORMAT); 154 } 155 156 (void) g_ll_to_str(dev_addr_ptr->gfc_port_dev. 157 priv_port.sf_port_wwn, wwn); 158 159 if (strstr(ses_path, SCSI_VHCI) != NULL) { 160 if (err = g_get_wwn_list(&wwn_list, 0)) { 161 return (err); 162 } 163 for (wwnlp = wwn_list, found = 0; 164 wwnlp != NULL; 165 wwnlp = wwnlp->wwn_next) { 166 if (strcmp(wwnlp->port_wwn_s, 167 wwn) == 0) { 168 found = 1; 169 break; 170 } 171 } 172 if (found) { 173 (void) strcpy(dev_path, 174 wwnlp->physical_path); 175 } else { 176 return (L_INVALID_PATH); 177 } 178 } else { 179 180 len = strlen(ses_path) - 181 strlen(strrchr(ses_path, '/')); 182 183 if (dtype != DTYPE_ESI) { 184 (void) sprintf(ssd, 185 "/ssd@w%s,0:c", wwn); 186 } else { 187 (void) sprintf(ssd, 188 "/ses@w%s,0:c", wwn); 189 } 190 191 /* TBD: Must find path, not just use :c */ 192 (void) strncpy(dev_path, ses_path, len); 193 dev_path[len] = '\0'; 194 (void) strcat(dev_path, ssd); 195 } 196 break; 197 case FC_TOP_FABRIC: 198 case FC_TOP_PUBLIC_LOOP: 199 /* First lets get the PA from the ses path passed in */ 200 if (err = l_get_pid_from_path(ses_path, map, &ses_pid)) { 201 return (err); 202 } 203 204 /* 205 * Now we go through every entry in the map and match the 206 * area and domain ids with the PA of the passed ses path. 207 * If we find a match, we then match the low order byte 208 */ 209 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count; 210 i++, dev_addr_ptr++) { 211 this_pid = dev_addr_ptr->gfc_port_dev.pub_port. 212 dev_did.port_id; 213 if ((this_pid & AREA_DOMAIN_ID) == 214 (ses_pid & AREA_DOMAIN_ID)) { 215 if ((uchar_t)(this_pid & 0xFF) == 216 g_switch_to_alpa[tid]) 217 break; 218 } 219 } 220 if (i >= map->count) { 221 *dev_path = '\0'; 222 return (L_INVALID_LOOP_MAP); 223 } 224 /* Make sure that the port WWN is valid */ 225 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.pub_port. 226 dev_pwwn.raw_wwn)) { 227 *dev_path = '\0'; 228 return (L_INVLD_WWN_FORMAT); 229 } 230 (void) g_ll_to_str(dev_addr_ptr->gfc_port_dev. 231 pub_port.dev_pwwn.raw_wwn, wwn); 232 233 234 235 if (strstr(ses_path, SCSI_VHCI) != NULL) { 236 if (err = g_get_wwn_list(&wwn_list, 0)) { 237 return (err); 238 } 239 for (wwnlp = wwn_list, found = 0; wwnlp != NULL; 240 wwnlp = wwnlp->wwn_next) { 241 if (strcmp(wwnlp->port_wwn_s, 242 wwn) == 0) { 243 found = 1; 244 } 245 } 246 if (found) { 247 (void) strcpy(dev_path, 248 wwnlp->physical_path); 249 } else { 250 return (L_INVALID_PATH); 251 } 252 } else { 253 len = strlen(ses_path) - 254 strlen(strrchr(ses_path, '/')); 255 256 if (dtype != DTYPE_ESI) { 257 (void) sprintf(ssd, "/ssd@w%s,0:c", wwn); 258 } else { 259 (void) sprintf(ssd, "/ses@w%s,0:c", wwn); 260 } 261 262 /* TBD: Must find path, not just use :c */ 263 (void) strncpy(dev_path, ses_path, len); 264 dev_path[len] = '\0'; 265 (void) strcat(dev_path, ssd); 266 } 267 268 if (stat(dev_path, &stat_buf) == -1) { 269 return (errno); 270 } 271 272 break; 273 case FC_TOP_PT_PT: 274 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 275 default: 276 return (L_UNEXPECTED_FC_TOPOLOGY); 277 } /* End of switch on port_topology */ 278 return (0); 279 } 280 281 282 283 /* 284 * checks for null wwn to a disk. 285 * and returns -1 if found, 0 286 * otherwise. 287 * 288 * OUTPUT: 289 * char *ses_path 290 * 291 * RETURNS: 292 * 0 if OK 293 * non-zero otherwise 294 */ 295 int 296 l_chk_null_wwn(Path_struct *path_struct, char *ses_path, 297 L_state *l_state, int verbose) 298 { 299 char *ptr, boxname[MAXPATHLEN]; 300 char node_wwn_s[WWN_SIZE * 2 + 1]; 301 Box_list *boxlist; 302 303 304 if ((path_struct == NULL) || (ses_path == NULL) || 305 (l_state == NULL)) { 306 return (L_INVALID_PATH_FORMAT); 307 } 308 309 /* 310 * verify and continue only if the argv 311 * has a format like box,{f/r}<slot #>. 312 * Otherwise, return to the caller. 313 * The only way to address null wwn disk 314 * is using the box,{f/r}<slot#> format. 315 */ 316 /* add support for new {f/r/s}<slot#> support for DPM */ 317 (void) strcpy(boxname, path_struct->argv); 318 if (((ptr = strstr(boxname, ",")) != NULL) && 319 ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') || 320 (*(ptr + 1) == 's'))) { 321 *ptr = NULL; 322 } else { 323 return (0); 324 } 325 326 327 /* 328 * Get the list of enclosures 329 * connected to the system. 330 */ 331 if (l_get_box_list(&boxlist, verbose) != 0) { 332 return (L_NO_ENCL_LIST_FOUND); 333 } 334 335 *ses_path = NULL; 336 337 /* 338 * The following method is safer to get an ses path 339 * to the enclosure than calling l_get_ses_path(), 340 * with physical path to null WWN disk. 341 * Because, l_get_ses_path uses the disk's 342 * al_pa to get the box id and then ses path 343 * to the box. When a disk has null wwn, it may 344 * not have a valid al_pa, and hard address. 345 * There is a possibility that l_get_ses_path() 346 * not returning ses path to the correct enclosure. 347 */ 348 while (boxlist != NULL) { 349 if ((strcmp(boxname, (char *)boxlist->b_name) == 0)) { 350 (void) strcpy(ses_path, boxlist->b_physical_path); 351 break; 352 } 353 boxlist = boxlist->box_next; 354 } 355 356 /* free the box list */ 357 (void) l_free_box_list(&boxlist); 358 359 if ((ses_path != NULL) && (strstr(ses_path, "ses") != NULL)) { 360 if (l_get_status(ses_path, l_state, 361 verbose) != 0) { 362 return (L_GET_STATUS_FAILED); 363 } 364 if (path_struct->f_flag) { 365 (void) strcpy(node_wwn_s, 366 l_state->drv_front[path_struct->slot].g_disk_state.node_wwn_s); 367 } else { 368 (void) strcpy(node_wwn_s, 369 l_state->drv_rear[path_struct->slot].g_disk_state.node_wwn_s); 370 } 371 372 W_DPRINTF("Found ses path: %s\n" 373 "and Node WWN: %s\n", ses_path, node_wwn_s); 374 375 /* check for null WWN */ 376 if (is_null_wwn((uchar_t *)node_wwn_s) == 0) { 377 return (0); /* Non-null wwn */ 378 } 379 W_DPRINTF("Found NULL WWN: %s\n", node_wwn_s); 380 return (1); 381 } 382 383 return (0); 384 385 } 386 387 388 389 /* 390 * If OVERALL_STATUS is sent as the "func", 391 * the code pointer must be valid (non NULL). 392 * Otherwise NULL is a valid input for the code pointer. 393 * 394 * RETURNS: 395 * 0 if OK 396 * non-zero otherwise 397 */ 398 int 399 l_encl_status_page_funcs(int func, char *code, int todo, char *ses_path, 400 struct l_state_struct *l_state, 401 int f_flag, int slot, int verbose_flag) 402 { 403 uchar_t *page_buf; 404 int fd, front_index, rear_index, offset, err; 405 unsigned short page_len; 406 struct device_element *elem; 407 408 if ((ses_path == NULL) || (l_state == NULL)) { 409 return (L_INVALID_PATH_FORMAT); 410 } 411 412 if ((page_buf = (uchar_t *)g_zalloc(MAX_REC_DIAG_LENGTH)) == NULL) { 413 return (L_MALLOC_FAILED); 414 } 415 416 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 417 (void) g_destroy_data(page_buf); 418 return (L_OPEN_PATH_FAIL); 419 } 420 421 if ((err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 422 L_PAGE_2, verbose_flag)) != 0) { 423 (void) g_destroy_data(page_buf); 424 (void) close(fd); 425 return (err); 426 } 427 428 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 429 430 if ((err = l_get_disk_element_index(l_state, &front_index, 431 &rear_index)) != 0) { 432 (void) g_destroy_data(page_buf); 433 (void) close(fd); 434 return (err); 435 } 436 /* Skip global element */ 437 front_index++; 438 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 439 strlen(DAK_OFF_NAME)) == 0) || 440 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 441 strlen(DAK_OFF_NAME)) == 0)) { 442 rear_index += l_state->total_num_drv/2 + 1; 443 } else 444 rear_index++; 445 446 if (f_flag) { 447 offset = (8 + (front_index + slot)*4); 448 } else { 449 offset = (8 + (rear_index + slot)*4); 450 } 451 452 elem = (struct device_element *)(page_buf + offset); 453 454 switch (func) { 455 case OVERALL_STATUS: 456 if (code == NULL) { 457 return (L_INVALID_ARG); 458 } 459 switch (todo) { 460 case INSERT_DEVICE: 461 *code = (elem->code != S_OK) ? elem->code : 0; 462 (void) g_destroy_data(page_buf); 463 (void) close(fd); 464 return (0); 465 case REMOVE_DEVICE: 466 *code = (elem->code != S_NOT_INSTALLED) ? 467 elem->code : 0; 468 (void) g_destroy_data(page_buf); 469 (void) close(fd); 470 return (0); 471 } 472 /* NOTREACHED */ 473 case SET_RQST_INSRT: 474 bzero(elem, sizeof (struct device_element)); 475 elem->select = 1; 476 elem->rdy_to_ins = 1; 477 break; 478 case SET_RQST_RMV: 479 bzero(elem, sizeof (struct device_element)); 480 elem->select = 1; 481 elem->rmv = 1; 482 elem->dev_off = 1; 483 elem->en_bypass_a = 1; 484 elem->en_bypass_b = 1; 485 break; 486 case SET_FAULT: 487 bzero(elem, sizeof (struct device_element)); 488 elem->select = 1; 489 elem->fault_req = 1; 490 elem->dev_off = 1; 491 elem->en_bypass_a = 1; 492 elem->en_bypass_b = 1; 493 break; 494 case SET_DRV_ON: 495 bzero(elem, sizeof (struct device_element)); 496 elem->select = 1; 497 break; 498 } 499 500 err = g_scsi_send_diag_cmd(fd, (uchar_t *)page_buf, page_len); 501 (void) g_destroy_data(page_buf); 502 (void) close(fd); 503 return (err); 504 } 505 506 507 508 /* 509 * Finds whether device id (tid) exists in the 510 * Arbitrated loop map or not. 511 * 512 * INPUT: 513 * ses_path - pointer to a ses path 514 * tid - the target id of the device we want to check on 515 * - only the low order 8 bits has the tid 516 * map - pointer to a map of the system 517 * verbose_flag - self explanatory 518 * 519 * OUTPUT: 520 * dev_path - the device path of the device with "tid". 521 * Caller is responsible for freeing it 522 * 523 * RETURNS: 524 * 1 if device present 525 * 0 otherwise 526 */ 527 int 528 l_device_present(char *ses_path, int tid, gfc_map_t *map, 529 int verbose_flag, char **dev_path) 530 { 531 char sf_path[MAXPATHLEN]; 532 uchar_t wwn[40], c; 533 int len, i, j, k, fnib, snib, this_pid; 534 int fd, ses_pid, al_pa, err; 535 char ssd[30]; 536 gfc_port_dev_info_t *dev_addr_ptr; 537 WWN_list *wwnlp, *wwn_list; 538 539 540 if (dev_path == NULL) 541 return (0); 542 543 if ((ses_path == NULL) || (map == NULL)) { 544 return (L_NO_SES_PATH); 545 } 546 547 *dev_path = NULL; 548 549 switch (map->hba_addr.port_topology) { 550 case FC_TOP_PRIVATE_LOOP: 551 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count; 552 i++, dev_addr_ptr++) { 553 if (dev_addr_ptr->gfc_port_dev. 554 priv_port.sf_inq_dtype != DTYPE_ESI) { 555 al_pa = dev_addr_ptr->gfc_port_dev. 556 priv_port.sf_al_pa; 557 if (tid == g_sf_alpa_to_switch[al_pa]) { 558 break; 559 } 560 } 561 } 562 if (i >= map->count) 563 return (0); 564 /* 565 * Make sure that the port WWN is valid 566 */ 567 if (is_null_wwn(dev_addr_ptr->gfc_port_dev. 568 priv_port.sf_port_wwn)) { 569 return (0); 570 } 571 for (j = 0, k = 0; j < WWN_SIZE; j++) { 572 c = dev_addr_ptr->gfc_port_dev.priv_port.sf_port_wwn[j]; 573 fnib = (((int)(c & 0xf0)) >> 4); 574 snib = (c & 0x0f); 575 if (fnib >= 0 && fnib <= 9) 576 wwn[k++] = '0' + fnib; 577 else if (fnib >= 10 && fnib <= 15) 578 wwn[k++] = 'a' + fnib - 10; 579 if (snib >= 0 && snib <= 9) 580 wwn[k++] = '0' + snib; 581 else if (snib >= 10 && snib <= 15) 582 wwn[k++] = 'a' + snib - 10; 583 } 584 wwn[k] = '\0'; 585 break; 586 case FC_TOP_PUBLIC_LOOP: 587 case FC_TOP_FABRIC: 588 /* 589 * Get the phys address (port id) of this ses device 590 */ 591 if (err = l_get_pid_from_path(ses_path, map, &ses_pid)) 592 return (err); 593 594 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count; 595 i++, dev_addr_ptr++) { 596 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype != 597 DTYPE_ESI) { 598 /* 599 * We have a device. First match the area and 600 * domain ids and if they match, then see if 601 * the 8bit tid matches the last 8 bits of 602 * 'this_pid' 603 */ 604 this_pid = dev_addr_ptr->gfc_port_dev. 605 pub_port.dev_did.port_id; 606 if ((this_pid & AREA_DOMAIN_ID) == 607 (ses_pid & AREA_DOMAIN_ID)) { 608 if (tid == g_sf_alpa_to_switch[ 609 this_pid & 0xFF]) 610 break; 611 } 612 } 613 } 614 615 if (i >= map->count) 616 return (0); 617 /* 618 * Make sure that the port WWN is valid 619 */ 620 if (is_null_wwn(dev_addr_ptr->gfc_port_dev. 621 pub_port.dev_pwwn.raw_wwn)) { 622 return (0); 623 } 624 for (j = 0, k = 0; j < WWN_SIZE; j++) { 625 c = dev_addr_ptr->gfc_port_dev.pub_port. 626 dev_pwwn.raw_wwn[j]; 627 fnib = (((int)(c & 0xf0)) >> 4); 628 snib = (c & 0x0f); 629 if (fnib >= 0 && fnib <= 9) 630 wwn[k++] = '0' + fnib; 631 else if (fnib >= 10 && fnib <= 15) 632 wwn[k++] = 'a' + fnib - 10; 633 if (snib >= 0 && snib <= 9) 634 wwn[k++] = '0' + snib; 635 else if (snib >= 10 && snib <= 15) 636 wwn[k++] = 'a' + snib - 10; 637 } 638 wwn[k] = '\0'; 639 break; 640 case FC_TOP_PT_PT: 641 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 642 default: 643 return (L_UNEXPECTED_FC_TOPOLOGY); 644 } /* End of switch on port_topology */ 645 646 if (strstr(ses_path, SCSI_VHCI) != NULL) { 647 if (err = g_get_wwn_list(&wwn_list, 0)) { 648 return (err); 649 } 650 for (wwnlp = wwn_list; wwnlp != NULL; 651 wwnlp = wwnlp->wwn_next) { 652 if (memcmp(wwnlp->port_wwn_s, wwn, WWN_S_LEN) == 0) { 653 break; 654 } 655 } 656 if (wwnlp != NULL) { 657 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 658 g_free_wwn_list(&wwn_list); 659 return (L_MALLOC_FAILED); 660 } 661 (void) strcpy(*dev_path, wwnlp->physical_path); 662 } else { 663 g_free_wwn_list(&wwn_list); 664 return (0); 665 } 666 } else { 667 668 len = strlen(ses_path) - strlen(strrchr(ses_path, '/')); 669 670 (void) sprintf(ssd, "ssd@w%s,0", wwn); 671 672 (void) strncpy(sf_path, ses_path, len); 673 sf_path[len] = '\0'; 674 P_DPRINTF(" l_device_present: wwn=%s, sf_path=%s\n", 675 wwn, sf_path); 676 677 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 678 return (L_MALLOC_FAILED); 679 } 680 (void) sprintf(*dev_path, "%s/%s", sf_path, ssd); 681 P_DPRINTF(" l_device_present: dev_path=%s\n", *dev_path); 682 683 (void) strcat(*dev_path, ":c"); 684 } 685 if ((fd = open(*dev_path, O_RDONLY)) == -1) { 686 free(*dev_path); 687 *dev_path = NULL; 688 return (0); 689 } 690 (void) close(fd); 691 return (1); 692 } 693 694 695 696 /* 697 * onlines the given list of devices 698 * and free up the allocated memory. 699 * 700 * RETURNS: 701 * N/A 702 */ 703 static void 704 online_dev(struct dlist *dl_head, int force_flag) 705 { 706 struct dlist *dl, *dl1; 707 708 for (dl = dl_head; dl != NULL; ) { 709 (void) g_online_drive(dl->multipath, force_flag); 710 (void) g_free_multipath(dl->multipath); 711 dl1 = dl; 712 dl = dl->next; 713 (void) g_destroy_data(dl1); 714 } 715 } 716 717 718 719 /* 720 * offlines all the disks in a 721 * SENA enclosure. 722 * 723 * RETURNS: 724 * 0 if O.K. 725 * non-zero otherwise 726 */ 727 int 728 l_offline_photon(struct hotplug_disk_list *hotplug_sena, 729 struct wwn_list_struct *wwn_list, 730 int force_flag, int verbose_flag) 731 { 732 int i, err; 733 struct dlist *dl_head, *dl_tail, *dl, *dl_ses; 734 char *dev_path, ses_path[MAXPATHLEN]; 735 L_state *l_state = NULL; 736 737 if (hotplug_sena == NULL) { 738 return (L_INVALID_PATH_FORMAT); 739 } 740 741 dl_head = dl_tail = NULL; 742 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 743 return (L_MALLOC_FAILED); 744 } 745 746 /* Get global status for this Photon */ 747 dl_ses = hotplug_sena->seslist; 748 while (dl_ses) { 749 (void) strcpy(ses_path, dl_ses->dev_path); 750 if (l_get_status(ses_path, l_state, verbose_flag) == 0) 751 break; 752 dl_ses = dl_ses->next; 753 } 754 755 if (dl_ses == NULL) { 756 (void) l_free_lstate(&l_state); 757 return (L_ENCL_INVALID_PATH); 758 } 759 760 for (i = 0; i < l_state->total_num_drv/2; i++) { 761 if (*l_state->drv_front[i].g_disk_state.physical_path) { 762 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 763 (void) online_dev(dl_head, force_flag); 764 (void) l_free_lstate(&l_state); 765 return (L_MALLOC_FAILED); 766 } 767 (void) strcpy(dev_path, 768 (char *)&l_state->drv_front[i].g_disk_state.physical_path); 769 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) { 770 (void) g_destroy_data(dev_path); 771 (void) online_dev(dl_head, force_flag); 772 (void) l_free_lstate(&l_state); 773 return (L_MALLOC_FAILED); 774 } 775 dl->dev_path = dev_path; 776 if ((err = g_get_multipath(dev_path, 777 &(dl->multipath), wwn_list, 0)) != 0) { 778 (void) g_destroy_data(dev_path); 779 if (dl->multipath != NULL) { 780 (void) g_free_multipath(dl->multipath); 781 } 782 (void) g_destroy_data(dl); 783 (void) online_dev(dl_head, force_flag); 784 (void) l_free_lstate(&l_state); 785 return (err); 786 } 787 if ((err = g_offline_drive(dl->multipath, 788 force_flag)) != 0) { 789 (void) g_destroy_data(dev_path); 790 (void) g_free_multipath(dl->multipath); 791 (void) g_destroy_data(dl); 792 (void) online_dev(dl_head, force_flag); 793 (void) l_free_lstate(&l_state); 794 return (err); 795 } 796 if (dl_head == NULL) { 797 dl_head = dl_tail = dl; 798 } else { 799 dl_tail->next = dl; 800 dl->prev = dl_tail; 801 dl_tail = dl; 802 } 803 (void) g_destroy_data(dev_path); 804 } 805 if (*l_state->drv_rear[i].g_disk_state.physical_path) { 806 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 807 (void) online_dev(dl_head, force_flag); 808 (void) l_free_lstate(&l_state); 809 return (L_MALLOC_FAILED); 810 } 811 (void) strcpy(dev_path, 812 (char *)&l_state->drv_rear[i].g_disk_state.physical_path); 813 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) { 814 (void) g_destroy_data(dev_path); 815 (void) online_dev(dl_head, force_flag); 816 (void) l_free_lstate(&l_state); 817 return (L_MALLOC_FAILED); 818 } 819 dl->dev_path = dev_path; 820 if ((err = g_get_multipath(dev_path, 821 &(dl->multipath), wwn_list, 0)) != 0) { 822 (void) g_destroy_data(dev_path); 823 if (dl->multipath != NULL) { 824 (void) g_free_multipath(dl->multipath); 825 } 826 (void) g_destroy_data(dl); 827 (void) online_dev(dl_head, force_flag); 828 (void) l_free_lstate(&l_state); 829 return (err); 830 } 831 if ((err = g_offline_drive(dl->multipath, 832 force_flag)) != 0) { 833 (void) g_destroy_data(dev_path); 834 (void) g_free_multipath(dl->multipath); 835 (void) g_destroy_data(dl); 836 (void) online_dev(dl_head, force_flag); 837 (void) l_free_lstate(&l_state); 838 return (err); 839 } 840 if (dl_head == NULL) { 841 dl_head = dl_tail = dl; 842 } else { 843 dl_tail->next = dl; 844 dl->prev = dl_tail; 845 dl_tail = dl; 846 } 847 (void) g_destroy_data(dev_path); 848 } 849 } 850 hotplug_sena->dlhead = dl_head; 851 (void) l_free_lstate(&l_state); 852 return (0); 853 854 } 855 856 857 858 /* 859 * prepares a char string 860 * containing the name of the 861 * device which will be hotplugged. 862 * 863 * RETURNS: 864 * N/A 865 */ 866 void 867 l_get_drive_name(char *drive_name, int slot, int f_flag, char *box_name) 868 { 869 int enc_type = 0; 870 L_inquiry inq; 871 char *physpath; 872 Path_struct *p_pathstruct; 873 874 if ((drive_name == NULL) || (box_name == NULL)) { 875 return; 876 } 877 878 if (!l_convert_name(box_name, &physpath, &p_pathstruct, 0)) { 879 if (!g_get_inquiry(physpath, &inq)) { 880 enc_type = l_get_enc_type(inq); 881 } 882 } 883 /* If either of the above fail, we use the default value of 0 */ 884 free(physpath); 885 free(p_pathstruct); 886 switch (enc_type) { 887 case DAK_ENC_TYPE: 888 if (f_flag != NULL) { 889 (void) sprintf(drive_name, MSGSTR(8502, 890 "Drive in \"%s\" slot %d"), box_name, slot); 891 } else { 892 (void) sprintf(drive_name, MSGSTR(8502, 893 "Drive in \"%s\" slot %d"), box_name, 894 slot + (MAX_DRIVES_DAK/2)); 895 } 896 break; 897 default: 898 if (f_flag != NULL) { 899 (void) sprintf(drive_name, MSGSTR(8500, 900 "Drive in \"%s\" front slot %d"), box_name, slot); 901 } else { 902 (void) sprintf(drive_name, MSGSTR(8501, 903 "Drive in \"%s\" rear slot %d"), box_name, slot); 904 } 905 break; 906 } 907 } 908