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