xref: /onnv-gate/usr/src/lib/storage/libg_fc/common/io.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM 
27*7836SJohn.Forte@Sun.COM /*LINTLIBRARY*/
28*7836SJohn.Forte@Sun.COM 
29*7836SJohn.Forte@Sun.COM /*
30*7836SJohn.Forte@Sun.COM  *
31*7836SJohn.Forte@Sun.COM  *	This module is part of the photon Command Line
32*7836SJohn.Forte@Sun.COM  *	Interface program.
33*7836SJohn.Forte@Sun.COM  *
34*7836SJohn.Forte@Sun.COM  */
35*7836SJohn.Forte@Sun.COM 
36*7836SJohn.Forte@Sun.COM /*
37*7836SJohn.Forte@Sun.COM  * I18N message number ranges
38*7836SJohn.Forte@Sun.COM  *  This file: 11500 - 11999
39*7836SJohn.Forte@Sun.COM  *  Shared common messages: 1 - 1999
40*7836SJohn.Forte@Sun.COM  */
41*7836SJohn.Forte@Sun.COM 
42*7836SJohn.Forte@Sun.COM /* #define		_POSIX_SOURCE 1 */
43*7836SJohn.Forte@Sun.COM 
44*7836SJohn.Forte@Sun.COM /*	Includes	*/
45*7836SJohn.Forte@Sun.COM #include	<stdlib.h>
46*7836SJohn.Forte@Sun.COM #include	<stdio.h>
47*7836SJohn.Forte@Sun.COM #include	<string.h>
48*7836SJohn.Forte@Sun.COM #include	<sys/file.h>
49*7836SJohn.Forte@Sun.COM #include	<sys/types.h>
50*7836SJohn.Forte@Sun.COM #include	<fcntl.h>
51*7836SJohn.Forte@Sun.COM #include	<sys/sunddi.h>
52*7836SJohn.Forte@Sun.COM #include	<sys/systm.h>
53*7836SJohn.Forte@Sun.COM #include	<sys/scsi/scsi.h>
54*7836SJohn.Forte@Sun.COM #include	<nl_types.h>
55*7836SJohn.Forte@Sun.COM #include	<unistd.h>
56*7836SJohn.Forte@Sun.COM #include	<l_common.h>
57*7836SJohn.Forte@Sun.COM #include	<stgcom.h>
58*7836SJohn.Forte@Sun.COM #include	<l_error.h>
59*7836SJohn.Forte@Sun.COM #include	<g_state.h>
60*7836SJohn.Forte@Sun.COM #include	<errno.h>
61*7836SJohn.Forte@Sun.COM #include	<devid.h>
62*7836SJohn.Forte@Sun.COM #include	<libdevinfo.h>
63*7836SJohn.Forte@Sun.COM 
64*7836SJohn.Forte@Sun.COM 
65*7836SJohn.Forte@Sun.COM /*	Defines		*/
66*7836SJohn.Forte@Sun.COM /* Because of a bug in Unisys Envsen card,  Bug ID:1266986. */
67*7836SJohn.Forte@Sun.COM #define	SCSI_ESI_PCV	0x01		/* Page Code Valid */
68*7836SJohn.Forte@Sun.COM #define	SCSI_ESI_PF	0x10		/* Page Format */
69*7836SJohn.Forte@Sun.COM #define	ACTION_MASK	0x1f		/* Persistent Reserve In command */
70*7836SJohn.Forte@Sun.COM #define	IMMED		1		/* make the stop immediate */
71*7836SJohn.Forte@Sun.COM #define	DAK_PROD_STR	"SUNWGS INT FCBPL"
72*7836SJohn.Forte@Sun.COM #define	DAK_BOXNAME_LEN	16		/* The length of the daktari boxname */
73*7836SJohn.Forte@Sun.COM #define	DAK_BOXNAME_OFF	36		/* The offset of the daktari boxname */
74*7836SJohn.Forte@Sun.COM 
75*7836SJohn.Forte@Sun.COM 
76*7836SJohn.Forte@Sun.COM 
77*7836SJohn.Forte@Sun.COM /*	Global variables	*/
78*7836SJohn.Forte@Sun.COM extern	nl_catd l_catd;
79*7836SJohn.Forte@Sun.COM 
80*7836SJohn.Forte@Sun.COM 
81*7836SJohn.Forte@Sun.COM /*	Forward declarations	*/
82*7836SJohn.Forte@Sun.COM static int scsi_read_capacity_16_cmd(int, struct scsi_capacity_16 *, int);
83*7836SJohn.Forte@Sun.COM 
84*7836SJohn.Forte@Sun.COM 
85*7836SJohn.Forte@Sun.COM /*	External functions	*/
86*7836SJohn.Forte@Sun.COM 
87*7836SJohn.Forte@Sun.COM 
88*7836SJohn.Forte@Sun.COM int
g_scsi_persistent_reserve_in_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t action)89*7836SJohn.Forte@Sun.COM g_scsi_persistent_reserve_in_cmd(int fd, uchar_t *buf_ptr,
90*7836SJohn.Forte@Sun.COM 	int buf_len, uchar_t action)
91*7836SJohn.Forte@Sun.COM {
92*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
93*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb = {SCMD_PERS_RESERV_IN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
94*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
95*7836SJohn.Forte@Sun.COM 
96*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
97*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
98*7836SJohn.Forte@Sun.COM 	}
99*7836SJohn.Forte@Sun.COM 
100*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
101*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
102*7836SJohn.Forte@Sun.COM 	cdb.byte1 = action & ACTION_MASK;
103*7836SJohn.Forte@Sun.COM 	cdb.byte7 = (buf_len>>8) & 0xff;
104*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
105*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
106*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
107*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
108*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
109*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
110*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
111*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
112*7836SJohn.Forte@Sun.COM 
113*7836SJohn.Forte@Sun.COM 	if (buf_len & 0x03) {
114*7836SJohn.Forte@Sun.COM 		return (L_PR_INVLD_TRNSFR_LEN);
115*7836SJohn.Forte@Sun.COM 	}
116*7836SJohn.Forte@Sun.COM 	/* Do in SILENT mode as cmd may not be supported. */
117*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
118*7836SJohn.Forte@Sun.COM }
119*7836SJohn.Forte@Sun.COM /*
120*7836SJohn.Forte@Sun.COM  *	Send Diagnostic command
121*7836SJohn.Forte@Sun.COM  *
122*7836SJohn.Forte@Sun.COM  *	NOTE: This function includes a delay.
123*7836SJohn.Forte@Sun.COM  */
124*7836SJohn.Forte@Sun.COM int
g_scsi_send_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len)125*7836SJohn.Forte@Sun.COM g_scsi_send_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len)
126*7836SJohn.Forte@Sun.COM {
127*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
128*7836SJohn.Forte@Sun.COM uchar_t	cdb[] = {SCMD_SDIAG, SCSI_ESI_PF, 0, 0, 0, 0};
129*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
130*7836SJohn.Forte@Sun.COM int		err;
131*7836SJohn.Forte@Sun.COM 
132*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
133*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
134*7836SJohn.Forte@Sun.COM 	}
135*7836SJohn.Forte@Sun.COM 
136*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
137*7836SJohn.Forte@Sun.COM 	cdb[3] = (buf_len>>8) & 0xff;
138*7836SJohn.Forte@Sun.COM 	cdb[4] = buf_len & 0xff;
139*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)cdb;
140*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
141*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
142*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
143*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
144*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
145*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
146*7836SJohn.Forte@Sun.COM 
147*7836SJohn.Forte@Sun.COM 	if (err = cmd(fd, &ucmd, USCSI_WRITE)) {
148*7836SJohn.Forte@Sun.COM 		return (err);
149*7836SJohn.Forte@Sun.COM 	}
150*7836SJohn.Forte@Sun.COM 	/*
151*7836SJohn.Forte@Sun.COM 	 * Allow time for things to stabilize.
152*7836SJohn.Forte@Sun.COM 	 */
153*7836SJohn.Forte@Sun.COM 	sleep(5);
154*7836SJohn.Forte@Sun.COM 	return (0);
155*7836SJohn.Forte@Sun.COM }
156*7836SJohn.Forte@Sun.COM 
157*7836SJohn.Forte@Sun.COM /*
158*7836SJohn.Forte@Sun.COM  * Internal routine to allow manipulation of the cdb[1] byte
159*7836SJohn.Forte@Sun.COM  * in receive diag.
160*7836SJohn.Forte@Sun.COM  */
161*7836SJohn.Forte@Sun.COM static int
rec_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code,uchar_t cdb_one)162*7836SJohn.Forte@Sun.COM rec_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code,
163*7836SJohn.Forte@Sun.COM 	uchar_t cdb_one)
164*7836SJohn.Forte@Sun.COM {
165*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
166*7836SJohn.Forte@Sun.COM uchar_t	cdb[] = {SCMD_GDIAG, 0, 0, 0, 0, 0};
167*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
168*7836SJohn.Forte@Sun.COM 
169*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
170*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
171*7836SJohn.Forte@Sun.COM 	}
172*7836SJohn.Forte@Sun.COM 
173*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
174*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
175*7836SJohn.Forte@Sun.COM 	cdb[1] = cdb_one;
176*7836SJohn.Forte@Sun.COM 	cdb[2] = page_code;
177*7836SJohn.Forte@Sun.COM 	cdb[3] = (buf_len>>8) & 0xff;
178*7836SJohn.Forte@Sun.COM 	cdb[4] = buf_len & 0xff;
179*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)cdb;
180*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
181*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
182*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
183*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
184*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
185*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
186*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ));
187*7836SJohn.Forte@Sun.COM }
188*7836SJohn.Forte@Sun.COM 
189*7836SJohn.Forte@Sun.COM 
190*7836SJohn.Forte@Sun.COM /*
191*7836SJohn.Forte@Sun.COM  *	Receive Diagnostic command
192*7836SJohn.Forte@Sun.COM  */
193*7836SJohn.Forte@Sun.COM int
g_scsi_rec_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code)194*7836SJohn.Forte@Sun.COM g_scsi_rec_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code)
195*7836SJohn.Forte@Sun.COM {
196*7836SJohn.Forte@Sun.COM int	status;
197*7836SJohn.Forte@Sun.COM 
198*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
199*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
200*7836SJohn.Forte@Sun.COM 	}
201*7836SJohn.Forte@Sun.COM 
202*7836SJohn.Forte@Sun.COM 	if (buf_len & 0x03) {
203*7836SJohn.Forte@Sun.COM 		return (L_RD_INVLD_TRNSFR_LEN);
204*7836SJohn.Forte@Sun.COM 	}
205*7836SJohn.Forte@Sun.COM 
206*7836SJohn.Forte@Sun.COM 	/*
207*7836SJohn.Forte@Sun.COM 	 * The a5k and newer enclosures abide by the SCSI spec
208*7836SJohn.Forte@Sun.COM 	 * (SPC-2: 7.15) but the SSA does not.  It requires
209*7836SJohn.Forte@Sun.COM 	 * 0x10 to be present in cdb[1].
210*7836SJohn.Forte@Sun.COM 	 *
211*7836SJohn.Forte@Sun.COM 	 * For enclosures that abide by the spec, the first call
212*7836SJohn.Forte@Sun.COM 	 * will work.  For SSAs the first call will fail, at which
213*7836SJohn.Forte@Sun.COM 	 * point we try again with the SSA specific value.
214*7836SJohn.Forte@Sun.COM 	 */
215*7836SJohn.Forte@Sun.COM 	status = rec_diag_cmd(fd, buf_ptr, buf_len, page_code, SCSI_ESI_PCV);
216*7836SJohn.Forte@Sun.COM 	if (status != 0) {
217*7836SJohn.Forte@Sun.COM 	    status = rec_diag_cmd(fd, buf_ptr, buf_len, page_code, SCSI_ESI_PF);
218*7836SJohn.Forte@Sun.COM 	}
219*7836SJohn.Forte@Sun.COM 	return (status);
220*7836SJohn.Forte@Sun.COM }
221*7836SJohn.Forte@Sun.COM 
222*7836SJohn.Forte@Sun.COM /*
223*7836SJohn.Forte@Sun.COM  *		Write buffer command set up to download firmware
224*7836SJohn.Forte@Sun.COM  */
225*7836SJohn.Forte@Sun.COM int
g_scsi_writebuffer_cmd(int fd,int off,uchar_t * buf_ptr,int buf_len,int sp,int bid)226*7836SJohn.Forte@Sun.COM g_scsi_writebuffer_cmd(int fd, int off, uchar_t *buf_ptr, int buf_len,
227*7836SJohn.Forte@Sun.COM 				int sp, int bid)
228*7836SJohn.Forte@Sun.COM {
229*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
230*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb = {SCMD_WRITE_BUFFER, 0x4, 0, 0, 0, 0, 0, 0, 0, 0};
231*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
232*7836SJohn.Forte@Sun.COM 
233*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
234*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
235*7836SJohn.Forte@Sun.COM 	}
236*7836SJohn.Forte@Sun.COM 
237*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
238*7836SJohn.Forte@Sun.COM 	cdb.byte1 |= sp;		/* set the save bit */
239*7836SJohn.Forte@Sun.COM 	cdb.byte2 = (char)(bid & 0xff);
240*7836SJohn.Forte@Sun.COM 	cdb.byte3 = off>>16;	/* bytes 3-5 contain file offset */
241*7836SJohn.Forte@Sun.COM 	cdb.byte4 = (off>>8) & 0xff;
242*7836SJohn.Forte@Sun.COM 	cdb.byte5 = off & 0xff;
243*7836SJohn.Forte@Sun.COM 	cdb.byte6 = buf_len>>16;	/* bytes 6-8 contain file length */
244*7836SJohn.Forte@Sun.COM 	cdb.byte7 = (buf_len>>8) & 0xff;
245*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
246*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
247*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
248*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
249*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
250*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
251*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
252*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 240;	/* long timeout required */
253*7836SJohn.Forte@Sun.COM 
254*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_WRITE));
255*7836SJohn.Forte@Sun.COM }
256*7836SJohn.Forte@Sun.COM 
257*7836SJohn.Forte@Sun.COM /*
258*7836SJohn.Forte@Sun.COM  *	Read buffer command set up to upload firmware
259*7836SJohn.Forte@Sun.COM  *	Reads from code image starting at offset
260*7836SJohn.Forte@Sun.COM  *	"code_off" for "buf_len" bytes.
261*7836SJohn.Forte@Sun.COM  */
262*7836SJohn.Forte@Sun.COM int
g_scsi_readbuffer_cmd(int fd,uchar_t * buf_ptr,int buf_len,int code_off)263*7836SJohn.Forte@Sun.COM g_scsi_readbuffer_cmd(int fd, uchar_t *buf_ptr, int buf_len, int code_off)
264*7836SJohn.Forte@Sun.COM {
265*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
266*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb = {SCMD_READ_BUFFER, 0x5, 0, 0, 0, 0, 0, 0, 0, 0};
267*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
268*7836SJohn.Forte@Sun.COM 
269*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
270*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
271*7836SJohn.Forte@Sun.COM 	}
272*7836SJohn.Forte@Sun.COM 
273*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
274*7836SJohn.Forte@Sun.COM 	cdb.byte3 = (code_off >> 16) & 0xff;
275*7836SJohn.Forte@Sun.COM 	cdb.byte4 = (code_off >> 8) & 0xff;
276*7836SJohn.Forte@Sun.COM 	cdb.byte5 = code_off & 0xff;
277*7836SJohn.Forte@Sun.COM 	cdb.byte6 = buf_len>>16;	/* bytes 6-8 contain file length */
278*7836SJohn.Forte@Sun.COM 	cdb.byte7 = (buf_len>>8) & 0xff;
279*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
280*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
281*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
282*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
283*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
284*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
285*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
286*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
287*7836SJohn.Forte@Sun.COM 
288*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ));
289*7836SJohn.Forte@Sun.COM }
290*7836SJohn.Forte@Sun.COM 
291*7836SJohn.Forte@Sun.COM int
g_scsi_inquiry_cmd(int fd,uchar_t * buf_ptr,int buf_len)292*7836SJohn.Forte@Sun.COM g_scsi_inquiry_cmd(int fd, uchar_t *buf_ptr, int buf_len)
293*7836SJohn.Forte@Sun.COM {
294*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
295*7836SJohn.Forte@Sun.COM my_cdb_g0	cdb = {SCMD_INQUIRY, 0, 0, 0, 0, 0};
296*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
297*7836SJohn.Forte@Sun.COM int	myreturn;
298*7836SJohn.Forte@Sun.COM 
299*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
300*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
301*7836SJohn.Forte@Sun.COM 	}
302*7836SJohn.Forte@Sun.COM 
303*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
304*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
305*7836SJohn.Forte@Sun.COM 	cdb.count = (uchar_t)buf_len;
306*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
307*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
308*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
309*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
310*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
311*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
312*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
313*7836SJohn.Forte@Sun.COM 
314*7836SJohn.Forte@Sun.COM 	myreturn = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
315*7836SJohn.Forte@Sun.COM 	if (myreturn) {
316*7836SJohn.Forte@Sun.COM 	    return (myreturn);	    /* != 0, error just return */
317*7836SJohn.Forte@Sun.COM 	}
318*7836SJohn.Forte@Sun.COM 
319*7836SJohn.Forte@Sun.COM 	/*
320*7836SJohn.Forte@Sun.COM 	 * This is a work around for the format of Daktari's
321*7836SJohn.Forte@Sun.COM 	 * SCSI inquiry page information.  The name of the enclosure
322*7836SJohn.Forte@Sun.COM 	 * is not in the same place that products like the a5000 place it
323*7836SJohn.Forte@Sun.COM 	 * so we have to copy the string to the expected location.
324*7836SJohn.Forte@Sun.COM 	 */
325*7836SJohn.Forte@Sun.COM 	if (strncmp((char *)&buf_ptr[16], DAK_PROD_STR,
326*7836SJohn.Forte@Sun.COM 			strlen(DAK_PROD_STR)) == 0) {
327*7836SJohn.Forte@Sun.COM 		strncpy((char *)&buf_ptr[96], (char *)&buf_ptr[DAK_BOXNAME_OFF],
328*7836SJohn.Forte@Sun.COM 		    DAK_BOXNAME_LEN);
329*7836SJohn.Forte@Sun.COM 	}
330*7836SJohn.Forte@Sun.COM 
331*7836SJohn.Forte@Sun.COM 	return (myreturn);
332*7836SJohn.Forte@Sun.COM }
333*7836SJohn.Forte@Sun.COM 
334*7836SJohn.Forte@Sun.COM int
g_scsi_log_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code)335*7836SJohn.Forte@Sun.COM g_scsi_log_sense_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code)
336*7836SJohn.Forte@Sun.COM {
337*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
338*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb =  {SCMD_LOG_SENSE, 0, 0x40, 0, 0, 0, 0, 0, 0, 0};
339*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
340*7836SJohn.Forte@Sun.COM 
341*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
342*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
343*7836SJohn.Forte@Sun.COM 	}
344*7836SJohn.Forte@Sun.COM 
345*7836SJohn.Forte@Sun.COM 	/* clear buffers on cmds that read data */
346*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
347*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
348*7836SJohn.Forte@Sun.COM 	cdb.byte2 |= page_code;			/* requested page */
349*7836SJohn.Forte@Sun.COM 	cdb.byte7 = buf_len>>8;
350*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
351*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
352*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
353*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
354*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
355*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
356*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
357*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
358*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ));
359*7836SJohn.Forte@Sun.COM }
360*7836SJohn.Forte@Sun.COM 
361*7836SJohn.Forte@Sun.COM /*
362*7836SJohn.Forte@Sun.COM  *		MODE SELECT
363*7836SJohn.Forte@Sun.COM  *
364*7836SJohn.Forte@Sun.COM  *		MODE SELECT USCSI command
365*7836SJohn.Forte@Sun.COM  *
366*7836SJohn.Forte@Sun.COM  *		sp is the save pages bit  - Must be bit 0 -
367*7836SJohn.Forte@Sun.COM  *
368*7836SJohn.Forte@Sun.COM  */
369*7836SJohn.Forte@Sun.COM int
g_scsi_mode_select_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t sp)370*7836SJohn.Forte@Sun.COM g_scsi_mode_select_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t sp)
371*7836SJohn.Forte@Sun.COM {
372*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
373*7836SJohn.Forte@Sun.COM /* 10 byte Mode Select cmd */
374*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb =  {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
375*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
376*7836SJohn.Forte@Sun.COM 
377*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
378*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
379*7836SJohn.Forte@Sun.COM 	}
380*7836SJohn.Forte@Sun.COM 
381*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
382*7836SJohn.Forte@Sun.COM 	cdb.byte1 = (sp & 1) | 0x10;		/* 0x10 is the PF bit  */
383*7836SJohn.Forte@Sun.COM 	cdb.byte7 = buf_len>>8;
384*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
385*7836SJohn.Forte@Sun.COM 
386*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
387*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
388*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
389*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
390*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
391*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
392*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
393*7836SJohn.Forte@Sun.COM 
394*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_WRITE));
395*7836SJohn.Forte@Sun.COM }
396*7836SJohn.Forte@Sun.COM 
397*7836SJohn.Forte@Sun.COM 
398*7836SJohn.Forte@Sun.COM /*
399*7836SJohn.Forte@Sun.COM  *		MODE SENSE USCSI command
400*7836SJohn.Forte@Sun.COM  *
401*7836SJohn.Forte@Sun.COM  *
402*7836SJohn.Forte@Sun.COM  *		pc = page control field
403*7836SJohn.Forte@Sun.COM  *		page_code = Pages to return
404*7836SJohn.Forte@Sun.COM  */
405*7836SJohn.Forte@Sun.COM int
g_scsi_mode_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t pc,uchar_t page_code)406*7836SJohn.Forte@Sun.COM g_scsi_mode_sense_cmd(int fd,
407*7836SJohn.Forte@Sun.COM 	uchar_t *buf_ptr,
408*7836SJohn.Forte@Sun.COM 	int buf_len,
409*7836SJohn.Forte@Sun.COM 	uchar_t pc,
410*7836SJohn.Forte@Sun.COM 	uchar_t page_code)
411*7836SJohn.Forte@Sun.COM {
412*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
413*7836SJohn.Forte@Sun.COM /* 10 byte Mode Select cmd */
414*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb =  {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
415*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
416*7836SJohn.Forte@Sun.COM int		status;
417*7836SJohn.Forte@Sun.COM static	int	uscsi_count;
418*7836SJohn.Forte@Sun.COM 
419*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
420*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
421*7836SJohn.Forte@Sun.COM 	}
422*7836SJohn.Forte@Sun.COM 
423*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
424*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
425*7836SJohn.Forte@Sun.COM 	/* Just for me  - a sanity check */
426*7836SJohn.Forte@Sun.COM 	if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) ||
427*7836SJohn.Forte@Sun.COM 		(buf_len > MAX_MODE_SENSE_LEN)) {
428*7836SJohn.Forte@Sun.COM 		return (L_ILLEGAL_MODE_SENSE_PAGE);
429*7836SJohn.Forte@Sun.COM 	}
430*7836SJohn.Forte@Sun.COM 	cdb.byte2 = (pc << 6) + page_code;
431*7836SJohn.Forte@Sun.COM 	cdb.byte7 = buf_len>>8;
432*7836SJohn.Forte@Sun.COM 	cdb.byte8 = buf_len & 0xff;
433*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
434*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
435*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
436*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
437*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
438*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
439*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
440*7836SJohn.Forte@Sun.COM 
441*7836SJohn.Forte@Sun.COM 	status = cmd(fd, &ucmd, USCSI_READ);
442*7836SJohn.Forte@Sun.COM 	/* Bytes actually transfered */
443*7836SJohn.Forte@Sun.COM 	if (status == 0) {
444*7836SJohn.Forte@Sun.COM 		uscsi_count = buf_len - ucmd.uscsi_resid;
445*7836SJohn.Forte@Sun.COM 		S_DPRINTF("  Number of bytes read on "
446*7836SJohn.Forte@Sun.COM 			"Mode Sense 0x%x\n", uscsi_count);
447*7836SJohn.Forte@Sun.COM 		if (getenv("_LUX_D_DEBUG") != NULL) {
448*7836SJohn.Forte@Sun.COM 			(void) g_dump("  Mode Sense data: ", buf_ptr,
449*7836SJohn.Forte@Sun.COM 			uscsi_count, HEX_ASCII);
450*7836SJohn.Forte@Sun.COM 		}
451*7836SJohn.Forte@Sun.COM 	}
452*7836SJohn.Forte@Sun.COM 	return (status);
453*7836SJohn.Forte@Sun.COM }
454*7836SJohn.Forte@Sun.COM 
455*7836SJohn.Forte@Sun.COM int
g_scsi_read_capacity_cmd(int fd,uchar_t * buf_ptr,int buf_len)456*7836SJohn.Forte@Sun.COM g_scsi_read_capacity_cmd(int fd, uchar_t *buf_ptr, int buf_len)
457*7836SJohn.Forte@Sun.COM {
458*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
459*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb = {SCMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
460*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
461*7836SJohn.Forte@Sun.COM 
462*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
463*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
464*7836SJohn.Forte@Sun.COM 	}
465*7836SJohn.Forte@Sun.COM 
466*7836SJohn.Forte@Sun.COM 	/* clear buffers on on cmds that read data */
467*7836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
468*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
469*7836SJohn.Forte@Sun.COM 
470*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
471*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
472*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
473*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
474*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
475*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
476*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
477*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ));
478*7836SJohn.Forte@Sun.COM }
479*7836SJohn.Forte@Sun.COM 
480*7836SJohn.Forte@Sun.COM int
g_scsi_read_capacity_1016_cmd(int fd,struct scsi_capacity_16 * cap_ptr,int buf_len)481*7836SJohn.Forte@Sun.COM g_scsi_read_capacity_1016_cmd(int fd,
482*7836SJohn.Forte@Sun.COM 		struct scsi_capacity_16 *cap_ptr, int buf_len)
483*7836SJohn.Forte@Sun.COM {
484*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
485*7836SJohn.Forte@Sun.COM my_cdb_g1	cdb = {SCMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
486*7836SJohn.Forte@Sun.COM struct scsi_extended_sense	sense;
487*7836SJohn.Forte@Sun.COM struct scsi_capacity	cap_old;
488*7836SJohn.Forte@Sun.COM int	ret;
489*7836SJohn.Forte@Sun.COM 
490*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (cap_ptr == NULL) ||
491*7836SJohn.Forte@Sun.COM 		(buf_len < sizeof (struct scsi_capacity_16))) {
492*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
493*7836SJohn.Forte@Sun.COM 	}
494*7836SJohn.Forte@Sun.COM 
495*7836SJohn.Forte@Sun.COM 	/* clear buffers on on cmds that read data */
496*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&cap_old, 0, sizeof (cap_old));
497*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
498*7836SJohn.Forte@Sun.COM 
499*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
500*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
501*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)&cap_old;
502*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = sizeof (cap_old);
503*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
504*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
505*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
506*7836SJohn.Forte@Sun.COM 
507*7836SJohn.Forte@Sun.COM 	ret = cmd(fd, &ucmd, USCSI_READ);
508*7836SJohn.Forte@Sun.COM 	if (cap_old.capacity == 0xffffffff) {
509*7836SJohn.Forte@Sun.COM 		/*
510*7836SJohn.Forte@Sun.COM 		 * A capacity of 0xffffffff in response to a
511*7836SJohn.Forte@Sun.COM 		 * READ CAPACITY 10 indicates that the lun
512*7836SJohn.Forte@Sun.COM 		 * is too large to report the size in a 32 bit
513*7836SJohn.Forte@Sun.COM 		 * value, and a READ CAPACITY 16 is required
514*7836SJohn.Forte@Sun.COM 		 * to get the correct size.
515*7836SJohn.Forte@Sun.COM 		 */
516*7836SJohn.Forte@Sun.COM 		ret = scsi_read_capacity_16_cmd(fd, cap_ptr, buf_len);
517*7836SJohn.Forte@Sun.COM 	} else {
518*7836SJohn.Forte@Sun.COM 		cap_ptr->sc_capacity = cap_old.capacity;
519*7836SJohn.Forte@Sun.COM 		cap_ptr->sc_lbasize = cap_old.lbasize;
520*7836SJohn.Forte@Sun.COM 	}
521*7836SJohn.Forte@Sun.COM 	return (ret);
522*7836SJohn.Forte@Sun.COM }
523*7836SJohn.Forte@Sun.COM 
524*7836SJohn.Forte@Sun.COM static int
scsi_read_capacity_16_cmd(int fd,struct scsi_capacity_16 * cap_ptr,int buf_len)525*7836SJohn.Forte@Sun.COM scsi_read_capacity_16_cmd(int fd,
526*7836SJohn.Forte@Sun.COM 		struct scsi_capacity_16 *cap_ptr, int buf_len)
527*7836SJohn.Forte@Sun.COM {
528*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
529*7836SJohn.Forte@Sun.COM union scsi_cdb		cdb;
530*7836SJohn.Forte@Sun.COM struct scsi_extended_sense	sense;
531*7836SJohn.Forte@Sun.COM 
532*7836SJohn.Forte@Sun.COM 	if ((fd < 0) || (cap_ptr == NULL) ||
533*7836SJohn.Forte@Sun.COM 		(buf_len < sizeof (struct scsi_capacity_16))) {
534*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
535*7836SJohn.Forte@Sun.COM 	}
536*7836SJohn.Forte@Sun.COM 	/* clear buffers on on cmds that read data */
537*7836SJohn.Forte@Sun.COM 	(void) memset((char *)cap_ptr, 0, buf_len);
538*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
539*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
540*7836SJohn.Forte@Sun.COM 
541*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
542*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP4;
543*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)cap_ptr;
544*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
545*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
546*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
547*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
548*7836SJohn.Forte@Sun.COM 
549*7836SJohn.Forte@Sun.COM 	/*
550*7836SJohn.Forte@Sun.COM 	 * Read Capacity (16) is a Service Action In command.  One
551*7836SJohn.Forte@Sun.COM 	 * command byte (0x9E) is overloaded for multiple operations,
552*7836SJohn.Forte@Sun.COM 	 * with the second CDB byte specifying the desired operation
553*7836SJohn.Forte@Sun.COM 	 */
554*7836SJohn.Forte@Sun.COM 	cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4;
555*7836SJohn.Forte@Sun.COM 	cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4;
556*7836SJohn.Forte@Sun.COM 
557*7836SJohn.Forte@Sun.COM 	/*
558*7836SJohn.Forte@Sun.COM 	 * Fill in allocation length field
559*7836SJohn.Forte@Sun.COM 	 */
560*7836SJohn.Forte@Sun.COM 	cdb.cdb_opaque[10] =
561*7836SJohn.Forte@Sun.COM 		(uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24);
562*7836SJohn.Forte@Sun.COM 	cdb.cdb_opaque[11] =
563*7836SJohn.Forte@Sun.COM 		(uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16);
564*7836SJohn.Forte@Sun.COM 	cdb.cdb_opaque[12] =
565*7836SJohn.Forte@Sun.COM 		(uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8);
566*7836SJohn.Forte@Sun.COM 	cdb.cdb_opaque[13] =
567*7836SJohn.Forte@Sun.COM 		(uchar_t)(ucmd.uscsi_buflen & 0x000000ff);
568*7836SJohn.Forte@Sun.COM 
569*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ));
570*7836SJohn.Forte@Sun.COM }
571*7836SJohn.Forte@Sun.COM 
572*7836SJohn.Forte@Sun.COM int
g_scsi_release_cmd(int fd)573*7836SJohn.Forte@Sun.COM g_scsi_release_cmd(int fd)
574*7836SJohn.Forte@Sun.COM {
575*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
576*7836SJohn.Forte@Sun.COM const my_cdb_g0	cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0};
577*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
578*7836SJohn.Forte@Sun.COM 
579*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
580*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
581*7836SJohn.Forte@Sun.COM 	}
582*7836SJohn.Forte@Sun.COM 
583*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
584*7836SJohn.Forte@Sun.COM 
585*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
586*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
587*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
588*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
589*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
590*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
591*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
592*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, 0));
593*7836SJohn.Forte@Sun.COM }
594*7836SJohn.Forte@Sun.COM 
595*7836SJohn.Forte@Sun.COM int
g_scsi_reserve_cmd(int fd)596*7836SJohn.Forte@Sun.COM g_scsi_reserve_cmd(int fd)
597*7836SJohn.Forte@Sun.COM {
598*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
599*7836SJohn.Forte@Sun.COM const my_cdb_g0	cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0};
600*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
601*7836SJohn.Forte@Sun.COM 
602*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
603*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
604*7836SJohn.Forte@Sun.COM 	}
605*7836SJohn.Forte@Sun.COM 
606*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
607*7836SJohn.Forte@Sun.COM 
608*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
609*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
610*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
611*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
612*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
613*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
614*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
615*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, 0));
616*7836SJohn.Forte@Sun.COM }
617*7836SJohn.Forte@Sun.COM 
618*7836SJohn.Forte@Sun.COM int
g_scsi_start_cmd(int fd)619*7836SJohn.Forte@Sun.COM g_scsi_start_cmd(int fd)
620*7836SJohn.Forte@Sun.COM {
621*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
622*7836SJohn.Forte@Sun.COM /*
623*7836SJohn.Forte@Sun.COM  * Use this to induce a SCSI error
624*7836SJohn.Forte@Sun.COM  *	const my_cdb_g0	cdb = {SCMD_START_STOP, 0, 0xff, 0, 1, 0};
625*7836SJohn.Forte@Sun.COM  */
626*7836SJohn.Forte@Sun.COM const my_cdb_g0	cdb = {SCMD_START_STOP, 0, 0, 0, 1, 0};
627*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
628*7836SJohn.Forte@Sun.COM 
629*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
630*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
631*7836SJohn.Forte@Sun.COM 	}
632*7836SJohn.Forte@Sun.COM 
633*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
634*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
635*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
636*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
637*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
638*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
639*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
640*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 240;	/* takes a while to start all */
641*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, 0));
642*7836SJohn.Forte@Sun.COM }
643*7836SJohn.Forte@Sun.COM 
644*7836SJohn.Forte@Sun.COM int
g_scsi_stop_cmd(int fd,int immediate_flag)645*7836SJohn.Forte@Sun.COM g_scsi_stop_cmd(int fd, int immediate_flag)
646*7836SJohn.Forte@Sun.COM {
647*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
648*7836SJohn.Forte@Sun.COM my_cdb_g0	cdb = {SCMD_START_STOP, 0, 0, 0, 0, 0};
649*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
650*7836SJohn.Forte@Sun.COM 
651*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
652*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
653*7836SJohn.Forte@Sun.COM 	}
654*7836SJohn.Forte@Sun.COM 
655*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
656*7836SJohn.Forte@Sun.COM 	if (immediate_flag) {
657*7836SJohn.Forte@Sun.COM 		cdb.lba_msb = IMMED;
658*7836SJohn.Forte@Sun.COM 	}
659*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
660*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
661*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
662*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
663*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
664*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
665*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
666*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, 0));
667*7836SJohn.Forte@Sun.COM }
668*7836SJohn.Forte@Sun.COM 
669*7836SJohn.Forte@Sun.COM int
g_scsi_tur(int fd)670*7836SJohn.Forte@Sun.COM g_scsi_tur(int fd)
671*7836SJohn.Forte@Sun.COM {
672*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
673*7836SJohn.Forte@Sun.COM const my_cdb_g0	cdb = {SCMD_TEST_UNIT_READY, 0, 0, 0, 0, 0};
674*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
675*7836SJohn.Forte@Sun.COM 
676*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
677*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
678*7836SJohn.Forte@Sun.COM 	}
679*7836SJohn.Forte@Sun.COM 
680*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
681*7836SJohn.Forte@Sun.COM 
682*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
683*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
684*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
685*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = NULL;
686*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
687*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
688*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
689*7836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, 0));
690*7836SJohn.Forte@Sun.COM }
691*7836SJohn.Forte@Sun.COM 
692*7836SJohn.Forte@Sun.COM /*
693*7836SJohn.Forte@Sun.COM  * NOTE: This function includes a delay.
694*7836SJohn.Forte@Sun.COM  */
695*7836SJohn.Forte@Sun.COM int
g_scsi_reset(int fd)696*7836SJohn.Forte@Sun.COM g_scsi_reset(int fd)
697*7836SJohn.Forte@Sun.COM {
698*7836SJohn.Forte@Sun.COM struct uscsi_cmd	ucmd;
699*7836SJohn.Forte@Sun.COM struct	scsi_extended_sense	sense;
700*7836SJohn.Forte@Sun.COM int	err;
701*7836SJohn.Forte@Sun.COM 
702*7836SJohn.Forte@Sun.COM 	if (fd < 0) {
703*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
704*7836SJohn.Forte@Sun.COM 	}
705*7836SJohn.Forte@Sun.COM 
706*7836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
707*7836SJohn.Forte@Sun.COM 
708*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = NULL;
709*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = NULL;
710*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
711*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = NULL;
712*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
713*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
714*7836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
715*7836SJohn.Forte@Sun.COM 	if (err = cmd(fd, &ucmd, USCSI_RESET)) {
716*7836SJohn.Forte@Sun.COM 		return (err);
717*7836SJohn.Forte@Sun.COM 	}
718*7836SJohn.Forte@Sun.COM 	/*
719*7836SJohn.Forte@Sun.COM 	 * Allow time for things to stabilize.
720*7836SJohn.Forte@Sun.COM 	 */
721*7836SJohn.Forte@Sun.COM 	sleep(20);
722*7836SJohn.Forte@Sun.COM 	return (0);
723*7836SJohn.Forte@Sun.COM }
724*7836SJohn.Forte@Sun.COM 
725*7836SJohn.Forte@Sun.COM 
726*7836SJohn.Forte@Sun.COM /*
727*7836SJohn.Forte@Sun.COM  * Description:
728*7836SJohn.Forte@Sun.COM  *    Retrieves a devid from a device path.
729*7836SJohn.Forte@Sun.COM  *
730*7836SJohn.Forte@Sun.COM  * Input Values:
731*7836SJohn.Forte@Sun.COM  *
732*7836SJohn.Forte@Sun.COM  *    devpath: Valid block device path.
733*7836SJohn.Forte@Sun.COM  *        Example:/devices/scsi_vhci/ssd@g280000602200416d6257333030303353:c,raw
734*7836SJohn.Forte@Sun.COM  *
735*7836SJohn.Forte@Sun.COM  *    devid: ptr to ddi_devid_t struct
736*7836SJohn.Forte@Sun.COM  *    root: root handle to device tree snapshot
737*7836SJohn.Forte@Sun.COM  *    drvr_name: driver name to start the node tree search
738*7836SJohn.Forte@Sun.COM  * On success, devid points to device tree handle to devid
739*7836SJohn.Forte@Sun.COM  * di_fini on root will invalidate devid pointer
740*7836SJohn.Forte@Sun.COM  *
741*7836SJohn.Forte@Sun.COM  * Return Value:
742*7836SJohn.Forte@Sun.COM  *    0 on success
743*7836SJohn.Forte@Sun.COM  *    non-zero on failure
744*7836SJohn.Forte@Sun.COM  */
745*7836SJohn.Forte@Sun.COM int
g_devid_get(char * devpath,ddi_devid_t * devid,di_node_t root,const char * drvr_name)746*7836SJohn.Forte@Sun.COM g_devid_get(char *devpath, ddi_devid_t *devid, di_node_t root,
747*7836SJohn.Forte@Sun.COM 		const char *drvr_name)
748*7836SJohn.Forte@Sun.COM {
749*7836SJohn.Forte@Sun.COM char *cptr;
750*7836SJohn.Forte@Sun.COM char rootpath[MAXPATHLEN];
751*7836SJohn.Forte@Sun.COM di_node_t node;
752*7836SJohn.Forte@Sun.COM char *devfs_path = NULL;
753*7836SJohn.Forte@Sun.COM hrtime_t	start_time, end_time;
754*7836SJohn.Forte@Sun.COM char *env = NULL;
755*7836SJohn.Forte@Sun.COM 
756*7836SJohn.Forte@Sun.COM 	if (devpath == NULL || devid == NULL || drvr_name == NULL) {
757*7836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
758*7836SJohn.Forte@Sun.COM 	}
759*7836SJohn.Forte@Sun.COM 
760*7836SJohn.Forte@Sun.COM 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
761*7836SJohn.Forte@Sun.COM 		start_time = gethrtime();
762*7836SJohn.Forte@Sun.COM 	}
763*7836SJohn.Forte@Sun.COM 
764*7836SJohn.Forte@Sun.COM 	*devid = NULL;
765*7836SJohn.Forte@Sun.COM 	rootpath[0] = '\0';
766*7836SJohn.Forte@Sun.COM 
767*7836SJohn.Forte@Sun.COM 	/*
768*7836SJohn.Forte@Sun.COM 	 * Form a valid root path by stripping off the /devices/ mount point
769*7836SJohn.Forte@Sun.COM 	 * prefix and the minor name (:a[,raw]).
770*7836SJohn.Forte@Sun.COM 	 */
771*7836SJohn.Forte@Sun.COM 	if (strstr(devpath, DEV_PREFIX)) {
772*7836SJohn.Forte@Sun.COM 		strcat(rootpath, devpath + strlen(DEV_PREFIX) - 1);
773*7836SJohn.Forte@Sun.COM 		if (strchr(devpath, ':')) {
774*7836SJohn.Forte@Sun.COM 			cptr = strrchr(rootpath, ':');
775*7836SJohn.Forte@Sun.COM 			*cptr = '\0';
776*7836SJohn.Forte@Sun.COM 		} else {
777*7836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
778*7836SJohn.Forte@Sun.COM 		}
779*7836SJohn.Forte@Sun.COM 	} else {
780*7836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
781*7836SJohn.Forte@Sun.COM 	}
782*7836SJohn.Forte@Sun.COM 
783*7836SJohn.Forte@Sun.COM 	/* point to first node which matches portdrvr */
784*7836SJohn.Forte@Sun.COM 	node = di_drv_first_node(drvr_name, root);
785*7836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
786*7836SJohn.Forte@Sun.COM 		/*
787*7836SJohn.Forte@Sun.COM 		 * Could not find driver node
788*7836SJohn.Forte@Sun.COM 		 */
789*7836SJohn.Forte@Sun.COM 		return (L_NO_DEVID);
790*7836SJohn.Forte@Sun.COM 	}
791*7836SJohn.Forte@Sun.COM 
792*7836SJohn.Forte@Sun.COM 	while (node != DI_NODE_NIL) {
793*7836SJohn.Forte@Sun.COM 		if ((devfs_path = di_devfs_path(node)) != NULL) {
794*7836SJohn.Forte@Sun.COM 			if (strcmp(rootpath, devfs_path) == 0) {
795*7836SJohn.Forte@Sun.COM 				*devid = di_devid(node);
796*7836SJohn.Forte@Sun.COM 				di_devfs_path_free(devfs_path);
797*7836SJohn.Forte@Sun.COM 				break;
798*7836SJohn.Forte@Sun.COM 			}
799*7836SJohn.Forte@Sun.COM 			di_devfs_path_free(devfs_path);
800*7836SJohn.Forte@Sun.COM 		}
801*7836SJohn.Forte@Sun.COM 		node = di_drv_next_node(node);
802*7836SJohn.Forte@Sun.COM 	}
803*7836SJohn.Forte@Sun.COM 
804*7836SJohn.Forte@Sun.COM 	if (env != NULL) {
805*7836SJohn.Forte@Sun.COM 		end_time = gethrtime();
806*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout,
807*7836SJohn.Forte@Sun.COM 		"      g_devid_get: "
808*7836SJohn.Forte@Sun.COM 		"\t\tTime = %lld millisec\n",
809*7836SJohn.Forte@Sun.COM 		(end_time - start_time)/1000000);
810*7836SJohn.Forte@Sun.COM 	}
811*7836SJohn.Forte@Sun.COM 	/* Did we get back a handle? */
812*7836SJohn.Forte@Sun.COM 	if (*devid != NULL) {
813*7836SJohn.Forte@Sun.COM 		return (0);
814*7836SJohn.Forte@Sun.COM 	} else { /* Couldn't get a devid. */
815*7836SJohn.Forte@Sun.COM 		return (L_NO_DEVID);
816*7836SJohn.Forte@Sun.COM 	}
817*7836SJohn.Forte@Sun.COM }
818