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.
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.
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]
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
30 #include <sys/param.h>
31 #include <sys/types.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>
49 #include "errorcodes.h"
51 #define MAX_MODE_SENSE_LEN 0xffff
54 #define RETRY_PATHLIST 1
55 #define BYTES_PER_LINE 16
56 #define SCMD_UNKNOWN 0xff
58 #define SCSI_VHCI "/devices/scsi_vhci/"
60 #define DEV_PREFIX "/devices/"
61 #define DEV_PREFIX_STRLEN strlen(DEV_PREFIX)
62 #define DEVICES_DIR "/devices"
64 extern char *dtype
[]; /* from adm.c */
65 extern int rand_r(unsigned int *);
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
,
75 static int issue_uscsi_cmd(int file
, struct uscsi_cmd
*command
, int flag
);
79 wait_random_time(void)
82 struct tm
*tmbuf
= NULL
;
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.
97 if ((timeval
= time(NULL
)) == -1) {
100 if ((tmbuf
= localtime(&timeval
)) == NULL
) {
101 return (-1); /* L_LOCALTIME_ERROR */
106 /* get a random number. */
107 seed
= (unsigned int) tmbuf
->tm_sec
;
109 random
= rand_r(&seed
);
112 random
= ((random
% 500) + 100) * MILLISEC
;
113 tval
.tv_sec
= random
/ MICROSEC
;
114 tval
.tv_usec
= random
% MICROSEC
;
116 if (select(0, NULL
, NULL
, NULL
, &tval
) == -1) {
117 return (-1); /* L_SELECT_ERROR */
123 * Special string dump for error message
126 string_dump(char *hdr
, uchar_t
*src
, int nbytes
, int format
, char msg_string
[])
133 assert(format
== HEX_ONLY
|| format
== HEX_ASCII
);
135 (void) strcpy(s
, hdr
);
136 for (p
= s
; *p
; p
++) {
142 (void) sprintf(&msg_string
[strlen(msg_string
)], "%s", p
);
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);
149 if (format
== HEX_ASCII
) {
150 for (i
= BYTES_PER_LINE
-n
; i
> 0; i
--) {
151 (void) sprintf(&msg_string
[strlen(msg_string
)],
154 (void) sprintf(&msg_string
[strlen(msg_string
)],
156 for (i
= 0; i
< n
; i
++) {
157 (void) sprintf(&msg_string
[strlen(msg_string
)],
158 "%c", isprint(src
[i
]) ? src
[i
] : '.');
161 (void) sprintf(&msg_string
[strlen(msg_string
)], "\n");
167 * Return a pointer to a string telling us the name of the command.
170 scsi_find_command_name(int cmd
)
173 * Names of commands. Must have SCMD_UNKNOWN at end of list.
175 struct scsi_command_name
{
178 } scsi_command_names
[29];
180 register struct scsi_command_name
*c
;
182 scsi_command_names
[0].command
= SCMD_TEST_UNIT_READY
;
183 scsi_command_names
[0].name
= MSGSTR(61, "Test Unit Ready");
185 scsi_command_names
[1].command
= SCMD_FORMAT
;
186 scsi_command_names
[1].name
= MSGSTR(110, "Format");
188 scsi_command_names
[2].command
= SCMD_REASSIGN_BLOCK
;
189 scsi_command_names
[2].name
= MSGSTR(77, "Reassign Block");
191 scsi_command_names
[3].command
= SCMD_READ
;
192 scsi_command_names
[3].name
= MSGSTR(27, "Read");
194 scsi_command_names
[4].command
= SCMD_WRITE
;
195 scsi_command_names
[4].name
= MSGSTR(54, "Write");
197 scsi_command_names
[5].command
= SCMD_READ_G1
;
198 scsi_command_names
[5].name
= MSGSTR(79, "Read(10 Byte)");
200 scsi_command_names
[6].command
= SCMD_WRITE_G1
;
201 scsi_command_names
[6].name
= MSGSTR(51, "Write(10 Byte)");
203 scsi_command_names
[7].command
= SCMD_MODE_SELECT
;
204 scsi_command_names
[7].name
= MSGSTR(97, "Mode Select");
206 scsi_command_names
[8].command
= SCMD_MODE_SENSE
;
207 scsi_command_names
[8].name
= MSGSTR(95, "Mode Sense");
209 scsi_command_names
[9].command
= SCMD_REASSIGN_BLOCK
;
210 scsi_command_names
[9].name
= MSGSTR(77, "Reassign Block");
212 scsi_command_names
[10].command
= SCMD_REQUEST_SENSE
;
213 scsi_command_names
[10].name
= MSGSTR(74, "Request Sense");
215 scsi_command_names
[11].command
= SCMD_READ_DEFECT_LIST
;
216 scsi_command_names
[11].name
= MSGSTR(80, "Read Defect List");
218 scsi_command_names
[12].command
= SCMD_INQUIRY
;
219 scsi_command_names
[12].name
= MSGSTR(102, "Inquiry");
221 scsi_command_names
[13].command
= SCMD_WRITE_BUFFER
;
222 scsi_command_names
[13].name
= MSGSTR(53, "Write Buffer");
224 scsi_command_names
[14].command
= SCMD_READ_BUFFER
;
225 scsi_command_names
[14].name
= MSGSTR(82, "Read Buffer");
227 scsi_command_names
[15].command
= SCMD_START_STOP
;
228 scsi_command_names
[15].name
= MSGSTR(67, "Start/Stop");
230 scsi_command_names
[16].command
= SCMD_RESERVE
;
231 scsi_command_names
[16].name
= MSGSTR(72, "Reserve");
233 scsi_command_names
[17].command
= SCMD_RELEASE
;
234 scsi_command_names
[17].name
= MSGSTR(75, "Release");
236 scsi_command_names
[18].command
= SCMD_MODE_SENSE_G1
;
237 scsi_command_names
[18].name
= MSGSTR(94, "Mode Sense(10 Byte)");
239 scsi_command_names
[19].command
= SCMD_MODE_SELECT_G1
;
240 scsi_command_names
[19].name
= MSGSTR(96, "Mode Select(10 Byte)");
242 scsi_command_names
[20].command
= SCMD_READ_CAPACITY
;
243 scsi_command_names
[20].name
= MSGSTR(81, "Read Capacity");
245 scsi_command_names
[21].command
= SCMD_SYNC_CACHE
;
246 scsi_command_names
[21].name
= MSGSTR(64, "Synchronize Cache");
248 scsi_command_names
[22].command
= SCMD_READ_DEFECT_LIST
;
249 scsi_command_names
[22].name
= MSGSTR(80, "Read Defect List");
251 scsi_command_names
[23].command
= SCMD_GDIAG
;
252 scsi_command_names
[23].name
= MSGSTR(108, "Get Diagnostic");
254 scsi_command_names
[24].command
= SCMD_SDIAG
;
255 scsi_command_names
[24].name
= MSGSTR(69, "Set Diagnostic");
257 scsi_command_names
[25].command
= SCMD_PERS_RESERV_IN
;
258 scsi_command_names
[25].name
= MSGSTR(10500, "Persistent Reserve In");
260 scsi_command_names
[26].command
= SCMD_PERS_RESERV_OUT
;
261 scsi_command_names
[26].name
= MSGSTR(10501, "Persistent Reserve out");
263 scsi_command_names
[27].command
= SCMD_LOG_SENSE
;
264 scsi_command_names
[27].name
= MSGSTR(10502, "Log Sense");
266 scsi_command_names
[28].command
= SCMD_UNKNOWN
;
267 scsi_command_names
[28].name
= MSGSTR(25, "Unknown");
270 for (c
= scsi_command_names
; c
->command
!= SCMD_UNKNOWN
; c
++)
271 if (c
->command
== cmd
)
278 * Function to create error message containing
279 * scsi request sense information
283 scsi_printerr(struct uscsi_cmd
*ucmd
, struct scsi_extended_sense
*rq
,
284 int rqlen
, char msg_string
[], char *err_string
)
288 switch (rq
->es_key
) {
290 (void) sprintf(msg_string
, MSGSTR(91, "No sense error"));
292 case KEY_RECOVERABLE_ERROR
:
293 (void) sprintf(msg_string
, MSGSTR(76, "Recoverable error"));
296 (void) sprintf(msg_string
,
298 "Device Not ready. Error: Random Retry Failed: %s\n."),
301 case KEY_MEDIUM_ERROR
:
302 (void) sprintf(msg_string
, MSGSTR(99, "Medium error"));
304 case KEY_HARDWARE_ERROR
:
305 (void) sprintf(msg_string
, MSGSTR(106, "Hardware error"));
307 case KEY_ILLEGAL_REQUEST
:
308 (void) sprintf(msg_string
, MSGSTR(103, "Illegal request"));
310 case KEY_UNIT_ATTENTION
:
311 (void) sprintf(msg_string
,
314 "Error: Random Retry Failed.\n"));
316 case KEY_WRITE_PROTECT
:
317 (void) sprintf(msg_string
, MSGSTR(52, "Write protect error"));
319 case KEY_BLANK_CHECK
:
320 (void) sprintf(msg_string
, MSGSTR(131, "Blank check error"));
322 case KEY_VENDOR_UNIQUE
:
323 (void) sprintf(msg_string
, MSGSTR(58, "Vendor unique error"));
325 case KEY_COPY_ABORTED
:
326 (void) sprintf(msg_string
, MSGSTR(123, "Copy aborted error"));
328 case KEY_ABORTED_COMMAND
:
329 (void) sprintf(msg_string
,
331 "Aborted command. Error: Random Retry Failed.\n"));
334 (void) sprintf(msg_string
, MSGSTR(117, "Equal error"));
336 case KEY_VOLUME_OVERFLOW
:
337 (void) sprintf(msg_string
, MSGSTR(57, "Volume overflow"));
340 (void) sprintf(msg_string
, MSGSTR(98, "Miscompare error"));
343 (void) sprintf(msg_string
, MSGSTR(10506,
344 "Reserved value found"));
347 (void) sprintf(msg_string
, MSGSTR(59, "Unknown error"));
351 (void) sprintf(&msg_string
[strlen(msg_string
)],
352 MSGSTR(10507, " during: %s"),
353 scsi_find_command_name(ucmd
->uscsi_cdb
[0]));
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
);
362 (void) sprintf(&msg_string
[strlen(msg_string
)], "\n");
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
);
370 * rq->es_add_info[ADD_SENSE_CODE],
371 * rq->es_add_info[ADD_SENSE_QUAL_CODE]);
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
);
381 string_dump(MSGSTR(43, " sense: "),
382 (uchar_t
*)rq
, 8 + rq
->es_add_len
, HEX_ONLY
, msg_string
);
383 rqlen
= rqlen
; /* not used */
388 * Execute a command and determine the result.
391 issue_uscsi_cmd(int file
, struct uscsi_cmd
*command
, int flag
)
393 struct scsi_extended_sense
*rqbuf
;
394 int status
, i
, retry_cnt
= 0, err
;
395 char errorMsg
[MAXLEN
];
398 * Set function flags for driver.
400 * Set Automatic request sense enable
403 command
->uscsi_flags
= USCSI_RQENABLE
;
404 command
->uscsi_flags
|= flag
;
406 /* intialize error message array */
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");
417 if (flag
& USCSI_RESET_ALL
) {
418 (void) printf(" Issuing a SCSI Reset All.\n");
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
));
429 (void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x"
431 command
->uscsi_cdblen
,
432 command
->uscsi_bufaddr
,
433 command
->uscsi_buflen
, command
->uscsi_flags
);
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
);
442 (void) fflush(stdout
);
447 * Default command timeout in case command left it 0
449 if (command
->uscsi_timeout
== 0) {
450 command
->uscsi_timeout
= 60;
452 /* Issue command - finally */
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
);
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",
477 * Just a SCSI error, create error message
478 * Retry once for Unit Attention,
479 * Not Ready, and Aborted Command
481 if ((command
->uscsi_rqbuf
!= NULL
) &&
482 (((char)command
->uscsi_rqlen
- (char)command
->uscsi_rqresid
) > 0)) {
484 rqbuf
= (struct scsi_extended_sense
*)command
->uscsi_rqbuf
;
486 switch (rqbuf
->es_key
) {
488 if (retry_cnt
++ < 1) {
489 ER_DPRINTF("Note: Device Not Ready."
492 if ((err
= wait_random_time()) == 0) {
500 case KEY_UNIT_ATTENTION
:
501 if (retry_cnt
++ < 1) {
503 " UNIT_ATTENTION: Retrying...\n");
509 case KEY_ABORTED_COMMAND
:
510 if (retry_cnt
++ < 1) {
511 ER_DPRINTF("Note: Command is aborted."
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
));
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.
538 switch ((uchar_t
)command
->uscsi_status
& STATUS_MASK
) {
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",
553 case STATUS_RESERVATION_CONFLICT
:
554 if (retry_cnt
++ < 1) {
555 if ((err
= wait_random_time()) == 0) {
557 " RESERVATION_CONFLICT:"
567 case STATUS_TERMINATED
:
568 if (retry_cnt
++ < 1) {
569 R_DPRINTF("Note: Command Terminated."
572 if ((err
= wait_random_time()) == 0) {
581 if (retry_cnt
++ < 1) {
582 R_DPRINTF("Note: Command Queue is full."
585 if ((err
= wait_random_time()) == 0) {
595 if (((getenv("_LUX_S_DEBUG") != NULL
) ||
596 (getenv("_LUX_ER_DEBUG") != NULL
)) &&
597 (errorMsg
[0] != '\0')) {
598 (void) fprintf(stdout
, " %s\n", errorMsg
);
600 return (L_SCSI_ERROR
| command
->uscsi_status
);
604 * MODE SENSE USCSI command
607 * pc = page control field
608 * page_code = Pages to return
611 scsi_mode_sense_cmd(int fd
,
617 struct uscsi_cmd ucmd
;
618 /* 10 byte Mode Select cmd */
619 union scsi_cdb cdb
= {SCMD_MODE_SENSE_G1
, 0, 0, 0, 0, 0, 0, 0, 0, 0};
620 struct scsi_extended_sense sense
;
622 static int uscsi_count
;
624 if ((fd
< 0) || (buf_ptr
== NULL
) || (buf_len
< 0)) {
625 return (-1); /* L_INVALID_ARG */
628 (void) memset(buf_ptr
, 0, buf_len
);
629 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
630 /* Just for me - a sanity check */
631 if ((page_code
> MODEPAGE_ALLPAGES
) || (pc
> 3) ||
632 (buf_len
> MAX_MODE_SENSE_LEN
)) {
633 return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */
635 cdb
.g1_addr3
= (pc
<< 6) + page_code
;
636 cdb
.g1_count1
= buf_len
>>8;
637 cdb
.g1_count0
= buf_len
& 0xff;
638 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
639 ucmd
.uscsi_cdblen
= CDB_GROUP1
;
640 ucmd
.uscsi_bufaddr
= (caddr_t
)buf_ptr
;
641 ucmd
.uscsi_buflen
= buf_len
;
642 ucmd
.uscsi_rqbuf
= (caddr_t
)&sense
;
643 ucmd
.uscsi_rqlen
= sizeof (struct scsi_extended_sense
);
644 ucmd
.uscsi_timeout
= 120;
646 status
= issue_uscsi_cmd(fd
, &ucmd
, USCSI_READ
);
647 /* Bytes actually transfered */
649 uscsi_count
= buf_len
- ucmd
.uscsi_resid
;
650 S_DPRINTF(" Number of bytes read on "
651 "Mode Sense 0x%x\n", uscsi_count
);
652 if (getenv("_LUX_D_DEBUG") != NULL
) {
653 (void) dump_hex_data(" Mode Sense data: ", buf_ptr
,
654 uscsi_count
, HEX_ASCII
);
661 scsi_release(char *path
)
663 struct uscsi_cmd ucmd
;
664 union scsi_cdb cdb
= {SCMD_RELEASE
, 0, 0, 0, 0, 0};
665 struct scsi_extended_sense sense
;
668 P_DPRINTF(" scsi_release: Release: Path %s\n", path
);
669 if ((fd
= open(path
, O_NDELAY
| O_RDONLY
)) == -1)
672 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
674 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
675 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
676 ucmd
.uscsi_bufaddr
= NULL
;
677 ucmd
.uscsi_buflen
= 0;
678 ucmd
.uscsi_rqbuf
= (caddr_t
)&sense
;
679 ucmd
.uscsi_rqlen
= sizeof (struct scsi_extended_sense
);
680 ucmd
.uscsi_timeout
= 60;
681 status
= (issue_uscsi_cmd(fd
, &ucmd
, 0));
688 scsi_reserve(char *path
)
690 struct uscsi_cmd ucmd
;
691 union scsi_cdb cdb
= {SCMD_RESERVE
, 0, 0, 0, 0, 0};
692 struct scsi_extended_sense sense
;
695 P_DPRINTF(" scsi_reserve: Reserve: Path %s\n", path
);
696 if ((fd
= open(path
, O_NDELAY
| O_RDONLY
)) == -1)
699 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
701 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
702 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
703 ucmd
.uscsi_bufaddr
= NULL
;
704 ucmd
.uscsi_buflen
= 0;
705 ucmd
.uscsi_rqbuf
= (caddr_t
)&sense
;
706 ucmd
.uscsi_rqlen
= sizeof (struct scsi_extended_sense
);
707 ucmd
.uscsi_timeout
= 60;
708 status
= (issue_uscsi_cmd(fd
, &ucmd
, 0));
715 * Print out fabric dev dtype
718 print_fabric_dtype_prop(uchar_t
*hba_port_wwn
, uchar_t
*port_wwn
,
721 if ((dtype_prop
& DTYPE_MASK
) < 0x10) {
722 (void) fprintf(stdout
, " 0x%-2x (%s)\n",
723 (dtype_prop
& DTYPE_MASK
),
724 dtype
[(dtype_prop
& DTYPE_MASK
)]);
725 } else if ((dtype_prop
& DTYPE_MASK
) < 0x1f) {
726 (void) fprintf(stdout
,
727 MSGSTR(2096, " 0x%-2x (Reserved)\n"),
728 (dtype_prop
& DTYPE_MASK
));
730 /* Check to see if this is the HBA */
731 if (wwnConversion(hba_port_wwn
) != wwnConversion(port_wwn
)) {
732 (void) fprintf(stdout
, MSGSTR(2097,
733 " 0x%-2x (Unknown Type)\n"),
734 (dtype_prop
& DTYPE_MASK
));
737 (void) fprintf(stdout
, MSGSTR(2241,
738 " 0x%-2x (Unknown Type,Host Bus Adapter)\n"),
739 (dtype_prop
& DTYPE_MASK
));
746 print_inq_data(char *arg_path
, char *path
, L_inquiry inq
, uchar_t
*serial
,
752 char byte_number
[MAXNAMELEN
];
753 static char *scsi_inquiry_labels_2
[21];
754 static char *scsi_inquiry_labels_3
[22];
755 #define MAX_ANSI_VERSION 6
756 static char *ansi_version
[MAX_ANSI_VERSION
];
758 * Intialize scsi_inquiry_labels_2 with i18n strings
760 scsi_inquiry_labels_2
[0] = MSGSTR(138, "Vendor: ");
761 scsi_inquiry_labels_2
[1] = MSGSTR(149, "Product: ");
762 scsi_inquiry_labels_2
[2] = MSGSTR(139, "Revision: ");
763 scsi_inquiry_labels_2
[3] = MSGSTR(143, "Firmware Revision ");
764 scsi_inquiry_labels_2
[4] = MSGSTR(144, "Serial Number ");
765 scsi_inquiry_labels_2
[5] = MSGSTR(140, "Device type: ");
766 scsi_inquiry_labels_2
[6] = MSGSTR(145, "Removable media: ");
767 scsi_inquiry_labels_2
[7] = MSGSTR(146, "ISO version: ");
768 scsi_inquiry_labels_2
[8] = MSGSTR(147, "ECMA version: ");
769 scsi_inquiry_labels_2
[9] = MSGSTR(148, "ANSI version: ");
770 scsi_inquiry_labels_2
[10] =
771 MSGSTR(2168, "Async event notification: ");
772 scsi_inquiry_labels_2
[11] =
773 MSGSTR(2169, "Terminate i/o process msg: ");
774 scsi_inquiry_labels_2
[12] = MSGSTR(150, "Response data format: ");
775 scsi_inquiry_labels_2
[13] = MSGSTR(151, "Additional length: ");
776 scsi_inquiry_labels_2
[14] = MSGSTR(152, "Relative addressing: ");
777 scsi_inquiry_labels_2
[15] =
778 MSGSTR(2170, "32 bit transfers: ");
779 scsi_inquiry_labels_2
[16] =
780 MSGSTR(2171, "16 bit transfers: ");
781 scsi_inquiry_labels_2
[17] =
782 MSGSTR(2172, "Synchronous transfers: ");
783 scsi_inquiry_labels_2
[18] = MSGSTR(153, "Linked commands: ");
784 scsi_inquiry_labels_2
[19] = MSGSTR(154, "Command queueing: ");
785 scsi_inquiry_labels_2
[20] =
786 MSGSTR(2173, "Soft reset option: ");
789 * Intialize scsi_inquiry_labels_3 with i18n strings
791 scsi_inquiry_labels_3
[0] = MSGSTR(138, "Vendor: ");
792 scsi_inquiry_labels_3
[1] = MSGSTR(149, "Product: ");
793 scsi_inquiry_labels_3
[2] = MSGSTR(139, "Revision: ");
794 scsi_inquiry_labels_3
[3] = MSGSTR(143, "Firmware Revision ");
795 scsi_inquiry_labels_3
[4] = MSGSTR(144, "Serial Number ");
796 scsi_inquiry_labels_3
[5] = MSGSTR(140, "Device type: ");
797 scsi_inquiry_labels_3
[6] = MSGSTR(145, "Removable media: ");
798 scsi_inquiry_labels_3
[7] = MSGSTR(2174, "Medium Changer Element: ");
799 scsi_inquiry_labels_3
[8] = MSGSTR(146, "ISO version: ");
800 scsi_inquiry_labels_3
[9] = MSGSTR(147, "ECMA version: ");
801 scsi_inquiry_labels_3
[10] = MSGSTR(148, "ANSI version: ");
802 scsi_inquiry_labels_3
[11] =
803 MSGSTR(2175, "Async event reporting: ");
804 scsi_inquiry_labels_3
[12] =
805 MSGSTR(2176, "Terminate task: ");
806 scsi_inquiry_labels_3
[13] =
807 MSGSTR(2177, "Normal ACA Supported: ");
808 scsi_inquiry_labels_3
[14] = MSGSTR(150, "Response data format: ");
809 scsi_inquiry_labels_3
[15] = MSGSTR(151, "Additional length: ");
810 scsi_inquiry_labels_3
[16] =
811 MSGSTR(2178, "Cmd received on port: ");
812 scsi_inquiry_labels_3
[17] =
813 MSGSTR(2179, "SIP Bits: ");
814 scsi_inquiry_labels_3
[18] = MSGSTR(152, "Relative addressing: ");
815 scsi_inquiry_labels_3
[19] = MSGSTR(153, "Linked commands: ");
816 scsi_inquiry_labels_3
[20] =
817 MSGSTR(2180, "Transfer Disable: ");
818 scsi_inquiry_labels_3
[21] = MSGSTR(154, "Command queueing: ");
821 * Intialize scsi_inquiry_labels_3 with i18n strings
823 ansi_version
[0] = MSGSTR(2181,
824 " (Device might or might not comply to an ANSI version)");
825 ansi_version
[1] = MSGSTR(2182,
826 " (This code is reserved for historical uses)");
827 ansi_version
[2] = MSGSTR(2183,
828 " (Device complies to ANSI X3.131-1994 (SCSI-2))");
829 ansi_version
[3] = MSGSTR(2184,
830 " (Device complies to ANSI INCITS 301-1997 (SPC))");
831 ansi_version
[4] = MSGSTR(2226,
832 " (Device complies to ANSI INCITS 351-2001 (SPC-2))");
833 ansi_version
[5] = MSGSTR(2227,
834 " (Device complies to ANSI INCITS 408-2005 (SPC-3))");
836 /* print inquiry information */
838 (void) fprintf(stdout
, MSGSTR(2185, "\nINQUIRY:\n"));
840 * arg_path is the path sent to luxadm by the user. if arg_path
841 * is a /devices path, then we do not need to print out physical
844 if (strcmp(arg_path
, path
) != 0 &&
845 strstr(arg_path
, "/devices/") == NULL
) {
846 (void) fprintf(stdout
, " ");
847 (void) fprintf(stdout
,
848 MSGSTR(5, "Physical Path:"));
849 (void) fprintf(stdout
, "\n %s\n", path
);
851 if (inq
.inq_ansi
< 3) {
852 p
= scsi_inquiry_labels_2
;
855 p
= scsi_inquiry_labels_3
;
858 if (inq
.inq_len
< 11) {
862 (void) fprintf(stdout
, "%s", *p
++);
863 print_chars(inq
.inq_vid
, sizeof (inq
.inq_vid
), 0);
864 (void) fprintf(stdout
, "\n");
866 if (inq
.inq_len
< 27) {
869 (void) fprintf(stdout
, "%s", *p
++);
870 print_chars(inq
.inq_pid
, sizeof (inq
.inq_pid
), 0);
871 (void) fprintf(stdout
, "\n");
873 if (inq
.inq_len
< 31) {
876 (void) fprintf(stdout
, "%s", *p
++);
877 print_chars(inq
.inq_revision
, sizeof (inq
.inq_revision
), 0);
878 (void) fprintf(stdout
, "\n");
880 if (inq
.inq_len
< 39) {
884 * If Pluto then print
885 * firmware rev & serial #.
887 if (strstr((char *)inq
.inq_pid
, "SSA") != 0) {
888 (void) fprintf(stdout
, "%s", *p
++);
889 print_chars(inq
.inq_firmware_rev
,
890 sizeof (inq
.inq_firmware_rev
), 0);
891 (void) fprintf(stdout
, "\n");
892 (void) fprintf(stdout
, "%s", *p
++);
893 print_chars(serial
, serial_len
, 0);
894 (void) fprintf(stdout
, "\n");
895 } else if ((inq
.inq_dtype
& DTYPE_MASK
) != DTYPE_ESI
) {
897 (void) fprintf(stdout
, "%s", *p
++);
898 print_chars(serial
, serial_len
, 0);
899 (void) fprintf(stdout
, "\n");
901 /* if we miss both the above if's */
906 (void) fprintf(stdout
, "%s0x%x (", *p
++, (inq
.inq_dtype
& DTYPE_MASK
));
907 if ((inq
.inq_dtype
& DTYPE_MASK
) < 0x10) {
908 (void) fprintf(stdout
, "%s", dtype
[inq
.inq_dtype
& DTYPE_MASK
]);
909 } else if ((inq
.inq_dtype
& DTYPE_MASK
) < 0x1f) {
910 (void) fprintf(stdout
, MSGSTR(71, "Reserved"));
912 (void) fprintf(stdout
, MSGSTR(2186, "Unknown device"));
914 (void) fprintf(stdout
, ")\n");
916 (void) fprintf(stdout
, "%s", *p
++);
917 if (inq
.inq_rmb
!= NULL
) {
918 (void) fprintf(stdout
, MSGSTR(40, "yes"));
920 (void) fprintf(stdout
, MSGSTR(45, "no"));
922 (void) fprintf(stdout
, "\n");
925 (void) fprintf(stdout
, "%s", *p
++);
926 if (inq
.inq_mchngr
!= NULL
) {
927 (void) fprintf(stdout
, MSGSTR(40, "yes"));
929 (void) fprintf(stdout
, MSGSTR(45, "no"));
931 (void) fprintf(stdout
, "\n");
933 (void) fprintf(stdout
, "%s%d\n", *p
++, inq
.inq_iso
);
934 (void) fprintf(stdout
, "%s%d\n", *p
++, inq
.inq_ecma
);
936 (void) fprintf(stdout
, "%s%d", *p
++, inq
.inq_ansi
);
937 if (inq
.inq_ansi
< MAX_ANSI_VERSION
) {
938 (void) fprintf(stdout
, "%s", ansi_version
[inq
.inq_ansi
]);
940 (void) fprintf(stdout
, " (%s)", MSGSTR(71, "Reserved"));
942 (void) fprintf(stdout
, "\n");
945 (void) fprintf(stdout
, "%s", *p
++);
946 (void) fprintf(stdout
, MSGSTR(40, "yes"));
947 (void) fprintf(stdout
, "\n");
952 (void) fprintf(stdout
, "%s", *p
++);
953 if (inq
.inq_normaca
!= NULL
) {
954 (void) fprintf(stdout
, MSGSTR(40, "yes"));
956 (void) fprintf(stdout
, MSGSTR(45, "no"));
958 (void) fprintf(stdout
, "\n");
960 if (inq
.inq_trmiop
) {
961 (void) fprintf(stdout
, "%s", *p
++);
962 (void) fprintf(stdout
, MSGSTR(40, "yes"));
963 (void) fprintf(stdout
, "\n");
967 (void) fprintf(stdout
, "%s%d\n", *p
++, inq
.inq_rdf
);
968 (void) fprintf(stdout
, "%s0x%x\n", *p
++, inq
.inq_len
);
970 if (inq
.inq_dual_p
) {
971 if (inq
.inq_port
!= NULL
) {
972 (void) fprintf(stdout
, MSGSTR(2187,
975 (void) fprintf(stdout
, MSGSTR(2188,
983 if (inq
.inq_SIP_1
|| inq
.ui
.inq_3
.inq_SIP_2
||
984 inq
.ui
.inq_3
.inq_SIP_3
) {
985 (void) fprintf(stdout
, "%s%d, %d, %d\n", *p
,
986 inq
.inq_SIP_1
, inq
.ui
.inq_3
.inq_SIP_2
,
987 inq
.ui
.inq_3
.inq_SIP_3
);
993 if (inq
.ui
.inq_2
.inq_2_reladdr
) {
994 (void) fprintf(stdout
, "%s", *p
);
995 (void) fprintf(stdout
, MSGSTR(40, "yes"));
996 (void) fprintf(stdout
, "\n");
1001 if (inq
.ui
.inq_2
.inq_wbus32
) {
1002 (void) fprintf(stdout
, "%s", *p
);
1003 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1004 (void) fprintf(stdout
, "\n");
1008 if (inq
.ui
.inq_2
.inq_wbus16
) {
1009 (void) fprintf(stdout
, "%s", *p
);
1010 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1011 (void) fprintf(stdout
, "\n");
1015 if (inq
.ui
.inq_2
.inq_sync
) {
1016 (void) fprintf(stdout
, "%s", *p
);
1017 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1018 (void) fprintf(stdout
, "\n");
1023 if (inq
.ui
.inq_2
.inq_linked
) {
1024 (void) fprintf(stdout
, "%s", *p
);
1025 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1026 (void) fprintf(stdout
, "\n");
1031 (void) fprintf(stdout
, "%s", *p
++);
1032 if (inq
.ui
.inq_3
.inq_trandis
!= NULL
) {
1033 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1035 (void) fprintf(stdout
, MSGSTR(45, "no"));
1037 (void) fprintf(stdout
, "\n");
1040 if (inq
.ui
.inq_2
.inq_cmdque
) {
1041 (void) fprintf(stdout
, "%s", *p
);
1042 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1043 (void) fprintf(stdout
, "\n");
1048 if (inq
.ui
.inq_2
.inq_sftre
) {
1049 (void) fprintf(stdout
, "%s", *p
);
1050 (void) fprintf(stdout
, MSGSTR(40, "yes"));
1051 (void) fprintf(stdout
, "\n");
1058 * Now print the vendor-specific data.
1060 v_parm
= inq
.inq_ven_specific_1
;
1061 if (inq
.inq_len
>= 32) {
1062 length
= inq
.inq_len
- 31;
1063 if (strstr((char *)inq
.inq_pid
, "SSA") != 0) {
1064 (void) fprintf(stdout
, MSGSTR(2189,
1065 "Number of Ports, Targets: %d,%d\n"),
1066 inq
.inq_ssa_ports
, inq
.inq_ssa_tgts
);
1069 } else if ((strstr((char *)inq
.inq_pid
, "SUN") != 0) ||
1070 (strncmp((char *)inq
.inq_vid
, "SUN ",
1071 sizeof (inq
.inq_vid
)) == 0)) {
1076 * Do hex Dump of rest of the data.
1079 (void) fprintf(stdout
,
1081 " VENDOR-SPECIFIC PARAMETERS\n"));
1082 (void) fprintf(stdout
,
1086 (void) sprintf(byte_number
,
1087 "%d ", inq
.inq_len
- length
+ 5);
1088 dump_hex_data(byte_number
, v_parm
,
1089 MIN(length
, inq
.inq_res3
- v_parm
), HEX_ASCII
);
1092 * Skip reserved bytes 56-95.
1094 length
-= (inq
.inq_box_name
- v_parm
);
1096 (void) sprintf(byte_number
, "%d ",
1097 inq
.inq_len
- length
+ 5);
1098 dump_hex_data(byte_number
, inq
.inq_box_name
,
1099 MIN(length
, sizeof (inq
.inq_box_name
) +
1100 sizeof (inq
.inq_avu
)), HEX_ASCII
);
1103 if (getenv("_LUX_D_DEBUG") != NULL
) {
1104 dump_hex_data("\nComplete Inquiry: ",
1106 MIN(inq
.inq_len
+ 5, sizeof (inq
)), HEX_ASCII
);
1111 * Internal routine to clean up ../'s in paths.
1112 * returns 0 if no "../" are left.
1114 * Wouldn't it be nice if there was a standard system library
1115 * routine to do this...?
1118 cleanup_dotdot_path(char *path
)
1120 char holder
[MAXPATHLEN
];
1122 char *previous_slash
;
1124 /* Find the first "/../" in the string */
1125 dotdot
= strstr(path
, "/../");
1126 if (dotdot
== NULL
) {
1132 * If the [0] character is '/' and "../" immediatly
1133 * follows it, then we can strip the ../
1135 * /../../foo/bar == /foo/bar
1138 if (dotdot
== path
) {
1139 strcpy(holder
, &path
[3]); /* strip "/.." */
1140 strcpy(path
, holder
);
1145 * Now look for the LAST "/" before the "/../"
1146 * as this is the parent dir we can get rid of.
1147 * We do this by temporarily truncating the string
1148 * at the '/' just before "../" using the dotdot pointer.
1151 previous_slash
= strrchr(path
, '/');
1152 if (previous_slash
== NULL
) {
1154 * hmm, somethings wrong. path looks something
1155 * like "foo/../bar/" so we can't really deal with it.
1160 * Now truncate the path just after the previous '/'
1161 * and slam everything after the "../" back on
1163 *(previous_slash
+1) = '\0';
1164 (void) strcat(path
, dotdot
+4);
1165 return (1); /* We may have more "../"s */
1169 * Follow symbolic links from the logical device name to
1170 * the /devfs physical device name. To be complete, we
1171 * handle the case of multiple links. This function
1172 * either returns NULL (no links, or some other error),
1173 * or the physical device name, alloc'ed on the heap.
1175 * NOTE: If the path is relative, it will be forced into
1176 * an absolute path by pre-pending the pwd to it.
1179 get_slash_devices_from_osDevName(char *osDevName
, int flag
)
1182 char source
[MAXPATHLEN
];
1183 char scratch
[MAXPATHLEN
];
1184 char pwd
[MAXPATHLEN
];
1185 char *tmp
, *phys_path
;
1187 boolean_t is_lstat_failed
= B_TRUE
;
1189 /* return NULL if path is NULL */
1190 if (osDevName
== NULL
) {
1194 strcpy(source
, osDevName
);
1198 * First make sure the path is absolute. If not, make it.
1199 * If it's already an absolute path, we have no need
1200 * to determine the cwd, so the program should still
1201 * function within security-by-obscurity directories.
1203 if (source
[0] != '/') {
1204 tmp
= getcwd(pwd
, MAXPATHLEN
);
1209 * Handle special case of "./foo/bar"
1211 if (source
[0] == '.' && source
[1] == '/') {
1212 strcpy(scratch
, source
+2);
1213 } else { /* no "./" so just take everything */
1214 strcpy(scratch
, source
);
1216 strcpy(source
, pwd
);
1217 (void) strcat(source
, "/");
1218 (void) strcat(source
, scratch
);
1222 * Clean up any "../"s that are in the path
1224 while (cleanup_dotdot_path(source
))
1228 * source is now an absolute path to the link we're
1231 if (flag
== NOT_IGNORE_DANGLING_LINK
) {
1233 * In order not to ingore dangling links, check
1234 * the lstat. If lstat succeeds, return the path
1236 * Note: osDevName input with /devices path from
1237 * a dangling /dev link doesn't pass lstat so
1240 if (stat(source
, &stbuf
) == -1) {
1241 if (!is_lstat_failed
&&
1242 strstr(source
, "/devices")) {
1244 * lstat succeeded previously and source
1245 * contains "/devices" then it is
1248 phys_path
= (char *)calloc(1,
1249 strlen(source
) + 1);
1250 if (phys_path
!= NULL
) {
1251 (void) strncpy(phys_path
,
1252 source
, strlen(source
) + 1);
1255 } else if (is_lstat_failed
) {
1256 /* check lstat result. */
1257 if (lstat(source
, &stbuf
) == -1) {
1261 is_lstat_failed
= B_FALSE
;
1265 * With algorithm that resolves a link
1266 * and then issues readlink(), should
1267 * not be reached here.
1272 if (lstat(source
, &stbuf
) == -1) {
1274 * when stat succeeds it is not
1275 * a dangling node so it is not
1281 } else if (flag
== STANDARD_DEVNAME_HANDLING
) {
1283 * See if there's a real file out there. If not,
1284 * we have a dangling link and we ignore it.
1286 if (stat(source
, &stbuf
) == -1) {
1289 if (lstat(source
, &stbuf
) == -1) {
1298 * If the file is not a link, we're done one
1299 * way or the other. If there were links,
1300 * return the full pathname of the resulting
1303 * Note: All of our temp's are on the stack,
1304 * so we have to copy the final result to the heap.
1306 if (!S_ISLNK(stbuf
.st_mode
)) {
1307 phys_path
= (char *)calloc(1, strlen(source
) + 1);
1308 if (phys_path
!= NULL
) {
1309 (void) strncpy(phys_path
, source
,
1310 strlen(source
) + 1);
1314 cnt
= readlink(source
, scratch
, sizeof (scratch
));
1319 * scratch is on the heap, and for some reason readlink
1320 * doesn't always terminate things properly so we have
1321 * to make certain we're properly terminated
1323 scratch
[cnt
] = '\0';
1326 * Now check to see if the link is relative. If so,
1327 * then we have to append it to the directory
1328 * which the source was in. (This is non trivial)
1330 if (scratch
[0] != '/') {
1331 tmp
= strrchr(source
, '/');
1332 if (tmp
== NULL
) { /* Whoa! Something's hosed! */
1333 O_DPRINTF("Internal error... corrupt path.\n");
1336 /* Now strip off just the directory path */
1337 *(tmp
+1) = '\0'; /* Keeping the last '/' */
1338 /* and append the new link */
1339 (void) strcat(source
, scratch
);
1341 * Note: At this point, source should have "../"s
1342 * but we'll clean it up in the next pass through
1346 /* It's an absolute link so no worries */
1347 strcpy(source
, scratch
);
1350 /* Never reach here */
1354 * Input - Space for client_path, phci_path and paddr fields of ioc structure
1355 * need to be allocated by the caller of this routine.
1358 get_scsi_vhci_pathinfo(char *dev_path
, sv_iocdata_t
*ioc
, int *path_count
)
1360 char *physical_path
, *physical_path_s
;
1363 int initial_path_count
;
1364 int current_path_count
;
1367 int malloc_error
= 0;
1369 int pathlist_retry_count
= 0;
1371 if (strncmp(dev_path
, SCSI_VHCI
, strlen(SCSI_VHCI
)) != NULL
) {
1372 if ((physical_path
= get_slash_devices_from_osDevName(
1373 dev_path
, STANDARD_DEVNAME_HANDLING
)) == NULL
) {
1374 return (L_INVALID_PATH
);
1376 if (strncmp(physical_path
, SCSI_VHCI
,
1377 strlen(SCSI_VHCI
)) != NULL
) {
1378 free(physical_path
);
1379 return (L_INVALID_PATH
);
1382 if ((physical_path
= calloc(1, MAXPATHLEN
)) == NULL
) {
1383 return (L_MALLOC_FAILED
);
1385 (void) strcpy(physical_path
, dev_path
);
1387 physical_path_s
= physical_path
;
1389 /* move beyond "/devices" prefix */
1390 physical_path
+= DEV_PREFIX_STRLEN
-1;
1391 /* remove :c,raw suffix */
1392 delimiter
= strrchr(physical_path
, ':');
1393 /* if we didn't find the ':' fine, else truncate */
1394 if (delimiter
!= NULL
) {
1399 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
1400 * at least twice. The first time will get the path count
1401 * and the size of the ioctl propoerty buffer. The second
1402 * time will get the path_info for each path.
1404 * It's possible that additional paths are added while this
1405 * code is running. If the path count increases between the
1406 * 2 ioctl's above, then we'll retry (and assume all is well).
1408 (void) strcpy(ioc
->client
, physical_path
);
1410 ioc
->ret_elem
= (uint_t
*)&(initial_path_count
);
1411 ioc
->ret_buf
= NULL
;
1413 /* free physical path */
1414 free(physical_path_s
);
1416 /* 0 buf_size asks driver to return actual size needed */
1417 /* open the ioctl file descriptor */
1418 if ((fd
= open("/devices/scsi_vhci:devctl", O_RDWR
)) < 0) {
1419 return (L_OPEN_PATH_FAIL
);
1422 retval
= ioctl(fd
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
, ioc
);
1425 return (L_SCSI_VHCI_ERROR
);
1427 prop_buf_size
= SV_PROP_MAX_BUF_SIZE
;
1430 while (pathlist_retry_count
<= RETRY_PATHLIST
) {
1431 ioc
->buf_elem
= initial_path_count
;
1432 /* Make driver put actual # paths in variable */
1433 ioc
->ret_elem
= (uint_t
*)&(current_path_count
);
1436 * Allocate space for array of path_info structures.
1437 * Allocate enough space for # paths from get_pathcount
1439 ioc
->ret_buf
= (sv_path_info_t
*)
1440 calloc(initial_path_count
, sizeof (sv_path_info_t
));
1441 if (ioc
->ret_buf
== NULL
) {
1443 return (L_MALLOC_FAILED
);
1447 * Allocate space for path properties returned by driver
1450 for (i
= 0; i
< initial_path_count
; i
++) {
1451 ioc
->ret_buf
[i
].ret_prop
.buf_size
= prop_buf_size
;
1452 if ((ioc
->ret_buf
[i
].ret_prop
.buf
=
1453 (caddr_t
)malloc(prop_buf_size
)) == NULL
) {
1457 if ((ioc
->ret_buf
[i
].ret_prop
.ret_buf_size
=
1458 (uint_t
*)malloc(sizeof (uint_t
))) == NULL
) {
1463 if (malloc_error
== 1) {
1464 for (i
= 0; i
< initial_path_count
; i
++) {
1465 free(ioc
->ret_buf
[i
].ret_prop
.buf
);
1466 free(ioc
->ret_buf
[i
].ret_prop
.ret_buf_size
);
1470 return (L_MALLOC_FAILED
);
1473 retval
= ioctl(fd
, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
, ioc
);
1475 for (i
= 0; i
< initial_path_count
; i
++) {
1476 free(ioc
->ret_buf
[i
].ret_prop
.buf
);
1477 free(ioc
->ret_buf
[i
].ret_prop
.ret_buf_size
);
1481 return (L_SCSI_VHCI_ERROR
);
1483 if (initial_path_count
< current_path_count
) {
1484 /* then a new path was added */
1485 pathlist_retry_count
++;
1486 initial_path_count
= current_path_count
;
1491 /* we are done with ioctl's, lose the fd */
1495 * Compare the length num elements from the ioctl response
1496 * and the caller's request - use smaller value.
1498 * pathlist_p->path_count now has count returned from ioctl.
1499 * ioc.buf_elem has the value the caller provided.
1501 if (initial_path_count
< current_path_count
) {
1502 /* More paths exist than we allocated space for */
1503 *path_count
= initial_path_count
;
1505 *path_count
= current_path_count
;
1512 get_mode_page(char *path
, uchar_t
**pg_buf
)
1514 struct mode_header_g1
*mode_header_ptr
;
1515 int status
, size
, fd
;
1517 /* open controller */
1518 if ((fd
= open(path
, O_NDELAY
| O_RDWR
)) == -1)
1519 return (-1); /* L_OPEN_PATH_FAIL */
1522 * Read the first part of the page to get the page size
1525 if ((*pg_buf
= (uchar_t
*)calloc(1, size
)) == NULL
) {
1527 return (L_MALLOC_FAILED
);
1530 if (status
= scsi_mode_sense_cmd(fd
, *pg_buf
, size
,
1531 0, MODEPAGE_ALLPAGES
)) {
1533 (void) free(*pg_buf
);
1536 /* Now get the size for all pages */
1537 mode_header_ptr
= (struct mode_header_g1
*)(void *)*pg_buf
;
1538 size
= ntohs(mode_header_ptr
->length
) +
1539 sizeof (mode_header_ptr
->length
);
1540 (void) free(*pg_buf
);
1541 if ((*pg_buf
= (uchar_t
*)calloc(1, size
)) == NULL
) {
1543 return (L_MALLOC_FAILED
);
1545 /* read all pages */
1546 if (status
= scsi_mode_sense_cmd(fd
, *pg_buf
, size
,
1547 0, MODEPAGE_ALLPAGES
)) {
1549 (void) free(*pg_buf
);
1557 * Dump a structure in hexadecimal.
1560 dump_hex_data(char *hdr
, uchar_t
*src
, int nbytes
, int format
)
1567 assert(format
== HEX_ONLY
|| format
== HEX_ASCII
);
1569 (void) strcpy(s
, hdr
);
1570 for (p
= s
; *p
; p
++) {
1575 while (nbytes
> 0) {
1576 (void) fprintf(stdout
, "%s", p
);
1578 n
= MIN(nbytes
, BYTES_PER_LINE
);
1579 for (i
= 0; i
< n
; i
++) {
1580 (void) fprintf(stdout
, "%02x ", src
[i
] & 0xff);
1582 if (format
== HEX_ASCII
) {
1583 for (i
= BYTES_PER_LINE
-n
; i
> 0; i
--) {
1584 (void) fprintf(stdout
, " ");
1586 (void) fprintf(stdout
, " ");
1587 for (i
= 0; i
< n
; i
++) {
1588 (void) fprintf(stdout
, "%c",
1589 isprint(src
[i
]) ? src
[i
] : '.');
1592 (void) fprintf(stdout
, "\n");