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: 8000 - 8499 37 * Shared common messages: 1 - 1999 38 */ 39 40 /* Includes */ 41 #include <stdlib.h> 42 #include <stdio.h> 43 #include <sys/file.h> 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <fcntl.h> 47 #include <unistd.h> 48 #include <errno.h> 49 #include <string.h> 50 #include <sys/scsi/scsi.h> 51 #include <nl_types.h> 52 #include <strings.h> 53 #include <sys/ddi.h> /* for max */ 54 #include <l_common.h> 55 #include <stgcom.h> 56 #include <l_error.h> 57 #include <a_state.h> 58 #include <a5k.h> 59 60 61 62 /* Defines */ 63 #define VERBPRINT if (verbose) (void) printf 64 65 66 /* 67 * take all paths supplied by dl offline. 68 * 69 * RETURNS: 70 * 0 = No error. 71 * *bsy_res_flag_p: 1 = The device is "busy". 72 * 73 * In pre-2.6 we just return success 74 */ 75 static int 76 d_offline_drive(struct dlist *dl, int *bsy_res_flag_p, int verbose) 77 { 78 char dev_path1[MAXPATHLEN]; 79 devctl_hdl_t devhdl; 80 81 82 /* for each path attempt to take it offline */ 83 for (; dl != NULL; dl = dl->next) { 84 85 /* save a copy of the pathname */ 86 (void) strcpy(dev_path1, dl->dev_path); 87 88 /* attempt to acquire the device */ 89 if ((devhdl = devctl_device_acquire(dev_path1, 90 DC_EXCL)) == NULL) { 91 if (errno != EBUSY) { 92 return (L_ACQUIRE_FAIL); 93 } 94 } 95 96 /* attempt to offline the drive */ 97 if (devctl_device_offline(devhdl) != 0) { 98 *bsy_res_flag_p = 1; 99 (void) devctl_release(devhdl); 100 return (0); 101 } 102 103 E_DPRINTF(" d_offline_drive: Offline succeeded:/n " 104 "%s\n", dev_path1); 105 /* offline succeeded -- release handle acquired above */ 106 (void) devctl_release(devhdl); 107 } 108 return (0); 109 } 110 111 112 113 114 /* 115 * Check to see if any of the disks that are attached 116 * to the selected port on this backplane are reserved or busy. 117 * 118 * INPUTS: 119 * RETURNS: 120 * 0 = No error. 121 * *bsy_res_flag_p: 1 = The device is "busy". 122 */ 123 124 int 125 l_check_busy_reserv_bp(char *ses_path, int front_flag, 126 int port_a_flag, int *bsy_res_flag_p, int verbose) 127 { 128 int err, i; 129 L_state *l_state = NULL; 130 struct dlist *p_list; 131 132 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 133 return (L_MALLOC_FAILED); 134 } 135 136 if (err = l_get_status(ses_path, l_state, verbose)) { 137 (void) l_free_lstate(&l_state); 138 return (err); 139 } 140 for (i = 0; i < (int)l_state->total_num_drv/2; i++) { 141 if ((front_flag && 142 (l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] & 143 L_RESERVED)) || (!front_flag && 144 (l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] & 145 L_RESERVED))) { 146 *bsy_res_flag_p = 1; 147 (void) l_free_lstate(&l_state); 148 return (0); 149 } 150 } 151 152 for (i = 0; i < (int)l_state->total_num_drv/2; i++) { 153 /* Get list of all paths to the requested port. */ 154 if (front_flag) { 155 if (port_a_flag) { 156 if ((err = g_get_port_multipath( 157 l_state->drv_front[i].g_disk_state.port_a_wwn_s, 158 &p_list, verbose)) != 0) { 159 (void) l_free_lstate(&l_state); 160 return (err); 161 } 162 } else { 163 if ((err = g_get_port_multipath( 164 l_state->drv_front[i].g_disk_state.port_b_wwn_s, 165 &p_list, verbose)) != 0) { 166 (void) l_free_lstate(&l_state); 167 return (err); 168 } 169 } 170 } else { 171 if (port_a_flag) { 172 if ((err = g_get_port_multipath( 173 l_state->drv_rear[i].g_disk_state.port_a_wwn_s, 174 &p_list, verbose)) != 0) { 175 (void) l_free_lstate(&l_state); 176 return (err); 177 } 178 } else { 179 if ((err = g_get_port_multipath( 180 l_state->drv_rear[i].g_disk_state.port_b_wwn_s, 181 &p_list, verbose)) != 0) { 182 (void) l_free_lstate(&l_state); 183 return (err); 184 } 185 } 186 } 187 if (err = d_offline_drive(p_list, 188 bsy_res_flag_p, verbose)) { 189 (void) g_free_multipath(p_list); 190 (void) l_free_lstate(&l_state); 191 return (err); 192 } 193 (void) g_free_multipath(p_list); 194 } 195 (void) l_free_lstate(&l_state); 196 return (0); 197 } 198 199 200 201 /* 202 * Request the enclosure services controller (IB) 203 * to set the LRC (Loop Redundancy Circuit) to the 204 * bypassed/enabled state for the backplane specified by 205 * the a and f flag and the enclosure or pathname. 206 */ 207 int 208 l_bp_bypass_enable(char *ses_path, int bypass_flag, int port_a_flag, 209 int front_flag, int force_flag, int verbose) 210 { 211 212 int fd, i; 213 int nobj = 0; 214 ses_objarg obj; 215 ses_object *all_objp = NULL, *all_objp_save = NULL; 216 int found = 0; 217 Bp_elem_st *bp; 218 char msg[MAXPATHLEN]; 219 int bsy_res_flag = 0; 220 int err; 221 222 if (ses_path == NULL) { 223 return (L_NO_SES_PATH); 224 } 225 226 /* 227 * Check for reservation and busy for all disks on this 228 * backplane. 229 */ 230 231 if (!force_flag && bypass_flag) { 232 if (err = l_check_busy_reserv_bp(ses_path, 233 front_flag, port_a_flag, &bsy_res_flag, verbose)) { 234 return (err); 235 } 236 if (bsy_res_flag) { 237 return (L_BP_BUSY_RESERVED); 238 } 239 } 240 241 242 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 243 return (errno); 244 } 245 246 if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t)&nobj) < 0) { 247 (void) close(fd); 248 return (errno); 249 } 250 if (nobj == 0) { 251 (void) close(fd); 252 return (L_IB_NO_ELEM_FOUND); 253 } 254 255 E_DPRINTF(" l_ib_bypass_bp: Number of SES objects: 0x%x\n", 256 nobj); 257 258 /* alloc some memory for the objmap */ 259 if ((all_objp = g_zalloc((nobj + 1) * sizeof (ses_object))) == NULL) { 260 (void) close(fd); 261 return (errno); 262 } 263 264 all_objp_save = all_objp; 265 266 if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t)all_objp) < 0) { 267 (void) close(fd); 268 (void) g_destroy_data(all_objp_save); 269 return (errno); 270 } 271 272 for (i = 0; i < nobj; i++, all_objp++) { 273 E_DPRINTF(" ID 0x%x\t Element type 0x%x\n", 274 all_objp->obj_id, all_objp->elem_type); 275 if (all_objp->elem_type == ELM_TYP_BP) { 276 found++; 277 break; 278 } 279 } 280 281 if (found == 0) { 282 (void) close(fd); 283 (void) g_destroy_data(all_objp_save); 284 return (L_NO_BP_ELEM_FOUND); 285 } 286 287 /* 288 * We found the backplane element. 289 */ 290 291 292 if (verbose) { 293 /* Get the status for backplane #0 */ 294 obj.obj_id = all_objp->obj_id; 295 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) { 296 (void) close(fd); 297 (void) g_destroy_data(all_objp_save); 298 return (errno); 299 } 300 (void) fprintf(stdout, MSGSTR(8000, 301 " Front backplane status: ")); 302 bp = (struct bp_element_status *)&obj.cstat[0]; 303 l_element_msg_string(bp->code, msg); 304 (void) fprintf(stdout, "%s\n", msg); 305 if (bp->byp_a_enabled || bp->en_bypass_a) { 306 (void) fprintf(stdout, " "); 307 (void) fprintf(stdout, 308 MSGSTR(130, "Bypass A enabled")); 309 (void) fprintf(stdout, ".\n"); 310 } 311 if (bp->byp_b_enabled || bp->en_bypass_b) { 312 (void) fprintf(stdout, " "); 313 (void) fprintf(stdout, 314 MSGSTR(129, "Bypass B enabled")); 315 (void) fprintf(stdout, ".\n"); 316 } 317 318 all_objp++; 319 obj.obj_id = all_objp->obj_id; 320 all_objp--; 321 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) { 322 (void) close(fd); 323 (void) g_destroy_data(all_objp_save); 324 return (errno); 325 } 326 (void) fprintf(stdout, MSGSTR(8001, 327 " Rear backplane status: ")); 328 bp = (struct bp_element_status *)&obj.cstat[0]; 329 l_element_msg_string(bp->code, msg); 330 (void) fprintf(stdout, "%s\n", msg); 331 if (bp->byp_a_enabled || bp->en_bypass_a) { 332 (void) fprintf(stdout, " "); 333 (void) fprintf(stdout, 334 MSGSTR(130, "Bypass A enabled")); 335 (void) fprintf(stdout, ".\n"); 336 } 337 if (bp->byp_b_enabled || bp->en_bypass_b) { 338 (void) fprintf(stdout, " "); 339 (void) fprintf(stdout, 340 MSGSTR(129, "Bypass B enabled")); 341 (void) fprintf(stdout, ".\n"); 342 } 343 } 344 345 /* Get the current status */ 346 if (!front_flag) { 347 all_objp++; 348 } 349 obj.obj_id = all_objp->obj_id; 350 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) { 351 (void) close(fd); 352 (void) g_destroy_data(all_objp_save); 353 return (errno); 354 } 355 /* Do the requested action. */ 356 bp = (struct bp_element_status *)&obj.cstat[0]; 357 bp->select = 1; 358 bp->code = 0; 359 if (port_a_flag) { 360 bp->en_bypass_a = bypass_flag; 361 } else { 362 bp->en_bypass_b = bypass_flag; 363 } 364 if (getenv("_LUX_E_DEBUG") != NULL) { 365 (void) printf(" Sending this structure to ID 0x%x" 366 " of type 0x%x\n", 367 obj.obj_id, all_objp->elem_type); 368 for (i = 0; i < 4; i++) { 369 (void) printf(" Byte %d 0x%x\n", i, 370 obj.cstat[i]); 371 } 372 } 373 374 if (ioctl(fd, SESIOC_SETOBJSTAT, (caddr_t)&obj) < 0) { 375 (void) close(fd); 376 (void) g_destroy_data(all_objp_save); 377 return (errno); 378 } 379 380 (void) g_destroy_data(all_objp_save); 381 (void) close(fd); 382 383 return (0); 384 } 385 386 387 388 389 /* 390 * This function will request the enclosure services 391 * controller (IB) to set the LRC (Loop Redundancy Circuit) to the 392 * bypassed/enabled state for the device specified by the 393 * enclosure,dev or pathname and the port specified by the a 394 * flag. 395 */ 396 397 int 398 l_dev_bypass_enable(struct path_struct *path_struct, int bypass_flag, 399 int force_flag, int port_a_flag, int verbose) 400 { 401 gfc_map_t map; 402 char ses_path[MAXPATHLEN]; 403 uchar_t *page_buf; 404 int err, fd, front_index, rear_index, offset; 405 int pathcnt = 1; 406 unsigned short page_len; 407 struct device_element *elem; 408 L_state *l_state = NULL; 409 struct device_element status; 410 int bsy_flag = 0, i, f_flag; 411 struct dlist *p_list; 412 char temppath[MAXPATHLEN]; 413 mp_pathlist_t pathlist; 414 int p_pw = 0, p_on = 0, p_st = 0; 415 L_inquiry inq; 416 417 if (path_struct == NULL) { 418 return (L_INVALID_PATH_FORMAT); 419 } 420 421 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) { 422 return (L_MALLOC_FAILED); 423 } 424 map.dev_addr = (gfc_port_dev_info_t *)NULL; 425 (void) strcpy(temppath, path_struct->p_physical_path); 426 if ((strstr(path_struct->p_physical_path, SCSI_VHCI) != NULL) && 427 (!g_get_pathlist(temppath, &pathlist))) { 428 pathcnt = pathlist.path_count; 429 p_pw = p_on = p_st = 0; 430 for (i = 0; i < pathcnt; i++) { 431 if (pathlist.path_info[i].path_state < 432 MAXPATHSTATE) { 433 if (strstr(pathlist.path_info[i]. 434 path_addr, 435 path_struct->argv) != NULL) { 436 p_pw = i; 437 break; 438 } 439 if (pathlist.path_info[i].path_state == 440 MDI_PATHINFO_STATE_ONLINE) { 441 p_on = i; 442 } 443 if (pathlist.path_info[i].path_state == 444 MDI_PATHINFO_STATE_STANDBY) { 445 p_st = i; 446 } 447 } 448 } 449 if (strstr(pathlist.path_info[p_pw].path_addr, 450 path_struct->argv) != NULL) { 451 /* matching input pwwn */ 452 (void) strcpy(temppath, 453 pathlist.path_info[p_pw].path_hba); 454 } else if (pathlist.path_info[p_on].path_state == 455 MDI_PATHINFO_STATE_ONLINE) { 456 /* on_line path */ 457 (void) strcpy(temppath, 458 pathlist.path_info[p_on].path_hba); 459 } else { 460 /* standby or path0 */ 461 (void) strcpy(temppath, 462 pathlist.path_info[p_st].path_hba); 463 } 464 free(pathlist.path_info); 465 (void) strcat(temppath, FC_CTLR); 466 } 467 468 /* 469 * Need to get a valid location, front/rear & slot. 470 * 471 * The path_struct will return a valid slot 472 * and the IB path or a disk path. 473 */ 474 475 if (!path_struct->ib_path_flag) { 476 if (err = g_get_dev_map(temppath, &map, verbose)) { 477 (void) l_free_lstate(&l_state); 478 return (err); 479 } 480 if (err = l_get_ses_path(path_struct->p_physical_path, 481 ses_path, &map, verbose)) { 482 (void) l_free_lstate(&l_state); 483 free((void *)map.dev_addr); 484 return (err); 485 } 486 } else { 487 (void) strcpy(ses_path, path_struct->p_physical_path); 488 } 489 if (!path_struct->slot_valid) { 490 if ((map.dev_addr == (gfc_port_dev_info_t *)NULL) && 491 ((err = g_get_dev_map(temppath, 492 &map, verbose)) != 0)) { 493 (void) l_free_lstate(&l_state); 494 return (err); 495 } 496 if ((err = l_get_ses_path(path_struct->p_physical_path, 497 ses_path, &map, verbose)) != 0) { 498 (void) l_free_lstate(&l_state); 499 free((void *)map.dev_addr); 500 return (err); 501 } 502 if ((err = l_get_status(ses_path, l_state, verbose)) != 0) { 503 (void) l_free_lstate(&l_state); 504 free((void *)map.dev_addr); 505 return (err); 506 } 507 508 /* We are passing the disks path */ 509 if ((err = l_get_slot(path_struct, l_state, verbose)) != 0) { 510 (void) l_free_lstate(&l_state); 511 free((void *)map.dev_addr); 512 return (err); 513 } 514 } 515 516 if (map.dev_addr != (gfc_port_dev_info_t *)NULL) { 517 free((void *)map.dev_addr); 518 } 519 520 if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) { 521 (void) l_free_lstate(&l_state); 522 return (errno); 523 } 524 525 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) { 526 (void) g_destroy_data(page_buf); 527 (void) l_free_lstate(&l_state); 528 return (errno); 529 } 530 531 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH, 532 L_PAGE_2, verbose)) { 533 (void) close(fd); 534 (void) g_destroy_data(page_buf); 535 (void) l_free_lstate(&l_state); 536 return (err); 537 } 538 539 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN; 540 541 /* Get index to the disk we are interested in */ 542 if (err = l_get_status(ses_path, l_state, verbose)) { 543 (void) close(fd); 544 (void) g_destroy_data(page_buf); 545 (void) l_free_lstate(&l_state); 546 return (err); 547 } 548 /* 549 * Now that we have the status check to see if 550 * busy or reserved, if bypassing. 551 */ 552 if ((!(force_flag | path_struct->ib_path_flag)) && 553 bypass_flag) { 554 i = path_struct->slot; 555 f_flag = path_struct->f_flag; 556 557 /* 558 * Check for reservation and busy 559 */ 560 if ((f_flag && 561 (l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] & 562 L_RESERVED)) || (!f_flag && 563 (l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] & 564 L_RESERVED))) { 565 (void) close(fd); 566 (void) g_destroy_data(page_buf); 567 (void) l_free_lstate(&l_state); 568 return (L_BP_RESERVED); 569 } 570 if (f_flag) { 571 if (port_a_flag) { 572 if ((err = g_get_port_multipath( 573 l_state->drv_front[i].g_disk_state.port_a_wwn_s, 574 &p_list, verbose)) != 0) { 575 (void) close(fd); 576 (void) g_destroy_data(page_buf); 577 (void) l_free_lstate(&l_state); 578 return (err); 579 } 580 } else { 581 if ((err = g_get_port_multipath( 582 l_state->drv_front[i].g_disk_state.port_b_wwn_s, 583 &p_list, verbose)) != 0) { 584 (void) close(fd); 585 (void) g_destroy_data(page_buf); 586 (void) l_free_lstate(&l_state); 587 return (err); 588 } 589 } 590 } else { 591 if (port_a_flag) { 592 if ((err = g_get_port_multipath( 593 l_state->drv_rear[i].g_disk_state.port_a_wwn_s, 594 &p_list, verbose)) != 0) { 595 (void) close(fd); 596 (void) g_destroy_data(page_buf); 597 (void) l_free_lstate(&l_state); 598 return (err); 599 } 600 } else { 601 if ((err = g_get_port_multipath( 602 l_state->drv_rear[i].g_disk_state.port_b_wwn_s, 603 &p_list, verbose)) != 0) { 604 (void) close(fd); 605 (void) g_destroy_data(page_buf); 606 (void) l_free_lstate(&l_state); 607 return (err); 608 } 609 } 610 } 611 if (err = d_offline_drive(p_list, 612 &bsy_flag, verbose)) { 613 (void) g_free_multipath(p_list); 614 (void) close(fd); 615 (void) g_destroy_data(page_buf); 616 (void) l_free_lstate(&l_state); 617 return (err); 618 } 619 (void) g_free_multipath(p_list); 620 if (bsy_flag) { 621 (void) close(fd); 622 (void) g_destroy_data(page_buf); 623 (void) l_free_lstate(&l_state); 624 return (L_BP_BUSY); 625 } 626 } 627 628 if (err = l_get_disk_element_index(l_state, &front_index, 629 &rear_index)) { 630 (void) close(fd); 631 (void) g_destroy_data(page_buf); 632 (void) l_free_lstate(&l_state); 633 return (err); 634 } 635 636 if (g_get_inquiry(ses_path, &inq)) { 637 return (L_SCSI_ERROR); 638 } 639 640 /* Skip global element */ 641 front_index++; 642 if ((strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME, 643 strlen(DAK_OFF_NAME)) == 0) || 644 (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR, 645 strlen(DAK_PROD_STR)) == 0)) { 646 rear_index += (MAX_DRIVES_DAK/2) + 1; 647 } else { 648 rear_index++; 649 } 650 651 if (path_struct->f_flag) { 652 offset = (8 + (front_index + path_struct->slot)*4); 653 } else { 654 offset = (8 + (rear_index + path_struct->slot)*4); 655 } 656 657 elem = (struct device_element *)(page_buf + offset); 658 /* 659 * now do requested action. 660 */ 661 bcopy((const void *)elem, (void *)&status, 662 sizeof (struct device_element)); /* save status */ 663 bzero(elem, sizeof (struct device_element)); 664 elem->select = 1; 665 elem->dev_off = status.dev_off; 666 elem->en_bypass_a = status.en_bypass_a; 667 elem->en_bypass_b = status.en_bypass_b; 668 669 /* Do requested action */ 670 if (port_a_flag) { 671 elem->en_bypass_a = bypass_flag; 672 } else { 673 elem->en_bypass_b = bypass_flag; 674 } 675 676 if (getenv("_LUX_E_DEBUG") != NULL) { 677 g_dump(" l_dev_bypass_enable: Updating LRC circuit state:\n" 678 " Device Status Element ", 679 (uchar_t *)elem, sizeof (struct device_element), 680 HEX_ONLY); 681 (void) fprintf(stdout, " for device at location:" 682 " enclosure:%s slot:%d %s\n", 683 l_state->ib_tbl.enclosure_name, 684 path_struct->slot, 685 path_struct->f_flag ? "front" : "rear"); 686 } 687 if (err = g_scsi_send_diag_cmd(fd, 688 (uchar_t *)page_buf, page_len)) { 689 (void) close(fd); 690 (void) g_destroy_data(page_buf); 691 (void) l_free_lstate(&l_state); 692 return (err); 693 } 694 695 (void) close(fd); 696 (void) g_destroy_data(page_buf); 697 (void) l_free_lstate(&l_state); 698 return (0); 699 } 700 701 702 703 /* 704 * Issue a Loop Port enable Primitive sequence 705 * to the device specified by the pathname. 706 */ 707 int 708 d_p_enable(char *path, int verbose) 709 /*ARGSUSED*/ 710 { 711 712 return (0); 713 } 714 715 /* 716 * Issue a Loop Port Bypass Primitive sequence 717 * to the device specified by the pathname. This requests the 718 * device to set its L_Port into the bypass mode. 719 */ 720 int 721 d_p_bypass(char *path, int verbose) 722 /*ARGSUSED*/ 723 { 724 725 return (0); 726 } 727