1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  */
25*fcf3ce44SJohn Forte 
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte /*LINTLIBRARY*/
28*fcf3ce44SJohn Forte 
29*fcf3ce44SJohn Forte /*
30*fcf3ce44SJohn Forte  *  This module is part of the photon Command Line
31*fcf3ce44SJohn Forte  *  Interface program.
32*fcf3ce44SJohn Forte  *
33*fcf3ce44SJohn Forte  */
34*fcf3ce44SJohn Forte 
35*fcf3ce44SJohn Forte /*
36*fcf3ce44SJohn Forte  * I18N message number ranges
37*fcf3ce44SJohn Forte  *  This file: 9500 - 9999
38*fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
39*fcf3ce44SJohn Forte  */
40*fcf3ce44SJohn Forte 
41*fcf3ce44SJohn Forte /*	Includes	*/
42*fcf3ce44SJohn Forte #include	<stdlib.h>
43*fcf3ce44SJohn Forte #include	<stdio.h>
44*fcf3ce44SJohn Forte #include	<sys/types.h>
45*fcf3ce44SJohn Forte #include	<unistd.h>
46*fcf3ce44SJohn Forte #include	<errno.h>
47*fcf3ce44SJohn Forte #include	<string.h>
48*fcf3ce44SJohn Forte #include	<sys/scsi/scsi.h>
49*fcf3ce44SJohn Forte #include	<nl_types.h>
50*fcf3ce44SJohn Forte #include	<sys/time.h>
51*fcf3ce44SJohn Forte #include	<l_common.h>
52*fcf3ce44SJohn Forte #include	<stgcom.h>
53*fcf3ce44SJohn Forte #include	<l_error.h>
54*fcf3ce44SJohn Forte #include	<g_state.h>
55*fcf3ce44SJohn Forte 
56*fcf3ce44SJohn Forte 
57*fcf3ce44SJohn Forte /*	Defines		*/
58*fcf3ce44SJohn Forte #define	MAXLEN		1000
59*fcf3ce44SJohn Forte 
60*fcf3ce44SJohn Forte 
61*fcf3ce44SJohn Forte /*	Global variables	*/
62*fcf3ce44SJohn Forte extern	nl_catd l_catd;
63*fcf3ce44SJohn Forte 
64*fcf3ce44SJohn Forte 
65*fcf3ce44SJohn Forte /*	External functions	*/
66*fcf3ce44SJohn Forte extern	int	rand_r(unsigned int *);
67*fcf3ce44SJohn Forte 
68*fcf3ce44SJohn Forte 
69*fcf3ce44SJohn Forte static int
wait_random_time(void)70*fcf3ce44SJohn Forte wait_random_time(void)
71*fcf3ce44SJohn Forte {
72*fcf3ce44SJohn Forte time_t		timeval;
73*fcf3ce44SJohn Forte struct tm	*tmbuf = NULL;
74*fcf3ce44SJohn Forte struct timeval	tval;
75*fcf3ce44SJohn Forte unsigned int	seed;
76*fcf3ce44SJohn Forte int		random;
77*fcf3ce44SJohn Forte pid_t		pid;
78*fcf3ce44SJohn Forte 
79*fcf3ce44SJohn Forte 
80*fcf3ce44SJohn Forte 	/*
81*fcf3ce44SJohn Forte 	 * Get the system time and use "system seconds"
82*fcf3ce44SJohn Forte 	 * as 'seed' to generate a random number. Then,
83*fcf3ce44SJohn Forte 	 * wait between 1/10 - 1/2 seconds before retry.
84*fcf3ce44SJohn Forte 	 * Get the current process id and ex-or it with
85*fcf3ce44SJohn Forte 	 * the seed so that the random number is always
86*fcf3ce44SJohn Forte 	 * different even in case of multiple processes
87*fcf3ce44SJohn Forte 	 * generate a random number at the same time.
88*fcf3ce44SJohn Forte 	 */
89*fcf3ce44SJohn Forte 	if ((timeval = time(NULL)) == -1) {
90*fcf3ce44SJohn Forte 		return (errno);
91*fcf3ce44SJohn Forte 	}
92*fcf3ce44SJohn Forte 	if ((tmbuf = localtime(&timeval)) == NULL) {
93*fcf3ce44SJohn Forte 		return (L_LOCALTIME_ERROR);
94*fcf3ce44SJohn Forte 	}
95*fcf3ce44SJohn Forte 
96*fcf3ce44SJohn Forte 	pid = getpid();
97*fcf3ce44SJohn Forte 
98*fcf3ce44SJohn Forte 	/* get a random number. */
99*fcf3ce44SJohn Forte 	seed = (unsigned int) tmbuf->tm_sec;
100*fcf3ce44SJohn Forte 	seed ^= pid;
101*fcf3ce44SJohn Forte 	random = rand_r(&seed);
102*fcf3ce44SJohn Forte 
103*fcf3ce44SJohn Forte 
104*fcf3ce44SJohn Forte 	random = ((random % 500) + 100) * MILLISEC;
105*fcf3ce44SJohn Forte 	tval.tv_sec = random / MICROSEC;
106*fcf3ce44SJohn Forte 	tval.tv_usec = random % MICROSEC;
107*fcf3ce44SJohn Forte 
108*fcf3ce44SJohn Forte 	if (select(0, NULL, NULL, NULL, &tval) == -1) {
109*fcf3ce44SJohn Forte 		return (L_SELECT_ERROR);
110*fcf3ce44SJohn Forte 	}
111*fcf3ce44SJohn Forte 	return (0);
112*fcf3ce44SJohn Forte }
113*fcf3ce44SJohn Forte 
114*fcf3ce44SJohn Forte 
115*fcf3ce44SJohn Forte 
116*fcf3ce44SJohn Forte /*
117*fcf3ce44SJohn Forte  * Execute a command and determine the result.
118*fcf3ce44SJohn Forte  */
119*fcf3ce44SJohn Forte int
cmd(int file,struct uscsi_cmd * command,int flag)120*fcf3ce44SJohn Forte cmd(int file, struct uscsi_cmd *command, int flag)
121*fcf3ce44SJohn Forte {
122*fcf3ce44SJohn Forte struct scsi_extended_sense	*rqbuf;
123*fcf3ce44SJohn Forte int				status, i, retry_cnt = 0, err;
124*fcf3ce44SJohn Forte char				errorMsg[MAXLEN];
125*fcf3ce44SJohn Forte 
126*fcf3ce44SJohn Forte 	/*
127*fcf3ce44SJohn Forte 	 * Set function flags for driver.
128*fcf3ce44SJohn Forte 	 *
129*fcf3ce44SJohn Forte 	 * Set Automatic request sense enable
130*fcf3ce44SJohn Forte 	 *
131*fcf3ce44SJohn Forte 	 */
132*fcf3ce44SJohn Forte 	command->uscsi_flags = USCSI_RQENABLE;
133*fcf3ce44SJohn Forte 	command->uscsi_flags |= flag;
134*fcf3ce44SJohn Forte 
135*fcf3ce44SJohn Forte 	/* intialize error message array */
136*fcf3ce44SJohn Forte 	errorMsg[0] = '\0';
137*fcf3ce44SJohn Forte 
138*fcf3ce44SJohn Forte 	/* print command for debug */
139*fcf3ce44SJohn Forte 	if (getenv("_LUX_S_DEBUG") != NULL) {
140*fcf3ce44SJohn Forte 		if ((command->uscsi_cdb == NULL) ||
141*fcf3ce44SJohn Forte 			(flag & USCSI_RESET) ||
142*fcf3ce44SJohn Forte 			(flag & USCSI_RESET_ALL)) {
143*fcf3ce44SJohn Forte 			if (flag & USCSI_RESET) {
144*fcf3ce44SJohn Forte 				(void) printf("  Issuing a SCSI Reset.\n");
145*fcf3ce44SJohn Forte 			}
146*fcf3ce44SJohn Forte 			if (flag & USCSI_RESET_ALL) {
147*fcf3ce44SJohn Forte 				(void) printf("  Issuing a SCSI Reset All.\n");
148*fcf3ce44SJohn Forte 			}
149*fcf3ce44SJohn Forte 
150*fcf3ce44SJohn Forte 		} else {
151*fcf3ce44SJohn Forte 			(void) printf("  Issuing the following "
152*fcf3ce44SJohn Forte 				"SCSI command: %s\n",
153*fcf3ce44SJohn Forte 			g_scsi_find_command_name(command->uscsi_cdb[0]));
154*fcf3ce44SJohn Forte 			(void) printf("	fd=0x%x cdb=", file);
155*fcf3ce44SJohn Forte 			for (i = 0; i < (int)command->uscsi_cdblen; i++) {
156*fcf3ce44SJohn Forte 				(void) printf("%x ", *(command->uscsi_cdb + i));
157*fcf3ce44SJohn Forte 			}
158*fcf3ce44SJohn Forte 			(void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x"
159*fcf3ce44SJohn Forte 				" flags=0x%x\n",
160*fcf3ce44SJohn Forte 			command->uscsi_cdblen,
161*fcf3ce44SJohn Forte 			command->uscsi_bufaddr,
162*fcf3ce44SJohn Forte 			command->uscsi_buflen, command->uscsi_flags);
163*fcf3ce44SJohn Forte 
164*fcf3ce44SJohn Forte 			if ((command->uscsi_buflen > 0) &&
165*fcf3ce44SJohn Forte 				((flag & USCSI_READ) == 0)) {
166*fcf3ce44SJohn Forte 				(void) g_dump("  Buffer data: ",
167*fcf3ce44SJohn Forte 				(uchar_t *)command->uscsi_bufaddr,
168*fcf3ce44SJohn Forte 				MIN(command->uscsi_buflen, 512), HEX_ASCII);
169*fcf3ce44SJohn Forte 			}
170*fcf3ce44SJohn Forte 		}
171*fcf3ce44SJohn Forte 		fflush(stdout);
172*fcf3ce44SJohn Forte 	}
173*fcf3ce44SJohn Forte 
174*fcf3ce44SJohn Forte 
175*fcf3ce44SJohn Forte 	/*
176*fcf3ce44SJohn Forte 	 * Default command timeout in case command left it 0
177*fcf3ce44SJohn Forte 	 */
178*fcf3ce44SJohn Forte 	if (command->uscsi_timeout == 0) {
179*fcf3ce44SJohn Forte 		command->uscsi_timeout = 60;
180*fcf3ce44SJohn Forte 	}
181*fcf3ce44SJohn Forte 	/*	Issue command - finally */
182*fcf3ce44SJohn Forte 
183*fcf3ce44SJohn Forte retry:
184*fcf3ce44SJohn Forte 	status = ioctl(file, USCSICMD, command);
185*fcf3ce44SJohn Forte 	if (status == 0 && command->uscsi_status == 0) {
186*fcf3ce44SJohn Forte 		if (getenv("_LUX_S_DEBUG") != NULL) {
187*fcf3ce44SJohn Forte 			if ((command->uscsi_buflen > 0) &&
188*fcf3ce44SJohn Forte 				(flag & USCSI_READ)) {
189*fcf3ce44SJohn Forte 				(void) g_dump("\tData read:",
190*fcf3ce44SJohn Forte 				(uchar_t *)command->uscsi_bufaddr,
191*fcf3ce44SJohn Forte 				MIN(command->uscsi_buflen, 512), HEX_ASCII);
192*fcf3ce44SJohn Forte 			}
193*fcf3ce44SJohn Forte 		}
194*fcf3ce44SJohn Forte 		return (status);
195*fcf3ce44SJohn Forte 	}
196*fcf3ce44SJohn Forte 	if ((status != 0) && (command->uscsi_status == 0)) {
197*fcf3ce44SJohn Forte 		if ((getenv("_LUX_S_DEBUG") != NULL) ||
198*fcf3ce44SJohn Forte 			(getenv("_LUX_ER_DEBUG") != NULL)) {
199*fcf3ce44SJohn Forte 			(void) printf("Unexpected USCSICMD ioctl error: %s\n",
200*fcf3ce44SJohn Forte 				strerror(errno));
201*fcf3ce44SJohn Forte 		}
202*fcf3ce44SJohn Forte 		return (status);
203*fcf3ce44SJohn Forte 	}
204*fcf3ce44SJohn Forte 
205*fcf3ce44SJohn Forte 	/*
206*fcf3ce44SJohn Forte 	 * Just a SCSI error, create error message
207*fcf3ce44SJohn Forte 	 * Retry once for Unit Attention,
208*fcf3ce44SJohn Forte 	 * Not Ready, and Aborted Command
209*fcf3ce44SJohn Forte 	 */
210*fcf3ce44SJohn Forte 	if ((command->uscsi_rqbuf != NULL) &&
211*fcf3ce44SJohn Forte 	    (((char)command->uscsi_rqlen - (char)command->uscsi_rqresid) > 0)) {
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 		rqbuf = (struct scsi_extended_sense *)command->uscsi_rqbuf;
214*fcf3ce44SJohn Forte 
215*fcf3ce44SJohn Forte 		switch (rqbuf->es_key) {
216*fcf3ce44SJohn Forte 		case KEY_NOT_READY:
217*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
218*fcf3ce44SJohn Forte 				ER_DPRINTF("Note: Device Not Ready."
219*fcf3ce44SJohn Forte 						" Retrying...\n");
220*fcf3ce44SJohn Forte 
221*fcf3ce44SJohn Forte 				if ((err = wait_random_time()) == 0) {
222*fcf3ce44SJohn Forte 					goto retry;
223*fcf3ce44SJohn Forte 				} else {
224*fcf3ce44SJohn Forte 					return (err);
225*fcf3ce44SJohn Forte 				}
226*fcf3ce44SJohn Forte 			}
227*fcf3ce44SJohn Forte 			break;
228*fcf3ce44SJohn Forte 
229*fcf3ce44SJohn Forte 		case KEY_UNIT_ATTENTION:
230*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
231*fcf3ce44SJohn Forte 				ER_DPRINTF("  cmd():"
232*fcf3ce44SJohn Forte 				" UNIT_ATTENTION: Retrying...\n");
233*fcf3ce44SJohn Forte 
234*fcf3ce44SJohn Forte 				goto retry;
235*fcf3ce44SJohn Forte 			}
236*fcf3ce44SJohn Forte 			break;
237*fcf3ce44SJohn Forte 
238*fcf3ce44SJohn Forte 		case KEY_ABORTED_COMMAND:
239*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
240*fcf3ce44SJohn Forte 				ER_DPRINTF("Note: Command is aborted."
241*fcf3ce44SJohn Forte 				" Retrying...\n");
242*fcf3ce44SJohn Forte 
243*fcf3ce44SJohn Forte 				goto retry;
244*fcf3ce44SJohn Forte 			}
245*fcf3ce44SJohn Forte 			break;
246*fcf3ce44SJohn Forte 		}
247*fcf3ce44SJohn Forte 		if ((getenv("_LUX_S_DEBUG") != NULL) ||
248*fcf3ce44SJohn Forte 			(getenv("_LUX_ER_DEBUG") != NULL)) {
249*fcf3ce44SJohn Forte 			g_scsi_printerr(command,
250*fcf3ce44SJohn Forte 			(struct scsi_extended_sense *)command->uscsi_rqbuf,
251*fcf3ce44SJohn Forte 			(command->uscsi_rqlen - command->uscsi_rqresid),
252*fcf3ce44SJohn Forte 				errorMsg, strerror(errno));
253*fcf3ce44SJohn Forte 		}
254*fcf3ce44SJohn Forte 
255*fcf3ce44SJohn Forte 	} else {
256*fcf3ce44SJohn Forte 
257*fcf3ce44SJohn Forte 		/*
258*fcf3ce44SJohn Forte 		 * Retry 5 times in case of BUSY, and only
259*fcf3ce44SJohn Forte 		 * once for Reservation-conflict, Command
260*fcf3ce44SJohn Forte 		 * Termination and Queue Full. Wait for
261*fcf3ce44SJohn Forte 		 * random amount of time (between 1/10 - 1/2 secs.)
262*fcf3ce44SJohn Forte 		 * between each retry. This random wait is to avoid
263*fcf3ce44SJohn Forte 		 * the multiple threads being executed at the same time
264*fcf3ce44SJohn Forte 		 * and also the constraint in Photon IB, where the
265*fcf3ce44SJohn Forte 		 * command queue has a depth of one command.
266*fcf3ce44SJohn Forte 		 */
267*fcf3ce44SJohn Forte 		switch ((uchar_t)command->uscsi_status & STATUS_MASK) {
268*fcf3ce44SJohn Forte 		case STATUS_BUSY:
269*fcf3ce44SJohn Forte 			if (retry_cnt++ < 5) {
270*fcf3ce44SJohn Forte 				if ((err = wait_random_time()) == 0) {
271*fcf3ce44SJohn Forte 					R_DPRINTF("  cmd(): No. of retries %d."
272*fcf3ce44SJohn Forte 					" STATUS_BUSY: Retrying...\n",
273*fcf3ce44SJohn Forte 					retry_cnt);
274*fcf3ce44SJohn Forte 					goto retry;
275*fcf3ce44SJohn Forte 
276*fcf3ce44SJohn Forte 				} else {
277*fcf3ce44SJohn Forte 					return (err);
278*fcf3ce44SJohn Forte 				}
279*fcf3ce44SJohn Forte 			}
280*fcf3ce44SJohn Forte 			break;
281*fcf3ce44SJohn Forte 
282*fcf3ce44SJohn Forte 		case STATUS_RESERVATION_CONFLICT:
283*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
284*fcf3ce44SJohn Forte 				if ((err = wait_random_time()) == 0) {
285*fcf3ce44SJohn Forte 					R_DPRINTF("  cmd():"
286*fcf3ce44SJohn Forte 					" RESERVATION_CONFLICT:"
287*fcf3ce44SJohn Forte 					" Retrying...\n");
288*fcf3ce44SJohn Forte 					goto retry;
289*fcf3ce44SJohn Forte 
290*fcf3ce44SJohn Forte 				} else {
291*fcf3ce44SJohn Forte 					return (err);
292*fcf3ce44SJohn Forte 				}
293*fcf3ce44SJohn Forte 			}
294*fcf3ce44SJohn Forte 			break;
295*fcf3ce44SJohn Forte 
296*fcf3ce44SJohn Forte 		case STATUS_TERMINATED:
297*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
298*fcf3ce44SJohn Forte 				R_DPRINTF("Note: Command Terminated."
299*fcf3ce44SJohn Forte 					" Retrying...\n");
300*fcf3ce44SJohn Forte 
301*fcf3ce44SJohn Forte 				if ((err = wait_random_time()) == 0) {
302*fcf3ce44SJohn Forte 					goto retry;
303*fcf3ce44SJohn Forte 				} else {
304*fcf3ce44SJohn Forte 					return (err);
305*fcf3ce44SJohn Forte 				}
306*fcf3ce44SJohn Forte 			}
307*fcf3ce44SJohn Forte 			break;
308*fcf3ce44SJohn Forte 
309*fcf3ce44SJohn Forte 		case STATUS_QFULL:
310*fcf3ce44SJohn Forte 			if (retry_cnt++ < 1) {
311*fcf3ce44SJohn Forte 				R_DPRINTF("Note: Command Queue is full."
312*fcf3ce44SJohn Forte 				" Retrying...\n");
313*fcf3ce44SJohn Forte 
314*fcf3ce44SJohn Forte 				if ((err = wait_random_time()) == 0) {
315*fcf3ce44SJohn Forte 					goto retry;
316*fcf3ce44SJohn Forte 				} else {
317*fcf3ce44SJohn Forte 					return (err);
318*fcf3ce44SJohn Forte 				}
319*fcf3ce44SJohn Forte 			}
320*fcf3ce44SJohn Forte 			break;
321*fcf3ce44SJohn Forte 		}
322*fcf3ce44SJohn Forte 
323*fcf3ce44SJohn Forte 	}
324*fcf3ce44SJohn Forte 	if (((getenv("_LUX_S_DEBUG") != NULL) ||
325*fcf3ce44SJohn Forte 		(getenv("_LUX_ER_DEBUG") != NULL)) &&
326*fcf3ce44SJohn Forte 		(errorMsg[0] != '\0')) {
327*fcf3ce44SJohn Forte 		(void) fprintf(stdout, "  %s\n", errorMsg);
328*fcf3ce44SJohn Forte 	}
329*fcf3ce44SJohn Forte 	return (L_SCSI_ERROR | command->uscsi_status);
330*fcf3ce44SJohn Forte }