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 28 29 /*LINTLIBRARY*/ 30 31 /* 32 * This module is part of the Fibre Channel Interface library. 33 * 34 */ 35 36 /* 37 * I18N message number ranges 38 * This file: 10500 - 10999 39 * Shared common messages: 1 - 1999 40 */ 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 <string.h> 51 #include <errno.h> 52 #include <assert.h> 53 #include <unistd.h> 54 #include <sys/types.h> 55 #include <sys/param.h> 56 #include <sys/dklabel.h> 57 #include <sys/autoconf.h> 58 #include <sys/utsname.h> 59 #include <sys/ddi.h> /* for min */ 60 #include <ctype.h> /* for isprint */ 61 #include <sys/scsi/scsi.h> 62 #include <dirent.h> /* for DIR */ 63 #include <nl_types.h> 64 #include <locale.h> 65 #include <thread.h> 66 #include <synch.h> 67 #include <l_common.h> 68 #include <stgcom.h> 69 #include <l_error.h> 70 #include <g_state.h> 71 #include <libdevinfo.h> 72 73 74 /* Defines */ 75 #define BYTES_PER_LINE 16 /* # of bytes to dump per line */ 76 #define SCMD_UNKNOWN 0xff 77 78 /* Bus strings - for internal use by g_get_path_type() only */ 79 #define PCI_BUS 1 80 #define SBUS 2 81 82 struct str_type { 83 char *string; 84 uint_t type; 85 }; 86 87 static struct str_type ValidBusStrings[] = { 88 {"pci@", PCI_BUS}, 89 {"sbus@", SBUS}, 90 {NULL, 0} 91 }; 92 93 94 /* 95 * Strings below were used before cougar driver(qlc) was proposed. 96 * {"scsi/", FC_PCI_FCA}, 97 * {"fibre-channel/", FC_PCI_FCA}, 98 */ 99 static struct str_type ValidFCAstrings[] = { 100 {"SUNW,ifp@", FC4_PCI_FCA | FC4_IFP_XPORT}, 101 {"SUNW,socal@", FC4_SOCAL_FCA}, 102 {NULL, 0} 103 }; 104 105 static struct str_type ValidXportStrings[] = { 106 {"/sf@", FC4_SF_XPORT}, 107 {"/fp@", FC_GEN_XPORT}, 108 {NULL, 0} 109 }; 110 111 struct _enclDisk { 112 char *vid; 113 char *pid; 114 }; 115 116 /* 117 * SENA/SUNWGS type enclosure disk table. This table contains vendor IDs and 118 * the non-unique portion of the product identifier sufficient for 119 * comparison. This table needs to be updated as new drives are supported 120 * in the SENA/SUNWGS type enclosures that do not have a corresponding match 121 * in this table. Currently, the v880 and v890 are the only shipping products 122 * that utilize the SUNWGS type enclosure. SENA is EOL'd. The risk of new 123 * devices being added that do not match an entry in this table is small but it 124 * does exist. 125 */ 126 static struct _enclDisk enclDiskTbl[] = { 127 {"SUN", "SENA"}, 128 {"SUN", "SUNWGS"}, 129 {"FUJITSU", "MA"}, 130 {"HITACHI", "DK"}, 131 {"HITACHI", "HU"}, 132 {"SEAGATE", "ST"}, 133 {NULL, NULL} 134 }; 135 136 137 /* i18n */ 138 nl_catd l_catd; 139 140 141 /* Internal Functions */ 142 static void string_dump(char *, uchar_t *, int, int, char msg_string[]); 143 144 /* 145 * Allocate space for and return a pointer to a string 146 * on the stack. If the string is null, create 147 * an empty string. 148 * Use g_destroy_data() to free when no longer used. 149 */ 150 char * 151 g_alloc_string(char *s) 152 { 153 char *ns; 154 155 if (s == (char *)NULL) { 156 ns = (char *)g_zalloc(1); 157 } else { 158 ns = (char *)g_zalloc(strlen(s) + 1); 159 if (ns != NULL) { 160 (void) strncpy(ns, s, (strlen(s) + 1)); 161 } 162 } 163 return (ns); 164 } 165 166 167 /* 168 * This routine is a wrapper for free. 169 */ 170 void 171 g_destroy_data(void *data) 172 { 173 A_DPRINTF(" g_destroy_data: Free\'ed buffer at 0x%x\n", 174 data); 175 free((void *)data); 176 } 177 178 179 /* 180 * Dump a structure in hexadecimal. 181 */ 182 void 183 g_dump(char *hdr, uchar_t *src, int nbytes, int format) 184 { 185 int i; 186 int n; 187 char *p; 188 char s[256]; 189 190 assert(format == HEX_ONLY || format == HEX_ASCII); 191 192 (void) strcpy(s, hdr); 193 for (p = s; *p; p++) { 194 *p = ' '; 195 } 196 197 p = hdr; 198 while (nbytes > 0) { 199 (void) fprintf(stdout, "%s", p); 200 p = s; 201 n = min(nbytes, BYTES_PER_LINE); 202 for (i = 0; i < n; i++) { 203 (void) fprintf(stdout, "%02x ", src[i] & 0xff); 204 } 205 if (format == HEX_ASCII) { 206 for (i = BYTES_PER_LINE-n; i > 0; i--) { 207 (void) fprintf(stdout, " "); 208 } 209 (void) fprintf(stdout, " "); 210 for (i = 0; i < n; i++) { 211 (void) fprintf(stdout, "%c", 212 isprint(src[i]) ? src[i] : '.'); 213 } 214 } 215 (void) fprintf(stdout, "\n"); 216 nbytes -= n; 217 src += n; 218 } 219 } 220 221 /* 222 * Internal routine to clean up ../'s in paths. 223 * returns 0 if no "../" are left. 224 * 225 * Wouldn't it be nice if there was a standard system library 226 * routine to do this...? 227 */ 228 static int 229 cleanup_dotdot_path(char *path) 230 { 231 char holder[MAXPATHLEN]; 232 char *dotdot; 233 char *previous_slash; 234 235 /* Find the first "/../" in the string */ 236 dotdot = strstr(path, "/../"); 237 if (dotdot == NULL) { 238 return (0); 239 } 240 241 242 /* 243 * If the [0] character is '/' and "../" immediatly 244 * follows it, then we can strip the ../ 245 * 246 * /../../foo/bar == /foo/bar 247 * 248 */ 249 if (dotdot == path) { 250 strcpy(holder, &path[3]); /* strip "/.." */ 251 strcpy(path, holder); 252 return (1); 253 } 254 255 /* 256 * Now look for the LAST "/" before the "/../" 257 * as this is the parent dir we can get rid of. 258 * We do this by temporarily truncating the string 259 * at the '/' just before "../" using the dotdot pointer. 260 */ 261 *dotdot = '\0'; 262 previous_slash = strrchr(path, '/'); 263 if (previous_slash == NULL) { 264 /* 265 * hmm, somethings wrong. path looks something 266 * like "foo/../bar/" so we can't really deal with it. 267 */ 268 return (0); 269 } 270 /* 271 * Now truncate the path just after the previous '/' 272 * and slam everything after the "../" back on 273 */ 274 *(previous_slash+1) = '\0'; 275 strcat(path, dotdot+4); 276 return (1); /* We may have more "../"s */ 277 } 278 279 280 /* 281 * Follow symbolic links from the logical device name to 282 * the /devfs physical device name. To be complete, we 283 * handle the case of multiple links. This function 284 * either returns NULL (no links, or some other error), 285 * or the physical device name, alloc'ed on the heap. 286 * 287 * NOTE: If the path is relative, it will be forced into 288 * an absolute path by pre-pending the pwd to it. 289 */ 290 char * 291 g_get_physical_name_from_link(char *path) 292 { 293 struct stat stbuf; 294 char source[MAXPATHLEN]; 295 char scratch[MAXPATHLEN]; 296 char pwd[MAXPATHLEN]; 297 char *tmp; 298 int cnt; 299 300 /* return NULL if path is NULL */ 301 if (path == NULL) { 302 return (NULL); 303 } 304 305 strcpy(source, path); 306 for (;;) { 307 308 /* 309 * First make sure the path is absolute. If not, make it. 310 * If it's already an absolute path, we have no need 311 * to determine the cwd, so the program should still 312 * function within security-by-obscurity directories. 313 */ 314 if (source[0] != '/') { 315 tmp = getcwd(pwd, MAXPATHLEN); 316 if (tmp == NULL) { 317 O_DPRINTF("getcwd() failed - %s\n", 318 strerror(errno)); 319 return (NULL); 320 } 321 /* 322 * Handle special case of "./foo/bar" 323 */ 324 if (source[0] == '.' && source[1] == '/') { 325 strcpy(scratch, source+2); 326 } else { /* no "./" so just take everything */ 327 strcpy(scratch, source); 328 } 329 strcpy(source, pwd); 330 strcat(source, "/"); 331 strcat(source, scratch); 332 } 333 334 /* 335 * Clean up any "../"s that are in the path 336 */ 337 while (cleanup_dotdot_path(source)); 338 339 /* 340 * source is now an absolute path to the link we're 341 * concerned with 342 * 343 * See if there's a real file out there. If not, 344 * we have a dangling link and we ignore it. 345 */ 346 347 if (stat(source, &stbuf) == -1) { 348 O_DPRINTF("stat() failed for %s- %s\n", 349 source, strerror(errno)); 350 return (NULL); 351 } 352 if (lstat(source, &stbuf) == -1) { 353 O_DPRINTF("lstat() failed for - %s\n", 354 source, strerror(errno)); 355 return (NULL); 356 } 357 /* 358 * If the file is not a link, we're done one 359 * way or the other. If there were links, 360 * return the full pathname of the resulting 361 * file. 362 * 363 * Note: All of our temp's are on the stack, 364 * so we have to copy the final result to the heap. 365 */ 366 if (!S_ISLNK(stbuf.st_mode)) { 367 return (g_alloc_string(source)); 368 } 369 cnt = readlink(source, scratch, sizeof (scratch)); 370 if (cnt < 0) { 371 O_DPRINTF("readlink() failed - %s\n", 372 strerror(errno)); 373 return (NULL); 374 } 375 /* 376 * scratch is on the heap, and for some reason readlink 377 * doesn't always terminate things properly so we have 378 * to make certain we're properly terminated 379 */ 380 scratch[cnt] = '\0'; 381 382 /* 383 * Now check to see if the link is relative. If so, 384 * then we have to append it to the directory 385 * which the source was in. (This is non trivial) 386 */ 387 if (scratch[0] != '/') { 388 tmp = strrchr(source, '/'); 389 if (tmp == NULL) { /* Whoa! Something's hosed! */ 390 O_DPRINTF("Internal error... corrupt path.\n"); 391 return (NULL); 392 } 393 /* Now strip off just the directory path */ 394 *(tmp+1) = '\0'; /* Keeping the last '/' */ 395 /* and append the new link */ 396 strcat(source, scratch); 397 /* 398 * Note: At this point, source should have "../"s 399 * but we'll clean it up in the next pass through 400 * the loop. 401 */ 402 } else { 403 /* It's an absolute link so no worries */ 404 strcpy(source, scratch); 405 } 406 } 407 /* Never reach here */ 408 } 409 410 /* 411 * Function for getting physical pathnames 412 * 413 * This function can handle 3 different inputs. 414 * 415 * 1) Inputs of the form cN 416 * This requires the program to search the /dev/rdsk 417 * directory for a device that is conected to the 418 * controller with number 'N' and then getting 419 * the physical pathname of the controller. 420 * The format of the controller pathname is 421 * /devices/.../.../SUNW,soc@x,x/SUNW,pln@xxxx,xxxxxxxx:ctlr 422 * The physical pathname is returned. 423 * 424 * 2) Inputs of the form /dev/rdsk/cNtNdNsN 425 * These are identified by being a link 426 * The physical path they are linked to is returned. 427 * 428 * 3) Inputs of the form /devices/... 429 * These are actual physical names. 430 * They are not converted. 431 */ 432 char * 433 g_get_physical_name(char *path) 434 { 435 struct stat stbuf; 436 char s[MAXPATHLEN]; 437 char namebuf[MAXPATHLEN]; 438 char savedir[MAXPATHLEN]; 439 char *result = NULL; 440 DIR *dirp; 441 struct dirent *entp; 442 char *dev_name, *char_ptr; 443 struct stat sb; 444 int found_flag = 0; 445 int status = 0; 446 int i; 447 448 /* return invalid path if path NULL */ 449 if (path == NULL) { 450 return (NULL); 451 } 452 453 (void) strcpy(s, path); 454 /* 455 * See if the form is cN 456 * Must handle scenaro where there is a file cN in this directory 457 * Bug ID: 1184633 458 * 459 * We could be in the /dev/rdsk directory and the file could be of 460 * the form cNdNsN (See man disks). 461 */ 462 status = stat(s, &stbuf); 463 if (((status == -1) && (errno == ENOENT)) || 464 ((s[0] == 'c') && ((int)strlen(s) > 1) && ((int)strlen(s) < 5))) { 465 /* 466 * Further qualify cN entry 467 */ 468 if ((s[0] != 'c') || ((int)strlen(s) <= 1) || 469 ((int)strlen(s) >= 5)) { 470 goto exit; 471 } 472 for (i = 1; i < (int)strlen(s); i++) { 473 if ((s[i] < '0') || (s[i] > '9')) { 474 goto exit; 475 } 476 } 477 /* 478 * path does not point to a file or file is of form cN 479 */ 480 P_DPRINTF(" g_get_physical_name: " 481 "Found entry of the form cN n=%s len=%d\n", 482 &s[1], strlen(s)); 483 484 dev_name = g_zalloc(sizeof ("/dev/rdsk")); 485 sprintf((char *)dev_name, "/dev/rdsk"); 486 487 if ((dirp = opendir(dev_name)) == NULL) { 488 g_destroy_data(dev_name); 489 goto exit; 490 } 491 492 while ((entp = readdir(dirp)) != NULL) { 493 if (strcmp(entp->d_name, ".") == 0 || 494 strcmp(entp->d_name, "..") == 0) 495 continue; 496 497 if (entp->d_name[0] != 'c') 498 /* 499 * Silently Ignore for now any names 500 * not stating with c 501 */ 502 continue; 503 504 sprintf(namebuf, "%s/%s", dev_name, entp->d_name); 505 506 if ((lstat(namebuf, &sb)) < 0) { 507 L_WARNINGS(MSGSTR(55, 508 "Warning: Cannot stat %s\n"), 509 namebuf); 510 continue; 511 } 512 513 if (!S_ISLNK(sb.st_mode)) { 514 L_WARNINGS(MSGSTR(56, 515 "Warning: %s is not a symbolic link\n"), 516 namebuf); 517 continue; 518 } 519 520 if (strstr(entp->d_name, s) != NULL) { 521 /* 522 * found link to device in /devices 523 * 524 * Further qualify to be sure I have 525 * not found entry of the form c10 526 * when I am searching for c1 527 */ 528 if (atoi(&s[1]) == atoi(&entp->d_name[1])) { 529 P_DPRINTF(" g_get_physical_name: " 530 "Found entry in /dev/rdsk matching %s: %s\n", 531 s, entp->d_name); 532 found_flag = 1; 533 break; 534 } 535 } 536 } 537 closedir(dirp); 538 g_destroy_data(dev_name); 539 540 if (found_flag) { 541 result = g_get_physical_name_from_link(namebuf); 542 if (result == NULL) { 543 goto exit; 544 } 545 /* 546 * Convert from device name to controller name 547 */ 548 char_ptr = strrchr(result, '/'); 549 *char_ptr = '\0'; /* Terminate sting */ 550 (void) strcat(result, CTLR_POSTFIX); 551 } 552 goto exit; 553 } 554 if (status == -1) 555 goto exit; 556 557 if (lstat(s, &stbuf) == -1) { 558 L_WARNINGS(MSGSTR(134, 559 "%s: lstat() failed - %s\n"), 560 s, strerror(errno)); 561 goto exit; 562 } 563 /* 564 */ 565 if (!S_ISLNK(stbuf.st_mode)) { 566 /* 567 * Path is not a linked file so must be 568 * a physical path 569 */ 570 if (S_ISCHR(stbuf.st_mode) || S_ISDIR(stbuf.st_mode)) { 571 /* Make sure a full path as that is required. */ 572 if (strstr(s, "/devices")) { 573 result = g_alloc_string(s); 574 } else { 575 if (getcwd(savedir, 576 sizeof (savedir)) == NULL) { 577 return (NULL); 578 } 579 /* 580 * Check for this format: 581 * ./ssd@0,1:g,raw 582 */ 583 if (s[0] == '.') { 584 strcat(savedir, &s[1]); 585 } else { 586 strcat(savedir, "/"); 587 strcat(savedir, s); 588 } 589 result = g_alloc_string(savedir); 590 } 591 } 592 } else { 593 /* 594 * Entry is linked file 595 * so follow link to physical name 596 */ 597 result = g_get_physical_name_from_link(path); 598 } 599 600 exit: 601 return (result); 602 } 603 604 /* 605 * Function to open a device 606 */ 607 int 608 g_object_open(char *path, int flag) 609 { 610 int fd = -1, retry = 0; 611 if (getenv("_LUX_O_DEBUG") != NULL) { 612 (void) printf(" Object_open:%s ", path); 613 if (flag & O_WRONLY) { 614 (void) printf("O_WRONLY,"); 615 } else if (flag & O_RDWR) { 616 (void) printf("O_RDWR,"); 617 } else { 618 (void) printf("O_RDONLY,"); 619 } 620 if (flag & O_NDELAY) { 621 (void) printf("O_NDELAY,"); 622 } 623 if (flag & O_APPEND) { 624 (void) printf("O_APPEND,"); 625 } 626 if (flag & O_DSYNC) { 627 (void) printf("O_DSYNC,"); 628 } 629 if (flag & O_RSYNC) { 630 (void) printf("O_RSYNC,"); 631 } 632 if (flag & O_SYNC) { 633 (void) printf("O_SYNC,"); 634 } 635 if (flag & O_NOCTTY) { 636 (void) printf("O_NOCTTY,"); 637 } 638 if (flag & O_CREAT) { 639 (void) printf("O_CREAT,"); 640 } 641 if (flag & O_EXCL) { 642 (void) printf("O_EXCL,"); 643 } 644 if (flag & O_TRUNC) { 645 (void) printf("O_TRUNC,"); 646 } 647 (void) printf("\n"); 648 } 649 650 /* Open retries introduced due to bugid 4473337 */ 651 errno = 0; 652 fd = open(path, flag); 653 while (fd < 0 && retry++ < RETRY_OBJECT_OPEN && ( 654 errno == EBUSY || errno == EAGAIN)) { 655 O_DPRINTF(" Object_open: Retried:%d %d %s\n", 656 retry, errno, path); 657 (void) usleep(WAIT_OBJECT_OPEN); 658 fd = open(path, flag); 659 } 660 if (fd < 0) { 661 O_DPRINTF(" Object_open: Open failed:%s\n", path); 662 } 663 return (fd); 664 } 665 666 667 /* 668 * Return a pointer to a string telling us the name of the command. 669 */ 670 char * 671 g_scsi_find_command_name(int cmd) 672 { 673 /* 674 * Names of commands. Must have SCMD_UNKNOWN at end of list. 675 */ 676 struct scsi_command_name { 677 int command; 678 char *name; 679 } scsi_command_names[29]; 680 681 register struct scsi_command_name *c; 682 683 scsi_command_names[0].command = SCMD_TEST_UNIT_READY; 684 scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready"); 685 686 scsi_command_names[1].command = SCMD_FORMAT; 687 scsi_command_names[1].name = MSGSTR(110, "Format"); 688 689 scsi_command_names[2].command = SCMD_REASSIGN_BLOCK; 690 scsi_command_names[2].name = MSGSTR(77, "Reassign Block"); 691 692 scsi_command_names[3].command = SCMD_READ; 693 scsi_command_names[3].name = MSGSTR(27, "Read"); 694 695 scsi_command_names[4].command = SCMD_WRITE; 696 scsi_command_names[4].name = MSGSTR(54, "Write"); 697 698 scsi_command_names[5].command = SCMD_READ_G1; 699 scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)"); 700 701 scsi_command_names[6].command = SCMD_WRITE_G1; 702 scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)"); 703 704 scsi_command_names[7].command = SCMD_MODE_SELECT; 705 scsi_command_names[7].name = MSGSTR(97, "Mode Select"); 706 707 scsi_command_names[8].command = SCMD_MODE_SENSE; 708 scsi_command_names[8].name = MSGSTR(95, "Mode Sense"); 709 710 scsi_command_names[9].command = SCMD_REASSIGN_BLOCK; 711 scsi_command_names[9].name = MSGSTR(77, "Reassign Block"); 712 713 scsi_command_names[10].command = SCMD_REQUEST_SENSE; 714 scsi_command_names[10].name = MSGSTR(74, "Request Sense"); 715 716 scsi_command_names[11].command = SCMD_READ_DEFECT_LIST; 717 scsi_command_names[11].name = MSGSTR(80, "Read Defect List"); 718 719 scsi_command_names[12].command = SCMD_INQUIRY; 720 scsi_command_names[12].name = MSGSTR(102, "Inquiry"); 721 722 scsi_command_names[13].command = SCMD_WRITE_BUFFER; 723 scsi_command_names[13].name = MSGSTR(53, "Write Buffer"); 724 725 scsi_command_names[14].command = SCMD_READ_BUFFER; 726 scsi_command_names[14].name = MSGSTR(82, "Read Buffer"); 727 728 scsi_command_names[15].command = SCMD_START_STOP; 729 scsi_command_names[15].name = MSGSTR(67, "Start/Stop"); 730 731 scsi_command_names[16].command = SCMD_RESERVE; 732 scsi_command_names[16].name = MSGSTR(72, "Reserve"); 733 734 scsi_command_names[17].command = SCMD_RELEASE; 735 scsi_command_names[17].name = MSGSTR(75, "Release"); 736 737 scsi_command_names[18].command = SCMD_MODE_SENSE_G1; 738 scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)"); 739 740 scsi_command_names[19].command = SCMD_MODE_SELECT_G1; 741 scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)"); 742 743 scsi_command_names[20].command = SCMD_READ_CAPACITY; 744 scsi_command_names[20].name = MSGSTR(81, "Read Capacity"); 745 746 scsi_command_names[21].command = SCMD_SYNC_CACHE; 747 scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache"); 748 749 scsi_command_names[22].command = SCMD_READ_DEFECT_LIST; 750 scsi_command_names[22].name = MSGSTR(80, "Read Defect List"); 751 752 scsi_command_names[23].command = SCMD_GDIAG; 753 scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic"); 754 755 scsi_command_names[24].command = SCMD_SDIAG; 756 scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic"); 757 758 scsi_command_names[25].command = SCMD_PERS_RESERV_IN; 759 scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In"); 760 761 scsi_command_names[26].command = SCMD_PERS_RESERV_OUT; 762 scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out"); 763 764 scsi_command_names[27].command = SCMD_LOG_SENSE; 765 scsi_command_names[27].name = MSGSTR(10502, "Log Sense"); 766 767 scsi_command_names[28].command = SCMD_UNKNOWN; 768 scsi_command_names[28].name = MSGSTR(25, "Unknown"); 769 770 771 for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++) 772 if (c->command == cmd) 773 break; 774 return (c->name); 775 } 776 777 778 /* 779 * Function to create error message containing 780 * scsi request sense information 781 */ 782 783 void 784 g_scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, 785 int rqlen, char msg_string[], char *err_string) 786 { 787 int blkno; 788 789 switch (rq->es_key) { 790 case KEY_NO_SENSE: 791 (void) sprintf(msg_string, MSGSTR(91, "No sense error")); 792 break; 793 case KEY_RECOVERABLE_ERROR: 794 (void) sprintf(msg_string, MSGSTR(76, "Recoverable error")); 795 break; 796 case KEY_NOT_READY: 797 (void) sprintf(msg_string, 798 MSGSTR(10503, 799 "Device Not ready." 800 " Error: Random Retry Failed: %s\n."), 801 err_string); 802 break; 803 case KEY_MEDIUM_ERROR: 804 (void) sprintf(msg_string, MSGSTR(99, "Medium error")); 805 break; 806 case KEY_HARDWARE_ERROR: 807 (void) sprintf(msg_string, MSGSTR(106, "Hardware error")); 808 break; 809 case KEY_ILLEGAL_REQUEST: 810 (void) sprintf(msg_string, MSGSTR(103, "Illegal request")); 811 break; 812 case KEY_UNIT_ATTENTION: 813 (void) sprintf(msg_string, 814 MSGSTR(10504, 815 "Unit attention." 816 "Error: Random Retry Failed.\n")); 817 break; 818 case KEY_WRITE_PROTECT: 819 (void) sprintf(msg_string, MSGSTR(52, "Write protect error")); 820 break; 821 case KEY_BLANK_CHECK: 822 (void) sprintf(msg_string, MSGSTR(131, "Blank check error")); 823 break; 824 case KEY_VENDOR_UNIQUE: 825 (void) sprintf(msg_string, MSGSTR(58, "Vendor unique error")); 826 break; 827 case KEY_COPY_ABORTED: 828 (void) sprintf(msg_string, MSGSTR(123, "Copy aborted error")); 829 break; 830 case KEY_ABORTED_COMMAND: 831 (void) sprintf(msg_string, 832 MSGSTR(10505, 833 "Aborted command." 834 " Error: Random Retry Failed.\n")); 835 break; 836 case KEY_EQUAL: 837 (void) sprintf(msg_string, MSGSTR(117, "Equal error")); 838 break; 839 case KEY_VOLUME_OVERFLOW: 840 (void) sprintf(msg_string, MSGSTR(57, "Volume overflow")); 841 break; 842 case KEY_MISCOMPARE: 843 (void) sprintf(msg_string, MSGSTR(98, "Miscompare error")); 844 break; 845 case KEY_RESERVED: 846 (void) sprintf(msg_string, MSGSTR(10506, 847 "Reserved value found")); 848 break; 849 default: 850 (void) sprintf(msg_string, MSGSTR(59, "Unknown error")); 851 break; 852 } 853 854 (void) sprintf(&msg_string[strlen(msg_string)], 855 MSGSTR(10507, " during: %s"), 856 g_scsi_find_command_name(ucmd->uscsi_cdb[0])); 857 858 if (rq->es_valid) { 859 blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) | 860 (rq->es_info_3 << 8) | rq->es_info_4; 861 (void) sprintf(&msg_string[strlen(msg_string)], 862 MSGSTR(49, ": block %d (0x%x)"), blkno, blkno); 863 } 864 865 (void) sprintf(&msg_string[strlen(msg_string)], "\n"); 866 867 if (rq->es_add_len >= 6) { 868 (void) sprintf(&msg_string[strlen(msg_string)], 869 MSGSTR(132, " Additional sense: 0x%x ASC Qualifier: 0x%x\n"), 870 rq->es_add_code, rq->es_qual_code); 871 /* 872 * rq->es_add_info[ADD_SENSE_CODE], 873 * rq->es_add_info[ADD_SENSE_QUAL_CODE]); 874 */ 875 } 876 if (rq->es_key == KEY_ILLEGAL_REQUEST) { 877 string_dump(MSGSTR(47, " cmd: "), (uchar_t *)ucmd, 878 sizeof (struct uscsi_cmd), HEX_ONLY, msg_string); 879 string_dump(MSGSTR(48, " cdb: "), 880 (uchar_t *)ucmd->uscsi_cdb, 881 ucmd->uscsi_cdblen, HEX_ONLY, msg_string); 882 } 883 string_dump(MSGSTR(43, " sense: "), 884 (uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY, 885 msg_string); 886 rqlen = rqlen; /* not used */ 887 } 888 889 890 /* 891 * Special string dump for error message 892 */ 893 static void 894 string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[]) 895 { 896 int i; 897 int n; 898 char *p; 899 char s[256]; 900 901 assert(format == HEX_ONLY || format == HEX_ASCII); 902 903 (void) strcpy(s, hdr); 904 for (p = s; *p; p++) { 905 *p = ' '; 906 } 907 908 p = hdr; 909 while (nbytes > 0) { 910 (void) sprintf(&msg_string[strlen(msg_string)], 911 "%s", p); 912 p = s; 913 n = min(nbytes, BYTES_PER_LINE); 914 for (i = 0; i < n; i++) { 915 (void) sprintf(&msg_string[strlen(msg_string)], 916 "%02x ", 917 src[i] & 0xff); 918 } 919 if (format == HEX_ASCII) { 920 for (i = BYTES_PER_LINE-n; i > 0; i--) { 921 (void) sprintf(&msg_string[strlen(msg_string)], 922 " "); 923 } 924 (void) sprintf(&msg_string[strlen(msg_string)], 925 " "); 926 for (i = 0; i < n; i++) { 927 (void) sprintf(&msg_string[strlen(msg_string)], 928 "%c", 929 isprint(src[i]) ? src[i] : '.'); 930 } 931 } 932 (void) sprintf(&msg_string[strlen(msg_string)], "\n"); 933 nbytes -= n; 934 src += n; 935 } 936 } 937 938 939 940 /* 941 * This routine is a wrapper for malloc. It allocates pre-zeroed space, 942 * and checks the return value so the caller doesn't have to. 943 */ 944 void * 945 g_zalloc(int count) 946 { 947 void *ptr; 948 949 ptr = (void *) calloc(1, (unsigned)count); 950 A_DPRINTF(" g_zalloc: Allocated 0x%x bytes " 951 "at 0x%x\n", count, ptr); 952 953 return (ptr); 954 } 955 956 /* 957 * Open up the i18n catalog. 958 * Returns: 959 * 0 = O.K. 960 * -1 = Failed (Will revert to default strings) 961 */ 962 int 963 g_i18n_catopen(void) 964 { 965 static int fileopen = 0; 966 static mutex_t mp; 967 968 if (setlocale(LC_ALL, "") == NULL) { 969 (void) fprintf(stderr, 970 "Cannot operate in the locale requested. " 971 "Continuing in the default C locale\n"); 972 } 973 if (mutex_lock(&mp) != 0) { 974 return (-1); 975 } 976 if (!fileopen) { 977 l_catd = catopen("a5k_g_fc_i18n_cat", NL_CAT_LOCALE); 978 if (l_catd == (nl_catd)-1) { 979 (void) mutex_unlock(&mp); 980 return (-1); 981 } 982 fileopen = 1; 983 } 984 (void) mutex_unlock(&mp); 985 return (0); 986 } 987 988 /* Macro used by g_get_path_type() */ 989 #define GetMatch(s_ptr) \ 990 for (found = 0, search_arr_ptr = s_ptr; \ 991 search_arr_ptr->string != NULL; \ 992 search_arr_ptr++) {\ 993 if (strstr(path_ptr, search_arr_ptr->string) != NULL) {\ 994 found = 1;\ 995 break;\ 996 }\ 997 } 998 999 /* 1000 * Input : A NULL terminated string 1001 * This string is checked to be an absolute device path 1002 * Output : 1003 * The FCA type and Xport type if found in the path on success 1004 * 0 on Failure 1005 * 1006 * Examples of valid device strings : 1007 * 1008 * Non Fabric FC driver : 1009 * /devices/io-unit@f,e0200000/sbi@0,0/SUNW,socal@1,0/sf@1,0:ctlr 1010 * /devices/io-unit@f,e2200000/sbi@0,0/SUNW,socal@3,0/sf@0,0/ssd@20,0:c,raw 1011 * /devices/sbus@1f,0/SUNW,socal@0,0/sf@0,0:devctl 1012 * /devices/sbus@1f,0/SUNW,socal@2,0/sf@1,0/ssd@w2200002037110cbf,0:b,raw 1013 * /devices/pci@1f,4000/SUNW,ifp@4:devctl 1014 * /devices/pci@1f,4000/SUNW,ifp@2/ssd@w2100002037049ba0,0:c,raw 1015 * /devices/pci@6,4000/pci@2/SUNW,ifp@5/ssd@w210000203708b44f,0:c,raw 1016 * 1017 * Fabric FC driver (fp) : 1018 * - offical device path for Qlogic 2202 with proper FCODE 1019 * as of 12/99. 1020 * /devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl 1021 * /devices/pci@e,2000/pci@2/SUNW,qlc@4/fp@0,0:devctl 1022 * 1023 */ 1024 uint_t 1025 g_get_path_type(char *path) 1026 { 1027 uint_t path_type = 0; 1028 int i = 0, pathcnt = 1; 1029 char *path_ptr = path; 1030 struct str_type *search_arr_ptr; /* updated by GetMatch macro */ 1031 char found; /* Updated by GetMatch marco */ 1032 char drvr_path1[MAXPATHLEN]; 1033 mp_pathlist_t pathlist; 1034 int p_on = 0, p_st = 0; 1035 1036 /* Path passed must be an absolute device path */ 1037 if (strncmp(path_ptr, DEV_PREFIX, DEV_PREFIX_LEN) || 1038 (strlen(path_ptr) == DEV_PREFIX_LEN)) { 1039 return (0); /* Invalid path */ 1040 } 1041 1042 /* if mpxio device, need to convert from vhci to phci */ 1043 if (strstr(path, SCSI_VHCI)) { 1044 (void) strcpy(drvr_path1, path); 1045 if (g_get_pathlist(drvr_path1, &pathlist)) { 1046 return (0); 1047 } 1048 pathcnt = pathlist.path_count; 1049 p_on = p_st = 0; 1050 for (i = 0; i < pathcnt; i++) { 1051 if (pathlist.path_info[i].path_state < MAXPATHSTATE) { 1052 if (pathlist.path_info[i].path_state == 1053 MDI_PATHINFO_STATE_ONLINE) { 1054 p_on = i; 1055 break; 1056 } else if (pathlist.path_info[i].path_state == 1057 MDI_PATHINFO_STATE_STANDBY) { 1058 p_st = i; 1059 } 1060 } 1061 } 1062 if (pathlist.path_info[p_on].path_state == 1063 MDI_PATHINFO_STATE_ONLINE) { 1064 /* on_line path */ 1065 (void) strcpy(drvr_path1, 1066 pathlist.path_info[p_on].path_hba); 1067 } else { 1068 /* standby or path0 */ 1069 (void) strcpy(drvr_path1, 1070 pathlist.path_info[p_st].path_hba); 1071 } 1072 free(pathlist.path_info); 1073 path_ptr = drvr_path1; 1074 } 1075 1076 GetMatch(ValidBusStrings); 1077 if (found == 0) { 1078 /* No valid bus string - so not a valid path */ 1079 return (0); 1080 } 1081 1082 GetMatch(ValidFCAstrings); /* Check for a valid FCA string */ 1083 if (found != 0) { 1084 path_type |= search_arr_ptr->type; 1085 } 1086 1087 /* 1088 * continue to check xport even without valid FCA string. 1089 * This is to support 3rd party FCA vendor on Leadville stack. 1090 */ 1091 GetMatch(ValidXportStrings); /* Check for a valid transport str */ 1092 if (found == 0) { 1093 return (path_type); 1094 } else { 1095 /* 1096 * if leadville tranport is detected and fca is not set yet, 1097 * set fca flag to generic FC_FCA_MASK. 1098 */ 1099 if ((search_arr_ptr->type == FC_GEN_XPORT) && 1100 (!(path_type & FC_FCA_MASK))) { 1101 path_type |= FC_FCA_MASK; 1102 } 1103 } 1104 path_type |= search_arr_ptr->type; 1105 1106 /* 1107 * A quick sanity check to make sure that we dont have 1108 * a combination that is not possible 1109 */ 1110 if (((path_type & (FC4_FCA_MASK | FC_XPORT_MASK)) == 1111 path_type) || 1112 ((path_type & (FC_FCA_MASK | FC4_XPORT_MASK)) == 1113 path_type)) { 1114 path_type = 0; 1115 } 1116 1117 return (path_type); 1118 } 1119 1120 1121 /* 1122 * g_get_port_path(char *, portlist_t *) 1123 * Purpose: Find all port nexus paths for a particular driver 1124 * Input: portdrvr 1125 * set to name of driver for which to find the paths 1126 * Output: portlist 1127 * allocated structure to hold paths found 1128 * user must call g_free_portlist(portlist_t *) to 1129 * free allocated memory 1130 */ 1131 int 1132 g_get_port_path(char *portdrvr, portlist_t *portlist) 1133 { 1134 di_node_t root; 1135 di_node_t node; 1136 di_minor_t minor_node; 1137 char hbapathfound[MAXPATHLEN]; 1138 char *tmppath; 1139 struct stat buf; 1140 1141 /* return invalid argument if *portdrvr or *portlist is NULL */ 1142 if ((portdrvr == NULL) || (portlist == NULL)) { 1143 return (L_INVALID_ARG); 1144 } 1145 1146 /* Create a snapshot of the kernel device tree */ 1147 root = di_init("/", DINFOCPYALL); 1148 if (root == DI_NODE_NIL) { 1149 return (L_DEV_SNAPSHOT_FAILED); 1150 } 1151 1152 /* point to first node which matches portdrvr */ 1153 node = di_drv_first_node(portdrvr, root); 1154 if (node == DI_NODE_NIL) { 1155 /* 1156 * Could not find driver node 1157 */ 1158 (void) di_fini(root); 1159 if (errno == EINVAL) 1160 return (L_PORT_DRIVER_NOT_FOUND); 1161 else 1162 return (L_PHYS_PATH_NOT_FOUND); 1163 } 1164 1165 while (node) { 1166 /* point to first minor node which matches node */ 1167 minor_node = di_minor_next(node, DI_MINOR_NIL); 1168 1169 /* if we have a minor node use it */ 1170 while (minor_node) { 1171 /* 1172 * Is this a devctl or pseudo node? 1173 * If not, skip it. 1174 * Soc+ HBA port device paths such as: 1175 * /devices/sbus@2,0/SUNW,socal@d,10000:0 1176 * are pseudo nodes as of S9 so we need to 1177 * include those as well. 1178 */ 1179 if (di_minor_nodetype(minor_node) && 1180 (strcmp(di_minor_nodetype(minor_node), 1181 DDI_NT_NEXUS) && 1182 strcmp(di_minor_nodetype(minor_node), 1183 DDI_PSEUDO))) { 1184 minor_node = di_minor_next(node, minor_node); 1185 continue; 1186 } 1187 /* 1188 * Prepend '/devices' to path 1189 * Note: The path returned from di_devfs_path 1190 * does NOT begin with '/devices'. 1191 * '/devices' is considered a mount point 1192 */ 1193 strcpy(hbapathfound, "/devices"); 1194 tmppath = di_devfs_path(node); 1195 strcat(hbapathfound, tmppath); 1196 (void) free(tmppath); 1197 strcat(hbapathfound, ":"); 1198 strcat(hbapathfound, di_minor_name(minor_node)); 1199 /* 1200 * Verify that the path is validly constructed 1201 */ 1202 if ((stat(hbapathfound, (struct stat *)&buf)) < 0) { 1203 (void) di_fini(root); 1204 return (L_STAT_ERROR); 1205 } 1206 /* allocate memory and copy constructed path */ 1207 if ((portlist->hbacnt > MAX_HBA_PORT - 1) || 1208 ((portlist->physpath[portlist->hbacnt] = 1209 (char *)malloc(MAXPATHLEN)) == NULL)) { 1210 (void) di_fini(root); 1211 return (L_MALLOC_FAILED); 1212 } 1213 strcpy(portlist->physpath[portlist->hbacnt], 1214 hbapathfound); 1215 portlist->hbacnt++; 1216 minor_node = di_minor_next(node, minor_node); 1217 } 1218 node = di_drv_next_node(node); 1219 } 1220 /* 1221 * Destroy the snapshot and return 1222 */ 1223 (void) di_fini(root); 1224 return (0); 1225 } 1226 1227 /* 1228 * Free the allocated portlist structure 1229 */ 1230 void 1231 g_free_portlist(portlist_t *portlist) 1232 { 1233 int x = 0; 1234 1235 /* return if portlist is NULL */ 1236 if (portlist == NULL) { 1237 return; 1238 } 1239 1240 for (x = 0; x < portlist->hbacnt; x++) { 1241 if (portlist->physpath[x] != NULL) { 1242 free(portlist->physpath[x]); 1243 } 1244 } 1245 } 1246 1247 /* 1248 * Check VID/PID against enclosure disk table 1249 */ 1250 boolean_t 1251 g_enclDiskChk(char *vid, char *pid) 1252 { 1253 int i; 1254 for (i = 0; enclDiskTbl[i].vid; i++) { 1255 if ((strncmp(vid, enclDiskTbl[i].vid, 1256 strlen(enclDiskTbl[i].vid)) == 0) && 1257 (strncmp(pid, enclDiskTbl[i].pid, 1258 strlen(enclDiskTbl[i].pid)) == 0)) { 1259 return (B_TRUE); 1260 } 1261 } 1262 return (B_FALSE); 1263 } 1264