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  */
21c470f575SYuri Pankov 
227c478bd9Sstevel@tonic-gate /*
2318c2aff7Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27c470f575SYuri Pankov /*
28c470f575SYuri Pankov  * Copyright 2017 Nexenta Systems, Inc.
29c470f575SYuri Pankov  */
30c470f575SYuri Pankov 
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stropts.h>
377c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
417c478bd9Sstevel@tonic-gate #include <kstat.h>
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate #include <devid.h>
447c478bd9Sstevel@tonic-gate #include <dirent.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /* included for uscsi */
477c478bd9Sstevel@tonic-gate #include <strings.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/types.h>
507c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h>
517c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
527c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/commands.h>
537c478bd9Sstevel@tonic-gate #include <sys/scsi/generic/mode.h>
547c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
577c478bd9Sstevel@tonic-gate #include "disks_private.h"
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_DISK	"disk"
607c478bd9Sstevel@tonic-gate #define	KSTAT_CLASS_ERROR	"device_error"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	SCSIBUFLEN		0xffff
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* byte get macros */
657c478bd9Sstevel@tonic-gate #define	b3(a)			(((a)>>24) & 0xFF)
667c478bd9Sstevel@tonic-gate #define	b2(a)			(((a)>>16) & 0xFF)
677c478bd9Sstevel@tonic-gate #define	b1(a)			(((a)>>8) & 0xFF)
687c478bd9Sstevel@tonic-gate #define	b0(a)			(((a)>>0) & 0xFF)
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static char *kstat_err_names[] = {
717c478bd9Sstevel@tonic-gate 	"Soft Errors",
727c478bd9Sstevel@tonic-gate 	"Hard Errors",
737c478bd9Sstevel@tonic-gate 	"Transport Errors",
747c478bd9Sstevel@tonic-gate 	"Media Error",
757c478bd9Sstevel@tonic-gate 	"Device Not Ready",
767c478bd9Sstevel@tonic-gate 	"No Device",
777c478bd9Sstevel@tonic-gate 	"Recoverable",
787c478bd9Sstevel@tonic-gate 	"Illegal Request",
797c478bd9Sstevel@tonic-gate 	"Predictive Failure Analysis",
807c478bd9Sstevel@tonic-gate 	NULL
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate static char *err_attr_names[] = {
847c478bd9Sstevel@tonic-gate 	DM_NSOFTERRS,
857c478bd9Sstevel@tonic-gate 	DM_NHARDERRS,
867c478bd9Sstevel@tonic-gate 	DM_NTRANSERRS,
877c478bd9Sstevel@tonic-gate 	DM_NMEDIAERRS,
887c478bd9Sstevel@tonic-gate 	DM_NDNRERRS,
897c478bd9Sstevel@tonic-gate 	DM_NNODEVERRS,
907c478bd9Sstevel@tonic-gate 	DM_NRECOVERRS,
917c478bd9Sstevel@tonic-gate 	DM_NILLREQERRS,
927c478bd9Sstevel@tonic-gate 	DM_FAILING,
937c478bd9Sstevel@tonic-gate 	NULL
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  *	**************** begin uscsi stuff ****************
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1017c478bd9Sstevel@tonic-gate #elif defined(_BIT_FIELDS_HTOL)
1027c478bd9Sstevel@tonic-gate #else
1037c478bd9Sstevel@tonic-gate #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
1047c478bd9Sstevel@tonic-gate #endif
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate struct conf_feature {
1077c478bd9Sstevel@tonic-gate 	uchar_t feature[2]; /* common to all */
1087c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1097c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
1107c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
1117c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
1127c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
1137c478bd9Sstevel@tonic-gate #else
1147c478bd9Sstevel@tonic-gate 	uchar_t reserved: 2;
1157c478bd9Sstevel@tonic-gate 	uchar_t version : 4;
1167c478bd9Sstevel@tonic-gate 	uchar_t persist : 1;
1177c478bd9Sstevel@tonic-gate 	uchar_t current : 1;
1187c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1197c478bd9Sstevel@tonic-gate 	uchar_t len;
1207c478bd9Sstevel@tonic-gate 	union features {
1217c478bd9Sstevel@tonic-gate 		struct generic {
1227c478bd9Sstevel@tonic-gate 			uchar_t data[1];
1237c478bd9Sstevel@tonic-gate 		} gen;
1247c478bd9Sstevel@tonic-gate 		uchar_t data[1];
1257c478bd9Sstevel@tonic-gate 		struct profile_list {
1267c478bd9Sstevel@tonic-gate 			uchar_t profile[2];
1277c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1287c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
1297c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
1307c478bd9Sstevel@tonic-gate #else
1317c478bd9Sstevel@tonic-gate 			uchar_t reserved1 : 7;
1327c478bd9Sstevel@tonic-gate 			uchar_t current_p : 1;
1337c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1347c478bd9Sstevel@tonic-gate 			uchar_t reserved2;
1357c478bd9Sstevel@tonic-gate 		} plist[1];
1367c478bd9Sstevel@tonic-gate 		struct core {
1377c478bd9Sstevel@tonic-gate 			uchar_t phys[4];
1387c478bd9Sstevel@tonic-gate 		} core;
1397c478bd9Sstevel@tonic-gate 		struct morphing {
1407c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1417c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
1427c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1437c478bd9Sstevel@tonic-gate #else
1447c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1457c478bd9Sstevel@tonic-gate 			uchar_t async		: 1;
1467c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1477c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
1487c478bd9Sstevel@tonic-gate 		} morphing;
1497c478bd9Sstevel@tonic-gate 		struct removable {
1507c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1517c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
1527c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
1537c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
1547c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
1557c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
1567c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
1577c478bd9Sstevel@tonic-gate #else
1587c478bd9Sstevel@tonic-gate 			uchar_t loading : 3;
1597c478bd9Sstevel@tonic-gate 			uchar_t resv2	: 1;
1607c478bd9Sstevel@tonic-gate 			uchar_t eject	: 1;
1617c478bd9Sstevel@tonic-gate 			uchar_t	pvnt	: 1;
1627c478bd9Sstevel@tonic-gate 			uchar_t	resv1	: 1;
1637c478bd9Sstevel@tonic-gate 			uchar_t lock	: 1;
1647c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1657c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
1667c478bd9Sstevel@tonic-gate 		} removable;
1677c478bd9Sstevel@tonic-gate 		struct random_readable {
1687c478bd9Sstevel@tonic-gate 			uchar_t lbsize[4];
1697c478bd9Sstevel@tonic-gate 			uchar_t blocking[2];
1707c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1717c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
1727c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1737c478bd9Sstevel@tonic-gate #else
1747c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 7;
1757c478bd9Sstevel@tonic-gate 			uchar_t pp		: 1;
1767c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1777c478bd9Sstevel@tonic-gate 			uchar_t reserved;
1787c478bd9Sstevel@tonic-gate 		} rread;
1797c478bd9Sstevel@tonic-gate 		struct cd_read {
1807c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1817c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
1827c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
1837c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
1847c478bd9Sstevel@tonic-gate #else
1857c478bd9Sstevel@tonic-gate 			uchar_t reserved1	: 6;
1867c478bd9Sstevel@tonic-gate 			uchar_t c2flag		: 1;
1877c478bd9Sstevel@tonic-gate 			uchar_t cdtext		: 1;
1887c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
1897c478bd9Sstevel@tonic-gate 		} cdread;
1907c478bd9Sstevel@tonic-gate 		struct cd_audio {
1917c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
1927c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
1937c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
1947c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
1957c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
1967c478bd9Sstevel@tonic-gate #else
1977c478bd9Sstevel@tonic-gate 			uchar_t resv	: 5;
1987c478bd9Sstevel@tonic-gate 			uchar_t scan	: 1;
1997c478bd9Sstevel@tonic-gate 			uchar_t scm	: 1;
2007c478bd9Sstevel@tonic-gate 			uchar_t sv	: 1;
2017c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2027c478bd9Sstevel@tonic-gate 			uchar_t reserved;
2037c478bd9Sstevel@tonic-gate 			uchar_t numlevels[2];
2047c478bd9Sstevel@tonic-gate 		} audio;
2057c478bd9Sstevel@tonic-gate 		struct dvd_css {
2067c478bd9Sstevel@tonic-gate 			uchar_t reserved[3];
2077c478bd9Sstevel@tonic-gate 			uchar_t version;
2087c478bd9Sstevel@tonic-gate 		} dvdcss;
2097c478bd9Sstevel@tonic-gate 	} features;
2107c478bd9Sstevel@tonic-gate };
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate #define	PROF_NON_REMOVABLE	0x0001
2137c478bd9Sstevel@tonic-gate #define	PROF_REMOVABLE		0x0002
2147c478bd9Sstevel@tonic-gate #define	PROF_MAGNETO_OPTICAL	0x0003
2157c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_WO		0x0004
2167c478bd9Sstevel@tonic-gate #define	PROF_OPTICAL_ASMO	0x0005
2177c478bd9Sstevel@tonic-gate #define	PROF_CDROM		0x0008
2187c478bd9Sstevel@tonic-gate #define	PROF_CDR		0x0009
2197c478bd9Sstevel@tonic-gate #define	PROF_CDRW		0x000a
2207c478bd9Sstevel@tonic-gate #define	PROF_DVDROM		0x0010
2217c478bd9Sstevel@tonic-gate #define	PROF_DVDR		0x0011
2227c478bd9Sstevel@tonic-gate #define	PROF_DVDRAM		0x0012
2237c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_REST		0x0013
2247c478bd9Sstevel@tonic-gate #define	PROF_DVDRW_SEQ		0x0014
2257c478bd9Sstevel@tonic-gate #define	PROF_DVDRW		0x001a
2267c478bd9Sstevel@tonic-gate #define	PROF_DDCD_ROM		0x0020
2277c478bd9Sstevel@tonic-gate #define	PROF_DDCD_R		0x0021
2287c478bd9Sstevel@tonic-gate #define	PROF_DDCD_RW		0x0022
2297c478bd9Sstevel@tonic-gate #define	PROF_NON_CONFORMING	0xffff
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate struct get_configuration {
2327c478bd9Sstevel@tonic-gate 	uchar_t len[4];
2337c478bd9Sstevel@tonic-gate 	uchar_t reserved[2];
2347c478bd9Sstevel@tonic-gate 	uchar_t curprof[2];
2357c478bd9Sstevel@tonic-gate 	struct conf_feature feature;
2367c478bd9Sstevel@tonic-gate };
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate struct capabilities {
2397c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2407c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
2417c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
2427c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
2437c478bd9Sstevel@tonic-gate #else
2447c478bd9Sstevel@tonic-gate 	uchar_t ps		: 1;
2457c478bd9Sstevel@tonic-gate 	uchar_t resv1		: 1;
2467c478bd9Sstevel@tonic-gate 	uchar_t pagecode	: 6;
2477c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2487c478bd9Sstevel@tonic-gate 	uchar_t pagelen;
2497c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2507c478bd9Sstevel@tonic-gate 	/* read capabilities */
2517c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
2527c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
2537c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
2547c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
2557c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
2567c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
2577c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
2587c478bd9Sstevel@tonic-gate #else
2597c478bd9Sstevel@tonic-gate 	uchar_t resv2		: 2;
2607c478bd9Sstevel@tonic-gate 	uchar_t dvdram_read	: 1;
2617c478bd9Sstevel@tonic-gate 	uchar_t dvdr_read	: 1;
2627c478bd9Sstevel@tonic-gate 	uchar_t dvdrom_read	: 1;
2637c478bd9Sstevel@tonic-gate 	uchar_t method2		: 1;
2647c478bd9Sstevel@tonic-gate 	uchar_t cdrw_read	: 1;
2657c478bd9Sstevel@tonic-gate 	uchar_t	cdr_read	: 1;
2667c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2677c478bd9Sstevel@tonic-gate #if defined(_BIT_FIELDS_LTOH)
2687c478bd9Sstevel@tonic-gate 	/* write capabilities */
2697c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
2707c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
2717c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
2727c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
2737c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
2747c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
2757c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
2767c478bd9Sstevel@tonic-gate #else
2777c478bd9Sstevel@tonic-gate 	/* write capabilities */
2787c478bd9Sstevel@tonic-gate 	uchar_t resv4		: 2;
2797c478bd9Sstevel@tonic-gate 	uchar_t dvdram_write	: 1;
2807c478bd9Sstevel@tonic-gate 	uchar_t dvdr_write	: 1;
2817c478bd9Sstevel@tonic-gate 	uchar_t resv3		: 1;
2827c478bd9Sstevel@tonic-gate 	uchar_t testwrite	: 1;
2837c478bd9Sstevel@tonic-gate 	uchar_t cdrw_write	: 1;
2847c478bd9Sstevel@tonic-gate 	uchar_t cdr_write	: 1;
2857c478bd9Sstevel@tonic-gate #endif	/* _BIT_FIELDS_LTOH */
2867c478bd9Sstevel@tonic-gate 	uchar_t misc0;
2877c478bd9Sstevel@tonic-gate 	uchar_t misc1;
2887c478bd9Sstevel@tonic-gate 	uchar_t misc2;
2897c478bd9Sstevel@tonic-gate 	uchar_t misc3;
2907c478bd9Sstevel@tonic-gate 	uchar_t obsolete0[2];
2917c478bd9Sstevel@tonic-gate 	uchar_t numvlevels[2];
2927c478bd9Sstevel@tonic-gate 	uchar_t bufsize[2];
2937c478bd9Sstevel@tonic-gate 	uchar_t obsolete1[4];
2947c478bd9Sstevel@tonic-gate 	uchar_t resv5;
2957c478bd9Sstevel@tonic-gate 	uchar_t misc4;
2967c478bd9Sstevel@tonic-gate 	uchar_t obsolete2;
2977c478bd9Sstevel@tonic-gate 	uchar_t copymgt[2];
2987c478bd9Sstevel@tonic-gate 	/* there is more to this page, but nothing we care about */
2997c478bd9Sstevel@tonic-gate };
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate struct mode_header_g2 {
3027c478bd9Sstevel@tonic-gate 	uchar_t modelen[2];
3037c478bd9Sstevel@tonic-gate 	uchar_t obsolete;
3047c478bd9Sstevel@tonic-gate 	uchar_t reserved[3];
3057c478bd9Sstevel@tonic-gate 	uchar_t desclen[2];
3067c478bd9Sstevel@tonic-gate };
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  * Mode sense/select page header information
3107c478bd9Sstevel@tonic-gate  */
3117c478bd9Sstevel@tonic-gate struct scsi_ms_header {
3127c478bd9Sstevel@tonic-gate 	struct mode_header	mode_header;
3137c478bd9Sstevel@tonic-gate 	struct block_descriptor	block_descriptor;
3147c478bd9Sstevel@tonic-gate };
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate #define	MODESENSE_PAGE_LEN(p)	(((int)((struct mode_page *)p)->length) + \
3177c478bd9Sstevel@tonic-gate 				    sizeof (struct mode_page))
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_CURRENT	(0 << 6)
3207c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_DEFAULT	(2 << 6)
3217c478bd9Sstevel@tonic-gate #define	MODE_SENSE_PC_SAVED	(3 << 6)
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate #define	MAX_MODE_SENSE_SIZE	255
3247c478bd9Sstevel@tonic-gate #define	IMPOSSIBLE_SCSI_STATUS	0xff
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate  *	********** end of uscsi stuff ************
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate static descriptor_t	**apply_filter(descriptor_t **drives, int filter[],
3317c478bd9Sstevel@tonic-gate 			    int *errp);
3327c478bd9Sstevel@tonic-gate static int		check_atapi(int fd);
3337c478bd9Sstevel@tonic-gate static int		conv_drive_type(uint_t drive_type);
3347c478bd9Sstevel@tonic-gate static uint64_t		convnum(uchar_t *nptr, int len);
3357c478bd9Sstevel@tonic-gate static void		fill_command_g1(struct uscsi_cmd *cmd,
3367c478bd9Sstevel@tonic-gate 			    union scsi_cdb *cdb, caddr_t buff, int blen);
3377c478bd9Sstevel@tonic-gate static void		fill_general_page_cdb_g1(union scsi_cdb *cdb,
3387c478bd9Sstevel@tonic-gate 			    int command, int lun, uchar_t c0, uchar_t c1);
3397c478bd9Sstevel@tonic-gate static void		fill_mode_page_cdb(union scsi_cdb *cdb, int page);
3407c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_alias(disk_t *diskp, int *errp);
3417c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_controllers(descriptor_t *dp, int *errp);
3427c478bd9Sstevel@tonic-gate static descriptor_t	**get_assoc_paths(descriptor_t *dp, int *errp);
3437c478bd9Sstevel@tonic-gate static int		get_attrs(disk_t *diskp, int fd, char *opath,
3447c478bd9Sstevel@tonic-gate 			    nvlist_t *nvp);
3457c478bd9Sstevel@tonic-gate static int		get_cdrom_drvtype(int fd);
3467c478bd9Sstevel@tonic-gate static int		get_disk_kstats(kstat_ctl_t *kc, char *diskname,
3477c478bd9Sstevel@tonic-gate 			    char *classname, nvlist_t *stats);
3487c478bd9Sstevel@tonic-gate static void		get_drive_type(disk_t *dp, int fd);
3497c478bd9Sstevel@tonic-gate static int		get_err_kstats(kstat_ctl_t *kc, char *diskname,
3507c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
3517c478bd9Sstevel@tonic-gate static int		get_io_kstats(kstat_ctl_t *kc, char *diskname,
3527c478bd9Sstevel@tonic-gate 			    nvlist_t *stats);
3537c478bd9Sstevel@tonic-gate static int		get_kstat_vals(kstat_t *ksp, nvlist_t *stats);
3547c478bd9Sstevel@tonic-gate static char		*get_err_attr_name(char *kstat_name);
3557c478bd9Sstevel@tonic-gate static int		get_rpm(disk_t *dp, int fd);
35659d8f100SGarrett D'Amore static int		get_solidstate(disk_t *dp, int fd);
3577c478bd9Sstevel@tonic-gate static int		update_stat64(nvlist_t *stats, char *attr,
3587c478bd9Sstevel@tonic-gate 			    uint64_t value);
3597c478bd9Sstevel@tonic-gate static int		update_stat32(nvlist_t *stats, char *attr,
3607c478bd9Sstevel@tonic-gate 			    uint32_t value);
3617c478bd9Sstevel@tonic-gate static int		uscsi_mode_sense(int fd, int page_code,
3627c478bd9Sstevel@tonic-gate 			    int page_control, caddr_t page_data, int page_size,
3637c478bd9Sstevel@tonic-gate 			    struct  scsi_ms_header *header);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate descriptor_t **
drive_get_assoc_descriptors(descriptor_t * dp,dm_desc_type_t type,int * errp)3667c478bd9Sstevel@tonic-gate drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
3677c478bd9Sstevel@tonic-gate     int *errp)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	switch (type) {
3707c478bd9Sstevel@tonic-gate 	case DM_CONTROLLER:
3717c478bd9Sstevel@tonic-gate 	    return (get_assoc_controllers(dp, errp));
3727c478bd9Sstevel@tonic-gate 	case DM_PATH:
3737c478bd9Sstevel@tonic-gate 	    return (get_assoc_paths(dp, errp));
3747c478bd9Sstevel@tonic-gate 	case DM_ALIAS:
3757c478bd9Sstevel@tonic-gate 	    return (get_assoc_alias(dp->p.disk, errp));
3767c478bd9Sstevel@tonic-gate 	case DM_MEDIA:
3777c478bd9Sstevel@tonic-gate 	    return (media_get_assocs(dp, errp));
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
3817c478bd9Sstevel@tonic-gate 	return (NULL);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * Get the drive descriptors for the given media/alias/devpath.
3867c478bd9Sstevel@tonic-gate  */
3877c478bd9Sstevel@tonic-gate descriptor_t **
drive_get_assocs(descriptor_t * desc,int * errp)3887c478bd9Sstevel@tonic-gate drive_get_assocs(descriptor_t *desc, int *errp)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* at most one drive is associated with these descriptors */
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	drives = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
3957c478bd9Sstevel@tonic-gate 	if (drives == NULL) {
3967c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
3977c478bd9Sstevel@tonic-gate 	    return (NULL);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
4017c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
4027c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
4037c478bd9Sstevel@tonic-gate 	    return (NULL);
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	drives[1] = NULL;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	return (drives);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate nvlist_t *
drive_get_attributes(descriptor_t * dp,int * errp)4127c478bd9Sstevel@tonic-gate drive_get_attributes(descriptor_t *dp, int *errp)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
4157c478bd9Sstevel@tonic-gate 	int		fd;
4167c478bd9Sstevel@tonic-gate 	char		opath[MAXPATHLEN];
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
4197c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
4207c478bd9Sstevel@tonic-gate 	    return (NULL);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	opath[0] = 0;
4247c478bd9Sstevel@tonic-gate 	fd = drive_open_disk(dp->p.disk, opath, sizeof (opath));
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	if ((*errp = get_attrs(dp->p.disk, fd, opath, attrs)) != 0) {
4277c478bd9Sstevel@tonic-gate 	    nvlist_free(attrs);
4287c478bd9Sstevel@tonic-gate 	    attrs = NULL;
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
4327c478bd9Sstevel@tonic-gate 	    (void) close(fd);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	return (attrs);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate  * Check if we have the drive in our list, based upon the device id.
4407c478bd9Sstevel@tonic-gate  * We got the device id from the dev tree walk.  This is encoded
4417c478bd9Sstevel@tonic-gate  * using devid_str_encode(3DEVID).   In order to check the device ids we need
4427c478bd9Sstevel@tonic-gate  * to use the devid_compare(3DEVID) function, so we need to decode the
4437c478bd9Sstevel@tonic-gate  * string representation of the device id.
4447c478bd9Sstevel@tonic-gate  */
4457c478bd9Sstevel@tonic-gate descriptor_t *
drive_get_descriptor_by_name(char * name,int * errp)4467c478bd9Sstevel@tonic-gate drive_get_descriptor_by_name(char *name, int *errp)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid;
4497c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
4507c478bd9Sstevel@tonic-gate 	descriptor_t	*drive = NULL;
4517c478bd9Sstevel@tonic-gate 	int		i;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
4547c478bd9Sstevel@tonic-gate 	    *errp = EINVAL;
4557c478bd9Sstevel@tonic-gate 	    return (NULL);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
4597c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
4607c478bd9Sstevel@tonic-gate 	    devid_free(devid);
4617c478bd9Sstevel@tonic-gate 	    return (NULL);
4627c478bd9Sstevel@tonic-gate 	}
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	/*
4657c478bd9Sstevel@tonic-gate 	 * We have to loop through all of them, freeing the ones we don't
4667c478bd9Sstevel@tonic-gate 	 * want.  Once drive is set, we don't need to compare any more.
4677c478bd9Sstevel@tonic-gate 	 */
4687c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
4697c478bd9Sstevel@tonic-gate 	    if (drive == NULL && drives[i]->p.disk->devid != NULL &&
4707c478bd9Sstevel@tonic-gate 		devid_compare(devid, drives[i]->p.disk->devid) == 0) {
4717c478bd9Sstevel@tonic-gate 		drive = drives[i];
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	    } else {
4747c478bd9Sstevel@tonic-gate 		/* clean up the unused descriptor */
4757c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
4767c478bd9Sstevel@tonic-gate 	    }
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	free(drives);
4797c478bd9Sstevel@tonic-gate 	devid_free(devid);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (drive == NULL) {
4827c478bd9Sstevel@tonic-gate 	    *errp = ENODEV;
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	return (drive);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate descriptor_t **
drive_get_descriptors(int filter[],int * errp)4897c478bd9Sstevel@tonic-gate drive_get_descriptors(int filter[], int *errp)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	descriptor_t	**drives;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	drives = cache_get_descriptors(DM_DRIVE, errp);
4947c478bd9Sstevel@tonic-gate 	if (*errp != 0) {
4957c478bd9Sstevel@tonic-gate 	    return (NULL);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (filter != NULL && filter[0] != DM_FILTER_END) {
4997c478bd9Sstevel@tonic-gate 	    descriptor_t	**found;
5007c478bd9Sstevel@tonic-gate 	    found = apply_filter(drives, filter, errp);
5017c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
5027c478bd9Sstevel@tonic-gate 		drives = NULL;
5037c478bd9Sstevel@tonic-gate 	    } else {
5047c478bd9Sstevel@tonic-gate 		drives = found;
5057c478bd9Sstevel@tonic-gate 	    }
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	return (drives);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate char *
drive_get_name(descriptor_t * dp)5127c478bd9Sstevel@tonic-gate drive_get_name(descriptor_t *dp)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	return (dp->p.disk->device_id);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate nvlist_t *
drive_get_stats(descriptor_t * dp,int stat_type,int * errp)5187c478bd9Sstevel@tonic-gate drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
5217c478bd9Sstevel@tonic-gate 	nvlist_t	*stats;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
5267c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
5277c478bd9Sstevel@tonic-gate 	    return (NULL);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_PERFORMANCE ||
5317c478bd9Sstevel@tonic-gate 	    stat_type == DM_DRV_STAT_DIAGNOSTIC) {
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	    alias_t	*ap;
5347c478bd9Sstevel@tonic-gate 	    kstat_ctl_t	*kc;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	    ap = diskp->aliases;
5377c478bd9Sstevel@tonic-gate 	    if (ap == NULL || ap->kstat_name == NULL) {
5387c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
5397c478bd9Sstevel@tonic-gate 		*errp = EACCES;
5407c478bd9Sstevel@tonic-gate 		return (NULL);
5417c478bd9Sstevel@tonic-gate 	    }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	    if ((kc = kstat_open()) == NULL) {
5447c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
5457c478bd9Sstevel@tonic-gate 		*errp = EACCES;
5467c478bd9Sstevel@tonic-gate 		return (NULL);
5477c478bd9Sstevel@tonic-gate 	    }
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	    while (ap != NULL) {
5507c478bd9Sstevel@tonic-gate 		int	status;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		if (ap->kstat_name == NULL) {
5537c478bd9Sstevel@tonic-gate 		    continue;
5547c478bd9Sstevel@tonic-gate 		}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		if (stat_type == DM_DRV_STAT_PERFORMANCE) {
5577c478bd9Sstevel@tonic-gate 		    status = get_io_kstats(kc, ap->kstat_name, stats);
5587c478bd9Sstevel@tonic-gate 		} else {
5597c478bd9Sstevel@tonic-gate 		    status = get_err_kstats(kc, ap->kstat_name, stats);
5607c478bd9Sstevel@tonic-gate 		}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 		if (status != 0) {
5637c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
5647c478bd9Sstevel@tonic-gate 		    (void) kstat_close(kc);
5657c478bd9Sstevel@tonic-gate 		    *errp = ENOMEM;
5667c478bd9Sstevel@tonic-gate 		    return (NULL);
5677c478bd9Sstevel@tonic-gate 		}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		ap = ap->next;
5707c478bd9Sstevel@tonic-gate 	    }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	    (void) kstat_close(kc);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	    *errp = 0;
5757c478bd9Sstevel@tonic-gate 	    return (stats);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (stat_type == DM_DRV_STAT_TEMPERATURE) {
5797c478bd9Sstevel@tonic-gate 	    int		fd;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	    if ((fd = drive_open_disk(diskp, NULL, 0)) >= 0) {
5827c478bd9Sstevel@tonic-gate 		struct dk_temperature	temp;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		if (ioctl(fd, DKIOCGTEMPERATURE, &temp) >= 0) {
5857c478bd9Sstevel@tonic-gate 		    if (nvlist_add_uint32(stats, DM_TEMPERATURE,
5867c478bd9Sstevel@tonic-gate 			temp.dkt_cur_temp) != 0) {
5877c478bd9Sstevel@tonic-gate 			*errp = ENOMEM;
5887c478bd9Sstevel@tonic-gate 			nvlist_free(stats);
5897c478bd9Sstevel@tonic-gate 			return (NULL);
5907c478bd9Sstevel@tonic-gate 		    }
5917c478bd9Sstevel@tonic-gate 		} else {
5927c478bd9Sstevel@tonic-gate 		    *errp = errno;
5937c478bd9Sstevel@tonic-gate 		    nvlist_free(stats);
5947c478bd9Sstevel@tonic-gate 		    return (NULL);
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 		(void) close(fd);
5977c478bd9Sstevel@tonic-gate 	    } else {
5987c478bd9Sstevel@tonic-gate 		*errp = errno;
5997c478bd9Sstevel@tonic-gate 		nvlist_free(stats);
6007c478bd9Sstevel@tonic-gate 		return (NULL);
6017c478bd9Sstevel@tonic-gate 	    }
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	    *errp = 0;
6047c478bd9Sstevel@tonic-gate 	    return (stats);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	nvlist_free(stats);
6087c478bd9Sstevel@tonic-gate 	*errp = EINVAL;
6097c478bd9Sstevel@tonic-gate 	return (NULL);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate int
drive_make_descriptors()6137c478bd9Sstevel@tonic-gate drive_make_descriptors()
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	int	error;
6167c478bd9Sstevel@tonic-gate 	disk_t	*dp;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	dp = cache_get_disklist();
6197c478bd9Sstevel@tonic-gate 	while (dp != NULL) {
6207c478bd9Sstevel@tonic-gate 	    cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
6217c478bd9Sstevel@tonic-gate 	    if (error != 0) {
6227c478bd9Sstevel@tonic-gate 		return (error);
6237c478bd9Sstevel@tonic-gate 	    }
6247c478bd9Sstevel@tonic-gate 	    dp = dp->next;
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	return (0);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate  * This function opens the disk generically (any slice).
6327c478bd9Sstevel@tonic-gate  */
6337c478bd9Sstevel@tonic-gate int
drive_open_disk(disk_t * diskp,char * opath,int len)6347c478bd9Sstevel@tonic-gate drive_open_disk(disk_t *diskp, char *opath, int len)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	/*
63718c2aff7Sartem 	 * Just open the first devpath.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
6407c478bd9Sstevel@tonic-gate 	    if (opath != NULL) {
6417c478bd9Sstevel@tonic-gate 		(void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
6427c478bd9Sstevel@tonic-gate 	    }
6437c478bd9Sstevel@tonic-gate 	    return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	return (-1);
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate static descriptor_t **
apply_filter(descriptor_t ** drives,int filter[],int * errp)6507c478bd9Sstevel@tonic-gate apply_filter(descriptor_t **drives, int filter[], int *errp)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	int		i;
6537c478bd9Sstevel@tonic-gate 	descriptor_t	**found;
6547c478bd9Sstevel@tonic-gate 	int		cnt;
6557c478bd9Sstevel@tonic-gate 	int		pos;
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/* count the number of drives in the snapshot */
6587c478bd9Sstevel@tonic-gate 	for (cnt = 0; drives[cnt]; cnt++);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
6617c478bd9Sstevel@tonic-gate 	if (found == NULL) {
6627c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
6637c478bd9Sstevel@tonic-gate 	    cache_free_descriptors(drives);
6647c478bd9Sstevel@tonic-gate 	    return (NULL);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	pos = 0;
6687c478bd9Sstevel@tonic-gate 	for (i = 0; drives[i]; i++) {
6697c478bd9Sstevel@tonic-gate 	    int j;
6707c478bd9Sstevel@tonic-gate 	    int match;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	    /* Make sure the drive type is set */
6737c478bd9Sstevel@tonic-gate 	    get_drive_type(drives[i]->p.disk, -1);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	    match = 0;
6767c478bd9Sstevel@tonic-gate 	    for (j = 0; filter[j] != DM_FILTER_END; j++) {
6777c478bd9Sstevel@tonic-gate 		if (drives[i]->p.disk->drv_type == filter[j]) {
6787c478bd9Sstevel@tonic-gate 		    found[pos++] = drives[i];
6797c478bd9Sstevel@tonic-gate 		    match = 1;
6807c478bd9Sstevel@tonic-gate 		    break;
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 	    }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	    if (!match) {
6857c478bd9Sstevel@tonic-gate 		cache_free_descriptor(drives[i]);
6867c478bd9Sstevel@tonic-gate 	    }
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 	found[pos] = NULL;
6897c478bd9Sstevel@tonic-gate 	free(drives);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	*errp = 0;
6927c478bd9Sstevel@tonic-gate 	return (found);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate static int
conv_drive_type(uint_t drive_type)6967c478bd9Sstevel@tonic-gate conv_drive_type(uint_t drive_type)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	switch (drive_type) {
6997c478bd9Sstevel@tonic-gate 	case DK_UNKNOWN:
7007c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
7017c478bd9Sstevel@tonic-gate 	case DK_MO_ERASABLE:
7027c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_ERASABLE);
7037c478bd9Sstevel@tonic-gate 	case DK_MO_WRITEONCE:
7047c478bd9Sstevel@tonic-gate 	    return (DM_DT_MO_WRITEONCE);
7057c478bd9Sstevel@tonic-gate 	case DK_AS_MO:
7067c478bd9Sstevel@tonic-gate 	    return (DM_DT_AS_MO);
7077c478bd9Sstevel@tonic-gate 	case DK_CDROM:
7087c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDROM);
7097c478bd9Sstevel@tonic-gate 	case DK_CDR:
7107c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDR);
7117c478bd9Sstevel@tonic-gate 	case DK_CDRW:
7127c478bd9Sstevel@tonic-gate 	    return (DM_DT_CDRW);
7137c478bd9Sstevel@tonic-gate 	case DK_DVDROM:
7147c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDROM);
7157c478bd9Sstevel@tonic-gate 	case DK_DVDR:
7167c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDR);
7177c478bd9Sstevel@tonic-gate 	case DK_DVDRAM:
7187c478bd9Sstevel@tonic-gate 	    return (DM_DT_DVDRAM);
7197c478bd9Sstevel@tonic-gate 	case DK_FIXED_DISK:
7207c478bd9Sstevel@tonic-gate 	    return (DM_DT_FIXED);
7217c478bd9Sstevel@tonic-gate 	case DK_FLOPPY:
7227c478bd9Sstevel@tonic-gate 	    return (DM_DT_FLOPPY);
7237c478bd9Sstevel@tonic-gate 	case DK_ZIP:
7247c478bd9Sstevel@tonic-gate 	    return (DM_DT_ZIP);
7257c478bd9Sstevel@tonic-gate 	case DK_JAZ:
7267c478bd9Sstevel@tonic-gate 	    return (DM_DT_JAZ);
7277c478bd9Sstevel@tonic-gate 	default:
7287c478bd9Sstevel@tonic-gate 	    return (DM_DT_UNKNOWN);
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate static descriptor_t **
get_assoc_alias(disk_t * diskp,int * errp)7337c478bd9Sstevel@tonic-gate get_assoc_alias(disk_t *diskp, int *errp)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	alias_t		*aliasp;
7367c478bd9Sstevel@tonic-gate 	uint_t		cnt;
7377c478bd9Sstevel@tonic-gate 	descriptor_t	**out_array;
7387c478bd9Sstevel@tonic-gate 	int		pos;
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	*errp = 0;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
7437c478bd9Sstevel@tonic-gate 	cnt = 0;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
7467c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
7477c478bd9Sstevel@tonic-gate 		cnt++;
7487c478bd9Sstevel@tonic-gate 	    }
7497c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/* set up the new array */
7537c478bd9Sstevel@tonic-gate 	out_array = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t));
7547c478bd9Sstevel@tonic-gate 	if (out_array == NULL) {
7557c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
7567c478bd9Sstevel@tonic-gate 	    return (NULL);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	aliasp = diskp->aliases;
7607c478bd9Sstevel@tonic-gate 	pos = 0;
7617c478bd9Sstevel@tonic-gate 	while (aliasp != NULL) {
7627c478bd9Sstevel@tonic-gate 	    if (aliasp->alias != NULL) {
7637c478bd9Sstevel@tonic-gate 		out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
7647c478bd9Sstevel@tonic-gate 		    aliasp->alias, NULL, errp);
7657c478bd9Sstevel@tonic-gate 		if (*errp != 0) {
7667c478bd9Sstevel@tonic-gate 		    cache_free_descriptors(out_array);
7677c478bd9Sstevel@tonic-gate 		    return (NULL);
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 	    }
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	    aliasp = aliasp->next;
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	out_array[pos] = NULL;
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	return (out_array);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate static descriptor_t **
get_assoc_controllers(descriptor_t * dp,int * errp)7807c478bd9Sstevel@tonic-gate get_assoc_controllers(descriptor_t *dp, int *errp)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	disk_t		*diskp;
7837c478bd9Sstevel@tonic-gate 	int		cnt;
7847c478bd9Sstevel@tonic-gate 	descriptor_t	**controllers;
7857c478bd9Sstevel@tonic-gate 	int		i;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	diskp = dp->p.disk;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
7907c478bd9Sstevel@tonic-gate 	for (cnt = 0; diskp->controllers[cnt]; cnt++);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/* make the snapshot */
7937c478bd9Sstevel@tonic-gate 	controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
7947c478bd9Sstevel@tonic-gate 	if (controllers == NULL) {
7957c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
7967c478bd9Sstevel@tonic-gate 	    return (NULL);
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	for (i = 0; diskp->controllers[i]; i++) {
8007c478bd9Sstevel@tonic-gate 	    controllers[i] = cache_get_desc(DM_CONTROLLER,
8017c478bd9Sstevel@tonic-gate 		diskp->controllers[i], NULL, NULL, errp);
8027c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
8037c478bd9Sstevel@tonic-gate 		cache_free_descriptors(controllers);
8047c478bd9Sstevel@tonic-gate 		return (NULL);
8057c478bd9Sstevel@tonic-gate 	    }
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	controllers[i] = NULL;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	*errp = 0;
8117c478bd9Sstevel@tonic-gate 	return (controllers);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate static descriptor_t **
get_assoc_paths(descriptor_t * dp,int * errp)8157c478bd9Sstevel@tonic-gate get_assoc_paths(descriptor_t *dp, int *errp)
8167c478bd9Sstevel@tonic-gate {
8177c478bd9Sstevel@tonic-gate 	path_t		**pp;
8187c478bd9Sstevel@tonic-gate 	int		cnt;
8197c478bd9Sstevel@tonic-gate 	descriptor_t	**paths;
8207c478bd9Sstevel@tonic-gate 	int		i;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	pp = dp->p.disk->paths;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	/* Count how many we have. */
8257c478bd9Sstevel@tonic-gate 	cnt = 0;
8267c478bd9Sstevel@tonic-gate 	if (pp != NULL) {
8277c478bd9Sstevel@tonic-gate 	    for (; pp[cnt]; cnt++);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	/* make the snapshot */
8317c478bd9Sstevel@tonic-gate 	paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
8327c478bd9Sstevel@tonic-gate 	if (paths == NULL) {
8337c478bd9Sstevel@tonic-gate 	    *errp = ENOMEM;
8347c478bd9Sstevel@tonic-gate 	    return (NULL);
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	/*
8387c478bd9Sstevel@tonic-gate 	 * We fill in the name field of the descriptor with the device_id
8397c478bd9Sstevel@tonic-gate 	 * when we deal with path descriptors originating from a drive.
8407c478bd9Sstevel@tonic-gate 	 * In that way we can use the device id within the path code to
8417c478bd9Sstevel@tonic-gate 	 * lookup the path state for this drive.
8427c478bd9Sstevel@tonic-gate 	 */
8437c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
8447c478bd9Sstevel@tonic-gate 	    paths[i] = cache_get_desc(DM_PATH, pp[i], dp->p.disk->device_id,
8457c478bd9Sstevel@tonic-gate 		NULL, errp);
8467c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
8477c478bd9Sstevel@tonic-gate 		cache_free_descriptors(paths);
8487c478bd9Sstevel@tonic-gate 		return (NULL);
8497c478bd9Sstevel@tonic-gate 	    }
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	paths[i] = NULL;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	*errp = 0;
8557c478bd9Sstevel@tonic-gate 	return (paths);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate static int
get_attrs(disk_t * diskp,int fd,char * opath,nvlist_t * attrs)8597c478bd9Sstevel@tonic-gate get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs)
8607c478bd9Sstevel@tonic-gate {
8617c478bd9Sstevel@tonic-gate 	if (diskp->removable) {
8627c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
8657c478bd9Sstevel@tonic-gate 		return (ENOMEM);
8667c478bd9Sstevel@tonic-gate 	    }
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	    /* Make sure media is inserted and spun up. */
8697c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
8707c478bd9Sstevel@tonic-gate 		if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
8717c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 	    }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	    /* can't tell diff between dead & no media on removable drives */
8767c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
8777c478bd9Sstevel@tonic-gate 		return (ENOMEM);
8787c478bd9Sstevel@tonic-gate 	    }
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	} else {
8837c478bd9Sstevel@tonic-gate 	    struct dk_minfo	minfo;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	    /* check if the fixed drive is up or not */
8867c478bd9Sstevel@tonic-gate 	    if (fd >= 0 && media_read_info(fd, &minfo)) {
8877c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
8887c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8897c478bd9Sstevel@tonic-gate 		}
8907c478bd9Sstevel@tonic-gate 	    } else {
8917c478bd9Sstevel@tonic-gate 		if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
8927c478bd9Sstevel@tonic-gate 		    return (ENOMEM);
8937c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 	    }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	    get_drive_type(diskp, fd);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
9007c478bd9Sstevel@tonic-gate 	    return (ENOMEM);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	if (diskp->product_id != NULL) {
9047c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
9057c478bd9Sstevel@tonic-gate 		!= 0) {
9067c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9077c478bd9Sstevel@tonic-gate 	    }
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 	if (diskp->vendor_id != NULL) {
9107c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
9117c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9127c478bd9Sstevel@tonic-gate 	    }
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (diskp->sync_speed != -1) {
9167c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
9177c478bd9Sstevel@tonic-gate 		!= 0) {
9187c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9197c478bd9Sstevel@tonic-gate 	    }
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	if (diskp->wide == 1) {
9237c478bd9Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
9247c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9257c478bd9Sstevel@tonic-gate 	    }
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if (diskp->rpm == 0) {
9297c478bd9Sstevel@tonic-gate 	    diskp->rpm = get_rpm(diskp, fd);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	if (diskp->rpm > 0) {
9337c478bd9Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) {
9347c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9357c478bd9Sstevel@tonic-gate 	    }
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (strlen(opath) > 0) {
9397c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
9407c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9417c478bd9Sstevel@tonic-gate 	    }
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
94459d8f100SGarrett D'Amore 	if (diskp->solid_state < 0) {
94559d8f100SGarrett D'Amore 		diskp->solid_state = get_solidstate(diskp, fd);
94659d8f100SGarrett D'Amore 	}
94759d8f100SGarrett D'Amore 
94859d8f100SGarrett D'Amore 	if (diskp->solid_state > 0) {
94959d8f100SGarrett D'Amore 		if (nvlist_add_boolean(attrs, DM_SOLIDSTATE) != 0) {
95059d8f100SGarrett D'Amore 			return (ENOMEM);
95159d8f100SGarrett D'Amore 		}
95259d8f100SGarrett D'Amore 	}
95359d8f100SGarrett D'Amore 
9547c478bd9Sstevel@tonic-gate 	return (0);
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate static int
get_disk_kstats(kstat_ctl_t * kc,char * diskname,char * classname,nvlist_t * stats)9587c478bd9Sstevel@tonic-gate get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
9597c478bd9Sstevel@tonic-gate 	nvlist_t *stats)
9607c478bd9Sstevel@tonic-gate {
9617c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
9627c478bd9Sstevel@tonic-gate 	size_t		class_len;
9637c478bd9Sstevel@tonic-gate 	int		err = 0;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	class_len = strlen(classname);
9667c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
9677c478bd9Sstevel@tonic-gate 	    if (strncmp(ksp->ks_class, classname, class_len) == 0) {
9687c478bd9Sstevel@tonic-gate 		char	kstat_name[KSTAT_STRLEN];
9697c478bd9Sstevel@tonic-gate 		char	*dname = kstat_name;
9707c478bd9Sstevel@tonic-gate 		char	*ename = ksp->ks_name;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		/* names are format: "sd0,err" - copy chars up to comma */
9737c478bd9Sstevel@tonic-gate 		while (*ename && *ename != ',') {
9747c478bd9Sstevel@tonic-gate 		    *dname++ = *ename++;
9757c478bd9Sstevel@tonic-gate 		}
976*bd401f05SToomas Soome 		*dname = '\0';
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		if (libdiskmgt_str_eq(diskname, kstat_name)) {
9797c478bd9Sstevel@tonic-gate 		    (void) kstat_read(kc, ksp, NULL);
9807c478bd9Sstevel@tonic-gate 		    err = get_kstat_vals(ksp, stats);
9817c478bd9Sstevel@tonic-gate 		    break;
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 	    }
9847c478bd9Sstevel@tonic-gate 	}
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	return (err);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate  * Getting the drive type depends on if the dev tree walk indicated that the
9917c478bd9Sstevel@tonic-gate  * drive was a CD-ROM or not.  The kernal lumps all of the removable multi-media
9927c478bd9Sstevel@tonic-gate  * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
9937c478bd9Sstevel@tonic-gate  * a uscsi cmd to check the drive type.
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static void
get_drive_type(disk_t * dp,int fd)9967c478bd9Sstevel@tonic-gate get_drive_type(disk_t *dp, int fd)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	if (dp->drv_type == DM_DT_UNKNOWN) {
9997c478bd9Sstevel@tonic-gate 	    int	opened_here = 0;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	    /* We may have already opened the device. */
10027c478bd9Sstevel@tonic-gate 	    if (fd < 0) {
10037c478bd9Sstevel@tonic-gate 		fd = drive_open_disk(dp, NULL, 0);
10047c478bd9Sstevel@tonic-gate 		opened_here = 1;
10057c478bd9Sstevel@tonic-gate 	    }
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	    if (fd >= 0) {
10087c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
10097c478bd9Sstevel@tonic-gate 		    /* use uscsi to determine drive type */
10107c478bd9Sstevel@tonic-gate 		    dp->drv_type = get_cdrom_drvtype(fd);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 		    /* if uscsi fails, just call it a cd-rom */
10137c478bd9Sstevel@tonic-gate 		    if (dp->drv_type == DM_DT_UNKNOWN) {
10147c478bd9Sstevel@tonic-gate 			dp->drv_type = DM_DT_CDROM;
10157c478bd9Sstevel@tonic-gate 		    }
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 		} else {
10187c478bd9Sstevel@tonic-gate 		    struct dk_minfo	minfo;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 		    if (media_read_info(fd, &minfo)) {
10217c478bd9Sstevel@tonic-gate 			dp->drv_type = conv_drive_type(minfo.dki_media_type);
10227c478bd9Sstevel@tonic-gate 		    }
10237c478bd9Sstevel@tonic-gate 		}
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 		if (opened_here) {
10267c478bd9Sstevel@tonic-gate 		    (void) close(fd);
10277c478bd9Sstevel@tonic-gate 		}
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	    } else {
10307c478bd9Sstevel@tonic-gate 		/* couldn't open */
10317c478bd9Sstevel@tonic-gate 		if (dp->cd_rom) {
10327c478bd9Sstevel@tonic-gate 		    dp->drv_type = DM_DT_CDROM;
10337c478bd9Sstevel@tonic-gate 		}
10347c478bd9Sstevel@tonic-gate 	    }
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate static char *
get_err_attr_name(char * kstat_name)10397c478bd9Sstevel@tonic-gate get_err_attr_name(char *kstat_name)
10407c478bd9Sstevel@tonic-gate {
10417c478bd9Sstevel@tonic-gate 	int	i;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	for (i = 0; kstat_err_names[i] != NULL; i++) {
10447c478bd9Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(kstat_name, kstat_err_names[i])) {
10457c478bd9Sstevel@tonic-gate 		return (err_attr_names[i]);
10467c478bd9Sstevel@tonic-gate 	    }
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	return (NULL);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate static int
get_err_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)10537c478bd9Sstevel@tonic-gate get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate static int
get_io_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)10597c478bd9Sstevel@tonic-gate get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
10607c478bd9Sstevel@tonic-gate {
10617c478bd9Sstevel@tonic-gate 	return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate static int
get_kstat_vals(kstat_t * ksp,nvlist_t * stats)10657c478bd9Sstevel@tonic-gate get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate 	if (ksp->ks_type == KSTAT_TYPE_IO) {
10687c478bd9Sstevel@tonic-gate 	    kstat_io_t *kiop;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	    kiop = KSTAT_IO_PTR(ksp);
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	    /* see sys/kstat.h kstat_io_t struct for more fields */
1073