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 * I18N message number ranges 28 * This file: 21000 - 21499 29 * Shared common messages: 1 - 1999 30 */ 31 32 33 34 /* 35 * Functions to support the download of FCode to PCI HBAs 36 * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port 37 * and Emulex cards 38 */ 39 #include <errno.h> 40 #include <ctype.h> 41 #include <fcntl.h> 42 #include <stdio.h> 43 #include <string.h> 44 #include <strings.h> 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <sys/stat.h> 48 #include <limits.h> 49 #include <signal.h> 50 #include <dirent.h> 51 #include <nl_types.h> 52 #include <utmpx.h> 53 #include <sys/mnttab.h> 54 #include <sys/file.h> 55 #include <sys/mtio.h> 56 #include <sys/scsi/impl/uscsi.h> 57 #include <sys/fibre-channel/fcio.h> 58 #include <stgcom.h> 59 #include <sys/scsi/adapters/ifpio.h> 60 #include <libdevinfo.h> 61 #include "luxadm.h" 62 63 /* Error codes - used by the fcode_load_file routine */ 64 #define FCODE_SUCCESS 0 /* successful completion */ 65 #define FCODE_LOAD_FAILURE 1 /* general failure */ 66 #define FCODE_IOCTL_FAILURE 2 /* FCODE ioctl download failure */ 67 68 #define HBA_MAX 128 69 #define FCODE_HDR 200 70 #define MAX_RETRIES 3 71 #define MAX_WAIT_TIME 30 72 73 /* 74 * EMULEX Fcode attributes 75 */ 76 #define EMULEX_FCODE_VERSION_LENGTH 16 77 #define EMULEX_READ_BUFFER_SIZE 128 78 79 /* Emulex specific error codes */ 80 #define EMLX_ERRNO_START 0x100 81 82 /* Diagnostic error codes */ 83 #define EMLX_TEST_FAILED (EMLX_ERRNO_START + 0) 84 85 /* Download image contains bad data */ 86 #define EMLX_IMAGE_BAD (EMLX_ERRNO_START + 1) 87 /* Download image not compatible with current hardware */ 88 #define EMLX_IMAGE_INCOMPATIBLE (EMLX_ERRNO_START + 2) 89 /* Unable to take adapter offline */ 90 #define EMLX_IMAGE_FAILED (EMLX_ERRNO_START + 3) 91 /* Image download failed */ 92 #define EMLX_OFFLINE_FAILED (EMLX_ERRNO_START + 4) 93 94 95 96 97 /* 98 * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode 99 * for Ivory is based on a 2200 chip but this value does not reflect that. 100 */ 101 #define SBUS_CHIP_ID 0x1969 102 #define IVORY_BUS "/sbus@" 103 #define IVORY_DRVR "/SUNW,qlc@" 104 105 /* Global variables */ 106 static char fc_trans[] = "SUNW,ifp"; /* fibre channel transport */ 107 static char fp_trans[] = "SUNW,qlc"; /* fca layer driver */ 108 static char fp_trans_id[] = "fp@"; /* transport layer id */ 109 static char qlgc2100[] = "FC100/P"; /* product name for 2100 */ 110 static char qlgc2200[] = "ISP2200"; /* product name for 2200 */ 111 static char qlgc2300[] = "ISP2300"; /* product name for 2300 */ 112 static char qlgc2312[] = "ISP2312"; /* product name for 2312 */ 113 /* 114 * The variable qlgc2200Sbus represents the string which is always the 115 * starting string of the version information in an ISP2200 Sbus Fcode. 116 */ 117 static char qlgc2200Sbus[] = "ISP2200 Sbus FC-AL Host Adapter Driver"; 118 static char pcibus_list[HBA_MAX][PATH_MAX]; 119 /* Internal functions */ 120 static int q_load_file(int, char *); 121 static int q_getbootdev(uchar_t *); 122 static int q_getdevctlpath(char *, int *); 123 static int q_warn(int); 124 static int q_findversion(int, int, uchar_t *, uint16_t *); 125 static int q_findfileversion(char *, uchar_t *, uint16_t *, int, int *); 126 static int q_findSbusfile(int, int *); 127 static int memstrstr(char *, char *, int, int); 128 static int fcode_load_file(int, char *, int *); 129 130 /* 131 * Functions to support Fcode download for Emulex HBAs 132 */ 133 static int emulex_fcodeversion(di_node_t, uchar_t *); 134 static void handle_emulex_error(int, char *); 135 136 /* 137 * Searches for and updates the cards. This is the "main" function 138 * and will give the output to the user by calling the subfunctions. 139 * args: FCode file; if NULL only the current FCode version is printed 140 */ 141 int 142 q_qlgc_update(unsigned int verbose, char *file) 143 /*ARGSUSED*/ 144 { 145 int fd, fcode_fd = -1, errnum = 0, devcnt = 0, retval = 0, isSbus = 0; 146 int sbus_off; 147 uint_t i, fflag = 0; 148 uint16_t chip_id = 0, file_id = 0; 149 uchar_t fcode_buf[FCODE_HDR]; 150 static uchar_t bootpath[PATH_MAX]; 151 static uchar_t version[MAXNAMELEN], version_file[MAXNAMELEN]; 152 char devpath[PATH_MAX], tmppath[PATH_MAX]; 153 void (*sigint)(); /* to store default SIGTERM setting */ 154 static struct utmpx *utmpp = NULL; /* pointer for getutxent() */ 155 char *ptr1, *ptr2; 156 char phys_path[PATH_MAX]; 157 /* 158 * The variables port1 and port2 are used to store the bus id 159 * e.g. the bus id for this path: 160 * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl 161 * is "sbus@12". They are initialized to a random value and are 162 * set such that they are not equal initially. 163 */ 164 static char port1[MAXNAMELEN] = {NULL}; 165 static char port2[MAXNAMELEN] = {NULL}; 166 167 if (file) { 168 fflag++; 169 170 /* check for a valid file */ 171 if ((fcode_fd = open(file, O_RDONLY)) < 0) { 172 (void) fprintf(stderr, 173 MSGSTR(21000, "Error: Could not open %s\n"), file); 174 return (1); 175 } 176 if (read(fcode_fd, fcode_buf, FCODE_HDR) != FCODE_HDR) { 177 perror(MSGSTR(21001, "read")); 178 (void) close(fcode_fd); 179 return (1); 180 } 181 182 /* 183 * Check if it's SBUS FCode by calling q_findSbusfile 184 * if it is then isSbus will be 1, if not it will be 0 185 * in case of an error, it will be -1 186 */ 187 isSbus = q_findSbusfile(fcode_fd, &sbus_off); 188 if (isSbus == -1) { 189 (void) close(fcode_fd); 190 return (1); 191 } 192 193 /* 194 * FCode header check - make sure it's PCI FCode 195 * Structure of FCode header (byte# refers to byte numbering 196 * in FCode spec, not the byte# of our fcode_buf buffer): 197 * header byte 00 0x55 prom signature byte one 198 * byte 01 0xaa prom signature byte two 199 * data byte 00-03 P C I R 200 * OR 201 * header byte 32 0x55 202 * byte 33 0xaa 203 * data byte 60-63 P C I R 204 * The second format with an offset of 32 is used for ifp prom 205 */ 206 if (!(((fcode_buf[0x00] == 0x55) && 207 (fcode_buf[0x01] == 0xaa) && 208 (fcode_buf[0x1c] == 'P') && 209 (fcode_buf[0x1d] == 'C') && 210 (fcode_buf[0x1e] == 'I') && 211 (fcode_buf[0x1f] == 'R')) || 212 213 ((fcode_buf[0x20] == 0x55) && 214 (fcode_buf[0x21] == 0xaa) && 215 (fcode_buf[0x3c] == 'P') && 216 (fcode_buf[0x3d] == 'C') && 217 (fcode_buf[0x3e] == 'I') && 218 (fcode_buf[0x3f] == 'R')) || 219 220 (isSbus))) { 221 (void) fprintf(stderr, MSGSTR(21002, 222 "Error: %s is not a valid FC100/P, " 223 "ISP2200, ISP23xx FCode file.\n"), 224 file); 225 (void) close(fcode_fd); 226 return (1); 227 } 228 229 /* check for single user mode */ 230 while ((utmpp = getutxent()) != NULL) { 231 if (strstr(utmpp->ut_line, "run-level") && 232 (strcmp(utmpp->ut_line, "run-level S") && 233 strcmp(utmpp->ut_line, "run-level 1"))) { 234 if (q_warn(1)) { 235 (void) endutxent(); 236 (void) close(fcode_fd); 237 return (1); 238 } 239 break; 240 } 241 } 242 (void) endutxent(); 243 244 /* get bootpath */ 245 if (!q_getbootdev((uchar_t *)&bootpath[0]) && 246 getenv("_LUX_D_DEBUG") != NULL) { 247 (void) fprintf(stdout, " Bootpath: %s\n", bootpath); 248 } 249 } 250 /* 251 * Get count of, and names of PCI slots with ifp device control 252 * (devctl) nodes. Search /devices. 253 */ 254 (void) strcpy(devpath, "/devices"); 255 if (q_getdevctlpath(devpath, (int *)&devcnt) == 0) { 256 (void) fprintf(stdout, MSGSTR(21003, 257 "\n Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"), 258 devcnt); 259 } else { 260 (void) fprintf(stderr, MSGSTR(21004, 261 "Error: Could not get /devices path to FC100/P," 262 "ISP2200, ISP23xx Cards.\n")); 263 retval++; 264 } 265 266 for (i = 0; i < devcnt; i++) { 267 268 (void) strncpy((char *)phys_path, &pcibus_list[i][0], 269 strlen(&pcibus_list[i][0])); 270 if (fflag && (strstr((char *)bootpath, 271 strtok((char *)phys_path, ":")) != NULL)) { 272 (void) fprintf(stderr, 273 MSGSTR(21005, "Ignoring %s (bootpath)\n"), 274 &pcibus_list[i][0]); 275 continue; 276 } 277 278 (void) fprintf(stdout, 279 MSGSTR(21006, "\n Opening Device: %s\n"), &pcibus_list[i][0]); 280 /* Check if the device is valid */ 281 if ((fd = open(&pcibus_list[i][0], O_RDWR)) < 0) { 282 (void) fprintf(stderr, 283 MSGSTR(21000, "Error: Could not open %s\n"), 284 &pcibus_list[i][0]); 285 retval++; 286 continue; 287 } 288 (void) close(fd); 289 /* 290 * Check FCode version present on the adapter (at last boot) 291 */ 292 if (q_findversion(verbose, i, (uchar_t *)&version[0], 293 &chip_id) == 0) { 294 if (strlen((char *)version) == 0) { 295 (void) fprintf(stdout, MSGSTR(21007, 296 " Detected FCode Version:\tNo version available for this FCode\n")); 297 } else { 298 (void) fprintf(stdout, MSGSTR(21008, 299 " Detected FCode Version:\t%s\n"), version); 300 } 301 } else { 302 chip_id = 0x0; 303 } 304 305 if (fflag) { 306 /* 307 * For ISP2200, Sbus HBA, do just 1 download 308 * for both the ports (dual port HBA) 309 * Here it is assumed that readdir() always 310 * returns the paths in pcibus_list[] in the 311 * sorted order. 312 */ 313 (void) strcpy(tmppath, pcibus_list[i]); 314 if (ptr1 = strstr(tmppath, IVORY_BUS)) { 315 if (ptr2 = strstr(ptr1, IVORY_DRVR)) { 316 ptr2 = strchr(ptr2, ','); 317 if (ptr2 = strchr(++ptr2, ',')) { 318 *ptr2 = '\0'; 319 } 320 } 321 (void) strcpy(port2, ptr1); 322 if (strcmp(port1, port2) == 0) { 323 (void) fprintf(stdout, MSGSTR(21037, 324 "/n New FCode has already been downloaded " 325 "to this ISP2200 SBus HBA Card.\n" 326 "It is sufficient to download to one " 327 "port of the ISP2200 SBus HBA Card. " 328 "Moving on...\n")); 329 continue; 330 } 331 } 332 /* 333 * Check version of the supplied FCode file (once) 334 */ 335 if ((file_id != 0 && version_file != NULL) || 336 (q_findfileversion((char *) 337 &fcode_buf[0], (uchar_t *)&version_file[0], 338 &file_id, isSbus, &sbus_off) == 0)) { 339 (void) fprintf(stdout, MSGSTR(21009, 340 " New FCode Version:\t\t%s\n"), 341 version_file); 342 } else { 343 (void) close(fcode_fd); 344 return (1); 345 } 346 347 /* 348 * Load the New FCode 349 * Give warning if file doesn't appear to be correct 350 * 351 */ 352 if (chip_id == 0) { 353 errnum = 2; /* can't get chip_id */ 354 retval++; 355 } else if (chip_id - file_id != 0) { 356 errnum = 3; /* file/card mismatch */ 357 retval++; 358 } else { 359 errnum = 0; /* everything is ok */ 360 } 361 362 if (!q_warn(errnum)) { 363 /* Disable user-interrupt Control-C */ 364 sigint = 365 (void (*)(int)) signal(SIGINT, SIG_IGN); 366 367 /* Load FCode */ 368 (void) fprintf(stdout, MSGSTR(21010, 369 " Loading FCode: %s\n"), file); 370 371 if (q_load_file(fcode_fd, 372 &pcibus_list[i][0]) == 0) { 373 (void) fprintf(stdout, MSGSTR(21011, 374 " Successful FCode download: %s\n"), 375 &pcibus_list[i][0]); 376 (void) strcpy(port1, port2); 377 } else { 378 (void) fprintf(stderr, MSGSTR(21012, 379 "Error: FCode download failed: %s\n"), 380 &pcibus_list[i][0]); 381 retval++; 382 } 383 /* Restore SIGINT (user interrupt) setting */ 384 (void) signal(SIGINT, sigint); 385 } 386 } 387 } 388 (void) fprintf(stdout, " "); 389 (void) fprintf(stdout, MSGSTR(125, "Complete\n")); 390 if (fcode_fd != -1) 391 (void) close(fcode_fd); 392 return (retval); 393 } 394 395 396 /* 397 * Retrieve the version banner from the card 398 * uses ioctl: FCIO_FCODE_MCODE_VERSION FCode revision 399 */ 400 static int 401 q_findversion(int verbose, int index, uchar_t *version, uint16_t *chip_id) 402 /*ARGSUSED*/ 403 { 404 int fd, ntries; 405 struct ifp_fm_version *version_buffer = NULL; 406 char prom_ver[100] = {NULL}; 407 char mcode_ver[100] = {NULL}; 408 fcio_t fcio; 409 410 if (strstr(&pcibus_list[index][0], fc_trans)) { 411 412 if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) { 413 (void) fprintf(stderr, 414 MSGSTR(21000, "Error: Could not open %s\n"), 415 &pcibus_list[index][0]); 416 return (1); 417 } 418 419 if ((version_buffer = (struct ifp_fm_version *)malloc( 420 sizeof (struct ifp_fm_version))) == NULL) { 421 (void) fprintf(stderr, 422 MSGSTR(21013, "Error: Memory allocation failed\n")); 423 (void) close(fd); 424 return (1); 425 } 426 427 version_buffer->fcode_ver = (char *)version; 428 version_buffer->mcode_ver = mcode_ver; 429 version_buffer->prom_ver = prom_ver; 430 version_buffer->fcode_ver_len = MAXNAMELEN - 1; 431 version_buffer->mcode_ver_len = 100; 432 version_buffer->prom_ver_len = 100; 433 434 if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, version_buffer) < 0) { 435 (void) fprintf(stderr, MSGSTR(21014, 436 "Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n")); 437 free(version_buffer); 438 (void) close(fd); 439 return (1); 440 } 441 version[version_buffer->fcode_ver_len] = '\0'; 442 443 /* Need a way to get card MCODE (firmware) to track certain HW bugs */ 444 if (getenv("_LUX_D_DEBUG") != NULL) { 445 (void) fprintf(stdout, " Device %i: QLGC chip_id %x\n", 446 index+1, *chip_id); 447 (void) fprintf(stdout, " FCode:%s\n MCODE:%s\n PROM:%s\n", 448 (char *)version, mcode_ver, prom_ver); 449 } 450 free(version_buffer); 451 452 } else if (strstr(&pcibus_list[index][0], fp_trans)) { 453 /* 454 * Get the fcode and prom's fw version 455 * using the fp ioctls. Currently, we pass 456 * only the fcode version to the calling function 457 * and ignore the FW version (using the existing 458 * implementation). 459 */ 460 461 if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) { 462 (void) fprintf(stderr, 463 MSGSTR(4511, "Could not open %s\n"), 464 &pcibus_list[index][0]); 465 (void) close(fd); 466 return (1); 467 } 468 /* Get the fcode version */ 469 bzero(version, sizeof (version)); 470 fcio.fcio_cmd = FCIO_GET_FCODE_REV; 471 /* Information read operation */ 472 fcio.fcio_xfer = FCIO_XFER_READ; 473 fcio.fcio_obuf = (caddr_t)version; 474 fcio.fcio_olen = MAXNAMELEN; 475 476 for (ntries = 0; ntries < MAX_RETRIES; ntries++) { 477 if (ioctl(fd, FCIO_CMD, &fcio) != 0) { 478 if ((errno == EAGAIN) && 479 (ntries+1 < MAX_RETRIES)) { 480 /* wait 30 secs */ 481 (void) sleep(MAX_WAIT_TIME); 482 continue; 483 } 484 (void) close(fd); 485 return (L_FCIO_GET_FCODE_REV_FAIL); 486 } 487 break; 488 } 489 version[MAXNAMELEN-1] = '\0'; 490 } 491 492 /* Get type of card from product name in FCode version banner */ 493 if (strstr((char *)version, qlgc2100)) { 494 *chip_id = 0x2100; 495 } else if (strstr((char *)version, qlgc2200)) { 496 *chip_id = 0x2200; 497 if (strstr((char *)version, "Sbus")) { 498 *chip_id = SBUS_CHIP_ID; 499 } 500 } else if (strstr((char *)version, qlgc2300)) { 501 *chip_id = 0x2300; 502 } else if (strstr((char *)version, qlgc2312)) { 503 *chip_id = 0x2312; 504 } else { 505 *chip_id = 0x0; 506 } 507 508 (void) close(fd); 509 return (0); 510 } 511 512 /* 513 * Retrieve the version banner and file type (2100 or 2200) from the file 514 */ 515 static int 516 q_findfileversion(char *dl_fcode, uchar_t *version_file, uint16_t *file_id, 517 int isSbus, int *sbus_offset) 518 { 519 int mark; 520 int qlc_offset = 0; 521 char temp[4] = {NULL}; 522 523 524 /* 525 * Get file version from FCode for 2100 or 2202 526 */ 527 if (isSbus) { 528 *file_id = SBUS_CHIP_ID; 529 } else { 530 if ((dl_fcode[0x23] == 0x22) || 531 (dl_fcode[0x23] == 0x23)) { 532 *file_id = dl_fcode[0x22] & 0xff; 533 *file_id |= (dl_fcode[0x23] << 8) & 0xff00; 534 } else { 535 *file_id = dl_fcode[0x42] & 0xff; 536 *file_id |= (dl_fcode[0x43] << 8) & 0xff00; 537 } 538 } 539 540 /* 541 * Ok, we're just checking for 2200 here. If it is we need 542 * to offset to find the banner. 543 */ 544 if ((*file_id == 0x2200) || 545 (*file_id == 0x2300) || 546 (*file_id == 0x2312)) { 547 qlc_offset = -32; 548 } 549 550 /* 551 * If this is an ISP2200 Sbus Fcode file, then search for the string 552 * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file 553 */ 554 if (isSbus) { 555 *file_id = SBUS_CHIP_ID; 556 qlc_offset = *sbus_offset; 557 /* Subtract 111 from the offset we add below for PCI Fcodes */ 558 qlc_offset -= 111; 559 } 560 561 /* Banner length varies; grab banner to end of date marker yr/mo/da */ 562 version_file[0] = '\0'; 563 for (mark = (111 + qlc_offset); mark < (191 + qlc_offset); mark++) { 564 (void) strncpy(temp, (char *)&dl_fcode[mark], 4); 565 if ((strncmp(&temp[0], "/", 1) == 0) && 566 (strncmp(&temp[3], "/", 1) == 0)) { 567 (void) strncat((char *)version_file, 568 (char *)&dl_fcode[mark], 6); 569 break; 570 } 571 (void) strncat((char *)version_file, temp, 1); 572 } 573 return (0); 574 } 575 576 /* 577 * Find if the FCode file is a ISP2200 SBUS Fcode file 578 */ 579 static int 580 q_findSbusfile(int fd, int *sbus_offset) 581 { 582 static int file_size; 583 char *sbus_info; 584 struct stat statinfo; 585 586 if (lseek(fd, 0, SEEK_SET) == -1) { 587 perror(MSGSTR(21022, "seek")); 588 return (-1); 589 } 590 if (fstat(fd, &statinfo)) { 591 perror(MSGSTR(21023, "fstat")); 592 return (-1); 593 } 594 file_size = statinfo.st_size; 595 596 if ((sbus_info = (char *)malloc(file_size)) == NULL) { 597 (void) fprintf(stderr, 598 MSGSTR(21013, "Error: Memory allocation failed\n")); 599 return (-1); 600 } 601 602 if (read(fd, sbus_info, file_size) < 0) { 603 perror(MSGSTR(21001, "read")); 604 free(sbus_info); 605 return (-1); 606 } 607 608 /* 609 * Search for the version string in the whole file 610 */ 611 if ((*sbus_offset = memstrstr((char *)sbus_info, qlgc2200Sbus, 612 file_size, strlen(qlgc2200Sbus))) != -1) { 613 free(sbus_info); 614 return (1); 615 } else { 616 free(sbus_info); 617 return (0); 618 } 619 } 620 621 622 /* 623 * Build a list of all the devctl entries for all the 2100/2200 based adapters 624 */ 625 static int 626 q_getdevctlpath(char *devpath, int *devcnt) 627 { 628 struct stat statbuf; 629 struct dirent *dirp = NULL; 630 DIR *dp = NULL; 631 char *ptr = NULL; 632 int err; 633 int testopen; 634 635 if (lstat(devpath, &statbuf) < 0) { 636 (void) fprintf(stderr, 637 MSGSTR(21016, "Error: %s lstat() error\n"), devpath); 638 return (1); 639 } 640 641 if ((strstr(devpath, fc_trans) || 642 (strstr(devpath, fp_trans_id) && strstr(devpath, fp_trans))) && 643 strstr(devpath, "devctl")) { 644 /* Verify the path is valid */ 645 if ((testopen = open(devpath, O_RDONLY)) >= 0) { 646 (void) close(testopen); 647 (void) strcpy(pcibus_list[*devcnt], devpath); 648 *devcnt += 1; 649 return (0); 650 } 651 } 652 653 if (S_ISDIR(statbuf.st_mode) == 0) { 654 /* 655 * not a directory so 656 * we don't care about it - return 657 */ 658 return (0); 659 } 660 661 /* 662 * It's a directory. Call ourself to 663 * traverse the path(s) 664 */ 665 ptr = devpath + strlen(devpath); 666 *ptr++ = '/'; 667 *ptr = 0; 668 669 /* Forget the /devices/pseudo/ directory */ 670 if (strcmp(devpath, "/devices/pseudo/") == 0) { 671 return (0); 672 } 673 674 if ((dp = opendir(devpath)) == NULL) { 675 (void) fprintf(stderr, 676 MSGSTR(21017, "Error: %s Can't read directory\n"), devpath); 677 return (1); 678 } 679 680 while ((dirp = readdir(dp)) != NULL) { 681 682 if (strcmp(dirp->d_name, ".") == 0 || 683 strcmp(dirp->d_name, "..") == 0) { 684 continue; 685 } 686 (void) strcpy(ptr, dirp->d_name); /* append name */ 687 err = q_getdevctlpath(devpath, devcnt); 688 } 689 690 if (closedir(dp) < 0) { 691 (void) fprintf(stderr, 692 MSGSTR(21018, "Error: Can't close directory %s\n"), devpath); 693 return (1); 694 } 695 return (err); 696 } 697 698 /* 699 * Get the boot device. Cannot load FCode to current boot device. 700 * Boot devices under volume management will prompt a warning. 701 */ 702 static int 703 q_getbootdev(uchar_t *bootpath) 704 { 705 struct mnttab mp; 706 struct mnttab mpref; 707 FILE *fp = NULL; 708 static char buf[BUFSIZ]; 709 char *p = NULL, *p1 = NULL; /* p = full device, p1 = chunk to rm */ 710 char *slot = ":devctl"; 711 char *root = "/"; 712 713 if ((fp = fopen(MNTTAB, "r")) == NULL) { 714 (void) fprintf(stderr, 715 MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB); 716 return (1); 717 } 718 719 mntnull(&mpref); 720 mpref.mnt_mountp = (char *)root; 721 722 if (getmntany(fp, &mp, &mpref) != 0 || 723 mpref.mnt_mountp == NULL) { 724 (void) fprintf(stderr, MSGSTR(21019, 725 "Error: Cannot get boot device, check %s.\n"), MNTTAB); 726 (void) fclose(fp); 727 return (1); 728 } 729 (void) fclose(fp); 730 731 /* 732 * If we can't get a link, we may be dealing with a volume mgr 733 * so give a warning. If a colon is present, we likely have a 734 * non-local disk or cd-rom, so no warning is necessary. 735 * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or 736 * storage-e4:/blah/blah remote boot server 737 */ 738 if (readlink(mp.mnt_special, buf, BUFSIZ) < 0) { 739 if (strstr(mp.mnt_special, ":") == NULL) { 740 (void) fprintf(stderr, MSGSTR(21020, 741 "\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB); 742 (void) fprintf(stderr, MSGSTR(21021, 743 "Do not upgrade FCode on adapters controlling the boot device.\n")); 744 } 745 return (1); 746 } 747 /* 748 * Copy boot device path to bootpath. First remove leading 749 * path junk (../../..) then if it's an ifp device, chop off 750 * the disk and add the devctl to the end of the path. 751 */ 752 if (p = strstr(buf, "/devices")) { 753 if (strstr(buf, fc_trans) != NULL) { 754 p1 = strrchr(p, '/'); 755 *p1 = '\0'; 756 } 757 } 758 (void) strcpy((char *)bootpath, (char *)p); 759 if (p1) { 760 (void) strcat((char *)bootpath, slot); 761 } 762 return (0); 763 } 764 765 /* 766 * Load FCode to card. 767 * uses ioctl: IFPIO_FCODE_DOWNLOAD 768 */ 769 static int 770 q_load_file(int fcode_fd, char *device) 771 { 772 static int dev_fd, fcode_size; 773 struct stat stat; 774 ifp_download_t *download_p = NULL; 775 fcio_t fcio; 776 uint16_t file_id = 0; 777 uchar_t *bin; 778 779 if (lseek(fcode_fd, 0, SEEK_SET) == -1) { 780 perror(MSGSTR(21022, "seek")); 781 (void) close(fcode_fd); 782 return (1); 783 } 784 if (fstat(fcode_fd, &stat) == -1) { 785 perror(MSGSTR(21023, "fstat")); 786 (void) close(fcode_fd); 787 return (1); 788 } 789 790 fcode_size = stat.st_size; 791 792 if (strstr(device, fc_trans)) { 793 if ((download_p = (ifp_download_t *)malloc( 794 sizeof (ifp_download_t) + fcode_size)) == NULL) { 795 (void) fprintf(stderr, 796 MSGSTR(21013, "Error: Memory allocation failed\n")); 797 (void) close(fcode_fd); 798 return (1); 799 } 800 } else { 801 if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) { 802 (void) fprintf(stderr, 803 MSGSTR(21013, "Error: Memory allocation failed\n")); 804 (void) close(fcode_fd); 805 return (1); 806 } 807 } 808 809 if (strstr(device, fc_trans)) { 810 if (read(fcode_fd, download_p->dl_fcode, fcode_size) 811 != fcode_size) { 812 perror(MSGSTR(21001, "read")); 813 free(download_p); 814 (void) close(fcode_fd); 815 return (1); 816 } 817 } else { 818 if (read(fcode_fd, bin, fcode_size) 819 != fcode_size) { 820 perror(MSGSTR(21001, "read")); 821 free(bin); 822 (void) close(fcode_fd); 823 return (1); 824 } 825 } 826 827 828 if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) { 829 (void) fprintf(stderr, 830 MSGSTR(21000, "Error: Could not open %s\n"), device); 831 free(download_p); 832 return (1); 833 } 834 if (strstr(device, fc_trans)) { 835 download_p->dl_fcode_len = fcode_size; 836 file_id = download_p->dl_fcode[0x42] & 0xff; 837 file_id |= (download_p->dl_fcode[0x43] << 8) & 0xff00; 838 download_p->dl_chip_id = file_id; 839 if (ioctl(dev_fd, IFPIO_FCODE_DOWNLOAD, download_p) < 0) { 840 (void) fprintf(stderr, MSGSTR(21024, 841 "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n")); 842 free(download_p); 843 (void) close(dev_fd); 844 return (1); 845 } 846 free(download_p); 847 } else if (strstr(device, fp_trans)) { 848 fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE; 849 /* Information read operation */ 850 fcio.fcio_xfer = FCIO_XFER_WRITE; 851 fcio.fcio_ibuf = (caddr_t)bin; 852 fcio.fcio_ilen = fcode_size; 853 854 if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) { 855 (void) fprintf(stderr, MSGSTR(21036, 856 "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n")); 857 free(download_p); 858 (void) close(dev_fd); 859 return (1); 860 } 861 free(bin); 862 } 863 (void) close(dev_fd); 864 return (0); 865 } 866 867 /* 868 * Issue warning strings and loop for Yes/No user interaction 869 * err# 0 -- we're ok, warn for pending FCode load 870 * 1 -- not in single user mode 871 * 2 -- can't get chip_id 872 * 3 -- card and file do not have same type (2100/2200) 873 */ 874 static int 875 q_warn(int errnum) 876 { 877 char input[1024]; 878 input[0] = '\0'; 879 880 if (errnum == 1) { 881 (void) fprintf(stderr, MSGSTR(21025, 882 "\nWarning: System is not in single-user mode.\n")); 883 (void) fprintf(stderr, MSGSTR(21026, 884 "Loading FCode will reset the adapter and terminate I/O activity\n")); 885 } else { 886 if (errnum == 2) { 887 (void) fprintf(stderr, MSGSTR(21027, 888 " Warning: FCode is missing or existing FCode has" 889 " unrecognized version.\n")); 890 return (1); 891 } else if (errnum == 3) { 892 (void) fprintf(stderr, MSGSTR(21028, 893 " Warning: New FCode file version does not match this" 894 " board type. Skipping...\n")); 895 return (1); 896 } 897 (void) fprintf(stderr, MSGSTR(21029, 898 "\nWARNING!! This program will update the FCode in this" 899 " FC100/PCI, ISP2200/PCI, ISP23xx/PCI " 900 " and Emulex devices.\n")); 901 (void) fprintf(stderr, MSGSTR(21030, 902 "This may take a few (5) minutes. Please be patient.\n")); 903 } 904 905 loop1: 906 (void) fprintf(stderr, MSGSTR(21031, 907 "Do you wish to continue ? (y/n) ")); 908 909 (void) gets(input); 910 911 if ((strcmp(input, MSGSTR(21032, "y")) == 0) || 912 (strcmp(input, MSGSTR(40, "yes")) == 0)) { 913 return (0); 914 } else if ((strcmp(input, MSGSTR(21033, "n")) == 0) || 915 (strcmp(input, MSGSTR(45, "no")) == 0)) { 916 (void) fprintf(stderr, 917 MSGSTR(21034, "Not Downloading FCode\n")); 918 return (1); 919 } else { 920 (void) fprintf(stderr, MSGSTR(21035, "Invalid input\n")); 921 goto loop1; 922 } 923 } 924 925 /* 926 * Name : memstrstr 927 * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2 928 * Returns : 929 * Offset of the start of contents-of-buf2 in buf1 if it is found 930 * -1 if buf1 does not contain contents of buf2 931 * Synopsis: 932 * This function works similar to strstr(). The difference is that null 933 * characters in the buffer are treated like any other character. So, buf1 934 * and buf2 can have embedded null characters in them. 935 */ 936 static int 937 memstrstr(char *s1, char *s2, int size1, int size2) 938 { 939 int count1, count2; 940 char *s1_ptr, *s2_ptr; 941 942 count1 = size1; count2 = size2; 943 s1_ptr = s1; s2_ptr = s2; 944 945 if ((size2 == 0)||(size1 == 0)) 946 return (-1); 947 948 for (count1 = 0; count1 < (size1 - size2 + 1); count1++) { 949 if (*s1_ptr++ == *s2_ptr++) { 950 if (--count2 == 0) { 951 return (count1 - size2 + 1); 952 } 953 continue; 954 } 955 count2 = size2; 956 s2_ptr = s2; 957 } 958 959 return (-1); 960 } 961 962 /* 963 * generic fcode load file routine. given a file descriptor to a fcode file 964 * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given 965 * device. Any ioctl errors will be returned in fcio_errno 966 * 967 * Arguments: 968 * fcode_fd file descriptor to a fcode file 969 * device path to the device we will be downloading the fcode onto 970 * fcio_errno pointer to an int that will be used to return any errors 971 * back to the caller 972 * Retrurn Values: 973 * 0 successful download 974 * >0 otherwise 975 */ 976 static int 977 fcode_load_file(int fcode_fd, char *device, int *fcio_errno) 978 { 979 980 fcio_t fcio; 981 static int dev_fd, fcode_size; 982 uchar_t *bin; 983 struct stat stat; 984 985 if (device == NULL || fcio_errno == NULL) { 986 return (FCODE_LOAD_FAILURE); 987 } 988 989 *fcio_errno = 0; 990 if (lseek(fcode_fd, 0, SEEK_SET) == -1) { 991 perror(MSGSTR(21022, "seek")); 992 return (FCODE_LOAD_FAILURE); 993 } 994 995 if (fstat(fcode_fd, &stat) == -1) { 996 perror(MSGSTR(21023, "fstat")); 997 return (FCODE_LOAD_FAILURE); 998 } 999 1000 fcode_size = stat.st_size; 1001 1002 if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) { 1003 (void) fprintf(stderr, 1004 MSGSTR(21013, "Error: Memory allocation failed\n")); 1005 return (FCODE_LOAD_FAILURE); 1006 } 1007 1008 if (read(fcode_fd, bin, fcode_size) 1009 != fcode_size) { 1010 perror(MSGSTR(21001, "read")); 1011 free(bin); 1012 return (FCODE_LOAD_FAILURE); 1013 } 1014 1015 if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) { 1016 (void) fprintf(stderr, 1017 MSGSTR(21122, "Error: Could not open %s, failed " 1018 "with errno %d\n"), device, errno); 1019 free(bin); 1020 return (FCODE_LOAD_FAILURE); 1021 } 1022 1023 fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE; 1024 fcio.fcio_xfer = FCIO_XFER_WRITE; 1025 fcio.fcio_ibuf = (caddr_t)bin; 1026 fcio.fcio_ilen = fcode_size; 1027 1028 if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) { 1029 (void) close(dev_fd); 1030 *fcio_errno = fcio.fcio_errno; 1031 free(bin); 1032 return (FCODE_IOCTL_FAILURE); 1033 } 1034 1035 free(bin); 1036 (void) close(dev_fd); 1037 return (FCODE_SUCCESS); 1038 } 1039 1040 /* 1041 * Searches for and updates the fcode for Emulex HBA cards 1042 * args: FCode file; if NULL only the current FCode 1043 * version is printed 1044 */ 1045 1046 int 1047 emulex_update(char *file) 1048 { 1049 1050 int fd, retval = 0; 1051 int devcnt = 0; 1052 uint_t state = 0, fflag = 0; 1053 static uchar_t bootpath[PATH_MAX]; 1054 int fcode_fd = -1; 1055 static struct utmpx *utmpp = NULL; 1056 di_node_t root; 1057 di_node_t node, sib_node, count_node; 1058 di_minor_t minor_node; 1059 char phys_path[PATH_MAX], *path; 1060 int errnum = 0, fcio_errno = 0; 1061 static uchar_t prom_ver_data[MAXNAMELEN]; 1062 static char ver_file[EMULEX_FCODE_VERSION_LENGTH]; 1063 void (*sigint)(); 1064 int prop_entries = -1; 1065 int *port_data = NULL; 1066 1067 if (file) { 1068 /* set the fcode download flag */ 1069 fflag++; 1070 1071 /* check for a valid file */ 1072 if ((fcode_fd = open(file, O_RDONLY)) < 0) { 1073 (void) fprintf(stderr, 1074 MSGSTR(21118, "Error: Could not open %s, failed " 1075 "with errno %d\n"), file, errno); 1076 return (1); 1077 } 1078 1079 /* check for single user mode */ 1080 while ((utmpp = getutxent()) != NULL) { 1081 if (strstr(utmpp->ut_line, "run-level") && 1082 (strcmp(utmpp->ut_line, "run-level S") && 1083 strcmp(utmpp->ut_line, "run-level 1"))) { 1084 if (q_warn(1)) { 1085 (void) endutxent(); 1086 (void) close(fcode_fd); 1087 return (1); 1088 } 1089 break; 1090 } 1091 } 1092 (void) endutxent(); 1093 1094 /* get bootpath */ 1095 if (!q_getbootdev((uchar_t *)&bootpath[0]) && 1096 getenv("_LUX_D_DEBUG") != NULL) { 1097 (void) fprintf(stdout, " Bootpath: %s\n", bootpath); 1098 } 1099 } 1100 1101 /* 1102 * Download the Fcode to all the emulex cards found 1103 */ 1104 1105 /* Create a snapshot of the kernel device tree */ 1106 if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 1107 (void) fprintf(stderr, MSGSTR(21114, 1108 "Error: Could not get /devices path to " 1109 "Emulex Devices.\n")); 1110 retval++; 1111 } 1112 1113 /* point to first node which matches emulex driver */ 1114 node = di_drv_first_node("emlxs", root); 1115 1116 if (node == DI_NODE_NIL) { 1117 /* 1118 * Could not find any emulex cards 1119 */ 1120 (void) di_fini(root); 1121 (void) fprintf(stderr, MSGSTR(21115, 1122 "\n Found Path to %d Emulex Devices.\n"), devcnt); 1123 retval++; 1124 } else { 1125 1126 count_node = node; 1127 while (count_node != DI_NODE_NIL) { 1128 state = di_state(count_node); 1129 if ((state & DI_DRIVER_DETACHED) 1130 != DI_DRIVER_DETACHED) { 1131 devcnt++; 1132 } 1133 count_node = di_drv_next_node(count_node); 1134 } 1135 (void) fprintf(stdout, MSGSTR(21116, 1136 "\n Found Path to %d Emulex Devices.\n"), devcnt); 1137 } 1138 1139 1140 /* 1141 * Traverse device tree to find all emulex cards 1142 */ 1143 while (node != DI_NODE_NIL) { 1144 1145 state = di_state(node); 1146 if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) { 1147 node = di_drv_next_node(node); 1148 continue; 1149 } 1150 1151 sib_node = di_child_node(node); 1152 while (sib_node != DI_NODE_NIL) { 1153 1154 state = di_state(sib_node); 1155 if ((state & DI_DRIVER_DETACHED) != 1156 DI_DRIVER_DETACHED) { 1157 1158 /* Found an attached node */ 1159 prop_entries = di_prop_lookup_ints( 1160 DDI_DEV_T_ANY, sib_node, 1161 "port", &port_data); 1162 if (prop_entries != -1) { 1163 1164 /* Found a node with "port" property */ 1165 minor_node = di_minor_next(sib_node, 1166 DI_MINOR_NIL); 1167 break; 1168 } 1169 } 1170 sib_node = di_sibling_node(sib_node); 1171 } 1172 1173 if (sib_node == DI_NODE_NIL) { 1174 return (1); 1175 } 1176 path = di_devfs_path(sib_node); 1177 (void) strcpy(phys_path, "/devices"); 1178 (void) strncat(phys_path, path, strlen(path)); 1179 di_devfs_path_free(path); 1180 1181 if (fflag && (strstr((char *)bootpath, 1182 (char *)phys_path) != NULL)) { 1183 (void) fprintf(stderr, 1184 MSGSTR(21117, "Ignoring %s (bootpath)\n"), 1185 phys_path); 1186 node = di_drv_next_node(node); 1187 continue; 1188 } 1189 1190 if (minor_node) { 1191 (void) strncat(phys_path, ":", 1); 1192 (void) strncat(phys_path, 1193 di_minor_name(minor_node), 1194 strlen(di_minor_name(minor_node))); 1195 } 1196 1197 (void) fprintf(stdout, 1198 MSGSTR(21107, "\n Opening Device: %s\n"), 1199 phys_path); 1200 1201 /* Check if the device is valid */ 1202 if ((fd = open(phys_path, O_RDWR)) < 0) { 1203 (void) fprintf(stderr, 1204 MSGSTR(21121, "Error: Could not open %s, failed " 1205 "with errno %d\n"), phys_path, errno); 1206 retval++; 1207 node = di_drv_next_node(node); 1208 continue; 1209 } 1210 1211 (void) close(fd); 1212 1213 /* 1214 * Check FCode version present on the adapter 1215 * (at last boot) 1216 */ 1217 memset(prom_ver_data, 0, sizeof (prom_ver_data)); 1218 if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0]) 1219 == 0) { 1220 errnum = 0; 1221 if (strlen((char *)prom_ver_data) == 0) { 1222 (void) fprintf(stdout, MSGSTR(21108, 1223 " Detected FCode Version:\tNo version available for this FCode\n")); 1224 } else { 1225 (void) fprintf(stdout, MSGSTR(21109, 1226 " Detected FCode Version:\t%s\n"), 1227 prom_ver_data); 1228 } 1229 } else { 1230 errnum = 2; /* can't get prom properties */ 1231 retval++; 1232 } 1233 1234 if (fflag) { 1235 1236 memset(ver_file, 0, sizeof (ver_file)); 1237 if (emulex_fcode_reader(fcode_fd, "fcode-version", 1238 ver_file, sizeof (ver_file)) == 0) { 1239 (void) fprintf(stdout, MSGSTR(21110, 1240 " New FCode Version:\t\t%s\n"), 1241 ver_file); 1242 } else { 1243 di_fini(root); 1244 (void) close(fcode_fd); 1245 return (1); 1246 } 1247 1248 /* 1249 * Load the New FCode 1250 * Give warning if file doesn't appear to be correct 1251 */ 1252 if (!q_warn(errnum)) { 1253 /* Disable user-interrupt Control-C */ 1254 sigint = 1255 (void (*)(int)) signal(SIGINT, SIG_IGN); 1256 /* Load FCode */ 1257 (void) fprintf(stdout, MSGSTR(21111, 1258 " Loading FCode: %s\n"), file); 1259 if (fcode_load_file(fcode_fd, phys_path, 1260 &fcio_errno) == FCODE_SUCCESS) { 1261 (void) fprintf(stdout, MSGSTR(21112, 1262 " Successful FCode download: %s\n"), 1263 phys_path); 1264 } else { 1265 handle_emulex_error(fcio_errno, 1266 phys_path); 1267 retval++; 1268 } 1269 1270 /* Restore SIGINT (user interrupt) setting */ 1271 (void) signal(SIGINT, sigint); 1272 } 1273 } 1274 1275 node = di_drv_next_node(node); 1276 } 1277 1278 di_fini(root); 1279 (void) fprintf(stdout, " "); 1280 (void) fprintf(stdout, MSGSTR(125, "Complete\n")); 1281 if (fcode_fd != -1) 1282 (void) close(fcode_fd); 1283 return (retval); 1284 1285 } 1286 1287 /* 1288 * Retrieve the version from the card. 1289 * uses PROM properties 1290 */ 1291 static int 1292 emulex_fcodeversion(di_node_t node, uchar_t *ver) { 1293 di_prom_prop_t promprop; 1294 di_prom_handle_t ph; 1295 char *promname; 1296 uchar_t *ver_data = NULL; 1297 int size, found = 0; 1298 1299 /* check to make sure ver is not NULL */ 1300 if (ver == NULL) { 1301 return (1); 1302 } 1303 1304 if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) { 1305 return (1); 1306 } 1307 1308 for (promprop = di_prom_prop_next(ph, node, 1309 DI_PROM_PROP_NIL); 1310 promprop != DI_PROM_PROP_NIL; 1311 promprop = di_prom_prop_next(ph, node, promprop)) { 1312 if (((promname = di_prom_prop_name( 1313 promprop)) != NULL) && 1314 (strcmp(promname, "fcode-version") == 0)) { 1315 size = di_prom_prop_data(promprop, &ver_data); 1316 (void) memset(ver, NULL, size); 1317 (void) memcpy(ver, ver_data, size); 1318 found = 1; 1319 } 1320 } 1321 1322 if (found) { 1323 return (0); 1324 } else { 1325 return (1); 1326 } 1327 } 1328 1329 /* 1330 * Retrieves information from the Emulex fcode 1331 * 1332 * Given a pattern, this routine will look for this pattern in the fcode 1333 * file and if found will return the pattern value 1334 * 1335 * possible patterns are manufacturer and fcode-version 1336 */ 1337 int 1338 emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value, 1339 uint32_t pattern_value_size) { 1340 int32_t i = 0; 1341 uint32_t n = 0; 1342 uint32_t b = 0; 1343 char byte1; 1344 char byte2; 1345 char byte3; 1346 char byte4; 1347 char buffer1[EMULEX_READ_BUFFER_SIZE]; 1348 char buffer2[EMULEX_READ_BUFFER_SIZE]; 1349 uint32_t plen, image_size; 1350 struct stat stat; 1351 uchar_t *image; 1352 1353 /* Check the arguments */ 1354 if (!fcode_fd || !pattern_value || pattern_value_size < 8) { 1355 return (1); 1356 } 1357 1358 if (fstat(fcode_fd, &stat) == -1) { 1359 perror(MSGSTR(21023, "fstat")); 1360 return (1); 1361 } 1362 image_size = stat.st_size; 1363 if (image_size < 2) { 1364 return (1); 1365 } 1366 if ((image = (uchar_t *)calloc(image_size, 1)) == NULL) { 1367 (void) fprintf(stderr, 1368 MSGSTR(21013, "Error: Memory allocation failed\n")); 1369 return (1); 1370 } 1371 1372 /* Read the fcode image file */ 1373 lseek(fcode_fd, 0, SEEK_SET); 1374 read(fcode_fd, image, image_size); 1375 1376 /* Initialize */ 1377 bzero(buffer1, sizeof (buffer1)); 1378 bzero(buffer2, sizeof (buffer2)); 1379 /* Default pattern_value string */ 1380 strcpy((char *)pattern_value, "<unknown>"); 1381 plen = strlen(pattern); 1382 n = 0; 1383 b = 0; 1384 i = 0; 1385 1386 /* Search entire image for pattern string */ 1387 while (i <= (image_size - 2)) { 1388 /* Read next two bytes */ 1389 byte1 = image[i++]; 1390 byte2 = image[i++]; 1391 1392 /* Check second byte first due to endianness */ 1393 1394 /* Save byte in circular buffer */ 1395 buffer1[b++] = byte2; 1396 if (b == sizeof (buffer1)) { 1397 b = 0; 1398 } 1399 1400 /* Check byte for pattern match */ 1401 if (pattern[n++] != byte2) { 1402 /* If no match, then reset pattern */ 1403 n = 0; 1404 } else { 1405 /* 1406 * If complete pattern has been matched then 1407 * exit loop 1408 */ 1409 if (n == plen) { 1410 goto found; 1411 } 1412 } 1413 1414 1415 /* Check first byte second due to endianness */ 1416 /* Save byte in circular buffer */ 1417 buffer1[b++] = byte1; 1418 if (b == sizeof (buffer1)) { 1419 b = 0; 1420 } 1421 /* Check byte for pattern match */ 1422 if (pattern[n++] != byte1) { 1423 /* If no match, then reset pattern */ 1424 n = 0; 1425 } else { 1426 /* 1427 * If complete pattern has been matched 1428 * then exit loop 1429 */ 1430 if (n == plen) { 1431 goto found; 1432 } 1433 } 1434 } 1435 1436 /* Not found. Try again with different endianess */ 1437 1438 /* Initialize */ 1439 bzero(buffer1, sizeof (buffer1)); 1440 bzero(buffer2, sizeof (buffer2)); 1441 n = 0; 1442 b = 0; 1443 i = 0; 1444 1445 /* Search entire 32bit endian image for pattern string */ 1446 while (i <= (image_size - 4)) { 1447 /* Read next four bytes */ 1448 byte1 = image[i++]; 1449 byte2 = image[i++]; 1450 byte3 = image[i++]; 1451 byte4 = image[i++]; 1452 1453 /* Save byte in circular buffer */ 1454 buffer1[b++] = byte4; 1455 if (b == sizeof (buffer1)) { 1456 b = 0; 1457 } 1458 1459 /* Check byte for pattern match */ 1460 if (pattern[n++] != byte4) { 1461 /* If no match, then reset pattern */ 1462 n = 0; 1463 } else { 1464 /* 1465 * If complete pattern has been matched then exit loop 1466 */ 1467 if (n == plen) { 1468 goto found; 1469 } 1470 } 1471 1472 /* Save byte in circular buffer */ 1473 buffer1[b++] = byte3; 1474 if (b == sizeof (buffer1)) { 1475 b = 0; 1476 } 1477 1478 /* Check byte for pattern match */ 1479 if (pattern[n++] != byte3) { 1480 /* If no match, then reset pattern */ 1481 n = 0; 1482 } else { 1483 /* 1484 * If complete pattern has been matched then exit loop 1485 */ 1486 if (n == plen) { 1487 goto found; 1488 } 1489 } 1490 1491 /* Save byte in circular buffer */ 1492 buffer1[b++] = byte2; 1493 if (b == sizeof (buffer1)) { 1494 b = 0; 1495 } 1496 1497 /* Check byte for pattern match */ 1498 if (pattern[n++] != byte2) { 1499 /* If no match, then reset pattern */ 1500 n = 0; 1501 } else { 1502 /* 1503 * If complete pattern has been matched then exit loop 1504 */ 1505 if (n == plen) { 1506 goto found; 1507 } 1508 } 1509 1510 /* Save byte in circular buffer */ 1511 buffer1[b++] = byte1; 1512 if (b == sizeof (buffer1)) { 1513 b = 0; 1514 } 1515 1516 /* Check byte for pattern match */ 1517 if (pattern[n++] != byte1) { 1518 /* If no match, then reset pattern */ 1519 n = 0; 1520 } else { 1521 /* 1522 * If complete pattern has been matched then exit loop 1523 */ 1524 if (n == plen) { 1525 goto found; 1526 } 1527 } 1528 } 1529 1530 free(image); 1531 return (1); 1532 1533 found: 1534 free(image); 1535 1536 /* Align buffer and eliminate non-printable characters */ 1537 for (i = 0; i < (sizeof (buffer1)-plen); i++) { 1538 byte1 = buffer1[b++]; 1539 if (b == sizeof (buffer1)) { 1540 b = 0; 1541 } 1542 /* Zero any non-printable characters */ 1543 if (byte1 >= 33 && byte1 <= 126) { 1544 buffer2[i] = byte1; 1545 } else { 1546 buffer2[i] = 0; 1547 } 1548 } 1549 1550 /* 1551 * Scan backwards for first non-zero string. This will be the 1552 * version string 1553 */ 1554 for (i = sizeof (buffer1)-plen-1; i >= 0; i--) { 1555 if (buffer2[i] != 0) { 1556 for (; i >= 0; i--) { 1557 if (buffer2[i] == 0) { 1558 i++; 1559 strncpy((char *)pattern_value, 1560 &buffer2[i], pattern_value_size); 1561 break; 1562 } 1563 } 1564 break; 1565 } 1566 } 1567 return (0); 1568 } 1569 1570 /* 1571 * error handling routine to handle emulex error conditions 1572 */ 1573 static void 1574 handle_emulex_error(int fcio_errno, char *phys_path) { 1575 if (fcio_errno == EMLX_IMAGE_BAD) { 1576 fprintf(stderr, MSGSTR(21119, 1577 "Error: Fcode download failed. " 1578 "Bad fcode image.\n")); 1579 } else if (fcio_errno == EMLX_IMAGE_INCOMPATIBLE) { 1580 fprintf(stderr, MSGSTR(21120, 1581 "Error: Fcode download failed. Fcode is not " 1582 "compatible with card.\n")); 1583 } else { 1584 (void) fprintf(stderr, MSGSTR(21036, 1585 "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n")); 1586 (void) fprintf(stderr, 1587 MSGSTR(21113, 1588 "Error: FCode download failed: %s\n"), 1589 phys_path); 1590 } 1591 } 1592