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 = '\0'; 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 = '\0'; 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, int f_flag, int slot, int verbose_flag) 401 { 402 uchar_t *page_buf; 403 int fd, front_index, rear_index, offset, err; 404 unsigned short page_len; 405 struct device_element *elem; 406 407 if ((ses_path == NULL) || (l_state == NULL)) { 408 return (L_INVALID_PATH_FORMAT); 409 } 410 411 if ((page_buf = (uchar_t *)g_zalloc(MAX_REC_DIAG_LENGTH)) == NULL) { 412 return (L_MALLOC_FAILED); 413 } 414 415 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 416 (void) g_destroy_data(page_buf); 417 return (L_OPEN_PATH_FAIL); 418 } 419 420 if ((err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 421 L_PAGE_2, verbose_flag)) != 0) { 422 (void) g_destroy_data(page_buf); 423 (void) close(fd); 424 return (err); 425 } 426 427 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 428 429 if ((err = l_get_disk_element_index(l_state, &front_index, 430 &rear_index)) != 0) { 431 (void) g_destroy_data(page_buf); 432 (void) close(fd); 433 return (err); 434 } 435 /* Skip global element */ 436 front_index++; 437 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME, 438 strlen(DAK_OFF_NAME)) == 0) || 439 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR, 440 strlen(DAK_OFF_NAME)) == 0)) { 441 rear_index += l_state->total_num_drv/2 + 1; 442 } else 443 rear_index++; 444 445 if (f_flag) { 446 offset = (8 + (front_index + slot)*4); 447 } else { 448 offset = (8 + (rear_index + slot)*4); 449 } 450 451 elem = (struct device_element *)(page_buf + offset); 452 453 switch (func) { 454 case OVERALL_STATUS: 455 if (code == NULL) { 456 return (L_INVALID_ARG); 457 } 458 switch (todo) { 459 case INSERT_DEVICE: 460 *code = (elem->code != S_OK) ? elem->code : 0; 461 (void) g_destroy_data(page_buf); 462 (void) close(fd); 463 return (0); 464 case REMOVE_DEVICE: 465 *code = (elem->code != S_NOT_INSTALLED) ? 466 elem->code : 0; 467 (void) g_destroy_data(page_buf); 468 (void) close(fd); 469 return (0); 470 } 471 /* NOTREACHED */ 472 case SET_RQST_INSRT: 473 bzero(elem, sizeof (struct device_element)); 474 elem->select = 1; 475 elem->rdy_to_ins = 1; 476 break; 477 case SET_RQST_RMV: 478 bzero(elem, sizeof (struct device_element)); 479 elem->select = 1; 480 elem->rmv = 1; 481 elem->dev_off = 1; 482 elem->en_bypass_a = 1; 483 elem->en_bypass_b = 1; 484 break; 485 case SET_FAULT: 486 bzero(elem, sizeof (struct device_element)); 487 elem->select = 1; 488 elem->fault_req = 1; 489 elem->dev_off = 1; 490 elem->en_bypass_a = 1; 491 elem->en_bypass_b = 1; 492 break; 493 case SET_DRV_ON: 494 bzero(elem, sizeof (struct device_element)); 495 elem->select = 1; 496 break; 497 } 498 499 err = g_scsi_send_diag_cmd(fd, (uchar_t *)page_buf, page_len); 500 (void) g_destroy_data(page_buf); 501 (void) close(fd); 502 return (err); 503 } 504 505 506 507 /* 508 * Finds whether device id (tid) exists in the 509 * Arbitrated loop map or not. 510 * 511 * INPUT: 512 * ses_path - pointer to a ses path 513 * tid - the target id of the device we want to check on 514 * - only the low order 8 bits has the tid 515 * map - pointer to a map of the system 516 * verbose_flag - self explanatory 517 * 518 * OUTPUT: 519 * dev_path - the device path of the device with "tid". 520 * Caller is responsible for freeing it 521 * 522 * RETURNS: 523 * 1 if device present 524 * 0 otherwise 525 */ 526 int 527 l_device_present(char *ses_path, int tid, gfc_map_t *map, 528 int verbose_flag, char **dev_path) 529 { 530 char sf_path[MAXPATHLEN]; 531 uchar_t wwn[40], c; 532 int len, i, j, k, fnib, snib, this_pid; 533 int fd, ses_pid, al_pa, err; 534 char ssd[30]; 535 gfc_port_dev_info_t *dev_addr_ptr; 536 WWN_list *wwnlp, *wwn_list; 537 538 539 if (dev_path == NULL) 540 return (0); 541 542 if ((ses_path == NULL) || (map == NULL)) { 543 return (L_NO_SES_PATH); 544 } 545 546 *dev_path = NULL; 547 548 switch (map->hba_addr.port_topology) { 549 case FC_TOP_PRIVATE_LOOP: 550 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count; 551 i++, dev_addr_ptr++) { 552 if (dev_addr_ptr->gfc_port_dev. 553 priv_port.sf_inq_dtype != DTYPE_ESI) { 554 al_pa = dev_addr_ptr->gfc_port_dev. 555 priv_port.sf_al_pa; 556 if (tid == g_sf_alpa_to_switch[al_pa]) { 557 break; 558 } 559 } 560 } 561 if (i >= map->count) 562 return (0); 563 /* 564 * Make sure that the port WWN is valid 565 */ 566 if (is_null_wwn(dev_addr_ptr->gfc_port_dev. 567 priv_port.sf_port_wwn)) { 568 return (0); 569 } 570 for (j = 0, k = 0; j < WWN_SIZE; j++) { 571 c = dev_addr_ptr->gfc_port_dev.priv_port.sf_port_wwn[j]; 572 fnib = (((int)(c & 0xf0)) >> 4); 573 snib = (c & 0x0f); 574 if (fnib >= 0 && fnib <= 9) 575 wwn[k++] = '0' + fnib; 576 else if (fnib >= 10 && fnib <= 15) 577 wwn[k++] = 'a' + fnib - 10; 578 if (snib >= 0 && snib <= 9) 579 wwn[k++] = '0' + snib; 580 else if (snib >= 10 && snib <= 15) 581 wwn[k++] = 'a' + snib - 10; 582 } 583 wwn[k] = '\0'; 584 break; 585 case FC_TOP_PUBLIC_LOOP: 586 case FC_TOP_FABRIC: 587 /* 588 * Get the phys address (port id) of this ses device 589 */ 590 if (err = l_get_pid_from_path(ses_path, map, &ses_pid)) 591 return (err); 592 593 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count; 594 i++, dev_addr_ptr++) { 595 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype != 596 DTYPE_ESI) { 597 /* 598 * We have a device. First match the area and 599 * domain ids and if they match, then see if 600 * the 8bit tid matches the last 8 bits of 601 * 'this_pid' 602 */ 603 this_pid = dev_addr_ptr->gfc_port_dev. 604 pub_port.dev_did.port_id; 605 if ((this_pid & AREA_DOMAIN_ID) == 606 (ses_pid & AREA_DOMAIN_ID)) { 607 if (tid == g_sf_alpa_to_switch[ 608 this_pid & 0xFF]) 609 break; 610 } 611 } 612 } 613 614 if (i >= map->count) 615 return (0); 616 /* 617 * Make sure that the port WWN is valid 618 */ 619 if (is_null_wwn(dev_addr_ptr->gfc_port_dev. 620 pub_port.dev_pwwn.raw_wwn)) { 621 return (0); 622 } 623 for (j = 0, k = 0; j < WWN_SIZE; j++) { 624 c = dev_addr_ptr->gfc_port_dev.pub_port. 625 dev_pwwn.raw_wwn[j]; 626 fnib = (((int)(c & 0xf0)) >> 4); 627 snib = (c & 0x0f); 628 if (fnib >= 0 && fnib <= 9) 629 wwn[k++] = '0' + fnib; 630 else if (fnib >= 10 && fnib <= 15) 631 wwn[k++] = 'a' + fnib - 10; 632 if (snib >= 0 && snib <= 9) 633 wwn[k++] = '0' + snib; 634 else if (snib >= 10 && snib <= 15) 635 wwn[k++] = 'a' + snib - 10; 636 } 637 wwn[k] = '\0'; 638 break; 639 case FC_TOP_PT_PT: 640 return (L_PT_PT_FC_TOP_NOT_SUPPORTED); 641 default: 642 return (L_UNEXPECTED_FC_TOPOLOGY); 643 } /* End of switch on port_topology */ 644 645 if (strstr(ses_path, SCSI_VHCI) != NULL) { 646 if (err = g_get_wwn_list(&wwn_list, 0)) { 647 return (err); 648 } 649 for (wwnlp = wwn_list; wwnlp != NULL; 650 wwnlp = wwnlp->wwn_next) { 651 if (memcmp(wwnlp->port_wwn_s, wwn, WWN_S_LEN) == 0) { 652 break; 653 } 654 } 655 if (wwnlp != NULL) { 656 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 657 g_free_wwn_list(&wwn_list); 658 return (L_MALLOC_FAILED); 659 } 660 (void) strcpy(*dev_path, wwnlp->physical_path); 661 } else { 662 g_free_wwn_list(&wwn_list); 663 return (0); 664 } 665 } else { 666 667 len = strlen(ses_path) - strlen(strrchr(ses_path, '/')); 668 669 (void) sprintf(ssd, "ssd@w%s,0", wwn); 670 671 (void) strncpy(sf_path, ses_path, len); 672 sf_path[len] = '\0'; 673 P_DPRINTF(" l_device_present: wwn=%s, sf_path=%s\n", 674 wwn, sf_path); 675 676 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 677 return (L_MALLOC_FAILED); 678 } 679 (void) sprintf(*dev_path, "%s/%s", sf_path, ssd); 680 P_DPRINTF(" l_device_present: dev_path=%s\n", *dev_path); 681 682 (void) strcat(*dev_path, ":c"); 683 } 684 if ((fd = open(*dev_path, O_RDONLY)) == -1) { 685 free(*dev_path); 686 *dev_path = NULL; 687 return (0); 688 } 689 (void) close(fd); 690 return (1); 691 } 692 693 694 695 /* 696 * onlines the given list of devices 697 * and free up the allocated memory. 698 * 699 * RETURNS: 700 * N/A 701 */ 702 static void 703 online_dev(struct dlist *dl_head, int force_flag) 704 { 705 struct dlist *dl, *dl1; 706 707 for (dl = dl_head; dl != NULL; ) { 708 (void) g_online_drive(dl->multipath, force_flag); 709 (void) g_free_multipath(dl->multipath); 710 dl1 = dl; 711 dl = dl->next; 712 (void) g_destroy_data(dl1); 713 } 714 } 715 716 717 718 /* 719 * offlines all the disks in a 720 * SENA enclosure. 721 * 722 * RETURNS: 723 * 0 if O.K. 724 * non-zero otherwise 725 */ 726 int 727 l_offline_photon(struct hotplug_disk_list *hotplug_sena, 728 struct wwn_list_struct *wwn_list, 729 int force_flag, int verbose_flag) 730 { 731 int i, err; 732 struct dlist *dl_head, *dl_tail, *dl, *dl_ses; 733 char *dev_path, ses_path[MAXPATHLEN]; 734 L_state *l_state = NULL; 735 736 if (hotplug_sena == NULL) { 737 return (L_INVALID_PATH_FORMAT); 738 } 739 740 dl_head = dl_tail = NULL; 741 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 742 return (L_MALLOC_FAILED); 743 } 744 745 /* Get global status for this Photon */ 746 dl_ses = hotplug_sena->seslist; 747 while (dl_ses) { 748 (void) strcpy(ses_path, dl_ses->dev_path); 749 if (l_get_status(ses_path, l_state, verbose_flag) == 0) 750 break; 751 dl_ses = dl_ses->next; 752 } 753 754 if (dl_ses == NULL) { 755 (void) l_free_lstate(&l_state); 756 return (L_ENCL_INVALID_PATH); 757 } 758 759 for (i = 0; i < l_state->total_num_drv/2; i++) { 760 if (*l_state->drv_front[i].g_disk_state.physical_path) { 761 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 762 (void) online_dev(dl_head, force_flag); 763 (void) l_free_lstate(&l_state); 764 return (L_MALLOC_FAILED); 765 } 766 (void) strcpy(dev_path, 767 (char *)&l_state->drv_front[i].g_disk_state.physical_path); 768 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) { 769 (void) g_destroy_data(dev_path); 770 (void) online_dev(dl_head, force_flag); 771 (void) l_free_lstate(&l_state); 772 return (L_MALLOC_FAILED); 773 } 774 dl->dev_path = dev_path; 775 if ((err = g_get_multipath(dev_path, 776 &(dl->multipath), wwn_list, 0)) != 0) { 777 (void) g_destroy_data(dev_path); 778 if (dl->multipath != NULL) { 779 (void) g_free_multipath(dl->multipath); 780 } 781 (void) g_destroy_data(dl); 782 (void) online_dev(dl_head, force_flag); 783 (void) l_free_lstate(&l_state); 784 return (err); 785 } 786 if ((err = g_offline_drive(dl->multipath, 787 force_flag)) != 0) { 788 (void) g_destroy_data(dev_path); 789 (void) g_free_multipath(dl->multipath); 790 (void) g_destroy_data(dl); 791 (void) online_dev(dl_head, force_flag); 792 (void) l_free_lstate(&l_state); 793 return (err); 794 } 795 if (dl_head == NULL) { 796 dl_head = dl_tail = dl; 797 } else { 798 dl_tail->next = dl; 799 dl->prev = dl_tail; 800 dl_tail = dl; 801 } 802 (void) g_destroy_data(dev_path); 803 } 804 if (*l_state->drv_rear[i].g_disk_state.physical_path) { 805 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) { 806 (void) online_dev(dl_head, force_flag); 807 (void) l_free_lstate(&l_state); 808 return (L_MALLOC_FAILED); 809 } 810 (void) strcpy(dev_path, 811 (char *)&l_state->drv_rear[i].g_disk_state.physical_path); 812 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) { 813 (void) g_destroy_data(dev_path); 814 (void) online_dev(dl_head, force_flag); 815 (void) l_free_lstate(&l_state); 816 return (L_MALLOC_FAILED); 817 } 818 dl->dev_path = dev_path; 819 if ((err = g_get_multipath(dev_path, 820 &(dl->multipath), wwn_list, 0)) != 0) { 821 (void) g_destroy_data(dev_path); 822 if (dl->multipath != NULL) { 823 (void) g_free_multipath(dl->multipath); 824 } 825 (void) g_destroy_data(dl); 826 (void) online_dev(dl_head, force_flag); 827 (void) l_free_lstate(&l_state); 828 return (err); 829 } 830 if ((err = g_offline_drive(dl->multipath, 831 force_flag)) != 0) { 832 (void) g_destroy_data(dev_path); 833 (void) g_free_multipath(dl->multipath); 834 (void) g_destroy_data(dl); 835 (void) online_dev(dl_head, force_flag); 836 (void) l_free_lstate(&l_state); 837 return (err); 838 } 839 if (dl_head == NULL) { 840 dl_head = dl_tail = dl; 841 } else { 842 dl_tail->next = dl; 843 dl->prev = dl_tail; 844 dl_tail = dl; 845 } 846 (void) g_destroy_data(dev_path); 847 } 848 } 849 hotplug_sena->dlhead = dl_head; 850 (void) l_free_lstate(&l_state); 851 return (0); 852 853 } 854 855 856 857 /* 858 * prepares a char string 859 * containing the name of the 860 * device which will be hotplugged. 861 * 862 * RETURNS: 863 * N/A 864 */ 865 void 866 l_get_drive_name(char *drive_name, int slot, int f_flag, char *box_name) 867 { 868 int enc_type = 0; 869 L_inquiry inq; 870 char *physpath; 871 Path_struct *p_pathstruct; 872 873 if ((drive_name == NULL) || (box_name == NULL)) { 874 return; 875 } 876 877 if (!l_convert_name(box_name, &physpath, &p_pathstruct, 0)) { 878 if (!g_get_inquiry(physpath, &inq)) { 879 enc_type = l_get_enc_type(inq); 880 } 881 } 882 /* If either of the above fail, we use the default value of 0 */ 883 free(physpath); 884 free(p_pathstruct); 885 switch (enc_type) { 886 case DAK_ENC_TYPE: 887 if (f_flag != 0) { 888 (void) sprintf(drive_name, MSGSTR(8502, 889 "Drive in \"%s\" slot %d"), box_name, slot); 890 } else { 891 (void) sprintf(drive_name, MSGSTR(8502, 892 "Drive in \"%s\" slot %d"), box_name, 893 slot + (MAX_DRIVES_DAK/2)); 894 } 895 break; 896 default: 897 if (f_flag != 0) { 898 (void) sprintf(drive_name, MSGSTR(8500, 899 "Drive in \"%s\" front slot %d"), box_name, slot); 900 } else { 901 (void) sprintf(drive_name, MSGSTR(8501, 902 "Drive in \"%s\" rear slot %d"), box_name, slot); 903 } 904 break; 905 } 906 } 907