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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 * This module is part of the photon Command Line
36 * I18N message number ranges
37 * This file: 9500 - 9999
38 * Shared common messages: 1 - 1999
44 #include <sys/types.h>
48 #include <sys/scsi/scsi.h>
61 /* Global variables */
62 extern nl_catd l_catd
;
65 /* External functions */
66 extern int rand_r(unsigned int *);
70 wait_random_time(void)
73 struct tm
*tmbuf
= NULL
;
81 * Get the system time and use "system seconds"
82 * as 'seed' to generate a random number. Then,
83 * wait between 1/10 - 1/2 seconds before retry.
84 * Get the current process id and ex-or it with
85 * the seed so that the random number is always
86 * different even in case of multiple processes
87 * generate a random number at the same time.
89 if ((timeval
= time(NULL
)) == -1) {
92 if ((tmbuf
= localtime(&timeval
)) == NULL
) {
93 return (L_LOCALTIME_ERROR
);
98 /* get a random number. */
99 seed
= (unsigned int) tmbuf
->tm_sec
;
101 random
= rand_r(&seed
);
104 random
= ((random
% 500) + 100) * MILLISEC
;
105 tval
.tv_sec
= random
/ MICROSEC
;
106 tval
.tv_usec
= random
% MICROSEC
;
108 if (select(0, NULL
, NULL
, NULL
, &tval
) == -1) {
109 return (L_SELECT_ERROR
);
117 * Execute a command and determine the result.
120 cmd(int file
, struct uscsi_cmd
*command
, int flag
)
122 struct scsi_extended_sense
*rqbuf
;
123 int status
, i
, retry_cnt
= 0, err
;
124 char errorMsg
[MAXLEN
];
127 * Set function flags for driver.
129 * Set Automatic request sense enable
132 command
->uscsi_flags
= USCSI_RQENABLE
;
133 command
->uscsi_flags
|= flag
;
135 /* intialize error message array */
138 /* print command for debug */
139 if (getenv("_LUX_S_DEBUG") != NULL
) {
140 if ((command
->uscsi_cdb
== NULL
) ||
141 (flag
& USCSI_RESET
) ||
142 (flag
& USCSI_RESET_ALL
)) {
143 if (flag
& USCSI_RESET
) {
144 (void) printf(" Issuing a SCSI Reset.\n");
146 if (flag
& USCSI_RESET_ALL
) {
147 (void) printf(" Issuing a SCSI Reset All.\n");
151 (void) printf(" Issuing the following "
152 "SCSI command: %s\n",
153 g_scsi_find_command_name(command
->uscsi_cdb
[0]));
154 (void) printf(" fd=0x%x cdb=", file
);
155 for (i
= 0; i
< (int)command
->uscsi_cdblen
; i
++) {
156 (void) printf("%x ", *(command
->uscsi_cdb
+ i
));
158 (void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x"
160 command
->uscsi_cdblen
,
161 command
->uscsi_bufaddr
,
162 command
->uscsi_buflen
, command
->uscsi_flags
);
164 if ((command
->uscsi_buflen
> 0) &&
165 ((flag
& USCSI_READ
) == 0)) {
166 (void) g_dump(" Buffer data: ",
167 (uchar_t
*)command
->uscsi_bufaddr
,
168 MIN(command
->uscsi_buflen
, 512), HEX_ASCII
);
176 * Default command timeout in case command left it 0
178 if (command
->uscsi_timeout
== 0) {
179 command
->uscsi_timeout
= 60;
181 /* Issue command - finally */
184 status
= ioctl(file
, USCSICMD
, command
);
185 if (status
== 0 && command
->uscsi_status
== 0) {
186 if (getenv("_LUX_S_DEBUG") != NULL
) {
187 if ((command
->uscsi_buflen
> 0) &&
188 (flag
& USCSI_READ
)) {
189 (void) g_dump("\tData read:",
190 (uchar_t
*)command
->uscsi_bufaddr
,
191 MIN(command
->uscsi_buflen
, 512), HEX_ASCII
);
196 if ((status
!= 0) && (command
->uscsi_status
== 0)) {
197 if ((getenv("_LUX_S_DEBUG") != NULL
) ||
198 (getenv("_LUX_ER_DEBUG") != NULL
)) {
199 (void) printf("Unexpected USCSICMD ioctl error: %s\n",
206 * Just a SCSI error, create error message
207 * Retry once for Unit Attention,
208 * Not Ready, and Aborted Command
210 if ((command
->uscsi_rqbuf
!= NULL
) &&
211 (((char)command
->uscsi_rqlen
- (char)command
->uscsi_rqresid
) > 0)) {
213 rqbuf
= (struct scsi_extended_sense
*)command
->uscsi_rqbuf
;
215 switch (rqbuf
->es_key
) {
217 if (retry_cnt
++ < 1) {
218 ER_DPRINTF("Note: Device Not Ready."
221 if ((err
= wait_random_time()) == 0) {
229 case KEY_UNIT_ATTENTION
:
230 if (retry_cnt
++ < 1) {
232 " UNIT_ATTENTION: Retrying...\n");
238 case KEY_ABORTED_COMMAND
:
239 if (retry_cnt
++ < 1) {
240 ER_DPRINTF("Note: Command is aborted."
247 if ((getenv("_LUX_S_DEBUG") != NULL
) ||
248 (getenv("_LUX_ER_DEBUG") != NULL
)) {
249 g_scsi_printerr(command
,
250 (struct scsi_extended_sense
*)command
->uscsi_rqbuf
,
251 (command
->uscsi_rqlen
- command
->uscsi_rqresid
),
252 errorMsg
, strerror(errno
));
258 * Retry 5 times in case of BUSY, and only
259 * once for Reservation-conflict, Command
260 * Termination and Queue Full. Wait for
261 * random amount of time (between 1/10 - 1/2 secs.)
262 * between each retry. This random wait is to avoid
263 * the multiple threads being executed at the same time
264 * and also the constraint in Photon IB, where the
265 * command queue has a depth of one command.
267 switch ((uchar_t
)command
->uscsi_status
& STATUS_MASK
) {
269 if (retry_cnt
++ < 5) {
270 if ((err
= wait_random_time()) == 0) {
271 R_DPRINTF(" cmd(): No. of retries %d."
272 " STATUS_BUSY: Retrying...\n",
282 case STATUS_RESERVATION_CONFLICT
:
283 if (retry_cnt
++ < 1) {
284 if ((err
= wait_random_time()) == 0) {
286 " RESERVATION_CONFLICT:"
296 case STATUS_TERMINATED
:
297 if (retry_cnt
++ < 1) {
298 R_DPRINTF("Note: Command Terminated."
301 if ((err
= wait_random_time()) == 0) {
310 if (retry_cnt
++ < 1) {
311 R_DPRINTF("Note: Command Queue is full."
314 if ((err
= wait_random_time()) == 0) {
324 if (((getenv("_LUX_S_DEBUG") != NULL
) ||
325 (getenv("_LUX_ER_DEBUG") != NULL
)) &&
326 (errorMsg
[0] != '\0')) {
327 (void) fprintf(stdout
, " %s\n", errorMsg
);
329 return (L_SCSI_ERROR
| command
->uscsi_status
);