xref: /titanic_52/usr/src/lib/libdiskmgt/common/drive.c (revision 59d8f1005b65ef8ad2c9ce040497daf81dd65085)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
518c2aff7Sartem  * Common Development and Distribution License (the "License").
618c2aff7Sartem  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2218c2aff7Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <fcntl.h>
277c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <kstat.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <devid.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /* included for uscsi */
427c478bd9Sstevel@tonic-gate #include <strings.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h>
467c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
477c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/commands.h>
487c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/mode.h>
497c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
527c478bd9Sstevel@tonic-gate #include "disks_private.h"
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_DISK	"disk"
557c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_ERROR	"device_error"
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	SCSIBUFLEN		0xffff
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* byte get macros */
607c478bd9Sstevel@tonic-gate #define	b3(a)			(((a)>>24) & 0xFF)
617c478bd9Sstevel@tonic-gate #define	b2(a)			(((a)>>16) & 0xFF)
627c478bd9Sstevel@tonic-gate #define	b1(a)			(((a)>>8) & 0xFF)
637c478bd9Sstevel@tonic-gate #define	b0(a)			(((a)>>0) & 0xFF)
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static char *kstat_err_names[] = {
667c478bd9Sstevel@tonic-gate 	"Soft Errors",
677c478bd9Sstevel@tonic-gate 	"Hard Errors",
687c478bd9Sstevel@tonic-gate 	"Transport Errors",
697c478bd9Sstevel@tonic-gate 	"Media Error",
707c478bd9Sstevel@tonic-gate 	"Device Not Ready",
717c478bd9Sstevel@tonic-gate 	"No Device",
727c478bd9Sstevel@tonic-gate 	"Recoverable",
737c478bd9Sstevel@tonic-gate 	"Illegal Request",
747c478bd9Sstevel@tonic-gate 	"Predictive Failure Analysis",
757c478bd9Sstevel@tonic-gate 	NULL
767c478bd9Sstevel@tonic-gate };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static char *err_attr_names[] = {
797c478bd9Sstevel@tonic-gate 	DM_NSOFTERRS,
807c478bd9Sstevel@tonic-gate 	DM_NHARDERRS,
817c478bd9Sstevel@tonic-gate 	DM_NTRANSERRS,
827c478bd9Sstevel@tonic-gate 	DM_NMEDIAERRS,
837c478bd9Sstevel@tonic-gate 	DM_NDNRERRS,
847c478bd9Sstevel@tonic-gate 	DM_NNODEVERRS,
857c478bd9Sstevel@tonic-gate 	DM_NRECOVERRS,
867c478bd9Sstevel@tonic-gate 	DM_NILLREQERRS,
877c478bd9Sstevel@tonic-gate 	DM_FAILING,
887c478bd9Sstevel@tonic-gate 	NULL
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  *	**************** begin uscsi stuff ****************
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
967c478bd9Sstevel@tonic-gate #elif defined(_BIT_FIELDS_HTOL)
977c478bd9Sstevel@tonic-gate #else
987c478bd9Sstevel@tonic-gate #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
997c478bd9Sstevel@tonic-gate #endif
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate struct conf_feature {
1027c478bd9Sstevel@tonic-gate 	uchar_t feature[2]; /* common to all */
1037c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1047c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
1057c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
1067c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
1077c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
1087c478bd9Sstevel@tonic-gate #else
1097c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
1107c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
1117c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
1127c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
1137c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1147c478bd9Sstevel@tonic-gate 	uchar_t len;
1157c478bd9Sstevel@tonic-gate 	union features {
1167c478bd9Sstevel@tonic-gate 		struct generic {
1177c478bd9Sstevel@tonic-gate 			uchar_t data[1];
1187c478bd9Sstevel@tonic-gate 		} gen;
1197c478bd9Sstevel@tonic-gate 		uchar_t data[1];
1207c478bd9Sstevel@tonic-gate 		struct profile_list {
1217c478bd9Sstevel@tonic-gate 			uchar_t profile[2];
1227c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1237c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
1247c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
1257c478bd9Sstevel@tonic-gate #else
1267c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
1277c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
1287c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1297c478bd9Sstevel@tonic-gate 			uchar_t reserved2;
1307c478bd9Sstevel@tonic-gate 		} plist[1];
1317c478bd9Sstevel@tonic-gate 		struct core {
1327c478bd9Sstevel@tonic-gate 			uchar_t phys[4];
1337c478bd9Sstevel@tonic-gate 		} core;
1347c478bd9Sstevel@tonic-gate 		struct morphing {
1357c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1367c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
1377c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1387c478bd9Sstevel@tonic-gate #else
1397c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1407c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
1417c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1427c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
1437c478bd9Sstevel@tonic-gate 		} morphing;
1447c478bd9Sstevel@tonic-gate 		struct removable {
1457c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1467c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
1477c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
1487c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
1497c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
1507c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
1517c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
1527c478bd9Sstevel@tonic-gate #else
1537c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
1547c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
1557c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
1567c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
1577c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
1587c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
1597c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1607c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
1617c478bd9Sstevel@tonic-gate 		} removable;
1627c478bd9Sstevel@tonic-gate 		struct random_readable {
1637c478bd9Sstevel@tonic-gate 			uchar_t lbsize[4];
1647c478bd9Sstevel@tonic-gate 			uchar_t blocking[2];
1657c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1667c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
1677c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1687c478bd9Sstevel@tonic-gate #else
1697c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1707c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
1717c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1727c478bd9Sstevel@tonic-gate 			uchar_t reserved;
1737c478bd9Sstevel@tonic-gate 		} rread;
1747c478bd9Sstevel@tonic-gate 		struct cd_read {
1757c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1767c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
1777c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
1787c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
1797c478bd9Sstevel@tonic-gate #else
1807c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
1817c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
1827c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
1837c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1847c478bd9Sstevel@tonic-gate 		} cdread;
1857c478bd9Sstevel@tonic-gate 		struct cd_audio {
1867c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1877c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
1887c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
1897c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
1907c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
1917c478bd9Sstevel@tonic-gate #else
1927c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
1937c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
1947c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
1957c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
1967c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1977c478bd9Sstevel@tonic-gate 			uchar_t reserved;
1987c478bd9Sstevel@tonic-gate 			uchar_t numlevels[2];
1997c478bd9Sstevel@tonic-gate 		} audio;
2007c478bd9Sstevel@tonic-gate 		struct dvd_css {
2017c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
2027c478bd9Sstevel@tonic-gate 			uchar_t version;
2037c478bd9Sstevel@tonic-gate 		} dvdcss;
2047c478bd9Sstevel@tonic-gate 	} features;
2057c478bd9Sstevel@tonic-gate };
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #define	PROF_NON_REMOVABLE	0x0001
2087c478bd9Sstevel@tonic-gate #define	PROF_REMOVABLE		0x0002
2097c478bd9Sstevel@tonic-gate #define	PROF_MAGNETO_OPTICAL	0x0003
2107c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_WO		0x0004
2117c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_ASMO	0x0005
2127c478bd9Sstevel@tonic-gate #define	PROF_CDROM		0x0008
2137c478bd9Sstevel@tonic-gate #define	PROF_CDR		0x0009
2147c478bd9Sstevel@tonic-gate #define	PROF_CDRW		0x000a
2157c478bd9Sstevel@tonic-gate #define	PROF_DVDROM		0x0010
2167c478bd9Sstevel@tonic-gate #define	PROF_DVDR		0x0011
2177c478bd9Sstevel@tonic-gate #define	PROF_DVDRAM		0x0012
2187c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_REST		0x0013
2197c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_SEQ		0x0014
2207c478bd9Sstevel@tonic-gate #define	PROF_DVDRW		0x001a
2217c478bd9Sstevel@tonic-gate #define	PROF_DDCD_ROM		0x0020
2227c478bd9Sstevel@tonic-gate #define	PROF_DDCD_R		0x0021
2237c478bd9Sstevel@tonic-gate #define	PROF_DDCD_RW		0x0022
2247c478bd9Sstevel@tonic-gate #define	PROF_NON_CONFORMING	0xffff
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate struct get_configuration {
2277c478bd9Sstevel@tonic-gate 	uchar_t len[4];
2287c478bd9Sstevel@tonic-gate 	uchar_t reserved[2];
2297c478bd9Sstevel@tonic-gate 	uchar_t curprof[2];
2307c478bd9Sstevel@tonic-gate 	struct conf_feature feature;
2317c478bd9Sstevel@tonic-gate };
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate struct capabilities {
2347c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2357c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
2367c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
2377c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
2387c478bd9Sstevel@tonic-gate #else
2397c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
2407c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
2417c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
2427c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2437c478bd9Sstevel@tonic-gate 	uchar_t pagelen;
2447c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2457c478bd9Sstevel@tonic-gate 	/* read capabilities */
2467c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
2477c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
2487c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
2497c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
2507c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
2517c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
2527c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
2537c478bd9Sstevel@tonic-gate #else
2547c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
2557c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
2567c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
2577c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
2587c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
2597c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
2607c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
2617c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2627c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2637c478bd9Sstevel@tonic-gate 	/* write capabilities */
2647c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
2657c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
2667c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
2677c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
2687c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
2697c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
2707c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
2717c478bd9Sstevel@tonic-gate #else
2727c478bd9Sstevel@tonic-gate 	/* write capabilities */
2737c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
2747c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
2757c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
2767c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
2777c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
2787c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
2797c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
2807c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2817c478bd9Sstevel@tonic-gate 	uchar_t misc0;
2827c478bd9Sstevel@tonic-gate 	uchar_t misc1;
2837c478bd9Sstevel@tonic-gate 	uchar_t misc2;
2847c478bd9Sstevel@tonic-gate 	uchar_t misc3;
2857c478bd9Sstevel@tonic-gate 	uchar_t obsolete0[2];
2867c478bd9Sstevel@tonic-gate 	uchar_t numvlevels[2];
2877c478bd9Sstevel@tonic-gate 	uchar_t bufsize[2];
2887c478bd9Sstevel@tonic-gate 	uchar_t obsolete1[4];
2897c478bd9Sstevel@tonic-gate 	uchar_t resv5;
2907c478bd9Sstevel@tonic-gate 	uchar_t misc4;
2917c478bd9Sstevel@tonic-gate 	uchar_t obsolete2;
2927c478bd9Sstevel@tonic-gate 	uchar_t copymgt[2];
2937c478bd9Sstevel@tonic-gate 	/* there is more to this page, but nothing we care about */
2947c478bd9Sstevel@tonic-gate };
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate struct mode_header_g2 {
2977c478bd9Sstevel@tonic-gate 	uchar_t modelen[2];
2987c478bd9Sstevel@tonic-gate 	uchar_t obsolete;
2997c478bd9Sstevel@tonic-gate 	uchar_t reserved[3];
3007c478bd9Sstevel@tonic-gate 	uchar_t desclen[2];
3017c478bd9Sstevel@tonic-gate };
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * Mode sense/select page header information
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate struct scsi_ms_header {
3077c478bd9Sstevel@tonic-gate 	struct mode_header	mode_header;
3087c478bd9Sstevel@tonic-gate 	struct block_descriptor	block_descriptor;
3097c478bd9Sstevel@tonic-gate };
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate #define	MODESENSE_PAGE_LEN(p)	(((int)((struct mode_page *)p)->length) + \
3127c478bd9Sstevel@tonic-gate 				    sizeof (struct mode_page))
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_CURRENT	(0 << 6)
3157c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_DEFAULT	(2 << 6)
3167c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_SAVED	(3 << 6)
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate #define	MAX_MODE_SENSE_SIZE	255
3197c478bd9Sstevel@tonic-gate #define	IMPOSSIBLE_SCSI_STATUS	0xff
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  *	********** end of uscsi stuff ************
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate static descriptor_t	**apply_filter(descriptor_t **drives, int filter[],
3267c478bd9Sstevel@tonic-gate 			    int *errp);
3277c478bd9Sstevel@tonic-gate static int		check_atapi(int fd);
3287c478bd9Sstevel@tonic-gate static int		conv_drive_type(uint_t drive_type);
3297c478bd9Sstevel@tonic-gate static uint64_t		convnum(uchar_t *nptr, int len);
3307c478bd9Sstevel@tonic-gate static void		fill_command_g1(struct uscsi_cmd *cmd,
3317c478bd9Sstevel@tonic-gate 			    union scsi_cdb *cdb, caddr_t buff, int blen);
3327c478bd9Sstevel@tonic-gate static void		fill_general_page_cdb_g1(union scsi_cdb *cdb,
3337c478bd9Sstevel@tonic-gate 			    int command, int lun, uchar_t c0, uchar_t c1);
3347c478bd9Sstevel@tonic-gate static void		fill_mode_page_cdb(union scsi_cdb *cdb, int page);
3357c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_alias(disk_t *diskp, int *errp);
3367c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_controllers(descriptor_t *dp, int *errp);
3377c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_paths(descriptor_t *dp, int *errp);
3387c478bd9Sstevel@tonic-gate static int		get_attrs(disk_t *diskp, int fd, char *opath,
3397c478bd9Sstevel@tonic-gate 			    nvlist_t *nvp);
3407c478bd9Sstevel@tonic-gate static int		get_cdrom_drvtype(int fd);
3417c478bd9Sstevel@tonic-gate static int		get_disk_kstats(kstat_ctl_t *kc, char *diskname,
3427c478bd9Sstevel@tonic-gate 			    char *classname, nvlist_t *stats);
3437c478bd9Sstevel@tonic-gate static void		get_drive_type(disk_t *dp, int fd);
3447c478bd9Sstevel@tonic-gate static int		get_err_kstats(kstat_ctl_t *kc, char *diskname,
3457c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
3467c478bd9Sstevel@tonic-gate static int		get_io_kstats(kstat_ctl_t *kc, char *diskname,
3477c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
3487c478bd9Sstevel@tonic-gate static int		get_kstat_vals(kstat_t *ksp, nvlist_t *stats);
3497c478bd9Sstevel@tonic-gate static char		*get_err_attr_name(char *kstat_name);
3507c478bd9Sstevel@tonic-gate static int		get_rpm(disk_t *dp, int fd);
351*59d8f100SGarrett D'Amore static int		get_solidstate(disk_t *dp, int fd);
3527c478bd9Sstevel@tonic-gate static int		update_stat64(nvlist_t *stats, char *attr,
3537c478bd9Sstevel@tonic-gate 			    uint64_t value);
3547c478bd9Sstevel@tonic-gate static int		update_stat32(nvlist_t *stats, char *attr,
3557c478bd9Sstevel@tonic-gate 			    uint32_t value);
3567c478bd9Sstevel@tonic-gate static int		uscsi_mode_sense(int fd, int page_code,
3577c478bd9Sstevel@tonic-gate 			    int page_control, caddr_t page_data, int page_size,
3587c478bd9Sstevel@tonic-gate 			    struct  scsi_ms_header *header);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate descriptor_t **
3617c478bd9Sstevel@tonic-gate drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
3627c478bd9Sstevel@tonic-gate     int *errp)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	switch (type) {
3657c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
3667c478bd9Sstevel@tonic-gate 	    return (get_assoc_controllers(dp, errp));
3677c478bd9Sstevel@tonic-gate 	case DM_PATH:
3687c478bd9Sstevel@tonic-gate 	    return (get_assoc_paths(dp, errp));
3697c478bd9Sstevel@tonic-gate 	case DM_ALIAS:
3707c478bd9Sstevel@tonic-gate 	    return (get_assoc_alias(dp->p.disk, errp));
3717c478bd9Sstevel@tonic-gate 	case DM_MEDIA:
3727c478bd9Sstevel@tonic-gate 	    return (media_get_assocs(dp, errp));
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
3767c478bd9Sstevel@tonic-gate 	return (NULL);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate  * Get the drive descriptors for the given media/alias/devpath.
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate descriptor_t **
3837c478bd9Sstevel@tonic-gate drive_get_assocs(descriptor_t *desc, int *errp)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	/* at most one drive is associated with these descriptors */
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	drives = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
3907c478bd9Sstevel@tonic-gate 	if (drives == NULL) {
3917c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
3927c478bd9Sstevel@tonic-gate 	    return (NULL);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
3967c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
3977c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
3987c478bd9Sstevel@tonic-gate 	    return (NULL);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	drives[1] = NULL;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	return (drives);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate nvlist_t *
4077c478bd9Sstevel@tonic-gate drive_get_attributes(descriptor_t *dp, int *errp)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
4107c478bd9Sstevel@tonic-gate 	int		fd;
4117c478bd9Sstevel@tonic-gate 	char		opath[MAXPATHLEN];
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
4147c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
4157c478bd9Sstevel@tonic-gate 	    return (NULL);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	opath[0] = 0;
4197c478bd9Sstevel@tonic-gate 	fd = drive_open_disk(dp->p.disk, opath, sizeof (opath));
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if ((*errp = get_attrs(dp->p.disk, fd, opath, attrs)) != 0) {
4227c478bd9Sstevel@tonic-gate 	    nvlist_free(attrs);
4237c478bd9Sstevel@tonic-gate 	    attrs = NULL;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
4277c478bd9Sstevel@tonic-gate 	    (void) close(fd);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	return (attrs);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate  * Check if we have the drive in our list, based upon the device id.
4357c478bd9Sstevel@tonic-gate  * We got the device id from the dev tree walk.  This is encoded
4367c478bd9Sstevel@tonic-gate  * using devid_str_encode(3DEVID).   In order to check the device ids we need
4377c478bd9Sstevel@tonic-gate  * to use the devid_compare(3DEVID) function, so we need to decode the
4387c478bd9Sstevel@tonic-gate  * string representation of the device id.
4397c478bd9Sstevel@tonic-gate  */
4407c478bd9Sstevel@tonic-gate descriptor_t *
4417c478bd9Sstevel@tonic-gate drive_get_descriptor_by_name(char *name, int *errp)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid;
4447c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
4457c478bd9Sstevel@tonic-gate 	descriptor_t	*drive = NULL;
4467c478bd9Sstevel@tonic-gate 	int		i;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
4497c478bd9Sstevel@tonic-gate 	    *errp = EINVAL;
4507c478bd9Sstevel@tonic-gate 	    return (NULL);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
4547c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
4557c478bd9Sstevel@tonic-gate 	    devid_free(devid);
4567c478bd9Sstevel@tonic-gate 	    return (NULL);
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * We have to loop through all of them, freeing the ones we don't
4617c478bd9Sstevel@tonic-gate 	 * want.  Once drive is set, we don't need to compare any more.
4627c478bd9Sstevel@tonic-gate 	 */
4637c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
4647c478bd9Sstevel@tonic-gate 	    if (drive == NULL && drives[i]->p.disk->devid != NULL &&
4657c478bd9Sstevel@tonic-gate 		devid_compare(devid, drives[i]->p.disk->devid) == 0) {
4667c478bd9Sstevel@tonic-gate 		drive = drives[i];
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	    } else {
4697c478bd9Sstevel@tonic-gate 		/* clean up the unused descriptor */
4707c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
4717c478bd9Sstevel@tonic-gate 	    }
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	free(drives);
4747c478bd9Sstevel@tonic-gate 	devid_free(devid);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (drive == NULL) {
4777c478bd9Sstevel@tonic-gate 	    *errp = ENODEV;
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	return (drive);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate descriptor_t **
4847c478bd9Sstevel@tonic-gate drive_get_descriptors(int filter[], int *errp)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
4897c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
4907c478bd9Sstevel@tonic-gate 	    return (NULL);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (filter != NULL && filter[0] != DM_FILTER_END) {
4947c478bd9Sstevel@tonic-gate 	    descriptor_t	**found;
4957c478bd9Sstevel@tonic-gate 	    found = apply_filter(drives, filter, errp);
4967c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
4977c478bd9Sstevel@tonic-gate 		drives = NULL;
4987c478bd9Sstevel@tonic-gate 	    } else {
4997c478bd9Sstevel@tonic-gate 		drives = found;
5007c478bd9Sstevel@tonic-gate 	    }
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	return (drives);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate char *
5077c478bd9Sstevel@tonic-gate drive_get_name(descriptor_t *dp)
5087c478bd9Sstevel@tonic-gate {
5097c478bd9Sstevel@tonic-gate 	return (dp->p.disk->device_id);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate nvlist_t *
5137c478bd9Sstevel@tonic-gate drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
5167c478bd9Sstevel@tonic-gate 	nvlist_t	*stats;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
5217c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
5227c478bd9Sstevel@tonic-gate 	    return (NULL);
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_PERFORMANCE ||
5267c478bd9Sstevel@tonic-gate 	    stat_type == DM_DRV_STAT_DIAGNOSTIC) {
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	    alias_t	*ap;
5297c478bd9Sstevel@tonic-gate 	    kstat_ctl_t	*kc;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	    ap = diskp->aliases;
5327c478bd9Sstevel@tonic-gate 	    if (ap == NULL || ap->kstat_name == NULL) {
5337c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
5347c478bd9Sstevel@tonic-gate 		*errp = EACCES;
5357c478bd9Sstevel@tonic-gate 		return (NULL);
5367c478bd9Sstevel@tonic-gate 	    }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	    if ((kc = kstat_open()) == NULL) {
5397c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
5407c478bd9Sstevel@tonic-gate 		*errp = EACCES;
5417c478bd9Sstevel@tonic-gate 		return (NULL);
5427c478bd9Sstevel@tonic-gate 	    }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	    while (ap != NULL) {
5457c478bd9Sstevel@tonic-gate 		int	status;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		if (ap->kstat_name == NULL) {
5487c478bd9Sstevel@tonic-gate 		    continue;
5497c478bd9Sstevel@tonic-gate 		}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		if (stat_type == DM_DRV_STAT_PERFORMANCE) {
5527c478bd9Sstevel@tonic-gate 		    status = get_io_kstats(kc, ap->kstat_name, stats);
5537c478bd9Sstevel@tonic-gate 		} else {
5547c478bd9Sstevel@tonic-gate 		    status = get_err_kstats(kc, ap->kstat_name, stats);
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 		if (status != 0) {
5587c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
5597c478bd9Sstevel@tonic-gate 		    (void) kstat_close(kc);
5607c478bd9Sstevel@tonic-gate 		    *errp = ENOMEM;
5617c478bd9Sstevel@tonic-gate 		    return (NULL);
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		ap = ap->next;
5657c478bd9Sstevel@tonic-gate 	    }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	    (void) kstat_close(kc);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	    *errp = 0;
5707c478bd9Sstevel@tonic-gate 	    return (stats);
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_TEMPERATURE) {
5747c478bd9Sstevel@tonic-gate 	    int		fd;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	    if ((fd = drive_open_disk(diskp, NULL, 0)) >= 0) {
5777c478bd9Sstevel@tonic-gate 		struct dk_temperature	temp;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGTEMPERATURE, &temp) >= 0) {
5807c478bd9Sstevel@tonic-gate 		    if (nvlist_add_uint32(stats, DM_TEMPERATURE,
5817c478bd9Sstevel@tonic-gate 			temp.dkt_cur_temp) != 0) {
5827c478bd9Sstevel@tonic-gate 			*errp = ENOMEM;
5837c478bd9Sstevel@tonic-gate 			nvlist_free(stats);
5847c478bd9Sstevel@tonic-gate 			return (NULL);
5857c478bd9Sstevel@tonic-gate 		    }
5867c478bd9Sstevel@tonic-gate 		} else {
5877c478bd9Sstevel@tonic-gate 		    *errp = errno;
5887c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
5897c478bd9Sstevel@tonic-gate 		    return (NULL);
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 		(void) close(fd);
5927c478bd9Sstevel@tonic-gate 	    } else {
5937c478bd9Sstevel@tonic-gate 		*errp = errno;
5947c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
5957c478bd9Sstevel@tonic-gate 		return (NULL);
5967c478bd9Sstevel@tonic-gate 	    }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	    *errp = 0;
5997c478bd9Sstevel@tonic-gate 	    return (stats);
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	nvlist_free(stats);
6037c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
6047c478bd9Sstevel@tonic-gate 	return (NULL);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate int
6087c478bd9Sstevel@tonic-gate drive_make_descriptors()
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int	error;
6117c478bd9Sstevel@tonic-gate 	disk_t	*dp;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	dp = cache_get_disklist();
6147c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
6157c478bd9Sstevel@tonic-gate 	    cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
6167c478bd9Sstevel@tonic-gate 	    if (error != 0) {
6177c478bd9Sstevel@tonic-gate 		return (error);
6187c478bd9Sstevel@tonic-gate 	    }
6197c478bd9Sstevel@tonic-gate 	    dp = dp->next;
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	return (0);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  * This function opens the disk generically (any slice).
6277c478bd9Sstevel@tonic-gate  */
6287c478bd9Sstevel@tonic-gate int
6297c478bd9Sstevel@tonic-gate drive_open_disk(disk_t *diskp, char *opath, int len)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	/*
63218c2aff7Sartem 	 * Just open the first devpath.
6337c478bd9Sstevel@tonic-gate 	 */
6347c478bd9Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
6357c478bd9Sstevel@tonic-gate 	    if (opath != NULL) {
6367c478bd9Sstevel@tonic-gate 		(void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
6377c478bd9Sstevel@tonic-gate 	    }
6387c478bd9Sstevel@tonic-gate 	    return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	return (-1);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate static descriptor_t **
6457c478bd9Sstevel@tonic-gate apply_filter(descriptor_t **drives, int filter[], int *errp)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	int		i;
6487c478bd9Sstevel@tonic-gate 	descriptor_t	**found;
6497c478bd9Sstevel@tonic-gate 	int		cnt;
6507c478bd9Sstevel@tonic-gate 	int		pos;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/* count the number of drives in the snapshot */
6537c478bd9Sstevel@tonic-gate 	for (cnt = 0; drives[cnt]; cnt++);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
6567c478bd9Sstevel@tonic-gate 	if (found == NULL) {
6577c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
6587c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
6597c478bd9Sstevel@tonic-gate 	    return (NULL);
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	pos = 0;
6637c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
6647c478bd9Sstevel@tonic-gate 	    int j;
6657c478bd9Sstevel@tonic-gate 	    int match;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	    /* Make sure the drive type is set */
6687c478bd9Sstevel@tonic-gate 	    get_drive_type(drives[i]->p.disk, -1);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	    match = 0;
6717c478bd9Sstevel@tonic-gate 	    for (j = 0; filter[j] != DM_FILTER_END; j++) {
6727c478bd9Sstevel@tonic-gate 		if (drives[i]->p.disk->drv_type == filter[j]) {
6737c478bd9Sstevel@tonic-gate 		    found[pos++] = drives[i];
6747c478bd9Sstevel@tonic-gate 		    match = 1;
6757c478bd9Sstevel@tonic-gate 		    break;
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 	    }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	    if (!match) {
6807c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
6817c478bd9Sstevel@tonic-gate 	    }
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 	found[pos] = NULL;
6847c478bd9Sstevel@tonic-gate 	free(drives);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	*errp = 0;
6877c478bd9Sstevel@tonic-gate 	return (found);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static int
6917c478bd9Sstevel@tonic-gate conv_drive_type(uint_t drive_type)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	switch (drive_type) {
6947c478bd9Sstevel@tonic-gate 	case DK_UNKNOWN:
6957c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
6967c478bd9Sstevel@tonic-gate 	case DK_MO_ERASABLE:
6977c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_ERASABLE);
6987c478bd9Sstevel@tonic-gate 	case DK_MO_WRITEONCE:
6997c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_WRITEONCE);
7007c478bd9Sstevel@tonic-gate 	case DK_AS_MO:
7017c478bd9Sstevel@tonic-gate 	    return (DM_DT_AS_MO);
7027c478bd9Sstevel@tonic-gate 	case DK_CDROM:
7037c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDROM);
7047c478bd9Sstevel@tonic-gate 	case DK_CDR:
7057c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDR);
7067c478bd9Sstevel@tonic-gate 	case DK_CDRW:
7077c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDRW);
7087c478bd9Sstevel@tonic-gate 	case DK_DVDROM:
7097c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDROM);
7107c478bd9Sstevel@tonic-gate 	case DK_DVDR:
7117c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDR);
7127c478bd9Sstevel@tonic-gate 	case DK_DVDRAM:
7137c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDRAM);
7147c478bd9Sstevel@tonic-gate 	case DK_FIXED_DISK:
7157c478bd9Sstevel@tonic-gate 	    return (DM_DT_FIXED);
7167c478bd9Sstevel@tonic-gate 	case DK_FLOPPY:
7177c478bd9Sstevel@tonic-gate 	    return (DM_DT_FLOPPY);
7187c478bd9Sstevel@tonic-gate 	case DK_ZIP:
7197c478bd9Sstevel@tonic-gate 	    return (DM_DT_ZIP);
7207c478bd9Sstevel@tonic-gate 	case DK_JAZ:
7217c478bd9Sstevel@tonic-gate 	    return (DM_DT_JAZ);
7227c478bd9Sstevel@tonic-gate 	default:
7237c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate static descriptor_t **
7287c478bd9Sstevel@tonic-gate get_assoc_alias(disk_t *diskp, int *errp)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	alias_t		*aliasp;
7317c478bd9Sstevel@tonic-gate 	uint_t		cnt;
7327c478bd9Sstevel@tonic-gate 	descriptor_t	**out_array;
7337c478bd9Sstevel@tonic-gate 	int		pos;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	*errp = 0;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
7387c478bd9Sstevel@tonic-gate 	cnt = 0;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
7417c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
7427c478bd9Sstevel@tonic-gate 		cnt++;
7437c478bd9Sstevel@tonic-gate 	    }
7447c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	/* set up the new array */
7487c478bd9Sstevel@tonic-gate 	out_array = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t));
7497c478bd9Sstevel@tonic-gate 	if (out_array == NULL) {
7507c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
7517c478bd9Sstevel@tonic-gate 	    return (NULL);
7527c478bd9Sstevel@tonic-gate 	}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
7557c478bd9Sstevel@tonic-gate 	pos = 0;
7567c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
7577c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
7587c478bd9Sstevel@tonic-gate 		out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
7597c478bd9Sstevel@tonic-gate 		    aliasp->alias, NULL, errp);
7607c478bd9Sstevel@tonic-gate 		if (*errp != 0) {
7617c478bd9Sstevel@tonic-gate 		    cache_free_descriptors(out_array);
7627c478bd9Sstevel@tonic-gate 		    return (NULL);
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 	    }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	out_array[pos] = NULL;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	return (out_array);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate static descriptor_t **
7757c478bd9Sstevel@tonic-gate get_assoc_controllers(descriptor_t *dp, int *errp)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
7787c478bd9Sstevel@tonic-gate 	int		cnt;
7797c478bd9Sstevel@tonic-gate 	descriptor_t	**controllers;
7807c478bd9Sstevel@tonic-gate 	int		i;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
7857c478bd9Sstevel@tonic-gate 	for (cnt = 0; diskp->controllers[cnt]; cnt++);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/* make the snapshot */
7887c478bd9Sstevel@tonic-gate 	controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
7897c478bd9Sstevel@tonic-gate 	if (controllers == NULL) {
7907c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
7917c478bd9Sstevel@tonic-gate 	    return (NULL);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	for (i = 0; diskp->controllers[i]; i++) {
7957c478bd9Sstevel@tonic-gate 	    controllers[i] = cache_get_desc(DM_CONTROLLER,
7967c478bd9Sstevel@tonic-gate 		diskp->controllers[i], NULL, NULL, errp);
7977c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
7987c478bd9Sstevel@tonic-gate 		cache_free_descriptors(controllers);
7997c478bd9Sstevel@tonic-gate 		return (NULL);
8007c478bd9Sstevel@tonic-gate 	    }
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	controllers[i] = NULL;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	*errp = 0;
8067c478bd9Sstevel@tonic-gate 	return (controllers);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate static descriptor_t **
8107c478bd9Sstevel@tonic-gate get_assoc_paths(descriptor_t *dp, int *errp)
8117c478bd9Sstevel@tonic-gate {
8127c478bd9Sstevel@tonic-gate 	path_t		**pp;
8137c478bd9Sstevel@tonic-gate 	int		cnt;
8147c478bd9Sstevel@tonic-gate 	descriptor_t	**paths;
8157c478bd9Sstevel@tonic-gate 	int		i;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	pp = dp->p.disk->paths;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
8207c478bd9Sstevel@tonic-gate 	cnt = 0;
8217c478bd9Sstevel@tonic-gate 	if (pp != NULL) {
8227c478bd9Sstevel@tonic-gate 	    for (; pp[cnt]; cnt++);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	/* make the snapshot */
8267c478bd9Sstevel@tonic-gate 	paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
8277c478bd9Sstevel@tonic-gate 	if (paths == NULL) {
8287c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
8297c478bd9Sstevel@tonic-gate 	    return (NULL);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/*
8337c478bd9Sstevel@tonic-gate 	 * We fill in the name field of the descriptor with the device_id
8347c478bd9Sstevel@tonic-gate 	 * when we deal with path descriptors originating from a drive.
8357c478bd9Sstevel@tonic-gate 	 * In that way we can use the device id within the path code to
8367c478bd9Sstevel@tonic-gate 	 * lookup the path state for this drive.
8377c478bd9Sstevel@tonic-gate 	 */
8387c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
8397c478bd9Sstevel@tonic-gate 	    paths[i] = cache_get_desc(DM_PATH, pp[i], dp->p.disk->device_id,
8407c478bd9Sstevel@tonic-gate 		NULL, errp);
8417c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
8427c478bd9Sstevel@tonic-gate 		cache_free_descriptors(paths);
8437c478bd9Sstevel@tonic-gate 		return (NULL);
8447c478bd9Sstevel@tonic-gate 	    }
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	paths[i] = NULL;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	*errp = 0;
8507c478bd9Sstevel@tonic-gate 	return (paths);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate static int
8547c478bd9Sstevel@tonic-gate get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	if (diskp->removable) {
8577c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
8607c478bd9Sstevel@tonic-gate 		return (ENOMEM);
8617c478bd9Sstevel@tonic-gate 	    }
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	    /* Make sure media is inserted and spun up. */
8647c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
8657c478bd9Sstevel@tonic-gate 		if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
8667c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 	    }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	    /* can't tell diff between dead & no media on removable drives */
8717c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
8727c478bd9Sstevel@tonic-gate 		return (ENOMEM);
8737c478bd9Sstevel@tonic-gate 	    }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	} else {
8787c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	    /* check if the fixed drive is up or not */
8817c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
8827c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
8837c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 	    } else {
8867c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
8877c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 	    }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
8957c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	if (diskp->product_id != NULL) {
8997c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
9007c478bd9Sstevel@tonic-gate 		!= 0) {
9017c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9027c478bd9Sstevel@tonic-gate 	    }
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 	if (diskp->vendor_id != NULL) {
9057c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
9067c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9077c478bd9Sstevel@tonic-gate 	    }
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	if (diskp->sync_speed != -1) {
9117c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
9127c478bd9Sstevel@tonic-gate 		!= 0) {
9137c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9147c478bd9Sstevel@tonic-gate 	    }
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (diskp->wide == 1) {
9187c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
9197c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9207c478bd9Sstevel@tonic-gate 	    }
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	if (diskp->rpm == 0) {
9247c478bd9Sstevel@tonic-gate 	    diskp->rpm = get_rpm(diskp, fd);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (diskp->rpm > 0) {
9287c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) {
9297c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9307c478bd9Sstevel@tonic-gate 	    }
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->cluster) {
9347c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_CLUSTERED) != 0) {
9357c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9367c478bd9Sstevel@tonic-gate 	    }
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	if (strlen(opath) > 0) {
9407c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
9417c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9427c478bd9Sstevel@tonic-gate 	    }
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
945*59d8f100SGarrett D'Amore 	if (diskp->solid_state < 0) {
946*59d8f100SGarrett D'Amore 		diskp->solid_state = get_solidstate(diskp, fd);
947*59d8f100SGarrett D'Amore 	}
948*59d8f100SGarrett D'Amore 
949*59d8f100SGarrett D'Amore 	if (diskp->solid_state > 0) {
950*59d8f100SGarrett D'Amore 		if (nvlist_add_boolean(attrs, DM_SOLIDSTATE) != 0) {
951*59d8f100SGarrett D'Amore 			return (ENOMEM);
952*59d8f100SGarrett D'Amore 		}
953*59d8f100SGarrett D'Amore 	}
954*59d8f100SGarrett D'Amore 
9557c478bd9Sstevel@tonic-gate 	return (0);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate static int
9597c478bd9Sstevel@tonic-gate get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
9607c478bd9Sstevel@tonic-gate 	nvlist_t *stats)
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
9637c478bd9Sstevel@tonic-gate 	size_t		class_len;
9647c478bd9Sstevel@tonic-gate 	int		err = 0;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	class_len = strlen(classname);
9677c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
9687c478bd9Sstevel@tonic-gate 	    if (strncmp(ksp->ks_class, classname, class_len) == 0) {
9697c478bd9Sstevel@tonic-gate 		char	kstat_name[KSTAT_STRLEN];
9707c478bd9Sstevel@tonic-gate 		char	*dname = kstat_name;
9717c478bd9Sstevel@tonic-gate 		char	*ename = ksp->ks_name;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		/* names are format: "sd0,err" - copy chars up to comma */
9747c478bd9Sstevel@tonic-gate 		while (*ename && *ename != ',') {
9757c478bd9Sstevel@tonic-gate 		    *dname++ = *ename++;
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 		*dname = NULL;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 		if (libdiskmgt_str_eq(diskname, kstat_name)) {
9807c478bd9Sstevel@tonic-gate 		    (void) kstat_read(kc, ksp, NULL);
9817c478bd9Sstevel@tonic-gate 		    err = get_kstat_vals(ksp, stats);
9827c478bd9Sstevel@tonic-gate 		    break;
9837c478bd9Sstevel@tonic-gate 		}
9847c478bd9Sstevel@tonic-gate 	    }
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	return (err);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * Getting the drive type depends on if the dev tree walk indicated that the
9927c478bd9Sstevel@tonic-gate  * drive was a CD-ROM or not.  The kernal lumps all of the removable multi-media
9937c478bd9Sstevel@tonic-gate  * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
9947c478bd9Sstevel@tonic-gate  * a uscsi cmd to check the drive type.
9957c478bd9Sstevel@tonic-gate  */
9967c478bd9Sstevel@tonic-gate static void
9977c478bd9Sstevel@tonic-gate get_drive_type(disk_t *dp, int fd)
9987c478bd9Sstevel@tonic-gate {
9997c478bd9Sstevel@tonic-gate 	if (dp->drv_type == DM_DT_UNKNOWN) {
10007c478bd9Sstevel@tonic-gate 	    int	opened_here = 0;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	    /* We may have already opened the device. */
10037c478bd9Sstevel@tonic-gate 	    if (fd < 0) {
10047c478bd9Sstevel@tonic-gate 		fd = drive_open_disk(dp, NULL, 0);
10057c478bd9Sstevel@tonic-gate 		opened_here = 1;
10067c478bd9Sstevel@tonic-gate 	    }
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	    if (fd >= 0) {
10097c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
10107c478bd9Sstevel@tonic-gate 		    /* use uscsi to determine drive type */
10117c478bd9Sstevel@tonic-gate 		    dp->drv_type = get_cdrom_drvtype(fd);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		    /* if uscsi fails, just call it a cd-rom */
10147c478bd9Sstevel@tonic-gate 		    if (dp->drv_type == DM_DT_UNKNOWN) {
10157c478bd9Sstevel@tonic-gate 			dp->drv_type = DM_DT_CDROM;
10167c478bd9Sstevel@tonic-gate 		    }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		} else {
10197c478bd9Sstevel@tonic-gate 		    struct dk_minfo	minfo;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		    if (media_read_info(fd, &minfo)) {
10227c478bd9Sstevel@tonic-gate 			dp->drv_type = conv_drive_type(minfo.dki_media_type);
10237c478bd9Sstevel@tonic-gate 		    }
10247c478bd9Sstevel@tonic-gate 		}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		if (opened_here) {
10277c478bd9Sstevel@tonic-gate 		    (void) close(fd);
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	    } else {
10317c478bd9Sstevel@tonic-gate 		/* couldn't open */
10327c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
10337c478bd9Sstevel@tonic-gate 		    dp->drv_type = DM_DT_CDROM;
10347c478bd9Sstevel@tonic-gate 		}
10357c478bd9Sstevel@tonic-gate 	    }
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate static char *
10407c478bd9Sstevel@tonic-gate get_err_attr_name(char *kstat_name)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate 	int	i;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	for (i = 0; kstat_err_names[i] != NULL; i++) {
10457c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(kstat_name, kstat_err_names[i])) {
10467c478bd9Sstevel@tonic-gate 		return (err_attr_names[i]);
10477c478bd9Sstevel@tonic-gate 	    }
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	return (NULL);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate static int
10547c478bd9Sstevel@tonic-gate get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
10557c478bd9Sstevel@tonic-gate {
10567c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate static int
10607c478bd9Sstevel@tonic-gate get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate static int
10667c478bd9Sstevel@tonic-gate get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
10677c478bd9Sstevel@tonic-gate {
10687c478bd9Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_IO) {
10697c478bd9Sstevel@tonic-gate 	    kstat_io_t *kiop;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	    kiop = KSTAT_IO_PTR(ksp);
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	    /* see sys/kstat.h kstat_io_t struct for more fields */
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) {
10767c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10777c478bd9Sstevel@tonic-gate 	    }
10787c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
10797c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10807c478bd9Sstevel@tonic-gate 	    }
10817c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
10827c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10837c478bd9Sstevel@tonic-gate 	    }
10847c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
10857c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10867c478bd9Sstevel@tonic-gate 	    }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	} else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
10897c478bd9Sstevel@tonic-gate 	    kstat_named_t *knp;
10907c478bd9Sstevel@tonic-gate 	    int		i;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	    knp = KSTAT_NAMED_PTR(ksp);
10937c478bd9Sstevel@tonic-gate 	    for (i = 0; i < ksp->ks_ndata; i++) {
10947c478bd9Sstevel@tonic-gate 		char	*attr_name;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 		if (knp[i].name[0] == 0)
10977c478bd9Sstevel@tonic-gate 		    continue;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 		if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
11007c478bd9Sstevel@tonic-gate 		    continue;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 		switch (knp[i].data_type) {
11057c478bd9Sstevel@tonic-gate 		case KSTAT_DATA_UINT32:
11067c478bd9Sstevel@tonic-gate 		    if (update_stat32(stats, attr_name, knp[i].value.ui32)
11077c478bd9Sstevel@tonic-gate 			!= 0) {
11087c478bd9Sstevel@tonic-gate 			return (ENOMEM);
11097c478bd9Sstevel@tonic-gate 		    }
11107c478bd9Sstevel@tonic-gate 		    break;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 		default:
11137c478bd9Sstevel@tonic-gate 		    /* Right now all of the error types are uint32 */
11147c478bd9Sstevel@tonic-gate 		    break;
11157c478bd9Sstevel@tonic-gate 		}
11167c478bd9Sstevel@tonic-gate 	    }
11177c478bd9Sstevel@tonic-gate 	}
11187c478bd9Sstevel@tonic-gate 	return (0);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate static int
11227c478bd9Sstevel@tonic-gate update_stat32(nvlist_t *stats, char *attr, uint32_t value)
11237c478bd9Sstevel@tonic-gate {
11247c478bd9Sstevel@tonic-gate 	int32_t	currval;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
11277c478bd9Sstevel@tonic-gate 	    value += currval;
11287c478bd9Sstevel@tonic-gate 	}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint32(stats, attr, value));
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate  * There can be more than one kstat value when we have multi-path drives
11357c478bd9Sstevel@tonic-gate  * that are not under mpxio (since there is more than one kstat name for
11367c478bd9Sstevel@tonic-gate  * the drive in this case).  So, we may have merge all of the kstat values
11377c478bd9Sstevel@tonic-gate  * to give an accurate set of stats for the drive.
11387c478bd9Sstevel@tonic-gate  */
11397c478bd9Sstevel@tonic-gate static int
11407c478bd9Sstevel@tonic-gate update_stat64(nvlist_t *stats, char *attr, uint64_t value)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate 	int64_t	currval;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
11457c478bd9Sstevel@tonic-gate 	    value += currval;
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint64(stats, attr, value));
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate  * uscsi function to get the rpm of the drive
11527c478bd9Sstevel@tonic-gate  */
11537c478bd9Sstevel@tonic-gate static int
11547c478bd9Sstevel@tonic-gate get_rpm(disk_t *dp, int fd)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	int	opened_here = 0;
11577c478bd9Sstevel@tonic-gate 	int	rpm = -1;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	/* We may have already opened the device. */
11607c478bd9Sstevel@tonic-gate 	if (fd < 0) {
11617c478bd9Sstevel@tonic-gate 	    fd = drive_open_disk(dp, NULL, 0);
11627c478bd9Sstevel@tonic-gate 	    opened_here = 1;
11637c478bd9Sstevel@tonic-gate 	}
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
11667c478bd9Sstevel@tonic-gate 	    int				status;
11677c478bd9Sstevel@tonic-gate 	    struct mode_geometry	*page4;
11687c478bd9Sstevel@tonic-gate 	    struct scsi_ms_header	header;
11697c478bd9Sstevel@tonic-gate 	    union {
11707c478bd9Sstevel@tonic-gate 		struct mode_geometry	page4;
11717c478bd9Sstevel@tonic-gate 		char			rawbuf[MAX_MODE_SENSE_SIZE];
11727c478bd9Sstevel@tonic-gate 	    } u_page4;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	    page4 = &u_page4.page4;
11757c478bd9Sstevel@tonic-gate 	    (void) memset(&u_page4, 0, sizeof (u_page4));
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	    status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11787c478bd9Sstevel@tonic-gate 		MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11797c478bd9Sstevel@tonic-gate 		&header);
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	    if (status) {
11827c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11837c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11847c478bd9Sstevel@tonic-gate 		    &header);
11857c478bd9Sstevel@tonic-gate 	    }
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	    if (status) {
11887c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11897c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11907c478bd9Sstevel@tonic-gate 		    &header);
11917c478bd9Sstevel@tonic-gate 	    }
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	    if (!status) {
11947c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
11957c478bd9Sstevel@tonic-gate 		page4->rpm = ntohs(page4->rpm);
11967c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 		rpm = page4->rpm;
11997c478bd9Sstevel@tonic-gate 	    }
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	    if (opened_here) {
12027c478bd9Sstevel@tonic-gate 		(void) close(fd);
12037c478bd9Sstevel@tonic-gate 	    }
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	return (rpm);
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate 
1209*59d8f100SGarrett D'Amore static int
1210*59d8f100SGarrett D'Amore get_solidstate(disk_t *dp, int fd)
1211*59d8f100SGarrett D'Amore {
1212*59d8f100SGarrett D'Amore 	int	opened_here = 0;
1213*59d8f100SGarrett D'Amore 	int	solid_state = -1;
1214*59d8f100SGarrett D'Amore 
1215*59d8f100SGarrett D'Amore 	/* We may have already opened the device. */
1216*59d8f100SGarrett D'Amore 	if (fd < 0) {
1217*59d8f100SGarrett D'Amore 		fd = drive_open_disk(dp, NULL, 0);
1218*59d8f100SGarrett D'Amore 		opened_here = 1;
1219*59d8f100SGarrett D'Amore 	}
1220*59d8f100SGarrett D'Amore 
1221*59d8f100SGarrett D'Amore 	if (fd >= 0) {
1222*59d8f100SGarrett D'Amore 		if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
1223*59d8f100SGarrett D'Amore 			solid_state = -1;
1224*59d8f100SGarrett D'Amore 		}
1225*59d8f100SGarrett D'Amore 	}
1226*59d8f100SGarrett D'Amore 
1227*59d8f100SGarrett D'Amore 	if (opened_here) {
1228*59d8f100SGarrett D'Amore 		(void) close(fd);
1229*59d8f100SGarrett D'Amore 	}
1230*59d8f100SGarrett D'Amore 
1231*59d8f100SGarrett D'Amore 	return (solid_state);
1232*59d8f100SGarrett D'Amore }
1233*59d8f100SGarrett D'Amore 
12347c478bd9Sstevel@tonic-gate /*
12357c478bd9Sstevel@tonic-gate  *	******** the rest of this is uscsi stuff for the drv type ********
12367c478bd9Sstevel@tonic-gate  */
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate /*
12397c478bd9Sstevel@tonic-gate  * We try a get_configuration uscsi cmd.  If that fails, try a
12407c478bd9Sstevel@tonic-gate  * atapi_capabilities cmd.  If both fail then this is an older CD-ROM.
12417c478bd9Sstevel@tonic-gate  */
12427c478bd9Sstevel@tonic-gate static int
12437c478bd9Sstevel@tonic-gate get_cdrom_drvtype(int fd)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
12467c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
12477c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	fill_general_page_cdb_g1(&cdb, SCMD_GET_CONFIGURATION, 0,
12507c478bd9Sstevel@tonic-gate 	    b0(sizeof (buff)), b1(sizeof (buff)));
12517c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
12547c478bd9Sstevel@tonic-gate 	    struct get_configuration	*config;
12557c478bd9Sstevel@tonic-gate 	    struct conf_feature		*feature;
12567c478bd9Sstevel@tonic-gate 	    int				flen;
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	    /* The first profile is the preferred one for the drive. */
12597c478bd9Sstevel@tonic-gate 	    config = (struct get_configuration *)buff;
12607c478bd9Sstevel@tonic-gate 	    feature = &config->feature;
12617c478bd9Sstevel@tonic-gate 	    flen = feature->len / sizeof (struct profile_list);
12627c478bd9Sstevel@tonic-gate 	    if (flen > 0) {
12637c478bd9Sstevel@tonic-gate 		int prof_num;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		prof_num = (int)convnum(feature->features.plist[0].profile, 2);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 		if (dm_debug > 1) {
12687c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
12697c478bd9Sstevel@tonic-gate 			prof_num);
12707c478bd9Sstevel@tonic-gate 		}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 		switch (prof_num) {
12737c478bd9Sstevel@tonic-gate 		case PROF_MAGNETO_OPTICAL:
12747c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_ERASABLE);
12757c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_WO:
12767c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_WRITEONCE);
12777c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_ASMO:
12787c478bd9Sstevel@tonic-gate 		    return (DM_DT_AS_MO);
12797c478bd9Sstevel@tonic-gate 		case PROF_CDROM:
12807c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDROM);
12817c478bd9Sstevel@tonic-gate 		case PROF_CDR:
12827c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDR);
12837c478bd9Sstevel@tonic-gate 		case PROF_CDRW:
12847c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDRW);
12857c478bd9Sstevel@tonic-gate 		case PROF_DVDROM:
12867c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDROM);
12877c478bd9Sstevel@tonic-gate 		case PROF_DVDRAM:
12887c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRAM);
12897c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_REST:
12907c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12917c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_SEQ:
12927c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12937c478bd9Sstevel@tonic-gate 		case PROF_DVDRW:
12947c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12957c478bd9Sstevel@tonic-gate 		case PROF_DDCD_ROM:
12967c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDROM);
12977c478bd9Sstevel@tonic-gate 		case PROF_DDCD_R:
12987c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDR);
12997c478bd9Sstevel@tonic-gate 		case PROF_DDCD_RW:
13007c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDRW);
13017c478bd9Sstevel@tonic-gate 		}
13027c478bd9Sstevel@tonic-gate 	    }
13037c478bd9Sstevel@tonic-gate 	}
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	/* see if the atapi capabilities give anything */
13067c478bd9Sstevel@tonic-gate 	return (check_atapi(fd));
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate static int
13107c478bd9Sstevel@tonic-gate check_atapi(int fd)
13117c478bd9Sstevel@tonic-gate {
13127c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
13137c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
13147c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES);
13177c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
13207c478bd9Sstevel@tonic-gate 	    int			bdesclen;
13217c478bd9Sstevel@tonic-gate 	    struct capabilities	*cap;
13227c478bd9Sstevel@tonic-gate 	    struct mode_header_g2 *mode;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	    mode = (struct mode_header_g2 *)buff;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	    bdesclen = (int)convnum(mode->desclen, 2);
13277c478bd9Sstevel@tonic-gate 	    cap = (struct capabilities *)
13287c478bd9Sstevel@tonic-gate 		&buff[sizeof (struct mode_header_g2) + bdesclen];
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	    if (dm_debug > 1) {
13317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "INFO: uscsi atapi capabilities\n");
13327c478bd9Sstevel@tonic-gate 	    }
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	    /* These are in order of how we want to report the drv type. */
13357c478bd9Sstevel@tonic-gate 	    if (cap->dvdram_write) {
13367c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDRAM);
13377c478bd9Sstevel@tonic-gate 	    }
13387c478bd9Sstevel@tonic-gate 	    if (cap->dvdr_write) {
13397c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDR);
13407c478bd9Sstevel@tonic-gate 	    }
13417c478bd9Sstevel@tonic-gate 	    if (cap->dvdrom_read) {
13427c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDROM);
13437c478bd9Sstevel@tonic-gate 	    }
13447c478bd9Sstevel@tonic-gate 	    if (cap->cdrw_write) {
13457c478bd9Sstevel@tonic-gate 		return (DM_DT_CDRW);
13467c478bd9Sstevel@tonic-gate 	    }
13477c478bd9Sstevel@tonic-gate 	    if (cap->cdr_write) {
13487c478bd9Sstevel@tonic-gate 		return (DM_DT_CDR);
13497c478bd9Sstevel@tonic-gate 	    }
13507c478bd9Sstevel@tonic-gate 	    if (cap->cdr_read) {
13517c478bd9Sstevel@tonic-gate 		return (DM_DT_CDROM);
13527c478bd9Sstevel@tonic-gate 	    }
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/* everything failed, so this is an older CD-ROM */
13567c478bd9Sstevel@tonic-gate 	if (dm_debug > 1) {
13577c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "INFO: uscsi failed\n");
13587c478bd9Sstevel@tonic-gate 	}
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	return (DM_DT_CDROM);
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate static uint64_t
13647c478bd9Sstevel@tonic-gate convnum(uchar_t *nptr, int len)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	uint64_t value;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	for (value = 0; len > 0; len--, nptr++)
13697c478bd9Sstevel@tonic-gate 		value = (value << 8) | *nptr;
13707c478bd9Sstevel@tonic-gate 	return (value);
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate static void
13747c478bd9Sstevel@tonic-gate fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb,
13757c478bd9Sstevel@tonic-gate 	caddr_t buff, int blen)
13767c478bd9Sstevel@tonic-gate {
13777c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cmd, sizeof (struct uscsi_cmd));
13787c478bd9Sstevel@tonic-gate 	bzero(buff, blen);
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdb = (caddr_t)cdb;
13817c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdblen = CDB_GROUP1;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	cmd->uscsi_bufaddr = buff;
13847c478bd9Sstevel@tonic-gate 	cmd->uscsi_buflen = blen;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ;
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate static void
13907c478bd9Sstevel@tonic-gate fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun,
13917c478bd9Sstevel@tonic-gate 	uchar_t c0, uchar_t c1)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
13947c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = command;
13957c478bd9Sstevel@tonic-gate 	cdb->scc_lun = lun;
13967c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = c0; /* max length for page */
13977c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = c1; /* max length for page */
13987c478bd9Sstevel@tonic-gate }
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate static void
14017c478bd9Sstevel@tonic-gate fill_mode_page_cdb(union scsi_cdb *cdb, int page)
14027c478bd9Sstevel@tonic-gate {
14037c478bd9Sstevel@tonic-gate 	/* group 1 mode page */
14047c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
14057c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = SCMD_MODE_SENSE_G1;
14067c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = 0xff; /* max length for mode page */
14077c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = 0xff; /* max length for mode page */
14087c478bd9Sstevel@tonic-gate 	cdb->g1_addr3 = page;
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate static int
14127c478bd9Sstevel@tonic-gate uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
14137c478bd9Sstevel@tonic-gate 	int page_size, struct  scsi_ms_header *header)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate 	caddr_t			mode_sense_buf;
14167c478bd9Sstevel@tonic-gate 	struct mode_header	*hdr;
14177c478bd9Sstevel@tonic-gate 	struct mode_page	*pg;
14187c478bd9Sstevel@tonic-gate 	int			nbytes;
14197c478bd9Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
14207c478bd9Sstevel@tonic-gate 	union scsi_cdb		cdb;
14217c478bd9Sstevel@tonic-gate 	int			status;
14227c478bd9Sstevel@tonic-gate 	int			maximum;
14237c478bd9Sstevel@tonic-gate 	char			rqbuf[255];
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	/*
14267c478bd9Sstevel@tonic-gate 	 * Allocate a buffer for the mode sense headers
14277c478bd9Sstevel@tonic-gate 	 * and mode sense data itself.
14287c478bd9Sstevel@tonic-gate 	 */
14297c478bd9Sstevel@tonic-gate 	nbytes = sizeof (struct block_descriptor) +
14307c478bd9Sstevel@tonic-gate 				sizeof (struct mode_header) + page_size;
14317c478bd9Sstevel@tonic-gate 	nbytes = page_size;
14327c478bd9Sstevel@tonic-gate 	if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
14337c478bd9Sstevel@tonic-gate 	    return (-1);
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	/*
14377c478bd9Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl
14387c478bd9Sstevel@tonic-gate 	 */
14397c478bd9Sstevel@tonic-gate 	(void) memset(mode_sense_buf, 0, nbytes);
14407c478bd9Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
14417c478bd9Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
14447c478bd9Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
14457c478bd9Sstevel@tonic-gate 	cdb.cdb_opaque[2] = page_control | page_code;
14467c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
14477c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
14487c478bd9Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = mode_sense_buf;
14497c478bd9Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_SILENT;
14527c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_READ;
14537c478bd9Sstevel@tonic-gate 	ucmd.uscsi_timeout = 30;
14547c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_RQENABLE;
14557c478bd9Sstevel@tonic-gate 	if (ucmd.uscsi_rqbuf == NULL)  {
14567c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqbuf = rqbuf;
14577c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqlen = sizeof (rqbuf);
14587c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqresid = sizeof (rqbuf);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 	ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	status = ioctl(fd, USCSICMD, &ucmd);
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	if (status || ucmd.uscsi_status != 0) {
14657c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14667c478bd9Sstevel@tonic-gate 	    return (-1);
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	/*
14707c478bd9Sstevel@tonic-gate 	 * Verify that the returned data looks reasonabled,
14717c478bd9Sstevel@tonic-gate 	 * find the actual page data, and copy it into the
14727c478bd9Sstevel@tonic-gate 	 * user's buffer.  Copy the mode_header and block_descriptor
14737c478bd9Sstevel@tonic-gate 	 * into the header structure, which can then be used to
14747c478bd9Sstevel@tonic-gate 	 * return the same data to the drive when issuing a mode select.
14757c478bd9Sstevel@tonic-gate 	 */
14767c478bd9Sstevel@tonic-gate 	hdr = (struct mode_header *)mode_sense_buf;
14777c478bd9Sstevel@tonic-gate 	(void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
14787c478bd9Sstevel@tonic-gate 	if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
14797c478bd9Sstevel@tonic-gate 	    hdr->bdesc_length != 0) {
14807c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14817c478bd9Sstevel@tonic-gate 	    return (-1);
14827c478bd9Sstevel@tonic-gate 	}
14837c478bd9Sstevel@tonic-gate 	(void) memcpy((caddr_t)header, mode_sense_buf,
14847c478bd9Sstevel@tonic-gate 	    (int) (sizeof (struct mode_header) + hdr->bdesc_length));
14857c478bd9Sstevel@tonic-gate 	pg = (struct mode_page *)((ulong_t)mode_sense_buf +
14867c478bd9Sstevel@tonic-gate 	    sizeof (struct mode_header) + hdr->bdesc_length);
14877c478bd9Sstevel@tonic-gate 	if (pg->code != page_code) {
14887c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14897c478bd9Sstevel@tonic-gate 	    return (-1);
14907c478bd9Sstevel@tonic-gate 	}
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	/*
14937c478bd9Sstevel@tonic-gate 	 * Accept up to "page_size" bytes of mode sense data.
14947c478bd9Sstevel@tonic-gate 	 * This allows us to accept both CCS and SCSI-2
14957c478bd9Sstevel@tonic-gate 	 * structures, as long as we request the greater
14967c478bd9Sstevel@tonic-gate 	 * of the two.
14977c478bd9Sstevel@tonic-gate 	 */
14987c478bd9Sstevel@tonic-gate 	maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
14997c478bd9Sstevel@tonic-gate 	if (((int)pg->length) > maximum) {
15007c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
15017c478bd9Sstevel@tonic-gate 	    return (-1);
15027c478bd9Sstevel@tonic-gate 	}
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	(void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	free(mode_sense_buf);
15077c478bd9Sstevel@tonic-gate 	return (0);
15087c478bd9Sstevel@tonic-gate }
1509