1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
30*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <stropts.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <unistd.h>
39*7c478bd9Sstevel@tonic-gate #include <kstat.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <devid.h>
42*7c478bd9Sstevel@tonic-gate #include <dirent.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate /* included for uscsi */
45*7c478bd9Sstevel@tonic-gate #include <strings.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/types.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/commands.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/mode.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
55*7c478bd9Sstevel@tonic-gate #include "disks_private.h"
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_DISK	"disk"
58*7c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_ERROR	"device_error"
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #define	SCSIBUFLEN		0xffff
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /* byte get macros */
63*7c478bd9Sstevel@tonic-gate #define	b3(a)			(((a)>>24) & 0xFF)
64*7c478bd9Sstevel@tonic-gate #define	b2(a)			(((a)>>16) & 0xFF)
65*7c478bd9Sstevel@tonic-gate #define	b1(a)			(((a)>>8) & 0xFF)
66*7c478bd9Sstevel@tonic-gate #define	b0(a)			(((a)>>0) & 0xFF)
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate static char *kstat_err_names[] = {
69*7c478bd9Sstevel@tonic-gate 	"Soft Errors",
70*7c478bd9Sstevel@tonic-gate 	"Hard Errors",
71*7c478bd9Sstevel@tonic-gate 	"Transport Errors",
72*7c478bd9Sstevel@tonic-gate 	"Media Error",
73*7c478bd9Sstevel@tonic-gate 	"Device Not Ready",
74*7c478bd9Sstevel@tonic-gate 	"No Device",
75*7c478bd9Sstevel@tonic-gate 	"Recoverable",
76*7c478bd9Sstevel@tonic-gate 	"Illegal Request",
77*7c478bd9Sstevel@tonic-gate 	"Predictive Failure Analysis",
78*7c478bd9Sstevel@tonic-gate 	NULL
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static char *err_attr_names[] = {
82*7c478bd9Sstevel@tonic-gate 	DM_NSOFTERRS,
83*7c478bd9Sstevel@tonic-gate 	DM_NHARDERRS,
84*7c478bd9Sstevel@tonic-gate 	DM_NTRANSERRS,
85*7c478bd9Sstevel@tonic-gate 	DM_NMEDIAERRS,
86*7c478bd9Sstevel@tonic-gate 	DM_NDNRERRS,
87*7c478bd9Sstevel@tonic-gate 	DM_NNODEVERRS,
88*7c478bd9Sstevel@tonic-gate 	DM_NRECOVERRS,
89*7c478bd9Sstevel@tonic-gate 	DM_NILLREQERRS,
90*7c478bd9Sstevel@tonic-gate 	DM_FAILING,
91*7c478bd9Sstevel@tonic-gate 	NULL
92*7c478bd9Sstevel@tonic-gate };
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  *	**************** begin uscsi stuff ****************
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
99*7c478bd9Sstevel@tonic-gate #elif defined(_BIT_FIELDS_HTOL)
100*7c478bd9Sstevel@tonic-gate #else
101*7c478bd9Sstevel@tonic-gate #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
102*7c478bd9Sstevel@tonic-gate #endif
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate struct conf_feature {
105*7c478bd9Sstevel@tonic-gate 	uchar_t feature[2]; /* common to all */
106*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
107*7c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
108*7c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
109*7c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
110*7c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
111*7c478bd9Sstevel@tonic-gate #else
112*7c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
113*7c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
114*7c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
115*7c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
116*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
117*7c478bd9Sstevel@tonic-gate 	uchar_t len;
118*7c478bd9Sstevel@tonic-gate 	union features {
119*7c478bd9Sstevel@tonic-gate 		struct generic {
120*7c478bd9Sstevel@tonic-gate 			uchar_t data[1];
121*7c478bd9Sstevel@tonic-gate 		} gen;
122*7c478bd9Sstevel@tonic-gate 		uchar_t data[1];
123*7c478bd9Sstevel@tonic-gate 		struct profile_list {
124*7c478bd9Sstevel@tonic-gate 			uchar_t profile[2];
125*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
126*7c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
127*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
128*7c478bd9Sstevel@tonic-gate #else
129*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
130*7c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
131*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
132*7c478bd9Sstevel@tonic-gate 			uchar_t reserved2;
133*7c478bd9Sstevel@tonic-gate 		} plist[1];
134*7c478bd9Sstevel@tonic-gate 		struct core {
135*7c478bd9Sstevel@tonic-gate 			uchar_t phys[4];
136*7c478bd9Sstevel@tonic-gate 		} core;
137*7c478bd9Sstevel@tonic-gate 		struct morphing {
138*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
139*7c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
140*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
141*7c478bd9Sstevel@tonic-gate #else
142*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
143*7c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
144*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
145*7c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
146*7c478bd9Sstevel@tonic-gate 		} morphing;
147*7c478bd9Sstevel@tonic-gate 		struct removable {
148*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
149*7c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
150*7c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
151*7c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
152*7c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
153*7c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
154*7c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
155*7c478bd9Sstevel@tonic-gate #else
156*7c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
157*7c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
158*7c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
159*7c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
160*7c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
161*7c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
162*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
163*7c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
164*7c478bd9Sstevel@tonic-gate 		} removable;
165*7c478bd9Sstevel@tonic-gate 		struct random_readable {
166*7c478bd9Sstevel@tonic-gate 			uchar_t lbsize[4];
167*7c478bd9Sstevel@tonic-gate 			uchar_t blocking[2];
168*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
169*7c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
170*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
171*7c478bd9Sstevel@tonic-gate #else
172*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
173*7c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
174*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
175*7c478bd9Sstevel@tonic-gate 			uchar_t reserved;
176*7c478bd9Sstevel@tonic-gate 		} rread;
177*7c478bd9Sstevel@tonic-gate 		struct cd_read {
178*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
179*7c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
180*7c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
181*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
182*7c478bd9Sstevel@tonic-gate #else
183*7c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
184*7c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
185*7c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
186*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
187*7c478bd9Sstevel@tonic-gate 		} cdread;
188*7c478bd9Sstevel@tonic-gate 		struct cd_audio {
189*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
190*7c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
191*7c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
192*7c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
193*7c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
194*7c478bd9Sstevel@tonic-gate #else
195*7c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
196*7c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
197*7c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
198*7c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
199*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
200*7c478bd9Sstevel@tonic-gate 			uchar_t reserved;
201*7c478bd9Sstevel@tonic-gate 			uchar_t numlevels[2];
202*7c478bd9Sstevel@tonic-gate 		} audio;
203*7c478bd9Sstevel@tonic-gate 		struct dvd_css {
204*7c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
205*7c478bd9Sstevel@tonic-gate 			uchar_t version;
206*7c478bd9Sstevel@tonic-gate 		} dvdcss;
207*7c478bd9Sstevel@tonic-gate 	} features;
208*7c478bd9Sstevel@tonic-gate };
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate #define	PROF_NON_REMOVABLE	0x0001
211*7c478bd9Sstevel@tonic-gate #define	PROF_REMOVABLE		0x0002
212*7c478bd9Sstevel@tonic-gate #define	PROF_MAGNETO_OPTICAL	0x0003
213*7c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_WO		0x0004
214*7c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_ASMO	0x0005
215*7c478bd9Sstevel@tonic-gate #define	PROF_CDROM		0x0008
216*7c478bd9Sstevel@tonic-gate #define	PROF_CDR		0x0009
217*7c478bd9Sstevel@tonic-gate #define	PROF_CDRW		0x000a
218*7c478bd9Sstevel@tonic-gate #define	PROF_DVDROM		0x0010
219*7c478bd9Sstevel@tonic-gate #define	PROF_DVDR		0x0011
220*7c478bd9Sstevel@tonic-gate #define	PROF_DVDRAM		0x0012
221*7c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_REST		0x0013
222*7c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_SEQ		0x0014
223*7c478bd9Sstevel@tonic-gate #define	PROF_DVDRW		0x001a
224*7c478bd9Sstevel@tonic-gate #define	PROF_DDCD_ROM		0x0020
225*7c478bd9Sstevel@tonic-gate #define	PROF_DDCD_R		0x0021
226*7c478bd9Sstevel@tonic-gate #define	PROF_DDCD_RW		0x0022
227*7c478bd9Sstevel@tonic-gate #define	PROF_NON_CONFORMING	0xffff
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate struct get_configuration {
230*7c478bd9Sstevel@tonic-gate 	uchar_t len[4];
231*7c478bd9Sstevel@tonic-gate 	uchar_t reserved[2];
232*7c478bd9Sstevel@tonic-gate 	uchar_t curprof[2];
233*7c478bd9Sstevel@tonic-gate 	struct conf_feature feature;
234*7c478bd9Sstevel@tonic-gate };
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate struct capabilities {
237*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
238*7c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
239*7c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
240*7c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
241*7c478bd9Sstevel@tonic-gate #else
242*7c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
243*7c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
244*7c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
245*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
246*7c478bd9Sstevel@tonic-gate 	uchar_t pagelen;
247*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
248*7c478bd9Sstevel@tonic-gate 	/* read capabilities */
249*7c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
250*7c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
251*7c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
252*7c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
253*7c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
254*7c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
255*7c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
256*7c478bd9Sstevel@tonic-gate #else
257*7c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
258*7c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
259*7c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
260*7c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
261*7c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
262*7c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
263*7c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
264*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
265*7c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
266*7c478bd9Sstevel@tonic-gate 	/* write capabilities */
267*7c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
268*7c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
269*7c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
270*7c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
271*7c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
272*7c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
273*7c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
274*7c478bd9Sstevel@tonic-gate #else
275*7c478bd9Sstevel@tonic-gate 	/* write capabilities */
276*7c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
277*7c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
278*7c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
279*7c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
280*7c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
281*7c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
282*7c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
283*7c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
284*7c478bd9Sstevel@tonic-gate 	uchar_t misc0;
285*7c478bd9Sstevel@tonic-gate 	uchar_t misc1;
286*7c478bd9Sstevel@tonic-gate 	uchar_t misc2;
287*7c478bd9Sstevel@tonic-gate 	uchar_t misc3;
288*7c478bd9Sstevel@tonic-gate 	uchar_t obsolete0[2];
289*7c478bd9Sstevel@tonic-gate 	uchar_t numvlevels[2];
290*7c478bd9Sstevel@tonic-gate 	uchar_t bufsize[2];
291*7c478bd9Sstevel@tonic-gate 	uchar_t obsolete1[4];
292*7c478bd9Sstevel@tonic-gate 	uchar_t resv5;
293*7c478bd9Sstevel@tonic-gate 	uchar_t misc4;
294*7c478bd9Sstevel@tonic-gate 	uchar_t obsolete2;
295*7c478bd9Sstevel@tonic-gate 	uchar_t copymgt[2];
296*7c478bd9Sstevel@tonic-gate 	/* there is more to this page, but nothing we care about */
297*7c478bd9Sstevel@tonic-gate };
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate struct mode_header_g2 {
300*7c478bd9Sstevel@tonic-gate 	uchar_t modelen[2];
301*7c478bd9Sstevel@tonic-gate 	uchar_t obsolete;
302*7c478bd9Sstevel@tonic-gate 	uchar_t reserved[3];
303*7c478bd9Sstevel@tonic-gate 	uchar_t desclen[2];
304*7c478bd9Sstevel@tonic-gate };
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate /*
307*7c478bd9Sstevel@tonic-gate  * Mode sense/select page header information
308*7c478bd9Sstevel@tonic-gate  */
309*7c478bd9Sstevel@tonic-gate struct scsi_ms_header {
310*7c478bd9Sstevel@tonic-gate 	struct mode_header	mode_header;
311*7c478bd9Sstevel@tonic-gate 	struct block_descriptor	block_descriptor;
312*7c478bd9Sstevel@tonic-gate };
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate #define	MODESENSE_PAGE_LEN(p)	(((int)((struct mode_page *)p)->length) + \
315*7c478bd9Sstevel@tonic-gate 				    sizeof (struct mode_page))
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_CURRENT	(0 << 6)
318*7c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_DEFAULT	(2 << 6)
319*7c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_SAVED	(3 << 6)
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate #define	MAX_MODE_SENSE_SIZE	255
322*7c478bd9Sstevel@tonic-gate #define	IMPOSSIBLE_SCSI_STATUS	0xff
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate /*
325*7c478bd9Sstevel@tonic-gate  *	********** end of uscsi stuff ************
326*7c478bd9Sstevel@tonic-gate  */
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate static descriptor_t	**apply_filter(descriptor_t **drives, int filter[],
329*7c478bd9Sstevel@tonic-gate 			    int *errp);
330*7c478bd9Sstevel@tonic-gate static int		check_atapi(int fd);
331*7c478bd9Sstevel@tonic-gate static int		conv_drive_type(uint_t drive_type);
332*7c478bd9Sstevel@tonic-gate static uint64_t		convnum(uchar_t *nptr, int len);
333*7c478bd9Sstevel@tonic-gate static void		fill_command_g1(struct uscsi_cmd *cmd,
334*7c478bd9Sstevel@tonic-gate 			    union scsi_cdb *cdb, caddr_t buff, int blen);
335*7c478bd9Sstevel@tonic-gate static void		fill_general_page_cdb_g1(union scsi_cdb *cdb,
336*7c478bd9Sstevel@tonic-gate 			    int command, int lun, uchar_t c0, uchar_t c1);
337*7c478bd9Sstevel@tonic-gate static void		fill_mode_page_cdb(union scsi_cdb *cdb, int page);
338*7c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_alias(disk_t *diskp, int *errp);
339*7c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_controllers(descriptor_t *dp, int *errp);
340*7c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_paths(descriptor_t *dp, int *errp);
341*7c478bd9Sstevel@tonic-gate static int		get_attrs(disk_t *diskp, int fd, char *opath,
342*7c478bd9Sstevel@tonic-gate 			    nvlist_t *nvp);
343*7c478bd9Sstevel@tonic-gate static int		get_cdrom_drvtype(int fd);
344*7c478bd9Sstevel@tonic-gate static int		get_disk_kstats(kstat_ctl_t *kc, char *diskname,
345*7c478bd9Sstevel@tonic-gate 			    char *classname, nvlist_t *stats);
346*7c478bd9Sstevel@tonic-gate static void		get_drive_type(disk_t *dp, int fd);
347*7c478bd9Sstevel@tonic-gate static int		get_err_kstats(kstat_ctl_t *kc, char *diskname,
348*7c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
349*7c478bd9Sstevel@tonic-gate static int		get_io_kstats(kstat_ctl_t *kc, char *diskname,
350*7c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
351*7c478bd9Sstevel@tonic-gate static int		get_kstat_vals(kstat_t *ksp, nvlist_t *stats);
352*7c478bd9Sstevel@tonic-gate static char		*get_err_attr_name(char *kstat_name);
353*7c478bd9Sstevel@tonic-gate static int		get_rpm(disk_t *dp, int fd);
354*7c478bd9Sstevel@tonic-gate static int		update_stat64(nvlist_t *stats, char *attr,
355*7c478bd9Sstevel@tonic-gate 			    uint64_t value);
356*7c478bd9Sstevel@tonic-gate static int		update_stat32(nvlist_t *stats, char *attr,
357*7c478bd9Sstevel@tonic-gate 			    uint32_t value);
358*7c478bd9Sstevel@tonic-gate static int		uscsi_mode_sense(int fd, int page_code,
359*7c478bd9Sstevel@tonic-gate 			    int page_control, caddr_t page_data, int page_size,
360*7c478bd9Sstevel@tonic-gate 			    struct  scsi_ms_header *header);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate descriptor_t **
363*7c478bd9Sstevel@tonic-gate drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
364*7c478bd9Sstevel@tonic-gate     int *errp)
365*7c478bd9Sstevel@tonic-gate {
366*7c478bd9Sstevel@tonic-gate 	switch (type) {
367*7c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
368*7c478bd9Sstevel@tonic-gate 	    return (get_assoc_controllers(dp, errp));
369*7c478bd9Sstevel@tonic-gate 	case DM_PATH:
370*7c478bd9Sstevel@tonic-gate 	    return (get_assoc_paths(dp, errp));
371*7c478bd9Sstevel@tonic-gate 	case DM_ALIAS:
372*7c478bd9Sstevel@tonic-gate 	    return (get_assoc_alias(dp->p.disk, errp));
373*7c478bd9Sstevel@tonic-gate 	case DM_MEDIA:
374*7c478bd9Sstevel@tonic-gate 	    return (media_get_assocs(dp, errp));
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
378*7c478bd9Sstevel@tonic-gate 	return (NULL);
379*7c478bd9Sstevel@tonic-gate }
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate /*
382*7c478bd9Sstevel@tonic-gate  * Get the drive descriptors for the given media/alias/devpath.
383*7c478bd9Sstevel@tonic-gate  */
384*7c478bd9Sstevel@tonic-gate descriptor_t **
385*7c478bd9Sstevel@tonic-gate drive_get_assocs(descriptor_t *desc, int *errp)
386*7c478bd9Sstevel@tonic-gate {
387*7c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	/* at most one drive is associated with these descriptors */
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	drives = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
392*7c478bd9Sstevel@tonic-gate 	if (drives == NULL) {
393*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
394*7c478bd9Sstevel@tonic-gate 	    return (NULL);
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
398*7c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
399*7c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
400*7c478bd9Sstevel@tonic-gate 	    return (NULL);
401*7c478bd9Sstevel@tonic-gate 	}
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	drives[1] = NULL;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	return (drives);
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate nvlist_t *
409*7c478bd9Sstevel@tonic-gate drive_get_attributes(descriptor_t *dp, int *errp)
410*7c478bd9Sstevel@tonic-gate {
411*7c478bd9Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
412*7c478bd9Sstevel@tonic-gate 	int		fd;
413*7c478bd9Sstevel@tonic-gate 	char		opath[MAXPATHLEN];
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
416*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
417*7c478bd9Sstevel@tonic-gate 	    return (NULL);
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	opath[0] = 0;
421*7c478bd9Sstevel@tonic-gate 	fd = drive_open_disk(dp->p.disk, opath, sizeof (opath));
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if ((*errp = get_attrs(dp->p.disk, fd, opath, attrs)) != 0) {
424*7c478bd9Sstevel@tonic-gate 	    nvlist_free(attrs);
425*7c478bd9Sstevel@tonic-gate 	    attrs = NULL;
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
429*7c478bd9Sstevel@tonic-gate 	    (void) close(fd);
430*7c478bd9Sstevel@tonic-gate 	}
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	return (attrs);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate /*
436*7c478bd9Sstevel@tonic-gate  * Check if we have the drive in our list, based upon the device id.
437*7c478bd9Sstevel@tonic-gate  * We got the device id from the dev tree walk.  This is encoded
438*7c478bd9Sstevel@tonic-gate  * using devid_str_encode(3DEVID).   In order to check the device ids we need
439*7c478bd9Sstevel@tonic-gate  * to use the devid_compare(3DEVID) function, so we need to decode the
440*7c478bd9Sstevel@tonic-gate  * string representation of the device id.
441*7c478bd9Sstevel@tonic-gate  */
442*7c478bd9Sstevel@tonic-gate descriptor_t *
443*7c478bd9Sstevel@tonic-gate drive_get_descriptor_by_name(char *name, int *errp)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid;
446*7c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
447*7c478bd9Sstevel@tonic-gate 	descriptor_t	*drive = NULL;
448*7c478bd9Sstevel@tonic-gate 	int		i;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
451*7c478bd9Sstevel@tonic-gate 	    *errp = EINVAL;
452*7c478bd9Sstevel@tonic-gate 	    return (NULL);
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
456*7c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
457*7c478bd9Sstevel@tonic-gate 	    devid_free(devid);
458*7c478bd9Sstevel@tonic-gate 	    return (NULL);
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	/*
462*7c478bd9Sstevel@tonic-gate 	 * We have to loop through all of them, freeing the ones we don't
463*7c478bd9Sstevel@tonic-gate 	 * want.  Once drive is set, we don't need to compare any more.
464*7c478bd9Sstevel@tonic-gate 	 */
465*7c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
466*7c478bd9Sstevel@tonic-gate 	    if (drive == NULL && drives[i]->p.disk->devid != NULL &&
467*7c478bd9Sstevel@tonic-gate 		devid_compare(devid, drives[i]->p.disk->devid) == 0) {
468*7c478bd9Sstevel@tonic-gate 		drive = drives[i];
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	    } else {
471*7c478bd9Sstevel@tonic-gate 		/* clean up the unused descriptor */
472*7c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
473*7c478bd9Sstevel@tonic-gate 	    }
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 	free(drives);
476*7c478bd9Sstevel@tonic-gate 	devid_free(devid);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	if (drive == NULL) {
479*7c478bd9Sstevel@tonic-gate 	    *errp = ENODEV;
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	return (drive);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate descriptor_t **
486*7c478bd9Sstevel@tonic-gate drive_get_descriptors(int filter[], int *errp)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
491*7c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
492*7c478bd9Sstevel@tonic-gate 	    return (NULL);
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if (filter != NULL && filter[0] != DM_FILTER_END) {
496*7c478bd9Sstevel@tonic-gate 	    descriptor_t	**found;
497*7c478bd9Sstevel@tonic-gate 	    found = apply_filter(drives, filter, errp);
498*7c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
499*7c478bd9Sstevel@tonic-gate 		drives = NULL;
500*7c478bd9Sstevel@tonic-gate 	    } else {
501*7c478bd9Sstevel@tonic-gate 		drives = found;
502*7c478bd9Sstevel@tonic-gate 	    }
503*7c478bd9Sstevel@tonic-gate 	}
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	return (drives);
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate char *
509*7c478bd9Sstevel@tonic-gate drive_get_name(descriptor_t *dp)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	return (dp->p.disk->device_id);
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate nvlist_t *
515*7c478bd9Sstevel@tonic-gate drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
518*7c478bd9Sstevel@tonic-gate 	nvlist_t	*stats;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
523*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
524*7c478bd9Sstevel@tonic-gate 	    return (NULL);
525*7c478bd9Sstevel@tonic-gate 	}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_PERFORMANCE ||
528*7c478bd9Sstevel@tonic-gate 	    stat_type == DM_DRV_STAT_DIAGNOSTIC) {
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	    alias_t	*ap;
531*7c478bd9Sstevel@tonic-gate 	    kstat_ctl_t	*kc;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	    ap = diskp->aliases;
534*7c478bd9Sstevel@tonic-gate 	    if (ap == NULL || ap->kstat_name == NULL) {
535*7c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
536*7c478bd9Sstevel@tonic-gate 		*errp = EACCES;
537*7c478bd9Sstevel@tonic-gate 		return (NULL);
538*7c478bd9Sstevel@tonic-gate 	    }
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	    if ((kc = kstat_open()) == NULL) {
541*7c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
542*7c478bd9Sstevel@tonic-gate 		*errp = EACCES;
543*7c478bd9Sstevel@tonic-gate 		return (NULL);
544*7c478bd9Sstevel@tonic-gate 	    }
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	    while (ap != NULL) {
547*7c478bd9Sstevel@tonic-gate 		int	status;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 		if (ap->kstat_name == NULL) {
550*7c478bd9Sstevel@tonic-gate 		    continue;
551*7c478bd9Sstevel@tonic-gate 		}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		if (stat_type == DM_DRV_STAT_PERFORMANCE) {
554*7c478bd9Sstevel@tonic-gate 		    status = get_io_kstats(kc, ap->kstat_name, stats);
555*7c478bd9Sstevel@tonic-gate 		} else {
556*7c478bd9Sstevel@tonic-gate 		    status = get_err_kstats(kc, ap->kstat_name, stats);
557*7c478bd9Sstevel@tonic-gate 		}
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		if (status != 0) {
560*7c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
561*7c478bd9Sstevel@tonic-gate 		    (void) kstat_close(kc);
562*7c478bd9Sstevel@tonic-gate 		    *errp = ENOMEM;
563*7c478bd9Sstevel@tonic-gate 		    return (NULL);
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		ap = ap->next;
567*7c478bd9Sstevel@tonic-gate 	    }
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	    (void) kstat_close(kc);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	    *errp = 0;
572*7c478bd9Sstevel@tonic-gate 	    return (stats);
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_TEMPERATURE) {
576*7c478bd9Sstevel@tonic-gate 	    int		fd;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	    if ((fd = drive_open_disk(diskp, NULL, 0)) >= 0) {
579*7c478bd9Sstevel@tonic-gate 		struct dk_temperature	temp;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGTEMPERATURE, &temp) >= 0) {
582*7c478bd9Sstevel@tonic-gate 		    if (nvlist_add_uint32(stats, DM_TEMPERATURE,
583*7c478bd9Sstevel@tonic-gate 			temp.dkt_cur_temp) != 0) {
584*7c478bd9Sstevel@tonic-gate 			*errp = ENOMEM;
585*7c478bd9Sstevel@tonic-gate 			nvlist_free(stats);
586*7c478bd9Sstevel@tonic-gate 			return (NULL);
587*7c478bd9Sstevel@tonic-gate 		    }
588*7c478bd9Sstevel@tonic-gate 		} else {
589*7c478bd9Sstevel@tonic-gate 		    *errp = errno;
590*7c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
591*7c478bd9Sstevel@tonic-gate 		    return (NULL);
592*7c478bd9Sstevel@tonic-gate 		}
593*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
594*7c478bd9Sstevel@tonic-gate 	    } else {
595*7c478bd9Sstevel@tonic-gate 		*errp = errno;
596*7c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
597*7c478bd9Sstevel@tonic-gate 		return (NULL);
598*7c478bd9Sstevel@tonic-gate 	    }
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	    *errp = 0;
601*7c478bd9Sstevel@tonic-gate 	    return (stats);
602*7c478bd9Sstevel@tonic-gate 	}
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	nvlist_free(stats);
605*7c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
606*7c478bd9Sstevel@tonic-gate 	return (NULL);
607*7c478bd9Sstevel@tonic-gate }
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate int
610*7c478bd9Sstevel@tonic-gate drive_make_descriptors()
611*7c478bd9Sstevel@tonic-gate {
612*7c478bd9Sstevel@tonic-gate 	int	error;
613*7c478bd9Sstevel@tonic-gate 	disk_t	*dp;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	dp = cache_get_disklist();
616*7c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
617*7c478bd9Sstevel@tonic-gate 	    cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
618*7c478bd9Sstevel@tonic-gate 	    if (error != 0) {
619*7c478bd9Sstevel@tonic-gate 		return (error);
620*7c478bd9Sstevel@tonic-gate 	    }
621*7c478bd9Sstevel@tonic-gate 	    dp = dp->next;
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	return (0);
625*7c478bd9Sstevel@tonic-gate }
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate /*
628*7c478bd9Sstevel@tonic-gate  * This function opens the disk generically (any slice).
629*7c478bd9Sstevel@tonic-gate  *
630*7c478bd9Sstevel@tonic-gate  * Opening the disk could fail because the disk is managed by the volume
631*7c478bd9Sstevel@tonic-gate  * manager.  Handle this if that is the case.  Note that the media APIs don't
632*7c478bd9Sstevel@tonic-gate  * always return a device.  If the media has slices (e.g. a solaris install
633*7c478bd9Sstevel@tonic-gate  * CD-ROM) then media_findname(volname) returns a directory with per slice
634*7c478bd9Sstevel@tonic-gate  * devices underneath.  We need to open one of those devices in this case.
635*7c478bd9Sstevel@tonic-gate  */
636*7c478bd9Sstevel@tonic-gate int
637*7c478bd9Sstevel@tonic-gate drive_open_disk(disk_t *diskp, char *opath, int len)
638*7c478bd9Sstevel@tonic-gate {
639*7c478bd9Sstevel@tonic-gate 	char	rmmedia_devpath[MAXPATHLEN];
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	if (diskp->removable && media_get_volm_path(diskp, rmmedia_devpath,
642*7c478bd9Sstevel@tonic-gate 	    sizeof (rmmedia_devpath))) {
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	    int		fd;
645*7c478bd9Sstevel@tonic-gate 	    struct stat	buf;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	    if (rmmedia_devpath[0] == 0) {
648*7c478bd9Sstevel@tonic-gate 		/* removable but no media */
649*7c478bd9Sstevel@tonic-gate 		return (-1);
650*7c478bd9Sstevel@tonic-gate 	    }
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	    if ((fd = open(rmmedia_devpath, O_RDONLY|O_NDELAY)) < 0) {
653*7c478bd9Sstevel@tonic-gate 		return (-1);
654*7c478bd9Sstevel@tonic-gate 	    }
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	    if (fstat(fd, &buf) != 0) {
657*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
658*7c478bd9Sstevel@tonic-gate 		return (-1);
659*7c478bd9Sstevel@tonic-gate 	    }
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	    if (buf.st_mode & S_IFCHR) {
662*7c478bd9Sstevel@tonic-gate 		/* opened, is device, so done */
663*7c478bd9Sstevel@tonic-gate 		if (opath != NULL) {
664*7c478bd9Sstevel@tonic-gate 		    (void) strlcpy(opath, rmmedia_devpath, len);
665*7c478bd9Sstevel@tonic-gate 		}
666*7c478bd9Sstevel@tonic-gate 		return (fd);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	    } else if (buf.st_mode & S_IFDIR) {
669*7c478bd9Sstevel@tonic-gate 		/* disk w/ slices so handle the directory */
670*7c478bd9Sstevel@tonic-gate 		DIR		*dirp;
671*7c478bd9Sstevel@tonic-gate 		struct dirent	*dentp;
672*7c478bd9Sstevel@tonic-gate 		int		dfd;
673*7c478bd9Sstevel@tonic-gate #ifdef _LP64
674*7c478bd9Sstevel@tonic-gate 		struct  dirent *result;
675*7c478bd9Sstevel@tonic-gate #endif
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 		/* each device file in the dir represents a slice */
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 		if ((dirp = fdopendir(fd)) == NULL) {
680*7c478bd9Sstevel@tonic-gate 		    (void) close(fd);
681*7c478bd9Sstevel@tonic-gate 		    return (-1);
682*7c478bd9Sstevel@tonic-gate 		}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		if ((dentp = (struct dirent *)malloc(sizeof (struct dirent) +
685*7c478bd9Sstevel@tonic-gate 		    _PC_NAME_MAX + 1)) == NULL) {
686*7c478bd9Sstevel@tonic-gate 		    /* out of memory */
687*7c478bd9Sstevel@tonic-gate 		    (void) close(fd);
688*7c478bd9Sstevel@tonic-gate 		    return (-1);
689*7c478bd9Sstevel@tonic-gate 		}
690*7c478bd9Sstevel@tonic-gate #ifdef _LP64
691*7c478bd9Sstevel@tonic-gate 		while (readdir_r(dirp, dentp, &result) != NULL) {
692*7c478bd9Sstevel@tonic-gate #else
693*7c478bd9Sstevel@tonic-gate 		while (readdir_r(dirp, dentp) != NULL) {
694*7c478bd9Sstevel@tonic-gate #endif
695*7c478bd9Sstevel@tonic-gate 		    char	slice_path[MAXPATHLEN];
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(".", dentp->d_name) ||
698*7c478bd9Sstevel@tonic-gate 			libdiskmgt_str_eq("..", dentp->d_name)) {
699*7c478bd9Sstevel@tonic-gate 			continue;
700*7c478bd9Sstevel@tonic-gate 		    }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 		    (void) snprintf(slice_path, sizeof (slice_path), "%s/%s",
703*7c478bd9Sstevel@tonic-gate 			rmmedia_devpath, dentp->d_name);
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 		    if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) < 0) {
706*7c478bd9Sstevel@tonic-gate 			continue;
707*7c478bd9Sstevel@tonic-gate 		    }
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 		    if (fstat(dfd, &buf) == 0 && (buf.st_mode & S_IFCHR)) {
710*7c478bd9Sstevel@tonic-gate 			/* opened, is device, so done */
711*7c478bd9Sstevel@tonic-gate 			free(dentp);
712*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
713*7c478bd9Sstevel@tonic-gate 			if (opath != NULL) {
714*7c478bd9Sstevel@tonic-gate 			    (void) strlcpy(opath, slice_path, len);
715*7c478bd9Sstevel@tonic-gate 			}
716*7c478bd9Sstevel@tonic-gate 			return (dfd);
717*7c478bd9Sstevel@tonic-gate 		    }
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		    /* not a device, keep looking */
720*7c478bd9Sstevel@tonic-gate 		    (void) close(dfd);
721*7c478bd9Sstevel@tonic-gate 		}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 		/* did not find a device under the rmmedia_path */
724*7c478bd9Sstevel@tonic-gate 		free(dentp);
725*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
726*7c478bd9Sstevel@tonic-gate 	    }
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	    /* didn't find a device under volume management control */
729*7c478bd9Sstevel@tonic-gate 	    return (-1);
730*7c478bd9Sstevel@tonic-gate 	}
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 	/*
733*7c478bd9Sstevel@tonic-gate 	 * Not removable media under volume management control so just open the
734*7c478bd9Sstevel@tonic-gate 	 * first devpath.
735*7c478bd9Sstevel@tonic-gate 	 */
736*7c478bd9Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
737*7c478bd9Sstevel@tonic-gate 	    if (opath != NULL) {
738*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
739*7c478bd9Sstevel@tonic-gate 	    }
740*7c478bd9Sstevel@tonic-gate 	    return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
741*7c478bd9Sstevel@tonic-gate 	}
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	return (-1);
744*7c478bd9Sstevel@tonic-gate }
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate static descriptor_t **
747*7c478bd9Sstevel@tonic-gate apply_filter(descriptor_t **drives, int filter[], int *errp)
748*7c478bd9Sstevel@tonic-gate {
749*7c478bd9Sstevel@tonic-gate 	int		i;
750*7c478bd9Sstevel@tonic-gate 	descriptor_t	**found;
751*7c478bd9Sstevel@tonic-gate 	int		cnt;
752*7c478bd9Sstevel@tonic-gate 	int		pos;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* count the number of drives in the snapshot */
755*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; drives[cnt]; cnt++);
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
758*7c478bd9Sstevel@tonic-gate 	if (found == NULL) {
759*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
760*7c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
761*7c478bd9Sstevel@tonic-gate 	    return (NULL);
762*7c478bd9Sstevel@tonic-gate 	}
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	pos = 0;
765*7c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
766*7c478bd9Sstevel@tonic-gate 	    int j;
767*7c478bd9Sstevel@tonic-gate 	    int match;
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	    /* Make sure the drive type is set */
770*7c478bd9Sstevel@tonic-gate 	    get_drive_type(drives[i]->p.disk, -1);
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	    match = 0;
773*7c478bd9Sstevel@tonic-gate 	    for (j = 0; filter[j] != DM_FILTER_END; j++) {
774*7c478bd9Sstevel@tonic-gate 		if (drives[i]->p.disk->drv_type == filter[j]) {
775*7c478bd9Sstevel@tonic-gate 		    found[pos++] = drives[i];
776*7c478bd9Sstevel@tonic-gate 		    match = 1;
777*7c478bd9Sstevel@tonic-gate 		    break;
778*7c478bd9Sstevel@tonic-gate 		}
779*7c478bd9Sstevel@tonic-gate 	    }
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	    if (!match) {
782*7c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
783*7c478bd9Sstevel@tonic-gate 	    }
784*7c478bd9Sstevel@tonic-gate 	}
785*7c478bd9Sstevel@tonic-gate 	found[pos] = NULL;
786*7c478bd9Sstevel@tonic-gate 	free(drives);
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	*errp = 0;
789*7c478bd9Sstevel@tonic-gate 	return (found);
790*7c478bd9Sstevel@tonic-gate }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate static int
793*7c478bd9Sstevel@tonic-gate conv_drive_type(uint_t drive_type)
794*7c478bd9Sstevel@tonic-gate {
795*7c478bd9Sstevel@tonic-gate 	switch (drive_type) {
796*7c478bd9Sstevel@tonic-gate 	case DK_UNKNOWN:
797*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
798*7c478bd9Sstevel@tonic-gate 	case DK_MO_ERASABLE:
799*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_ERASABLE);
800*7c478bd9Sstevel@tonic-gate 	case DK_MO_WRITEONCE:
801*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_WRITEONCE);
802*7c478bd9Sstevel@tonic-gate 	case DK_AS_MO:
803*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_AS_MO);
804*7c478bd9Sstevel@tonic-gate 	case DK_CDROM:
805*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDROM);
806*7c478bd9Sstevel@tonic-gate 	case DK_CDR:
807*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDR);
808*7c478bd9Sstevel@tonic-gate 	case DK_CDRW:
809*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDRW);
810*7c478bd9Sstevel@tonic-gate 	case DK_DVDROM:
811*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDROM);
812*7c478bd9Sstevel@tonic-gate 	case DK_DVDR:
813*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDR);
814*7c478bd9Sstevel@tonic-gate 	case DK_DVDRAM:
815*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDRAM);
816*7c478bd9Sstevel@tonic-gate 	case DK_FIXED_DISK:
817*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_FIXED);
818*7c478bd9Sstevel@tonic-gate 	case DK_FLOPPY:
819*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_FLOPPY);
820*7c478bd9Sstevel@tonic-gate 	case DK_ZIP:
821*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_ZIP);
822*7c478bd9Sstevel@tonic-gate 	case DK_JAZ:
823*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_JAZ);
824*7c478bd9Sstevel@tonic-gate 	default:
825*7c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
826*7c478bd9Sstevel@tonic-gate 	}
827*7c478bd9Sstevel@tonic-gate }
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate static descriptor_t **
830*7c478bd9Sstevel@tonic-gate get_assoc_alias(disk_t *diskp, int *errp)
831*7c478bd9Sstevel@tonic-gate {
832*7c478bd9Sstevel@tonic-gate 	alias_t		*aliasp;
833*7c478bd9Sstevel@tonic-gate 	uint_t		cnt;
834*7c478bd9Sstevel@tonic-gate 	descriptor_t	**out_array;
835*7c478bd9Sstevel@tonic-gate 	int		pos;
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	*errp = 0;
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
840*7c478bd9Sstevel@tonic-gate 	cnt = 0;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
843*7c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
844*7c478bd9Sstevel@tonic-gate 		cnt++;
845*7c478bd9Sstevel@tonic-gate 	    }
846*7c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	/* set up the new array */
850*7c478bd9Sstevel@tonic-gate 	out_array = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t));
851*7c478bd9Sstevel@tonic-gate 	if (out_array == NULL) {
852*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
853*7c478bd9Sstevel@tonic-gate 	    return (NULL);
854*7c478bd9Sstevel@tonic-gate 	}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
857*7c478bd9Sstevel@tonic-gate 	pos = 0;
858*7c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
859*7c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
860*7c478bd9Sstevel@tonic-gate 		out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
861*7c478bd9Sstevel@tonic-gate 		    aliasp->alias, NULL, errp);
862*7c478bd9Sstevel@tonic-gate 		if (*errp != 0) {
863*7c478bd9Sstevel@tonic-gate 		    cache_free_descriptors(out_array);
864*7c478bd9Sstevel@tonic-gate 		    return (NULL);
865*7c478bd9Sstevel@tonic-gate 		}
866*7c478bd9Sstevel@tonic-gate 	    }
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
869*7c478bd9Sstevel@tonic-gate 	}
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	out_array[pos] = NULL;
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	return (out_array);
874*7c478bd9Sstevel@tonic-gate }
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate static descriptor_t **
877*7c478bd9Sstevel@tonic-gate get_assoc_controllers(descriptor_t *dp, int *errp)
878*7c478bd9Sstevel@tonic-gate {
879*7c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
880*7c478bd9Sstevel@tonic-gate 	int		cnt;
881*7c478bd9Sstevel@tonic-gate 	descriptor_t	**controllers;
882*7c478bd9Sstevel@tonic-gate 	int		i;
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
887*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; diskp->controllers[cnt]; cnt++);
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	/* make the snapshot */
890*7c478bd9Sstevel@tonic-gate 	controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
891*7c478bd9Sstevel@tonic-gate 	if (controllers == NULL) {
892*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
893*7c478bd9Sstevel@tonic-gate 	    return (NULL);
894*7c478bd9Sstevel@tonic-gate 	}
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	for (i = 0; diskp->controllers[i]; i++) {
897*7c478bd9Sstevel@tonic-gate 	    controllers[i] = cache_get_desc(DM_CONTROLLER,
898*7c478bd9Sstevel@tonic-gate 		diskp->controllers[i], NULL, NULL, errp);
899*7c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
900*7c478bd9Sstevel@tonic-gate 		cache_free_descriptors(controllers);
901*7c478bd9Sstevel@tonic-gate 		return (NULL);
902*7c478bd9Sstevel@tonic-gate 	    }
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	controllers[i] = NULL;
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	*errp = 0;
908*7c478bd9Sstevel@tonic-gate 	return (controllers);
909*7c478bd9Sstevel@tonic-gate }
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate static descriptor_t **
912*7c478bd9Sstevel@tonic-gate get_assoc_paths(descriptor_t *dp, int *errp)
913*7c478bd9Sstevel@tonic-gate {
914*7c478bd9Sstevel@tonic-gate 	path_t		**pp;
915*7c478bd9Sstevel@tonic-gate 	int		cnt;
916*7c478bd9Sstevel@tonic-gate 	descriptor_t	**paths;
917*7c478bd9Sstevel@tonic-gate 	int		i;
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	pp = dp->p.disk->paths;
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
922*7c478bd9Sstevel@tonic-gate 	cnt = 0;
923*7c478bd9Sstevel@tonic-gate 	if (pp != NULL) {
924*7c478bd9Sstevel@tonic-gate 	    for (; pp[cnt]; cnt++);
925*7c478bd9Sstevel@tonic-gate 	}
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 	/* make the snapshot */
928*7c478bd9Sstevel@tonic-gate 	paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
929*7c478bd9Sstevel@tonic-gate 	if (paths == NULL) {
930*7c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
931*7c478bd9Sstevel@tonic-gate 	    return (NULL);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	/*
935*7c478bd9Sstevel@tonic-gate 	 * We fill in the name field of the descriptor with the device_id
936*7c478bd9Sstevel@tonic-gate 	 * when we deal with path descriptors originating from a drive.
937*7c478bd9Sstevel@tonic-gate 	 * In that way we can use the device id within the path code to
938*7c478bd9Sstevel@tonic-gate 	 * lookup the path state for this drive.
939*7c478bd9Sstevel@tonic-gate 	 */
940*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
941*7c478bd9Sstevel@tonic-gate 	    paths[i] = cache_get_desc(DM_PATH, pp[i], dp->p.disk->device_id,
942*7c478bd9Sstevel@tonic-gate 		NULL, errp);
943*7c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
944*7c478bd9Sstevel@tonic-gate 		cache_free_descriptors(paths);
945*7c478bd9Sstevel@tonic-gate 		return (NULL);
946*7c478bd9Sstevel@tonic-gate 	    }
947*7c478bd9Sstevel@tonic-gate 	}
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	paths[i] = NULL;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	*errp = 0;
952*7c478bd9Sstevel@tonic-gate 	return (paths);
953*7c478bd9Sstevel@tonic-gate }
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate static int
956*7c478bd9Sstevel@tonic-gate get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs)
957*7c478bd9Sstevel@tonic-gate {
958*7c478bd9Sstevel@tonic-gate 	if (diskp->removable) {
959*7c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
962*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
963*7c478bd9Sstevel@tonic-gate 	    }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	    /* Make sure media is inserted and spun up. */
966*7c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
967*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
968*7c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
969*7c478bd9Sstevel@tonic-gate 		}
970*7c478bd9Sstevel@tonic-gate 	    }
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	    /* can't tell diff between dead & no media on removable drives */
973*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
974*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
975*7c478bd9Sstevel@tonic-gate 	    }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	} else {
980*7c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	    /* check if the fixed drive is up or not */
983*7c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
984*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
985*7c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
986*7c478bd9Sstevel@tonic-gate 		}
987*7c478bd9Sstevel@tonic-gate 	    } else {
988*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
989*7c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
990*7c478bd9Sstevel@tonic-gate 		}
991*7c478bd9Sstevel@tonic-gate 	    }
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
997*7c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	if (diskp->product_id != NULL) {
1001*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
1002*7c478bd9Sstevel@tonic-gate 		!= 0) {
1003*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1004*7c478bd9Sstevel@tonic-gate 	    }
1005*7c478bd9Sstevel@tonic-gate 	}
1006*7c478bd9Sstevel@tonic-gate 	if (diskp->vendor_id != NULL) {
1007*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
1008*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1009*7c478bd9Sstevel@tonic-gate 	    }
1010*7c478bd9Sstevel@tonic-gate 	}
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	if (diskp->sync_speed != -1) {
1013*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
1014*7c478bd9Sstevel@tonic-gate 		!= 0) {
1015*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1016*7c478bd9Sstevel@tonic-gate 	    }
1017*7c478bd9Sstevel@tonic-gate 	}
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 	if (diskp->wide == 1) {
1020*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
1021*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1022*7c478bd9Sstevel@tonic-gate 	    }
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	if (diskp->rpm == 0) {
1026*7c478bd9Sstevel@tonic-gate 	    diskp->rpm = get_rpm(diskp, fd);
1027*7c478bd9Sstevel@tonic-gate 	}
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if (diskp->rpm > 0) {
1030*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) {
1031*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1032*7c478bd9Sstevel@tonic-gate 	    }
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->cluster) {
1036*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_CLUSTERED) != 0) {
1037*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1038*7c478bd9Sstevel@tonic-gate 	    }
1039*7c478bd9Sstevel@tonic-gate 	}
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	if (strlen(opath) > 0) {
1042*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
1043*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1044*7c478bd9Sstevel@tonic-gate 	    }
1045*7c478bd9Sstevel@tonic-gate 	}
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	return (0);
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate static int
1051*7c478bd9Sstevel@tonic-gate get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
1052*7c478bd9Sstevel@tonic-gate 	nvlist_t *stats)
1053*7c478bd9Sstevel@tonic-gate {
1054*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
1055*7c478bd9Sstevel@tonic-gate 	size_t		class_len;
1056*7c478bd9Sstevel@tonic-gate 	int		err = 0;
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	class_len = strlen(classname);
1059*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1060*7c478bd9Sstevel@tonic-gate 	    if (strncmp(ksp->ks_class, classname, class_len) == 0) {
1061*7c478bd9Sstevel@tonic-gate 		char	kstat_name[KSTAT_STRLEN];
1062*7c478bd9Sstevel@tonic-gate 		char	*dname = kstat_name;
1063*7c478bd9Sstevel@tonic-gate 		char	*ename = ksp->ks_name;
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 		/* names are format: "sd0,err" - copy chars up to comma */
1066*7c478bd9Sstevel@tonic-gate 		while (*ename && *ename != ',') {
1067*7c478bd9Sstevel@tonic-gate 		    *dname++ = *ename++;
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 		*dname = NULL;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 		if (libdiskmgt_str_eq(diskname, kstat_name)) {
1072*7c478bd9Sstevel@tonic-gate 		    (void) kstat_read(kc, ksp, NULL);
1073*7c478bd9Sstevel@tonic-gate 		    err = get_kstat_vals(ksp, stats);
1074*7c478bd9Sstevel@tonic-gate 		    break;
1075*7c478bd9Sstevel@tonic-gate 		}
1076*7c478bd9Sstevel@tonic-gate 	    }
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	return (err);
1080*7c478bd9Sstevel@tonic-gate }
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate /*
1083*7c478bd9Sstevel@tonic-gate  * Getting the drive type depends on if the dev tree walk indicated that the
1084*7c478bd9Sstevel@tonic-gate  * drive was a CD-ROM or not.  The kernal lumps all of the removable multi-media
1085*7c478bd9Sstevel@tonic-gate  * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
1086*7c478bd9Sstevel@tonic-gate  * a uscsi cmd to check the drive type.
1087*7c478bd9Sstevel@tonic-gate  */
1088*7c478bd9Sstevel@tonic-gate static void
1089*7c478bd9Sstevel@tonic-gate get_drive_type(disk_t *dp, int fd)
1090*7c478bd9Sstevel@tonic-gate {
1091*7c478bd9Sstevel@tonic-gate 	if (dp->drv_type == DM_DT_UNKNOWN) {
1092*7c478bd9Sstevel@tonic-gate 	    int	opened_here = 0;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	    /* We may have already opened the device. */
1095*7c478bd9Sstevel@tonic-gate 	    if (fd < 0) {
1096*7c478bd9Sstevel@tonic-gate 		fd = drive_open_disk(dp, NULL, 0);
1097*7c478bd9Sstevel@tonic-gate 		opened_here = 1;
1098*7c478bd9Sstevel@tonic-gate 	    }
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	    if (fd >= 0) {
1101*7c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
1102*7c478bd9Sstevel@tonic-gate 		    /* use uscsi to determine drive type */
1103*7c478bd9Sstevel@tonic-gate 		    dp->drv_type = get_cdrom_drvtype(fd);
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 		    /* if uscsi fails, just call it a cd-rom */
1106*7c478bd9Sstevel@tonic-gate 		    if (dp->drv_type == DM_DT_UNKNOWN) {
1107*7c478bd9Sstevel@tonic-gate 			dp->drv_type = DM_DT_CDROM;
1108*7c478bd9Sstevel@tonic-gate 		    }
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate 		} else {
1111*7c478bd9Sstevel@tonic-gate 		    struct dk_minfo	minfo;
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 		    if (media_read_info(fd, &minfo)) {
1114*7c478bd9Sstevel@tonic-gate 			dp->drv_type = conv_drive_type(minfo.dki_media_type);
1115*7c478bd9Sstevel@tonic-gate 		    }
1116*7c478bd9Sstevel@tonic-gate 		}
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 		if (opened_here) {
1119*7c478bd9Sstevel@tonic-gate 		    (void) close(fd);
1120*7c478bd9Sstevel@tonic-gate 		}
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	    } else {
1123*7c478bd9Sstevel@tonic-gate 		/* couldn't open */
1124*7c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
1125*7c478bd9Sstevel@tonic-gate 		    dp->drv_type = DM_DT_CDROM;
1126*7c478bd9Sstevel@tonic-gate 		}
1127*7c478bd9Sstevel@tonic-gate 	    }
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate }
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate static char *
1132*7c478bd9Sstevel@tonic-gate get_err_attr_name(char *kstat_name)
1133*7c478bd9Sstevel@tonic-gate {
1134*7c478bd9Sstevel@tonic-gate 	int	i;
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate 	for (i = 0; kstat_err_names[i] != NULL; i++) {
1137*7c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(kstat_name, kstat_err_names[i])) {
1138*7c478bd9Sstevel@tonic-gate 		return (err_attr_names[i]);
1139*7c478bd9Sstevel@tonic-gate 	    }
1140*7c478bd9Sstevel@tonic-gate 	}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	return (NULL);
1143*7c478bd9Sstevel@tonic-gate }
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate static int
1146*7c478bd9Sstevel@tonic-gate get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1147*7c478bd9Sstevel@tonic-gate {
1148*7c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
1149*7c478bd9Sstevel@tonic-gate }
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate static int
1152*7c478bd9Sstevel@tonic-gate get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1153*7c478bd9Sstevel@tonic-gate {
1154*7c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
1155*7c478bd9Sstevel@tonic-gate }
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate static int
1158*7c478bd9Sstevel@tonic-gate get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
1159*7c478bd9Sstevel@tonic-gate {
1160*7c478bd9Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_IO) {
1161*7c478bd9Sstevel@tonic-gate 	    kstat_io_t *kiop;
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 	    kiop = KSTAT_IO_PTR(ksp);
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	    /* see sys/kstat.h kstat_io_t struct for more fields */
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) {
1168*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1169*7c478bd9Sstevel@tonic-gate 	    }
1170*7c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
1171*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1172*7c478bd9Sstevel@tonic-gate 	    }
1173*7c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
1174*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1175*7c478bd9Sstevel@tonic-gate 	    }
1176*7c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
1177*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1178*7c478bd9Sstevel@tonic-gate 	    }
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	} else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
1181*7c478bd9Sstevel@tonic-gate 	    kstat_named_t *knp;
1182*7c478bd9Sstevel@tonic-gate 	    int		i;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	    knp = KSTAT_NAMED_PTR(ksp);
1185*7c478bd9Sstevel@tonic-gate 	    for (i = 0; i < ksp->ks_ndata; i++) {
1186*7c478bd9Sstevel@tonic-gate 		char	*attr_name;
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 		if (knp[i].name[0] == 0)
1189*7c478bd9Sstevel@tonic-gate 		    continue;
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 		if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
1192*7c478bd9Sstevel@tonic-gate 		    continue;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 		}
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 		switch (knp[i].data_type) {
1197*7c478bd9Sstevel@tonic-gate 		case KSTAT_DATA_UINT32:
1198*7c478bd9Sstevel@tonic-gate 		    if (update_stat32(stats, attr_name, knp[i].value.ui32)
1199*7c478bd9Sstevel@tonic-gate 			!= 0) {
1200*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1201*7c478bd9Sstevel@tonic-gate 		    }
1202*7c478bd9Sstevel@tonic-gate 		    break;
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 		default:
1205*7c478bd9Sstevel@tonic-gate 		    /* Right now all of the error types are uint32 */
1206*7c478bd9Sstevel@tonic-gate 		    break;
1207*7c478bd9Sstevel@tonic-gate 		}
1208*7c478bd9Sstevel@tonic-gate 	    }
1209*7c478bd9Sstevel@tonic-gate 	}
1210*7c478bd9Sstevel@tonic-gate 	return (0);
1211*7c478bd9Sstevel@tonic-gate }
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate static int
1214*7c478bd9Sstevel@tonic-gate update_stat32(nvlist_t *stats, char *attr, uint32_t value)
1215*7c478bd9Sstevel@tonic-gate {
1216*7c478bd9Sstevel@tonic-gate 	int32_t	currval;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
1219*7c478bd9Sstevel@tonic-gate 	    value += currval;
1220*7c478bd9Sstevel@tonic-gate 	}
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint32(stats, attr, value));
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate /*
1226*7c478bd9Sstevel@tonic-gate  * There can be more than one kstat value when we have multi-path drives
1227*7c478bd9Sstevel@tonic-gate  * that are not under mpxio (since there is more than one kstat name for
1228*7c478bd9Sstevel@tonic-gate  * the drive in this case).  So, we may have merge all of the kstat values
1229*7c478bd9Sstevel@tonic-gate  * to give an accurate set of stats for the drive.
1230*7c478bd9Sstevel@tonic-gate  */
1231*7c478bd9Sstevel@tonic-gate static int
1232*7c478bd9Sstevel@tonic-gate update_stat64(nvlist_t *stats, char *attr, uint64_t value)
1233*7c478bd9Sstevel@tonic-gate {
1234*7c478bd9Sstevel@tonic-gate 	int64_t	currval;
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
1237*7c478bd9Sstevel@tonic-gate 	    value += currval;
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint64(stats, attr, value));
1240*7c478bd9Sstevel@tonic-gate }
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate /*
1243*7c478bd9Sstevel@tonic-gate  * uscsi function to get the rpm of the drive
1244*7c478bd9Sstevel@tonic-gate  */
1245*7c478bd9Sstevel@tonic-gate static int
1246*7c478bd9Sstevel@tonic-gate get_rpm(disk_t *dp, int fd)
1247*7c478bd9Sstevel@tonic-gate {
1248*7c478bd9Sstevel@tonic-gate 	int	opened_here = 0;
1249*7c478bd9Sstevel@tonic-gate 	int	rpm = -1;
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	/* We may have already opened the device. */
1252*7c478bd9Sstevel@tonic-gate 	if (fd < 0) {
1253*7c478bd9Sstevel@tonic-gate 	    fd = drive_open_disk(dp, NULL, 0);
1254*7c478bd9Sstevel@tonic-gate 	    opened_here = 1;
1255*7c478bd9Sstevel@tonic-gate 	}
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
1258*7c478bd9Sstevel@tonic-gate 	    int				status;
1259*7c478bd9Sstevel@tonic-gate 	    struct mode_geometry	*page4;
1260*7c478bd9Sstevel@tonic-gate 	    struct scsi_ms_header	header;
1261*7c478bd9Sstevel@tonic-gate 	    union {
1262*7c478bd9Sstevel@tonic-gate 		struct mode_geometry	page4;
1263*7c478bd9Sstevel@tonic-gate 		char			rawbuf[MAX_MODE_SENSE_SIZE];
1264*7c478bd9Sstevel@tonic-gate 	    } u_page4;
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	    page4 = &u_page4.page4;
1267*7c478bd9Sstevel@tonic-gate 	    (void) memset(&u_page4, 0, sizeof (u_page4));
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	    status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1270*7c478bd9Sstevel@tonic-gate 		MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1271*7c478bd9Sstevel@tonic-gate 		&header);
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	    if (status) {
1274*7c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1275*7c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1276*7c478bd9Sstevel@tonic-gate 		    &header);
1277*7c478bd9Sstevel@tonic-gate 	    }
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	    if (status) {
1280*7c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1281*7c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1282*7c478bd9Sstevel@tonic-gate 		    &header);
1283*7c478bd9Sstevel@tonic-gate 	    }
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	    if (!status) {
1286*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
1287*7c478bd9Sstevel@tonic-gate 		page4->rpm = ntohs(page4->rpm);
1288*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 		rpm = page4->rpm;
1291*7c478bd9Sstevel@tonic-gate 	    }
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	    if (opened_here) {
1294*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1295*7c478bd9Sstevel@tonic-gate 	    }
1296*7c478bd9Sstevel@tonic-gate 	}
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	return (rpm);
1299*7c478bd9Sstevel@tonic-gate }
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate /*
1302*7c478bd9Sstevel@tonic-gate  *	******** the rest of this is uscsi stuff for the drv type ********
1303*7c478bd9Sstevel@tonic-gate  */
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate /*
1306*7c478bd9Sstevel@tonic-gate  * We try a get_configuration uscsi cmd.  If that fails, try a
1307*7c478bd9Sstevel@tonic-gate  * atapi_capabilities cmd.  If both fail then this is an older CD-ROM.
1308*7c478bd9Sstevel@tonic-gate  */
1309*7c478bd9Sstevel@tonic-gate static int
1310*7c478bd9Sstevel@tonic-gate get_cdrom_drvtype(int fd)
1311*7c478bd9Sstevel@tonic-gate {
1312*7c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
1313*7c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
1314*7c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	fill_general_page_cdb_g1(&cdb, SCMD_GET_CONFIGURATION, 0,
1317*7c478bd9Sstevel@tonic-gate 	    b0(sizeof (buff)), b1(sizeof (buff)));
1318*7c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1321*7c478bd9Sstevel@tonic-gate 	    struct get_configuration	*config;
1322*7c478bd9Sstevel@tonic-gate 	    struct conf_feature		*feature;
1323*7c478bd9Sstevel@tonic-gate 	    int				flen;
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	    /* The first profile is the preferred one for the drive. */
1326*7c478bd9Sstevel@tonic-gate 	    config = (struct get_configuration *)buff;
1327*7c478bd9Sstevel@tonic-gate 	    feature = &config->feature;
1328*7c478bd9Sstevel@tonic-gate 	    flen = feature->len / sizeof (struct profile_list);
1329*7c478bd9Sstevel@tonic-gate 	    if (flen > 0) {
1330*7c478bd9Sstevel@tonic-gate 		int prof_num;
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 		prof_num = (int)convnum(feature->features.plist[0].profile, 2);
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		if (dm_debug > 1) {
1335*7c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
1336*7c478bd9Sstevel@tonic-gate 			prof_num);
1337*7c478bd9Sstevel@tonic-gate 		}
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 		switch (prof_num) {
1340*7c478bd9Sstevel@tonic-gate 		case PROF_MAGNETO_OPTICAL:
1341*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_ERASABLE);
1342*7c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_WO:
1343*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_WRITEONCE);
1344*7c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_ASMO:
1345*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_AS_MO);
1346*7c478bd9Sstevel@tonic-gate 		case PROF_CDROM:
1347*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDROM);
1348*7c478bd9Sstevel@tonic-gate 		case PROF_CDR:
1349*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDR);
1350*7c478bd9Sstevel@tonic-gate 		case PROF_CDRW:
1351*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDRW);
1352*7c478bd9Sstevel@tonic-gate 		case PROF_DVDROM:
1353*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDROM);
1354*7c478bd9Sstevel@tonic-gate 		case PROF_DVDRAM:
1355*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRAM);
1356*7c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_REST:
1357*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
1358*7c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_SEQ:
1359*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
1360*7c478bd9Sstevel@tonic-gate 		case PROF_DVDRW:
1361*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
1362*7c478bd9Sstevel@tonic-gate 		case PROF_DDCD_ROM:
1363*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDROM);
1364*7c478bd9Sstevel@tonic-gate 		case PROF_DDCD_R:
1365*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDR);
1366*7c478bd9Sstevel@tonic-gate 		case PROF_DDCD_RW:
1367*7c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDRW);
1368*7c478bd9Sstevel@tonic-gate 		}
1369*7c478bd9Sstevel@tonic-gate 	    }
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	/* see if the atapi capabilities give anything */
1373*7c478bd9Sstevel@tonic-gate 	return (check_atapi(fd));
1374*7c478bd9Sstevel@tonic-gate }
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate static int
1377*7c478bd9Sstevel@tonic-gate check_atapi(int fd)
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
1380*7c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
1381*7c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
1382*7c478bd9Sstevel@tonic-gate 
1383*7c478bd9Sstevel@tonic-gate 	fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES);
1384*7c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
1385*7c478bd9Sstevel@tonic-gate 
1386*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1387*7c478bd9Sstevel@tonic-gate 	    int			bdesclen;
1388*7c478bd9Sstevel@tonic-gate 	    struct capabilities	*cap;
1389*7c478bd9Sstevel@tonic-gate 	    struct mode_header_g2 *mode;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	    mode = (struct mode_header_g2 *)buff;
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 	    bdesclen = (int)convnum(mode->desclen, 2);
1394*7c478bd9Sstevel@tonic-gate 	    cap = (struct capabilities *)
1395*7c478bd9Sstevel@tonic-gate 		&buff[sizeof (struct mode_header_g2) + bdesclen];
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 	    if (dm_debug > 1) {
1398*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "INFO: uscsi atapi capabilities\n");
1399*7c478bd9Sstevel@tonic-gate 	    }
1400*7c478bd9Sstevel@tonic-gate 
1401*7c478bd9Sstevel@tonic-gate 	    /* These are in order of how we want to report the drv type. */
1402*7c478bd9Sstevel@tonic-gate 	    if (cap->dvdram_write) {
1403*7c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDRAM);
1404*7c478bd9Sstevel@tonic-gate 	    }
1405*7c478bd9Sstevel@tonic-gate 	    if (cap->dvdr_write) {
1406*7c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDR);
1407*7c478bd9Sstevel@tonic-gate 	    }
1408*7c478bd9Sstevel@tonic-gate 	    if (cap->dvdrom_read) {
1409*7c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDROM);
1410*7c478bd9Sstevel@tonic-gate 	    }
1411*7c478bd9Sstevel@tonic-gate 	    if (cap->cdrw_write) {
1412*7c478bd9Sstevel@tonic-gate 		return (DM_DT_CDRW);
1413*7c478bd9Sstevel@tonic-gate 	    }
1414*7c478bd9Sstevel@tonic-gate 	    if (cap->cdr_write) {
1415*7c478bd9Sstevel@tonic-gate 		return (DM_DT_CDR);
1416*7c478bd9Sstevel@tonic-gate 	    }
1417*7c478bd9Sstevel@tonic-gate 	    if (cap->cdr_read) {
1418*7c478bd9Sstevel@tonic-gate 		return (DM_DT_CDROM);
1419*7c478bd9Sstevel@tonic-gate 	    }
1420*7c478bd9Sstevel@tonic-gate 	}
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	/* everything failed, so this is an older CD-ROM */
1423*7c478bd9Sstevel@tonic-gate 	if (dm_debug > 1) {
1424*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "INFO: uscsi failed\n");
1425*7c478bd9Sstevel@tonic-gate 	}
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	return (DM_DT_CDROM);
1428*7c478bd9Sstevel@tonic-gate }
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate static uint64_t
1431*7c478bd9Sstevel@tonic-gate convnum(uchar_t *nptr, int len)
1432*7c478bd9Sstevel@tonic-gate {
1433*7c478bd9Sstevel@tonic-gate 	uint64_t value;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	for (value = 0; len > 0; len--, nptr++)
1436*7c478bd9Sstevel@tonic-gate 		value = (value << 8) | *nptr;
1437*7c478bd9Sstevel@tonic-gate 	return (value);
1438*7c478bd9Sstevel@tonic-gate }
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate static void
1441*7c478bd9Sstevel@tonic-gate fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb,
1442*7c478bd9Sstevel@tonic-gate 	caddr_t buff, int blen)
1443*7c478bd9Sstevel@tonic-gate {
1444*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cmd, sizeof (struct uscsi_cmd));
1445*7c478bd9Sstevel@tonic-gate 	bzero(buff, blen);
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdb = (caddr_t)cdb;
1448*7c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdblen = CDB_GROUP1;
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 	cmd->uscsi_bufaddr = buff;
1451*7c478bd9Sstevel@tonic-gate 	cmd->uscsi_buflen = blen;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ;
1454*7c478bd9Sstevel@tonic-gate }
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate static void
1457*7c478bd9Sstevel@tonic-gate fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun,
1458*7c478bd9Sstevel@tonic-gate 	uchar_t c0, uchar_t c1)
1459*7c478bd9Sstevel@tonic-gate {
1460*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
1461*7c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = command;
1462*7c478bd9Sstevel@tonic-gate 	cdb->scc_lun = lun;
1463*7c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = c0; /* max length for page */
1464*7c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = c1; /* max length for page */
1465*7c478bd9Sstevel@tonic-gate }
1466*7c478bd9Sstevel@tonic-gate 
1467*7c478bd9Sstevel@tonic-gate static void
1468*7c478bd9Sstevel@tonic-gate fill_mode_page_cdb(union scsi_cdb *cdb, int page)
1469*7c478bd9Sstevel@tonic-gate {
1470*7c478bd9Sstevel@tonic-gate 	/* group 1 mode page */
1471*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
1472*7c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = SCMD_MODE_SENSE_G1;
1473*7c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = 0xff; /* max length for mode page */
1474*7c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = 0xff; /* max length for mode page */
1475*7c478bd9Sstevel@tonic-gate 	cdb->g1_addr3 = page;
1476*7c478bd9Sstevel@tonic-gate }
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate static int
1479*7c478bd9Sstevel@tonic-gate uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
1480*7c478bd9Sstevel@tonic-gate 	int page_size, struct  scsi_ms_header *header)
1481*7c478bd9Sstevel@tonic-gate {
1482*7c478bd9Sstevel@tonic-gate 	caddr_t			mode_sense_buf;
1483*7c478bd9Sstevel@tonic-gate 	struct mode_header	*hdr;
1484*7c478bd9Sstevel@tonic-gate 	struct mode_page	*pg;
1485*7c478bd9Sstevel@tonic-gate 	int			nbytes;
1486*7c478bd9Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
1487*7c478bd9Sstevel@tonic-gate 	union scsi_cdb		cdb;
1488*7c478bd9Sstevel@tonic-gate 	int			status;
1489*7c478bd9Sstevel@tonic-gate 	int			maximum;
1490*7c478bd9Sstevel@tonic-gate 	char			rqbuf[255];
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	/*
1493*7c478bd9Sstevel@tonic-gate 	 * Allocate a buffer for the mode sense headers
1494*7c478bd9Sstevel@tonic-gate 	 * and mode sense data itself.
1495*7c478bd9Sstevel@tonic-gate 	 */
1496*7c478bd9Sstevel@tonic-gate 	nbytes = sizeof (struct block_descriptor) +
1497*7c478bd9Sstevel@tonic-gate 				sizeof (struct mode_header) + page_size;
1498*7c478bd9Sstevel@tonic-gate 	nbytes = page_size;
1499*7c478bd9Sstevel@tonic-gate 	if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
1500*7c478bd9Sstevel@tonic-gate 	    return (-1);
1501*7c478bd9Sstevel@tonic-gate 	}
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	/*
1504*7c478bd9Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl
1505*7c478bd9Sstevel@tonic-gate 	 */
1506*7c478bd9Sstevel@tonic-gate 	(void) memset(mode_sense_buf, 0, nbytes);
1507*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
1508*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
1511*7c478bd9Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
1512*7c478bd9Sstevel@tonic-gate 	cdb.cdb_opaque[2] = page_control | page_code;
1513*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
1514*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
1515*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = mode_sense_buf;
1516*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_SILENT;
1519*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_READ;
1520*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_timeout = 30;
1521*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_RQENABLE;
1522*7c478bd9Sstevel@tonic-gate 	if (ucmd.uscsi_rqbuf == NULL)  {
1523*7c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqbuf = rqbuf;
1524*7c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqlen = sizeof (rqbuf);
1525*7c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqresid = sizeof (rqbuf);
1526*7c478bd9Sstevel@tonic-gate 	}
1527*7c478bd9Sstevel@tonic-gate 	ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate 	status = ioctl(fd, USCSICMD, &ucmd);
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	if (status || ucmd.uscsi_status != 0) {
1532*7c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
1533*7c478bd9Sstevel@tonic-gate 	    return (-1);
1534*7c478bd9Sstevel@tonic-gate 	}
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate 	/*
1537*7c478bd9Sstevel@tonic-gate 	 * Verify that the returned data looks reasonabled,
1538*7c478bd9Sstevel@tonic-gate 	 * find the actual page data, and copy it into the
1539*7c478bd9Sstevel@tonic-gate 	 * user's buffer.  Copy the mode_header and block_descriptor
1540*7c478bd9Sstevel@tonic-gate 	 * into the header structure, which can then be used to
1541*7c478bd9Sstevel@tonic-gate 	 * return the same data to the drive when issuing a mode select.
1542*7c478bd9Sstevel@tonic-gate 	 */
1543*7c478bd9Sstevel@tonic-gate 	hdr = (struct mode_header *)mode_sense_buf;
1544*7c478bd9Sstevel@tonic-gate 	(void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
1545*7c478bd9Sstevel@tonic-gate 	if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
1546*7c478bd9Sstevel@tonic-gate 	    hdr->bdesc_length != 0) {
1547*7c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
1548*7c478bd9Sstevel@tonic-gate 	    return (-1);
1549*7c478bd9Sstevel@tonic-gate 	}
1550*7c478bd9Sstevel@tonic-gate 	(void) memcpy((caddr_t)header, mode_sense_buf,
1551*7c478bd9Sstevel@tonic-gate 	    (int) (sizeof (struct mode_header) + hdr->bdesc_length));
1552*7c478bd9Sstevel@tonic-gate 	pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1553*7c478bd9Sstevel@tonic-gate 	    sizeof (struct mode_header) + hdr->bdesc_length);
1554*7c478bd9Sstevel@tonic-gate 	if (pg->code != page_code) {
1555*7c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
1556*7c478bd9Sstevel@tonic-gate 	    return (-1);
1557*7c478bd9Sstevel@tonic-gate 	}
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 	/*
1560*7c478bd9Sstevel@tonic-gate 	 * Accept up to "page_size" bytes of mode sense data.
1561*7c478bd9Sstevel@tonic-gate 	 * This allows us to accept both CCS and SCSI-2
1562*7c478bd9Sstevel@tonic-gate 	 * structures, as long as we request the greater
1563*7c478bd9Sstevel@tonic-gate 	 * of the two.
1564*7c478bd9Sstevel@tonic-gate 	 */
1565*7c478bd9Sstevel@tonic-gate 	maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
1566*7c478bd9Sstevel@tonic-gate 	if (((int)pg->length) > maximum) {
1567*7c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
1568*7c478bd9Sstevel@tonic-gate 	    return (-1);
1569*7c478bd9Sstevel@tonic-gate 	}
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 	(void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 	free(mode_sense_buf);
1574*7c478bd9Sstevel@tonic-gate 	return (0);
1575*7c478bd9Sstevel@tonic-gate }
1576