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