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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <assert.h>
39 #include <sys/scsi/impl/uscsi.h>
40 #include <sys/scsi/generic/commands.h>
41 #include <sys/scsi/impl/commands.h>
42 #include <sys/scsi/generic/sense.h>
43 #include <sys/scsi/generic/mode.h>
44 #include <sys/scsi/generic/status.h>
45 #include <sys/scsi/generic/inquiry.h>
46 #include <sys/scsi/adapters/scsi_vhci.h>
47 #include <sys/byteorder.h>
48 #include "common.h"
49 #include "errorcodes.h"
50
51 #define MAX_MODE_SENSE_LEN 0xffff
52 #define MAXLEN 1000
53
54 #define RETRY_PATHLIST 1
55 #define BYTES_PER_LINE 16
56 #define SCMD_UNKNOWN 0xff
57
58 #define SCSI_VHCI "/devices/scsi_vhci/"
59 #define SLASH "/"
60 #define DEV_PREFIX "/devices/"
61 #define DEV_PREFIX_STRLEN strlen(DEV_PREFIX)
62 #define DEVICES_DIR "/devices"
63
64 extern char *dtype[]; /* from adm.c */
65 extern int rand_r(unsigned int *);
66
67 static int cleanup_dotdot_path(char *path);
68 static int wait_random_time(void);
69 static char *scsi_find_command_name(int cmd);
70 static void scsi_printerr(struct uscsi_cmd *ucmd,
71 struct scsi_extended_sense *rq, int rqlen,
72 char msg_string[], char *err_string);
73 static void string_dump(char *hdr, uchar_t *src, int nbytes, int format,
74 char msg_string[]);
75 static int issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag);
76
77
78 static int
wait_random_time(void)79 wait_random_time(void)
80 {
81 time_t timeval;
82 struct tm *tmbuf = NULL;
83 struct timeval tval;
84 unsigned int seed;
85 int random;
86 pid_t pid;
87
88 /*
89 * Get the system time and use "system seconds"
90 * as 'seed' to generate a random number. Then,
91 * wait between 1/10 - 1/2 seconds before retry.
92 * Get the current process id and ex-or it with
93 * the seed so that the random number is always
94 * different even in case of multiple processes
95 * generate a random number at the same time.
96 */
97 if ((timeval = time(NULL)) == -1) {
98 return (errno);
99 }
100 if ((tmbuf = localtime(&timeval)) == NULL) {
101 return (-1); /* L_LOCALTIME_ERROR */
102 }
103
104 pid = getpid();
105
106 /* get a random number. */
107 seed = (unsigned int) tmbuf->tm_sec;
108 seed ^= pid;
109 random = rand_r(&seed);
110
111
112 random = ((random % 500) + 100) * MILLISEC;
113 tval.tv_sec = random / MICROSEC;
114 tval.tv_usec = random % MICROSEC;
115
116 if (select(0, NULL, NULL, NULL, &tval) == -1) {
117 return (-1); /* L_SELECT_ERROR */
118 }
119 return (0);
120 }
121
122 /*
123 * Special string dump for error message
124 */
125 static void
string_dump(char * hdr,uchar_t * src,int nbytes,int format,char msg_string[])126 string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[])
127 {
128 int i;
129 int n;
130 char *p;
131 char s[256];
132
133 assert(format == HEX_ONLY || format == HEX_ASCII);
134
135 (void) strcpy(s, hdr);
136 for (p = s; *p; p++) {
137 *p = ' ';
138 }
139
140 p = hdr;
141 while (nbytes > 0) {
142 (void) sprintf(&msg_string[strlen(msg_string)], "%s", p);
143 p = s;
144 n = MIN(nbytes, BYTES_PER_LINE);
145 for (i = 0; i < n; i++) {
146 (void) sprintf(&msg_string[strlen(msg_string)],
147 "%02x ", src[i] & 0xff);
148 }
149 if (format == HEX_ASCII) {
150 for (i = BYTES_PER_LINE-n; i > 0; i--) {
151 (void) sprintf(&msg_string[strlen(msg_string)],
152 " ");
153 }
154 (void) sprintf(&msg_string[strlen(msg_string)],
155 " ");
156 for (i = 0; i < n; i++) {
157 (void) sprintf(&msg_string[strlen(msg_string)],
158 "%c", isprint(src[i]) ? src[i] : '.');
159 }
160 }
161 (void) sprintf(&msg_string[strlen(msg_string)], "\n");
162 nbytes -= n;
163 src += n;
164 }
165 }
166 /*
167 * Return a pointer to a string telling us the name of the command.
168 */
169 static char *
scsi_find_command_name(int cmd)170 scsi_find_command_name(int cmd)
171 {
172 /*
173 * Names of commands. Must have SCMD_UNKNOWN at end of list.
174 */
175 struct scsi_command_name {
176 int command;
177 char *name;
178 } scsi_command_names[29];
179
180 register struct scsi_command_name *c;
181
182 scsi_command_names[0].command = SCMD_TEST_UNIT_READY;
183 scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready");
184
185 scsi_command_names[1].command = SCMD_FORMAT;
186 scsi_command_names[1].name = MSGSTR(110, "Format");
187
188 scsi_command_names[2].command = SCMD_REASSIGN_BLOCK;
189 scsi_command_names[2].name = MSGSTR(77, "Reassign Block");
190
191 scsi_command_names[3].command = SCMD_READ;
192 scsi_command_names[3].name = MSGSTR(27, "Read");
193
194 scsi_command_names[4].command = SCMD_WRITE;
195 scsi_command_names[4].name = MSGSTR(54, "Write");
196
197 scsi_command_names[5].command = SCMD_READ_G1;
198 scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)");
199
200 scsi_command_names[6].command = SCMD_WRITE_G1;
201 scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)");
202
203 scsi_command_names[7].command = SCMD_MODE_SELECT;
204 scsi_command_names[7].name = MSGSTR(97, "Mode Select");
205
206 scsi_command_names[8].command = SCMD_MODE_SENSE;
207 scsi_command_names[8].name = MSGSTR(95, "Mode Sense");
208
209 scsi_command_names[9].command = SCMD_REASSIGN_BLOCK;
210 scsi_command_names[9].name = MSGSTR(77, "Reassign Block");
211
212 scsi_command_names[10].command = SCMD_REQUEST_SENSE;
213 scsi_command_names[10].name = MSGSTR(74, "Request Sense");
214
215 scsi_command_names[11].command = SCMD_READ_DEFECT_LIST;
216 scsi_command_names[11].name = MSGSTR(80, "Read Defect List");
217
218 scsi_command_names[12].command = SCMD_INQUIRY;
219 scsi_command_names[12].name = MSGSTR(102, "Inquiry");
220
221 scsi_command_names[13].command = SCMD_WRITE_BUFFER;
222 scsi_command_names[13].name = MSGSTR(53, "Write Buffer");
223
224 scsi_command_names[14].command = SCMD_READ_BUFFER;
225 scsi_command_names[14].name = MSGSTR(82, "Read Buffer");
226
227 scsi_command_names[15].command = SCMD_START_STOP;
228 scsi_command_names[15].name = MSGSTR(67, "Start/Stop");
229
230 scsi_command_names[16].command = SCMD_RESERVE;
231 scsi_command_names[16].name = MSGSTR(72, "Reserve");
232
233 scsi_command_names[17].command = SCMD_RELEASE;
234 scsi_command_names[17].name = MSGSTR(75, "Release");
235
236 scsi_command_names[18].command = SCMD_MODE_SENSE_G1;
237 scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)");
238
239 scsi_command_names[19].command = SCMD_MODE_SELECT_G1;
240 scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)");
241
242 scsi_command_names[20].command = SCMD_READ_CAPACITY;
243 scsi_command_names[20].name = MSGSTR(81, "Read Capacity");
244
245 scsi_command_names[21].command = SCMD_SYNC_CACHE;
246 scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache");
247
248 scsi_command_names[22].command = SCMD_READ_DEFECT_LIST;
249 scsi_command_names[22].name = MSGSTR(80, "Read Defect List");
250
251 scsi_command_names[23].command = SCMD_GDIAG;
252 scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic");
253
254 scsi_command_names[24].command = SCMD_SDIAG;
255 scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic");
256
257 scsi_command_names[25].command = SCMD_PERS_RESERV_IN;
258 scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In");
259
260 scsi_command_names[26].command = SCMD_PERS_RESERV_OUT;
261 scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out");
262
263 scsi_command_names[27].command = SCMD_LOG_SENSE;
264 scsi_command_names[27].name = MSGSTR(10502, "Log Sense");
265
266 scsi_command_names[28].command = SCMD_UNKNOWN;
267 scsi_command_names[28].name = MSGSTR(25, "Unknown");
268
269
270 for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++)
271 if (c->command == cmd)
272 break;
273 return (c->name);
274 }
275
276
277 /*
278 * Function to create error message containing
279 * scsi request sense information
280 */
281
282 static void
scsi_printerr(struct uscsi_cmd * ucmd,struct scsi_extended_sense * rq,int rqlen,char msg_string[],char * err_string)283 scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq,
284 int rqlen, char msg_string[], char *err_string)
285 {
286 int blkno;
287
288 switch (rq->es_key) {
289 case KEY_NO_SENSE:
290 (void) sprintf(msg_string, MSGSTR(91, "No sense error"));
291 break;
292 case KEY_RECOVERABLE_ERROR:
293 (void) sprintf(msg_string, MSGSTR(76, "Recoverable error"));
294 break;
295 case KEY_NOT_READY:
296 (void) sprintf(msg_string,
297 MSGSTR(10503,
298 "Device Not ready. Error: Random Retry Failed: %s\n."),
299 err_string);
300 break;
301 case KEY_MEDIUM_ERROR:
302 (void) sprintf(msg_string, MSGSTR(99, "Medium error"));
303 break;
304 case KEY_HARDWARE_ERROR:
305 (void) sprintf(msg_string, MSGSTR(106, "Hardware error"));
306 break;
307 case KEY_ILLEGAL_REQUEST:
308 (void) sprintf(msg_string, MSGSTR(103, "Illegal request"));
309 break;
310 case KEY_UNIT_ATTENTION:
311 (void) sprintf(msg_string,
312 MSGSTR(10504,
313 "Unit attention."
314 "Error: Random Retry Failed.\n"));
315 break;
316 case KEY_WRITE_PROTECT:
317 (void) sprintf(msg_string, MSGSTR(52, "Write protect error"));
318 break;
319 case KEY_BLANK_CHECK:
320 (void) sprintf(msg_string, MSGSTR(131, "Blank check error"));
321 break;
322 case KEY_VENDOR_UNIQUE:
323 (void) sprintf(msg_string, MSGSTR(58, "Vendor unique error"));
324 break;
325 case KEY_COPY_ABORTED:
326 (void) sprintf(msg_string, MSGSTR(123, "Copy aborted error"));
327 break;
328 case KEY_ABORTED_COMMAND:
329 (void) sprintf(msg_string,
330 MSGSTR(10505,
331 "Aborted command. Error: Random Retry Failed.\n"));
332 break;
333 case KEY_EQUAL:
334 (void) sprintf(msg_string, MSGSTR(117, "Equal error"));
335 break;
336 case KEY_VOLUME_OVERFLOW:
337 (void) sprintf(msg_string, MSGSTR(57, "Volume overflow"));
338 break;
339 case KEY_MISCOMPARE:
340 (void) sprintf(msg_string, MSGSTR(98, "Miscompare error"));
341 break;
342 case KEY_RESERVED:
343 (void) sprintf(msg_string, MSGSTR(10506,
344 "Reserved value found"));
345 break;
346 default:
347 (void) sprintf(msg_string, MSGSTR(59, "Unknown error"));
348 break;
349 }
350
351 (void) sprintf(&msg_string[strlen(msg_string)],
352 MSGSTR(10507, " during: %s"),
353 scsi_find_command_name(ucmd->uscsi_cdb[0]));
354
355 if (rq->es_valid) {
356 blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) |
357 (rq->es_info_3 << 8) | rq->es_info_4;
358 (void) sprintf(&msg_string[strlen(msg_string)],
359 MSGSTR(49, ": block %d (0x%x)"), blkno, blkno);
360 }
361
362 (void) sprintf(&msg_string[strlen(msg_string)], "\n");
363
364 if (rq->es_add_len >= 6) {
365 (void) sprintf(&msg_string[strlen(msg_string)],
366 MSGSTR(132, " Additional sense: 0x%x "
367 "ASC Qualifier: 0x%x\n"),
368 rq->es_add_code, rq->es_qual_code);
369 /*
370 * rq->es_add_info[ADD_SENSE_CODE],
371 * rq->es_add_info[ADD_SENSE_QUAL_CODE]);
372 */
373 }
374 if (rq->es_key == KEY_ILLEGAL_REQUEST) {
375 string_dump(MSGSTR(47, " cmd: "), (uchar_t *)ucmd,
376 sizeof (struct uscsi_cmd), HEX_ONLY, msg_string);
377 string_dump(MSGSTR(48, " cdb: "),
378 (uchar_t *)ucmd->uscsi_cdb,
379 ucmd->uscsi_cdblen, HEX_ONLY, msg_string);
380 }
381 string_dump(MSGSTR(43, " sense: "),
382 (uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY, msg_string);
383 rqlen = rqlen; /* not used */
384 }
385
386
387 /*
388 * Execute a command and determine the result.
389 */
390 static int
issue_uscsi_cmd(int file,struct uscsi_cmd * command,int flag)391 issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag)
392 {
393 struct scsi_extended_sense *rqbuf;
394 int status, i, retry_cnt = 0, err;
395 char errorMsg[MAXLEN];
396
397 /*
398 * Set function flags for driver.
399 *
400 * Set Automatic request sense enable
401 *
402 */
403 command->uscsi_flags = USCSI_RQENABLE;
404 command->uscsi_flags |= flag;
405
406 /* intialize error message array */
407 errorMsg[0] = '\0';
408
409 /* print command for debug */
410 if (getenv("_LUX_S_DEBUG") != NULL) {
411 if ((command->uscsi_cdb == NULL) ||
412 (flag & USCSI_RESET) ||
413 (flag & USCSI_RESET_ALL)) {
414 if (flag & USCSI_RESET) {
415 (void) printf(" Issuing a SCSI Reset.\n");
416 }
417 if (flag & USCSI_RESET_ALL) {
418 (void) printf(" Issuing a SCSI Reset All.\n");
419 }
420
421 } else {
422 (void) printf(" Issuing the following "
423 "SCSI command: %s\n",
424 scsi_find_command_name(command->uscsi_cdb[0]));
425 (void) printf(" fd=0x%x cdb=", file);
426 for (i = 0; i < (int)command->uscsi_cdblen; i++) {
427 (void) printf("%x ", *(command->uscsi_cdb + i));
428 }
429 (void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x"
430 " flags=0x%x\n",
431 command->uscsi_cdblen,
432 command->uscsi_bufaddr,
433 command->uscsi_buflen, command->uscsi_flags);
434
435 if ((command->uscsi_buflen > 0) &&
436 ((flag & USCSI_READ) == 0)) {
437 (void) dump_hex_data(" Buffer data: ",
438 (uchar_t *)command->uscsi_bufaddr,
439 MIN(command->uscsi_buflen, 512), HEX_ASCII);
440 }
441 }
442 (void) fflush(stdout);
443 }
444
445
446 /*
447 * Default command timeout in case command left it 0
448 */
449 if (command->uscsi_timeout == 0) {
450 command->uscsi_timeout = 60;
451 }
452 /* Issue command - finally */
453
454 retry:
455 status = ioctl(file, USCSICMD, command);
456 if (status == 0 && command->uscsi_status == 0) {
457 if (getenv("_LUX_S_DEBUG") != NULL) {
458 if ((command->uscsi_buflen > 0) &&
459 (flag & USCSI_READ)) {
460 (void) dump_hex_data("\tData read:",
461 (uchar_t *)command->uscsi_bufaddr,
462 MIN(command->uscsi_buflen, 512), HEX_ASCII);
463 }
464 }
465 return (status);
466 }
467 if ((status != 0) && (command->uscsi_status == 0)) {
468 if ((getenv("_LUX_S_DEBUG") != NULL) ||
469 (getenv("_LUX_ER_DEBUG") != NULL)) {
470 (void) printf("Unexpected USCSICMD ioctl error: %s\n",
471 strerror(errno));
472 }
473 return (status);
474 }
475
476 /*
477 * Just a SCSI error, create error message
478 * Retry once for Unit Attention,
479 * Not Ready, and Aborted Command
480 */
481 if ((command->uscsi_rqbuf != NULL) &&
482 (((char)command->uscsi_rqlen - (char)command->uscsi_rqresid) > 0)) {
483
484 rqbuf = (struct scsi_extended_sense *)command->uscsi_rqbuf;
485
486 switch (rqbuf->es_key) {
487 case KEY_NOT_READY:
488 if (retry_cnt++ < 1) {
489 ER_DPRINTF("Note: Device Not Ready."
490 " Retrying...\n");
491
492 if ((err = wait_random_time()) == 0) {
493 goto retry;
494 } else {
495 return (err);
496 }
497 }
498 break;
499
500 case KEY_UNIT_ATTENTION:
501 if (retry_cnt++ < 1) {
502 ER_DPRINTF(" cmd():"
503 " UNIT_ATTENTION: Retrying...\n");
504
505 goto retry;
506 }
507 break;
508
509 case KEY_ABORTED_COMMAND:
510 if (retry_cnt++ < 1) {
511 ER_DPRINTF("Note: Command is aborted."
512 " Retrying...\n");
513
514 goto retry;
515 }
516 break;
517 }
518 if ((getenv("_LUX_S_DEBUG") != NULL) ||
519 (getenv("_LUX_ER_DEBUG") != NULL)) {
520 scsi_printerr(command,
521 (struct scsi_extended_sense *)command->uscsi_rqbuf,
522 (command->uscsi_rqlen - command->uscsi_rqresid),
523 errorMsg, strerror(errno));
524 }
525
526 } else {
527
528 /*
529 * Retry 5 times in case of BUSY, and only
530 * once for Reservation-conflict, Command
531 * Termination and Queue Full. Wait for
532 * random amount of time (between 1/10 - 1/2 secs.)
533 * between each retry. This random wait is to avoid
534 * the multiple threads being executed at the same time
535 * and also the constraint in Photon IB, where the
536 * command queue has a depth of one command.
537 */
538 switch ((uchar_t)command->uscsi_status & STATUS_MASK) {
539 case STATUS_BUSY:
540 if (retry_cnt++ < 5) {
541 if ((err = wait_random_time()) == 0) {
542 R_DPRINTF(" cmd(): No. of retries %d."
543 " STATUS_BUSY: Retrying...\n",
544 retry_cnt);
545 goto retry;
546
547 } else {
548 return (err);
549 }
550 }
551 break;
552
553 case STATUS_RESERVATION_CONFLICT:
554 if (retry_cnt++ < 1) {
555 if ((err = wait_random_time()) == 0) {
556 R_DPRINTF(" cmd():"
557 " RESERVATION_CONFLICT:"
558 " Retrying...\n");
559 goto retry;
560
561 } else {
562 return (err);
563 }
564 }
565 break;
566
567 case STATUS_TERMINATED:
568 if (retry_cnt++ < 1) {
569 R_DPRINTF("Note: Command Terminated."
570 " Retrying...\n");
571
572 if ((err = wait_random_time()) == 0) {
573 goto retry;
574 } else {
575 return (err);
576 }
577 }
578 break;
579
580 case STATUS_QFULL:
581 if (retry_cnt++ < 1) {
582 R_DPRINTF("Note: Command Queue is full."
583 " Retrying...\n");
584
585 if ((err = wait_random_time()) == 0) {
586 goto retry;
587 } else {
588 return (err);
589 }
590 }
591 break;
592 }
593
594 }
595 if (((getenv("_LUX_S_DEBUG") != NULL) ||
596 (getenv("_LUX_ER_DEBUG") != NULL)) &&
597 (errorMsg[0] != '\0')) {
598 (void) fprintf(stdout, " %s\n", errorMsg);
599 }
600 return (L_SCSI_ERROR | command->uscsi_status);
601 }
602
603 /*
604 * MODE SENSE USCSI command
605 *
606 *
607 * pc = page control field
608 * page_code = Pages to return
609 */
610 int
scsi_mode_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t pc,uchar_t page_code)611 scsi_mode_sense_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t pc,
612 uchar_t page_code)
613 {
614 struct uscsi_cmd ucmd;
615 /* 10 byte Mode Select cmd */
616 union scsi_cdb cdb = {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
617 struct scsi_extended_sense sense;
618 int status;
619 static int uscsi_count;
620
621 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
622 return (-1); /* L_INVALID_ARG */
623 }
624
625 (void) memset(buf_ptr, 0, buf_len);
626 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
627 /* Just for me - a sanity check */
628 if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) ||
629 (buf_len > MAX_MODE_SENSE_LEN)) {
630 return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */
631 }
632 cdb.g1_addr3 = (pc << 6) + page_code;
633 cdb.g1_count1 = buf_len>>8;
634 cdb.g1_count0 = buf_len & 0xff;
635 ucmd.uscsi_cdb = (caddr_t)&cdb;
636 ucmd.uscsi_cdblen = CDB_GROUP1;
637 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
638 ucmd.uscsi_buflen = buf_len;
639 ucmd.uscsi_rqbuf = (caddr_t)&sense;
640 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
641 ucmd.uscsi_timeout = 120;
642
643 status = issue_uscsi_cmd(fd, &ucmd, USCSI_READ);
644 /* Bytes actually transfered */
645 if (status == 0) {
646 uscsi_count = buf_len - ucmd.uscsi_resid;
647 S_DPRINTF(" Number of bytes read on "
648 "Mode Sense 0x%x\n", uscsi_count);
649 if (getenv("_LUX_D_DEBUG") != NULL) {
650 (void) dump_hex_data(" Mode Sense data: ", buf_ptr,
651 uscsi_count, HEX_ASCII);
652 }
653 }
654 return (status);
655 }
656
657 int
scsi_release(char * path)658 scsi_release(char *path)
659 {
660 struct uscsi_cmd ucmd;
661 union scsi_cdb cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0};
662 struct scsi_extended_sense sense;
663 int fd, status;
664
665 P_DPRINTF(" scsi_release: Release: Path %s\n", path);
666 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1)
667 return (1);
668
669 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
670
671 ucmd.uscsi_cdb = (caddr_t)&cdb;
672 ucmd.uscsi_cdblen = CDB_GROUP0;
673 ucmd.uscsi_bufaddr = NULL;
674 ucmd.uscsi_buflen = 0;
675 ucmd.uscsi_rqbuf = (caddr_t)&sense;
676 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
677 ucmd.uscsi_timeout = 60;
678 status = (issue_uscsi_cmd(fd, &ucmd, 0));
679
680 (void) close(fd);
681 return (status);
682 }
683
684 int
scsi_reserve(char * path)685 scsi_reserve(char *path)
686 {
687 struct uscsi_cmd ucmd;
688 union scsi_cdb cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0};
689 struct scsi_extended_sense sense;
690 int fd, status;
691
692 P_DPRINTF(" scsi_reserve: Reserve: Path %s\n", path);
693 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1)
694 return (1);
695
696 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
697
698 ucmd.uscsi_cdb = (caddr_t)&cdb;
699 ucmd.uscsi_cdblen = CDB_GROUP0;
700 ucmd.uscsi_bufaddr = NULL;
701 ucmd.uscsi_buflen = 0;
702 ucmd.uscsi_rqbuf = (caddr_t)&sense;
703 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
704 ucmd.uscsi_timeout = 60;
705 status = (issue_uscsi_cmd(fd, &ucmd, 0));
706
707 (void) close(fd);
708 return (status);
709 }
710
711 /*
712 * Print out fabric dev dtype
713 */
714 void
print_fabric_dtype_prop(uchar_t * hba_port_wwn,uchar_t * port_wwn,uchar_t dtype_prop)715 print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn,
716 uchar_t dtype_prop)
717 {
718 if ((dtype_prop & DTYPE_MASK) < 0x10) {
719 (void) fprintf(stdout, " 0x%-2x (%s)\n",
720 (dtype_prop & DTYPE_MASK),
721 dtype[(dtype_prop & DTYPE_MASK)]);
722 } else if ((dtype_prop & DTYPE_MASK) < 0x1f) {
723 (void) fprintf(stdout,
724 MSGSTR(2096, " 0x%-2x (Reserved)\n"),
725 (dtype_prop & DTYPE_MASK));
726 } else {
727 /* Check to see if this is the HBA */
728 if (wwnConversion(hba_port_wwn) != wwnConversion(port_wwn)) {
729 (void) fprintf(stdout, MSGSTR(2097,
730 " 0x%-2x (Unknown Type)\n"),
731 (dtype_prop & DTYPE_MASK));
732 } else {
733 /* MATCH */
734 (void) fprintf(stdout, MSGSTR(2241,
735 " 0x%-2x (Unknown Type,Host Bus Adapter)\n"),
736 (dtype_prop & DTYPE_MASK));
737 }
738 }
739 }
740
741
742 void
print_inq_data(char * arg_path,char * path,L_inquiry inq,uchar_t * serial,size_t serial_len)743 print_inq_data(char *arg_path, char *path, L_inquiry inq, uchar_t *serial,
744 size_t serial_len)
745 {
746 char **p;
747 uchar_t *v_parm;
748 int scsi_3, length;
749 char byte_number[MAXNAMELEN];
750 static char *scsi_inquiry_labels_2[21];
751 static char *scsi_inquiry_labels_3[22];
752 #define MAX_ANSI_VERSION 6
753 static char *ansi_version[MAX_ANSI_VERSION];
754 /*
755 * Intialize scsi_inquiry_labels_2 with i18n strings
756 */
757 scsi_inquiry_labels_2[0] = MSGSTR(138, "Vendor: ");
758 scsi_inquiry_labels_2[1] = MSGSTR(149, "Product: ");
759 scsi_inquiry_labels_2[2] = MSGSTR(139, "Revision: ");
760 scsi_inquiry_labels_2[3] = MSGSTR(143, "Firmware Revision ");
761 scsi_inquiry_labels_2[4] = MSGSTR(144, "Serial Number ");
762 scsi_inquiry_labels_2[5] = MSGSTR(140, "Device type: ");
763 scsi_inquiry_labels_2[6] = MSGSTR(145, "Removable media: ");
764 scsi_inquiry_labels_2[7] = MSGSTR(146, "ISO version: ");
765 scsi_inquiry_labels_2[8] = MSGSTR(147, "ECMA version: ");
766 scsi_inquiry_labels_2[9] = MSGSTR(148, "ANSI version: ");
767 scsi_inquiry_labels_2[10] =
768 MSGSTR(2168, "Async event notification: ");
769 scsi_inquiry_labels_2[11] =
770 MSGSTR(2169, "Terminate i/o process msg: ");
771 scsi_inquiry_labels_2[12] = MSGSTR(150, "Response data format: ");
772 scsi_inquiry_labels_2[13] = MSGSTR(151, "Additional length: ");
773 scsi_inquiry_labels_2[14] = MSGSTR(152, "Relative addressing: ");
774 scsi_inquiry_labels_2[15] =
775 MSGSTR(2170, "32 bit transfers: ");
776 scsi_inquiry_labels_2[16] =
777 MSGSTR(2171, "16 bit transfers: ");
778 scsi_inquiry_labels_2[17] =
779 MSGSTR(2172, "Synchronous transfers: ");
780 scsi_inquiry_labels_2[18] = MSGSTR(153, "Linked commands: ");
781 scsi_inquiry_labels_2[19] = MSGSTR(154, "Command queueing: ");
782 scsi_inquiry_labels_2[20] =
783 MSGSTR(2173, "Soft reset option: ");
784
785 /*
786 * Intialize scsi_inquiry_labels_3 with i18n strings
787 */
788 scsi_inquiry_labels_3[0] = MSGSTR(138, "Vendor: ");
789 scsi_inquiry_labels_3[1] = MSGSTR(149, "Product: ");
790 scsi_inquiry_labels_3[2] = MSGSTR(139, "Revision: ");
791 scsi_inquiry_labels_3[3] = MSGSTR(143, "Firmware Revision ");
792 scsi_inquiry_labels_3[4] = MSGSTR(144, "Serial Number ");
793 scsi_inquiry_labels_3[5] = MSGSTR(140, "Device type: ");
794 scsi_inquiry_labels_3[6] = MSGSTR(145, "Removable media: ");
795 scsi_inquiry_labels_3[7] = MSGSTR(2174, "Medium Changer Element: ");
796 scsi_inquiry_labels_3[8] = MSGSTR(146, "ISO version: ");
797 scsi_inquiry_labels_3[9] = MSGSTR(147, "ECMA version: ");
798 scsi_inquiry_labels_3[10] = MSGSTR(148, "ANSI version: ");
799 scsi_inquiry_labels_3[11] =
800 MSGSTR(2175, "Async event reporting: ");
801 scsi_inquiry_labels_3[12] =
802 MSGSTR(2176, "Terminate task: ");
803 scsi_inquiry_labels_3[13] =
804 MSGSTR(2177, "Normal ACA Supported: ");
805 scsi_inquiry_labels_3[14] = MSGSTR(150, "Response data format: ");
806 scsi_inquiry_labels_3[15] = MSGSTR(151, "Additional length: ");
807 scsi_inquiry_labels_3[16] =
808 MSGSTR(2178, "Cmd received on port: ");
809 scsi_inquiry_labels_3[17] =
810 MSGSTR(2179, "SIP Bits: ");
811 scsi_inquiry_labels_3[18] = MSGSTR(152, "Relative addressing: ");
812 scsi_inquiry_labels_3[19] = MSGSTR(153, "Linked commands: ");
813 scsi_inquiry_labels_3[20] =
814 MSGSTR(2180, "Transfer Disable: ");
815 scsi_inquiry_labels_3[21] = MSGSTR(154, "Command queueing: ");
816
817 /*
818 * Intialize scsi_inquiry_labels_3 with i18n strings
819 */
820 ansi_version[0] = MSGSTR(2181,
821 " (Device might or might not comply to an ANSI version)");
822 ansi_version[1] = MSGSTR(2182,
823 " (This code is reserved for historical uses)");
824 ansi_version[2] = MSGSTR(2183,
825 " (Device complies to ANSI X3.131-1994 (SCSI-2))");
826 ansi_version[3] = MSGSTR(2184,
827 " (Device complies to ANSI INCITS 301-1997 (SPC))");
828 ansi_version[4] = MSGSTR(2226,
829 " (Device complies to ANSI INCITS 351-2001 (SPC-2))");
830 ansi_version[5] = MSGSTR(2227,
831 " (Device complies to ANSI INCITS 408-2005 (SPC-3))");
832
833 /* print inquiry information */
834
835 (void) fprintf(stdout, MSGSTR(2185, "\nINQUIRY:\n"));
836 /*
837 * arg_path is the path sent to luxadm by the user. if arg_path
838 * is a /devices path, then we do not need to print out physical
839 * path info
840 */
841 if (strcmp(arg_path, path) != 0 &&
842 strstr(arg_path, "/devices/") == NULL) {
843 (void) fprintf(stdout, " ");
844 (void) fprintf(stdout,
845 MSGSTR(5, "Physical Path:"));
846 (void) fprintf(stdout, "\n %s\n", path);
847 }
848 if (inq.inq_ansi < 3) {
849 p = scsi_inquiry_labels_2;
850 scsi_3 = 0;
851 } else {
852 p = scsi_inquiry_labels_3;
853 scsi_3 = 1;
854 }
855 if (inq.inq_len < 11) {
856 p += 1;
857 } else {
858 /* */
859 (void) fprintf(stdout, "%s", *p++);
860 print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);
861 (void) fprintf(stdout, "\n");
862 }
863 if (inq.inq_len < 27) {
864 p += 1;
865 } else {
866 (void) fprintf(stdout, "%s", *p++);
867 print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);
868 (void) fprintf(stdout, "\n");
869 }
870 if (inq.inq_len < 31) {
871 p += 1;
872 } else {
873 (void) fprintf(stdout, "%s", *p++);
874 print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);
875 (void) fprintf(stdout, "\n");
876 }
877 if (inq.inq_len < 39) {
878 p += 2;
879 } else {
880 /*
881 * If Pluto then print
882 * firmware rev & serial #.
883 */
884 if (strstr((char *)inq.inq_pid, "SSA") != 0) {
885 (void) fprintf(stdout, "%s", *p++);
886 print_chars(inq.inq_firmware_rev,
887 sizeof (inq.inq_firmware_rev), 0);
888 (void) fprintf(stdout, "\n");
889 (void) fprintf(stdout, "%s", *p++);
890 print_chars(serial, serial_len, 0);
891 (void) fprintf(stdout, "\n");
892 } else if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_ESI) {
893 p++;
894 (void) fprintf(stdout, "%s", *p++);
895 print_chars(serial, serial_len, 0);
896 (void) fprintf(stdout, "\n");
897 } else {
898 /* if we miss both the above if's */
899 p += 2;
900 }
901 }
902
903 (void) fprintf(stdout, "%s0x%x (", *p++, (inq.inq_dtype & DTYPE_MASK));
904 if ((inq.inq_dtype & DTYPE_MASK) < 0x10) {
905 (void) fprintf(stdout, "%s", dtype[inq.inq_dtype & DTYPE_MASK]);
906 } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) {
907 (void) fprintf(stdout, MSGSTR(71, "Reserved"));
908 } else {
909 (void) fprintf(stdout, MSGSTR(2186, "Unknown device"));
910 }
911 (void) fprintf(stdout, ")\n");
912
913 (void) fprintf(stdout, "%s", *p++);
914 if (inq.inq_rmb != 0) {
915 (void) fprintf(stdout, MSGSTR(40, "yes"));
916 } else {
917 (void) fprintf(stdout, MSGSTR(45, "no"));
918 }
919 (void) fprintf(stdout, "\n");
920
921 if (scsi_3) {
922 (void) fprintf(stdout, "%s", *p++);
923 if (inq.inq_mchngr != 0) {
924 (void) fprintf(stdout, MSGSTR(40, "yes"));
925 } else {
926 (void) fprintf(stdout, MSGSTR(45, "no"));
927 }
928 (void) fprintf(stdout, "\n");
929 }
930 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_iso);
931 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_ecma);
932
933 (void) fprintf(stdout, "%s%d", *p++, inq.inq_ansi);
934 if (inq.inq_ansi < MAX_ANSI_VERSION) {
935 (void) fprintf(stdout, "%s", ansi_version[inq.inq_ansi]);
936 } else
937 (void) fprintf(stdout, " (%s)", MSGSTR(71, "Reserved"));
938
939 (void) fprintf(stdout, "\n");
940
941 if (inq.inq_aenc) {
942 (void) fprintf(stdout, "%s", *p++);
943 (void) fprintf(stdout, MSGSTR(40, "yes"));
944 (void) fprintf(stdout, "\n");
945 } else {
946 p++;
947 }
948 if (scsi_3) {
949 (void) fprintf(stdout, "%s", *p++);
950 if (inq.inq_normaca != 0) {
951 (void) fprintf(stdout, MSGSTR(40, "yes"));
952 } else {
953 (void) fprintf(stdout, MSGSTR(45, "no"));
954 }
955 (void) fprintf(stdout, "\n");
956 }
957 if (inq.inq_trmiop) {
958 (void) fprintf(stdout, "%s", *p++);
959 (void) fprintf(stdout, MSGSTR(40, "yes"));
960 (void) fprintf(stdout, "\n");
961 } else {
962 p++;
963 }
964 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_rdf);
965 (void) fprintf(stdout, "%s0x%x\n", *p++, inq.inq_len);
966 if (scsi_3) {
967 if (inq.inq_dual_p) {
968 if (inq.inq_port != 0) {
969 (void) fprintf(stdout, MSGSTR(2187,
970 "%sa\n"), *p++);
971 } else {
972 (void) fprintf(stdout, MSGSTR(2188,
973 "%sb\n"), *p++);
974 }
975 } else {
976 p++;
977 }
978 }
979 if (scsi_3) {
980 if (inq.inq_SIP_1 || inq.ui.inq_3.inq_SIP_2 ||
981 inq.ui.inq_3.inq_SIP_3) {
982 (void) fprintf(stdout, "%s%d, %d, %d\n", *p,
983 inq.inq_SIP_1, inq.ui.inq_3.inq_SIP_2,
984 inq.ui.inq_3.inq_SIP_3);
985 }
986 p++;
987
988 }
989
990 if (inq.ui.inq_2.inq_2_reladdr) {
991 (void) fprintf(stdout, "%s", *p);
992 (void) fprintf(stdout, MSGSTR(40, "yes"));
993 (void) fprintf(stdout, "\n");
994 }
995 p++;
996
997 if (!scsi_3) {
998 if (inq.ui.inq_2.inq_wbus32) {
999 (void) fprintf(stdout, "%s", *p);
1000 (void) fprintf(stdout, MSGSTR(40, "yes"));
1001 (void) fprintf(stdout, "\n");
1002 }
1003 p++;
1004
1005 if (inq.ui.inq_2.inq_wbus16) {
1006 (void) fprintf(stdout, "%s", *p);
1007 (void) fprintf(stdout, MSGSTR(40, "yes"));
1008 (void) fprintf(stdout, "\n");
1009 }
1010 p++;
1011
1012 if (inq.ui.inq_2.inq_sync) {
1013 (void) fprintf(stdout, "%s", *p);
1014 (void) fprintf(stdout, MSGSTR(40, "yes"));
1015 (void) fprintf(stdout, "\n");
1016 }
1017 p++;
1018
1019 }
1020 if (inq.ui.inq_2.inq_linked) {
1021 (void) fprintf(stdout, "%s", *p);
1022 (void) fprintf(stdout, MSGSTR(40, "yes"));
1023 (void) fprintf(stdout, "\n");
1024 }
1025 p++;
1026
1027 if (scsi_3) {
1028 (void) fprintf(stdout, "%s", *p++);
1029 if (inq.ui.inq_3.inq_trandis != 0) {
1030 (void) fprintf(stdout, MSGSTR(40, "yes"));
1031 } else {
1032 (void) fprintf(stdout, MSGSTR(45, "no"));
1033 }
1034 (void) fprintf(stdout, "\n");
1035 }
1036
1037 if (inq.ui.inq_2.inq_cmdque) {
1038 (void) fprintf(stdout, "%s", *p);
1039 (void) fprintf(stdout, MSGSTR(40, "yes"));
1040 (void) fprintf(stdout, "\n");
1041 }
1042 p++;
1043
1044 if (!scsi_3) {
1045 if (inq.ui.inq_2.inq_sftre) {
1046 (void) fprintf(stdout, "%s", *p);
1047 (void) fprintf(stdout, MSGSTR(40, "yes"));
1048 (void) fprintf(stdout, "\n");
1049 }
1050 p++;
1051
1052 }
1053
1054 /*
1055 * Now print the vendor-specific data.
1056 */
1057 v_parm = inq.inq_ven_specific_1;
1058 if (inq.inq_len >= 32) {
1059 length = inq.inq_len - 31;
1060 if (strstr((char *)inq.inq_pid, "SSA") != 0) {
1061 (void) fprintf(stdout, MSGSTR(2189,
1062 "Number of Ports, Targets: %d,%d\n"),
1063 inq.inq_ssa_ports, inq.inq_ssa_tgts);
1064 v_parm += 20;
1065 length -= 20;
1066 } else if ((strstr((char *)inq.inq_pid, "SUN") != 0) ||
1067 (strncmp((char *)inq.inq_vid, "SUN ",
1068 sizeof (inq.inq_vid)) == 0)) {
1069 v_parm += 16;
1070 length -= 16;
1071 }
1072 /*
1073 * Do hex Dump of rest of the data.
1074 */
1075 if (length > 0) {
1076 (void) fprintf(stdout,
1077 MSGSTR(2190,
1078 " VENDOR-SPECIFIC PARAMETERS\n"));
1079 (void) fprintf(stdout,
1080 MSGSTR(2191,
1081 "Byte# Hex Value "
1082 " ASCII\n"));
1083 (void) sprintf(byte_number,
1084 "%d ", inq.inq_len - length + 5);
1085 dump_hex_data(byte_number, v_parm,
1086 MIN(length, inq.inq_res3 - v_parm), HEX_ASCII);
1087 }
1088 /*
1089 * Skip reserved bytes 56-95.
1090 */
1091 length -= (inq.inq_box_name - v_parm);
1092 if (length > 0) {
1093 (void) sprintf(byte_number, "%d ",
1094 inq.inq_len - length + 5);
1095 dump_hex_data(byte_number, inq.inq_box_name,
1096 MIN(length, sizeof (inq.inq_box_name) +
1097 sizeof (inq.inq_avu)), HEX_ASCII);
1098 }
1099 }
1100 if (getenv("_LUX_D_DEBUG") != NULL) {
1101 dump_hex_data("\nComplete Inquiry: ",
1102 (uchar_t *)&inq,
1103 MIN(inq.inq_len + 5, sizeof (inq)), HEX_ASCII);
1104 }
1105 }
1106
1107 /*
1108 * Internal routine to clean up ../'s in paths.
1109 * returns 0 if no "../" are left.
1110 *
1111 * Wouldn't it be nice if there was a standard system library
1112 * routine to do this...?
1113 */
1114 static int
cleanup_dotdot_path(char * path)1115 cleanup_dotdot_path(char *path)
1116 {
1117 char holder[MAXPATHLEN];
1118 char *dotdot;
1119 char *previous_slash;
1120
1121 /* Find the first "/../" in the string */
1122 dotdot = strstr(path, "/../");
1123 if (dotdot == NULL) {
1124 return (0);
1125 }
1126
1127
1128 /*
1129 * If the [0] character is '/' and "../" immediatly
1130 * follows it, then we can strip the ../
1131 *
1132 * /../../foo/bar == /foo/bar
1133 *
1134 */
1135 if (dotdot == path) {
1136 strcpy(holder, &path[3]); /* strip "/.." */
1137 strcpy(path, holder);
1138 return (1);
1139 }
1140
1141 /*
1142 * Now look for the LAST "/" before the "/../"
1143 * as this is the parent dir we can get rid of.
1144 * We do this by temporarily truncating the string
1145 * at the '/' just before "../" using the dotdot pointer.
1146 */
1147 *dotdot = '\0';
1148 previous_slash = strrchr(path, '/');
1149 if (previous_slash == NULL) {
1150 /*
1151 * hmm, somethings wrong. path looks something
1152 * like "foo/../bar/" so we can't really deal with it.
1153 */
1154 return (0);
1155 }
1156 /*
1157 * Now truncate the path just after the previous '/'
1158 * and slam everything after the "../" back on
1159 */
1160 *(previous_slash+1) = '\0';
1161 (void) strcat(path, dotdot+4);
1162 return (1); /* We may have more "../"s */
1163 }
1164
1165 /*
1166 * Follow symbolic links from the logical device name to
1167 * the /devfs physical device name. To be complete, we
1168 * handle the case of multiple links. This function
1169 * either returns NULL (no links, or some other error),
1170 * or the physical device name, alloc'ed on the heap.
1171 *
1172 * NOTE: If the path is relative, it will be forced into
1173 * an absolute path by pre-pending the pwd to it.
1174 */
1175 char *
get_slash_devices_from_osDevName(char * osDevName,int flag)1176 get_slash_devices_from_osDevName(char *osDevName, int flag)
1177 {
1178 struct stat stbuf;
1179 char source[MAXPATHLEN];
1180 char scratch[MAXPATHLEN];
1181 char pwd[MAXPATHLEN];
1182 char *tmp, *phys_path;
1183 int cnt;
1184 boolean_t is_lstat_failed = B_TRUE;
1185
1186 /* return NULL if path is NULL */
1187 if (osDevName == NULL) {
1188 return (NULL);
1189 }
1190
1191 strcpy(source, osDevName);
1192 for (;;) {
1193
1194 /*
1195 * First make sure the path is absolute. If not, make it.
1196 * If it's already an absolute path, we have no need
1197 * to determine the cwd, so the program should still
1198 * function within security-by-obscurity directories.
1199 */
1200 if (source[0] != '/') {
1201 tmp = getcwd(pwd, MAXPATHLEN);
1202 if (tmp == NULL) {
1203 return (NULL);
1204 }
1205 /*
1206 * Handle special case of "./foo/bar"
1207 */
1208 if (source[0] == '.' && source[1] == '/') {
1209 strcpy(scratch, source+2);
1210 } else { /* no "./" so just take everything */
1211 strcpy(scratch, source);
1212 }
1213 strcpy(source, pwd);
1214 (void) strcat(source, "/");
1215 (void) strcat(source, scratch);
1216 }
1217
1218 /*
1219 * Clean up any "../"s that are in the path
1220 */
1221 while (cleanup_dotdot_path(source))
1222 ;
1223
1224 /*
1225 * source is now an absolute path to the link we're
1226 * concerned with
1227 */
1228 if (flag == NOT_IGNORE_DANGLING_LINK) {
1229 /*
1230 * In order not to ingore dangling links, check
1231 * the lstat. If lstat succeeds, return the path
1232 * from readlink.
1233 * Note: osDevName input with /devices path from
1234 * a dangling /dev link doesn't pass lstat so
1235 * NULL is returned.
1236 */
1237 if (stat(source, &stbuf) == -1) {
1238 if (!is_lstat_failed &&
1239 strstr(source, "/devices")) {
1240 /*
1241 * lstat succeeded previously and source
1242 * contains "/devices" then it is
1243 * dangling node.
1244 */
1245 phys_path = (char *)calloc(1,
1246 strlen(source) + 1);
1247 if (phys_path != NULL) {
1248 (void) strncpy(phys_path,
1249 source, strlen(source) + 1);
1250 }
1251 return (phys_path);
1252 } else if (is_lstat_failed) {
1253 /* check lstat result. */
1254 if (lstat(source, &stbuf) == -1) {
1255 return (NULL);
1256 } else {
1257 /* and continue */
1258 is_lstat_failed = B_FALSE;
1259 }
1260 } else {
1261 /*
1262 * With algorithm that resolves a link
1263 * and then issues readlink(), should
1264 * not be reached here.
1265 */
1266 return (NULL);
1267 }
1268 } else {
1269 if (lstat(source, &stbuf) == -1) {
1270 /*
1271 * when stat succeeds it is not
1272 * a dangling node so it is not
1273 * a special case.
1274 */
1275 return (NULL);
1276 }
1277 }
1278 } else if (flag == STANDARD_DEVNAME_HANDLING) {
1279 /*
1280 * See if there's a real file out there. If not,
1281 * we have a dangling link and we ignore it.
1282 */
1283 if (stat(source, &stbuf) == -1) {
1284 return (NULL);
1285 }
1286 if (lstat(source, &stbuf) == -1) {
1287 return (NULL);
1288 }
1289 } else {
1290 /* invalid flag */
1291 return (NULL);
1292 }
1293
1294 /*
1295 * If the file is not a link, we're done one
1296 * way or the other. If there were links,
1297 * return the full pathname of the resulting
1298 * file.
1299 *
1300 * Note: All of our temp's are on the stack,
1301 * so we have to copy the final result to the heap.
1302 */
1303 if (!S_ISLNK(stbuf.st_mode)) {
1304 phys_path = (char *)calloc(1, strlen(source) + 1);
1305 if (phys_path != NULL) {
1306 (void) strncpy(phys_path, source,
1307 strlen(source) + 1);
1308 }
1309 return (phys_path);
1310 }
1311 cnt = readlink(source, scratch, sizeof (scratch));
1312 if (cnt < 0) {
1313 return (NULL);
1314 }
1315 /*
1316 * scratch is on the heap, and for some reason readlink
1317 * doesn't always terminate things properly so we have
1318 * to make certain we're properly terminated
1319 */
1320 scratch[cnt] = '\0';
1321
1322 /*
1323 * Now check to see if the link is relative. If so,
1324 * then we have to append it to the directory
1325 * which the source was in. (This is non trivial)
1326 */
1327 if (scratch[0] != '/') {
1328 tmp = strrchr(source, '/');
1329 if (tmp == NULL) { /* Whoa! Something's hosed! */
1330 O_DPRINTF("Internal error... corrupt path.\n");
1331 return (NULL);
1332 }
1333 /* Now strip off just the directory path */
1334 *(tmp+1) = '\0'; /* Keeping the last '/' */
1335 /* and append the new link */
1336 (void) strcat(source, scratch);
1337 /*
1338 * Note: At this point, source should have "../"s
1339 * but we'll clean it up in the next pass through
1340 * the loop.
1341 */
1342 } else {
1343 /* It's an absolute link so no worries */
1344 strcpy(source, scratch);
1345 }
1346 }
1347 /* Never reach here */
1348 }
1349
1350 /*
1351 * Input - Space for client_path, phci_path and paddr fields of ioc structure
1352 * need to be allocated by the caller of this routine.
1353 */
1354 int
get_scsi_vhci_pathinfo(char * dev_path,sv_iocdata_t * ioc,int * path_count)1355 get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count)
1356 {
1357 char *physical_path, *physical_path_s;
1358 int retval;
1359 int fd;
1360 int initial_path_count;
1361 int current_path_count;
1362 int i;
1363 char *delimiter;
1364 int malloc_error = 0;
1365 int prop_buf_size;
1366 int pathlist_retry_count = 0;
1367
1368 if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) {
1369 if ((physical_path = get_slash_devices_from_osDevName(
1370 dev_path, STANDARD_DEVNAME_HANDLING)) == NULL) {
1371 return (L_INVALID_PATH);
1372 }
1373 if (strncmp(physical_path, SCSI_VHCI,
1374 strlen(SCSI_VHCI)) != 0) {
1375 free(physical_path);
1376 return (L_INVALID_PATH);
1377 }
1378 } else {
1379 if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) {
1380 return (L_MALLOC_FAILED);
1381 }
1382 (void) strcpy(physical_path, dev_path);
1383 }
1384 physical_path_s = physical_path;
1385
1386 /* move beyond "/devices" prefix */
1387 physical_path += DEV_PREFIX_STRLEN-1;
1388 /* remove :c,raw suffix */
1389 delimiter = strrchr(physical_path, ':');
1390 /* if we didn't find the ':' fine, else truncate */
1391 if (delimiter != NULL) {
1392 *delimiter = '\0';
1393 }
1394
1395 /*
1396 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
1397 * at least twice. The first time will get the path count
1398 * and the size of the ioctl propoerty buffer. The second
1399 * time will get the path_info for each path.
1400 *
1401 * It's possible that additional paths are added while this
1402 * code is running. If the path count increases between the
1403 * 2 ioctl's above, then we'll retry (and assume all is well).
1404 */
1405 (void) strcpy(ioc->client, physical_path);
1406 ioc->buf_elem = 1;
1407 ioc->ret_elem = (uint_t *)&(initial_path_count);
1408 ioc->ret_buf = NULL;
1409
1410 /* free physical path */
1411 free(physical_path_s);
1412
1413 /* 0 buf_size asks driver to return actual size needed */
1414 /* open the ioctl file descriptor */
1415 if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) {
1416 return (L_OPEN_PATH_FAIL);
1417 }
1418
1419 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
1420 if (retval != 0) {
1421 close(fd);
1422 return (L_SCSI_VHCI_ERROR);
1423 }
1424 prop_buf_size = SV_PROP_MAX_BUF_SIZE;
1425
1426
1427 while (pathlist_retry_count <= RETRY_PATHLIST) {
1428 ioc->buf_elem = initial_path_count;
1429 /* Make driver put actual # paths in variable */
1430 ioc->ret_elem = (uint_t *)&(current_path_count);
1431
1432 /*
1433 * Allocate space for array of path_info structures.
1434 * Allocate enough space for # paths from get_pathcount
1435 */
1436 ioc->ret_buf = (sv_path_info_t *)
1437 calloc(initial_path_count, sizeof (sv_path_info_t));
1438 if (ioc->ret_buf == NULL) {
1439 close(fd);
1440 return (L_MALLOC_FAILED);
1441 }
1442
1443 /*
1444 * Allocate space for path properties returned by driver
1445 */
1446 malloc_error = 0;
1447 for (i = 0; i < initial_path_count; i++) {
1448 ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size;
1449 if ((ioc->ret_buf[i].ret_prop.buf =
1450 (caddr_t)malloc(prop_buf_size)) == NULL) {
1451 malloc_error = 1;
1452 break;
1453 }
1454 if ((ioc->ret_buf[i].ret_prop.ret_buf_size =
1455 (uint_t *)malloc(sizeof (uint_t))) == NULL) {
1456 malloc_error = 1;
1457 break;
1458 }
1459 }
1460 if (malloc_error == 1) {
1461 for (i = 0; i < initial_path_count; i++) {
1462 free(ioc->ret_buf[i].ret_prop.buf);
1463 free(ioc->ret_buf[i].ret_prop.ret_buf_size);
1464 }
1465 free(ioc->ret_buf);
1466 close(fd);
1467 return (L_MALLOC_FAILED);
1468 }
1469
1470 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
1471 if (retval != 0) {
1472 for (i = 0; i < initial_path_count; i++) {
1473 free(ioc->ret_buf[i].ret_prop.buf);
1474 free(ioc->ret_buf[i].ret_prop.ret_buf_size);
1475 }
1476 free(ioc->ret_buf);
1477 close(fd);
1478 return (L_SCSI_VHCI_ERROR);
1479 }
1480 if (initial_path_count < current_path_count) {
1481 /* then a new path was added */
1482 pathlist_retry_count++;
1483 initial_path_count = current_path_count;
1484 } else {
1485 break;
1486 }
1487 }
1488 /* we are done with ioctl's, lose the fd */
1489 close(fd);
1490
1491 /*
1492 * Compare the length num elements from the ioctl response
1493 * and the caller's request - use smaller value.
1494 *
1495 * pathlist_p->path_count now has count returned from ioctl.
1496 * ioc.buf_elem has the value the caller provided.
1497 */
1498 if (initial_path_count < current_path_count) {
1499 /* More paths exist than we allocated space for */
1500 *path_count = initial_path_count;
1501 } else {
1502 *path_count = current_path_count;
1503 }
1504
1505 return (0);
1506 }
1507
1508 int
get_mode_page(char * path,uchar_t ** pg_buf)1509 get_mode_page(char *path, uchar_t **pg_buf)
1510 {
1511 struct mode_header_g1 *mode_header_ptr;
1512 int status, size, fd;
1513
1514 /* open controller */
1515 if ((fd = open(path, O_NDELAY | O_RDWR)) == -1)
1516 return (-1); /* L_OPEN_PATH_FAIL */
1517
1518 /*
1519 * Read the first part of the page to get the page size
1520 */
1521 size = 20;
1522 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) {
1523 (void) close(fd);
1524 return (L_MALLOC_FAILED);
1525 }
1526 /* read page */
1527 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size,
1528 0, MODEPAGE_ALLPAGES)) {
1529 (void) close(fd);
1530 (void) free(*pg_buf);
1531 return (status);
1532 }
1533 /* Now get the size for all pages */
1534 mode_header_ptr = (struct mode_header_g1 *)(void *)*pg_buf;
1535 size = ntohs(mode_header_ptr->length) +
1536 sizeof (mode_header_ptr->length);
1537 (void) free(*pg_buf);
1538 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) {
1539 (void) close(fd);
1540 return (L_MALLOC_FAILED);
1541 }
1542 /* read all pages */
1543 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size,
1544 0, MODEPAGE_ALLPAGES)) {
1545 (void) close(fd);
1546 (void) free(*pg_buf);
1547 return (status);
1548 }
1549 (void) close(fd);
1550 return (0);
1551 }
1552
1553 /*
1554 * Dump a structure in hexadecimal.
1555 */
1556 void
dump_hex_data(char * hdr,uchar_t * src,int nbytes,int format)1557 dump_hex_data(char *hdr, uchar_t *src, int nbytes, int format)
1558 {
1559 int i;
1560 int n;
1561 char *p;
1562 char s[256];
1563
1564 assert(format == HEX_ONLY || format == HEX_ASCII);
1565
1566 (void) strcpy(s, hdr);
1567 for (p = s; *p; p++) {
1568 *p = ' ';
1569 }
1570
1571 p = hdr;
1572 while (nbytes > 0) {
1573 (void) fprintf(stdout, "%s", p);
1574 p = s;
1575 n = MIN(nbytes, BYTES_PER_LINE);
1576 for (i = 0; i < n; i++) {
1577 (void) fprintf(stdout, "%02x ", src[i] & 0xff);
1578 }
1579 if (format == HEX_ASCII) {
1580 for (i = BYTES_PER_LINE-n; i > 0; i--) {
1581 (void) fprintf(stdout, " ");
1582 }
1583 (void) fprintf(stdout, " ");
1584 for (i = 0; i < n; i++) {
1585 (void) fprintf(stdout, "%c",
1586 isprint(src[i]) ? src[i] : '.');
1587 }
1588 }
1589 (void) fprintf(stdout, "\n");
1590 nbytes -= n;
1591 src += n;
1592 }
1593 }
1594