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
q_qlgc_update(unsigned int verbose,char * file)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] = {NULL};
163 static char port2[MAXNAMELEN] = {NULL};
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
q_findversion(int verbose,int index,uchar_t * version,uint16_t * chip_id)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] = {NULL};
405 char mcode_ver[100] = {NULL};
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
q_findfileversion(char * dl_fcode,uchar_t * version_file,uint16_t * file_id,int isSbus,int * sbus_offset)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] = {NULL};
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
q_findSbusfile(int fd,int * sbus_offset)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
q_getdevctlpath(char * devpath,int * devcnt)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
q_getbootdev(uchar_t * bootpath)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
q_load_file(int fcode_fd,char * device)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
q_warn(int errnum)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
memstrstr(char * s1,char * s2,int size1,int size2)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
fcode_load_file(int fcode_fd,char * device,int * fcio_errno)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
emulex_update(char * file)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
emulex_fcodeversion(di_node_t node,uchar_t * ver)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, NULL, 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
emulex_fcode_reader(int fcode_fd,char * pattern,char * pattern_value,uint32_t pattern_value_size)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
handle_emulex_error(int fcio_errno,char * phys_path)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