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