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