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 */
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) {
10757c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10767c478bd9Sstevel@tonic-gate 	    }
10777c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
10787c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10797c478bd9Sstevel@tonic-gate 	    }
10807c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
10817c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10827c478bd9Sstevel@tonic-gate 	    }
10837c478bd9Sstevel@tonic-gate 	    if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
10847c478bd9Sstevel@tonic-gate 		return (ENOMEM);
10857c478bd9Sstevel@tonic-gate 	    }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	} else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
10887c478bd9Sstevel@tonic-gate 	    kstat_named_t *knp;
10897c478bd9Sstevel@tonic-gate 	    int		i;
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	    knp = KSTAT_NAMED_PTR(ksp);
10927c478bd9Sstevel@tonic-gate 	    for (i = 0; i < ksp->ks_ndata; i++) {
10937c478bd9Sstevel@tonic-gate 		char	*attr_name;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 		if (knp[i].name[0] == 0)
10967c478bd9Sstevel@tonic-gate 		    continue;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
10997c478bd9Sstevel@tonic-gate 		    continue;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 		}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 		switch (knp[i].data_type) {
11047c478bd9Sstevel@tonic-gate 		case KSTAT_DATA_UINT32:
11057c478bd9Sstevel@tonic-gate 		    if (update_stat32(stats, attr_name, knp[i].value.ui32)
11067c478bd9Sstevel@tonic-gate 			!= 0) {
11077c478bd9Sstevel@tonic-gate 			return (ENOMEM);
11087c478bd9Sstevel@tonic-gate 		    }
11097c478bd9Sstevel@tonic-gate 		    break;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 		default:
11127c478bd9Sstevel@tonic-gate 		    /* Right now all of the error types are uint32 */
11137c478bd9Sstevel@tonic-gate 		    break;
11147c478bd9Sstevel@tonic-gate 		}
11157c478bd9Sstevel@tonic-gate 	    }
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 	return (0);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate static int
update_stat32(nvlist_t * stats,char * attr,uint32_t value)11217c478bd9Sstevel@tonic-gate update_stat32(nvlist_t *stats, char *attr, uint32_t value)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	int32_t	currval;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
11267c478bd9Sstevel@tonic-gate 	    value += currval;
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint32(stats, attr, value));
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate  * There can be more than one kstat value when we have multi-path drives
11347c478bd9Sstevel@tonic-gate  * that are not under mpxio (since there is more than one kstat name for
11357c478bd9Sstevel@tonic-gate  * the drive in this case).  So, we may have merge all of the kstat values
11367c478bd9Sstevel@tonic-gate  * to give an accurate set of stats for the drive.
11377c478bd9Sstevel@tonic-gate  */
11387c478bd9Sstevel@tonic-gate static int
update_stat64(nvlist_t * stats,char * attr,uint64_t value)11397c478bd9Sstevel@tonic-gate update_stat64(nvlist_t *stats, char *attr, uint64_t value)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	int64_t	currval;
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
11447c478bd9Sstevel@tonic-gate 	    value += currval;
11457c478bd9Sstevel@tonic-gate 	}
11467c478bd9Sstevel@tonic-gate 	return (nvlist_add_uint64(stats, attr, value));
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate /*
11507c478bd9Sstevel@tonic-gate  * uscsi function to get the rpm of the drive
11517c478bd9Sstevel@tonic-gate  */
11527c478bd9Sstevel@tonic-gate static int
get_rpm(disk_t * dp,int fd)11537c478bd9Sstevel@tonic-gate get_rpm(disk_t *dp, int fd)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate 	int	opened_here = 0;
11567c478bd9Sstevel@tonic-gate 	int	rpm = -1;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	/* We may have already opened the device. */
11597c478bd9Sstevel@tonic-gate 	if (fd < 0) {
11607c478bd9Sstevel@tonic-gate 	    fd = drive_open_disk(dp, NULL, 0);
11617c478bd9Sstevel@tonic-gate 	    opened_here = 1;
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
11657c478bd9Sstevel@tonic-gate 	    int				status;
11667c478bd9Sstevel@tonic-gate 	    struct mode_geometry	*page4;
11677c478bd9Sstevel@tonic-gate 	    struct scsi_ms_header	header;
11687c478bd9Sstevel@tonic-gate 	    union {
11697c478bd9Sstevel@tonic-gate 		struct mode_geometry	page4;
11707c478bd9Sstevel@tonic-gate 		char			rawbuf[MAX_MODE_SENSE_SIZE];
11717c478bd9Sstevel@tonic-gate 	    } u_page4;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	    page4 = &u_page4.page4;
11747c478bd9Sstevel@tonic-gate 	    (void) memset(&u_page4, 0, sizeof (u_page4));
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	    status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11777c478bd9Sstevel@tonic-gate 		MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11787c478bd9Sstevel@tonic-gate 		&header);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	    if (status) {
11817c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11827c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11837c478bd9Sstevel@tonic-gate 		    &header);
11847c478bd9Sstevel@tonic-gate 	    }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	    if (status) {
11877c478bd9Sstevel@tonic-gate 		status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
11887c478bd9Sstevel@tonic-gate 		    MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
11897c478bd9Sstevel@tonic-gate 		    &header);
11907c478bd9Sstevel@tonic-gate 	    }
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	    if (!status) {
11937c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
11947c478bd9Sstevel@tonic-gate 		page4->rpm = ntohs(page4->rpm);
11957c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 		rpm = page4->rpm;
11987c478bd9Sstevel@tonic-gate 	    }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	    if (opened_here) {
12017c478bd9Sstevel@tonic-gate 		(void) close(fd);
12027c478bd9Sstevel@tonic-gate 	    }
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	return (rpm);
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate 
120859d8f100SGarrett D'Amore static int
get_solidstate(disk_t * dp,int fd)120959d8f100SGarrett D'Amore get_solidstate(disk_t *dp, int fd)
121059d8f100SGarrett D'Amore {
121159d8f100SGarrett D'Amore 	int	opened_here = 0;
121259d8f100SGarrett D'Amore 	int	solid_state = -1;
121359d8f100SGarrett D'Amore 
121459d8f100SGarrett D'Amore 	/* We may have already opened the device. */
121559d8f100SGarrett D'Amore 	if (fd < 0) {
121659d8f100SGarrett D'Amore 		fd = drive_open_disk(dp, NULL, 0);
121759d8f100SGarrett D'Amore 		opened_here = 1;
121859d8f100SGarrett D'Amore 	}
121959d8f100SGarrett D'Amore 
122059d8f100SGarrett D'Amore 	if (fd >= 0) {
122159d8f100SGarrett D'Amore 		if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
122259d8f100SGarrett D'Amore 			solid_state = -1;
122359d8f100SGarrett D'Amore 		}
122459d8f100SGarrett D'Amore 	}
122559d8f100SGarrett D'Amore 
122659d8f100SGarrett D'Amore 	if (opened_here) {
122759d8f100SGarrett D'Amore 		(void) close(fd);
122859d8f100SGarrett D'Amore 	}
122959d8f100SGarrett D'Amore 
123059d8f100SGarrett D'Amore 	return (solid_state);
123159d8f100SGarrett D'Amore }
123259d8f100SGarrett D'Amore 
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate  *	******** the rest of this is uscsi stuff for the drv type ********
12357c478bd9Sstevel@tonic-gate  */
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate  * We try a get_configuration uscsi cmd.  If that fails, try a
12397c478bd9Sstevel@tonic-gate  * atapi_capabilities cmd.  If both fail then this is an older CD-ROM.
12407c478bd9Sstevel@tonic-gate  */
12417c478bd9Sstevel@tonic-gate static int
get_cdrom_drvtype(int fd)12427c478bd9Sstevel@tonic-gate get_cdrom_drvtype(int fd)
12437c478bd9Sstevel@tonic-gate {
12447c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
12457c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
12467c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	fill_general_page_cdb_g1(&cdb, SCMD_GET_CONFIGURATION, 0,
12497c478bd9Sstevel@tonic-gate 	    b0(sizeof (buff)), b1(sizeof (buff)));
12507c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
12537c478bd9Sstevel@tonic-gate 	    struct get_configuration	*config;
12547c478bd9Sstevel@tonic-gate 	    struct conf_feature		*feature;
12557c478bd9Sstevel@tonic-gate 	    int				flen;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	    /* The first profile is the preferred one for the drive. */
12587c478bd9Sstevel@tonic-gate 	    config = (struct get_configuration *)buff;
12597c478bd9Sstevel@tonic-gate 	    feature = &config->feature;
12607c478bd9Sstevel@tonic-gate 	    flen = feature->len / sizeof (struct profile_list);
12617c478bd9Sstevel@tonic-gate 	    if (flen > 0) {
12627c478bd9Sstevel@tonic-gate 		int prof_num;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		prof_num = (int)convnum(feature->features.plist[0].profile, 2);
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		if (dm_debug > 1) {
12677c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
12687c478bd9Sstevel@tonic-gate 			prof_num);
12697c478bd9Sstevel@tonic-gate 		}
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 		switch (prof_num) {
12727c478bd9Sstevel@tonic-gate 		case PROF_MAGNETO_OPTICAL:
12737c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_ERASABLE);
12747c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_WO:
12757c478bd9Sstevel@tonic-gate 		    return (DM_DT_MO_WRITEONCE);
12767c478bd9Sstevel@tonic-gate 		case PROF_OPTICAL_ASMO:
12777c478bd9Sstevel@tonic-gate 		    return (DM_DT_AS_MO);
12787c478bd9Sstevel@tonic-gate 		case PROF_CDROM:
12797c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDROM);
12807c478bd9Sstevel@tonic-gate 		case PROF_CDR:
12817c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDR);
12827c478bd9Sstevel@tonic-gate 		case PROF_CDRW:
12837c478bd9Sstevel@tonic-gate 		    return (DM_DT_CDRW);
12847c478bd9Sstevel@tonic-gate 		case PROF_DVDROM:
12857c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDROM);
12867c478bd9Sstevel@tonic-gate 		case PROF_DVDRAM:
12877c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRAM);
12887c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_REST:
12897c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12907c478bd9Sstevel@tonic-gate 		case PROF_DVDRW_SEQ:
12917c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12927c478bd9Sstevel@tonic-gate 		case PROF_DVDRW:
12937c478bd9Sstevel@tonic-gate 		    return (DM_DT_DVDRW);
12947c478bd9Sstevel@tonic-gate 		case PROF_DDCD_ROM:
12957c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDROM);
12967c478bd9Sstevel@tonic-gate 		case PROF_DDCD_R:
12977c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDR);
12987c478bd9Sstevel@tonic-gate 		case PROF_DDCD_RW:
12997c478bd9Sstevel@tonic-gate 		    return (DM_DT_DDCDRW);
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 	    }
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	/* see if the atapi capabilities give anything */
13057c478bd9Sstevel@tonic-gate 	return (check_atapi(fd));
13067c478bd9Sstevel@tonic-gate }
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate static int
check_atapi(int fd)13097c478bd9Sstevel@tonic-gate check_atapi(int fd)
13107c478bd9Sstevel@tonic-gate {
13117c478bd9Sstevel@tonic-gate 	union scsi_cdb cdb;
13127c478bd9Sstevel@tonic-gate 	struct uscsi_cmd cmd;
13137c478bd9Sstevel@tonic-gate 	uchar_t buff[SCSIBUFLEN];
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES);
13167c478bd9Sstevel@tonic-gate 	fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	if (ioctl(fd, USCSICMD, &cmd) >= 0) {
13197c478bd9Sstevel@tonic-gate 	    int			bdesclen;
13207c478bd9Sstevel@tonic-gate 	    struct capabilities	*cap;
13217c478bd9Sstevel@tonic-gate 	    struct mode_header_g2 *mode;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	    mode = (struct mode_header_g2 *)buff;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	    bdesclen = (int)convnum(mode->desclen, 2);
13267c478bd9Sstevel@tonic-gate 	    cap = (struct capabilities *)
13277c478bd9Sstevel@tonic-gate 		&buff[sizeof (struct mode_header_g2) + bdesclen];
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	    if (dm_debug > 1) {
13307c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "INFO: uscsi atapi capabilities\n");
13317c478bd9Sstevel@tonic-gate 	    }
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	    /* These are in order of how we want to report the drv type. */
13347c478bd9Sstevel@tonic-gate 	    if (cap->dvdram_write) {
13357c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDRAM);
13367c478bd9Sstevel@tonic-gate 	    }
13377c478bd9Sstevel@tonic-gate 	    if (cap->dvdr_write) {
13387c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDR);
13397c478bd9Sstevel@tonic-gate 	    }
13407c478bd9Sstevel@tonic-gate 	    if (cap->dvdrom_read) {
13417c478bd9Sstevel@tonic-gate 		return (DM_DT_DVDROM);
13427c478bd9Sstevel@tonic-gate 	    }
13437c478bd9Sstevel@tonic-gate 	    if (cap->cdrw_write) {
13447c478bd9Sstevel@tonic-gate 		return (DM_DT_CDRW);
13457c478bd9Sstevel@tonic-gate 	    }
13467c478bd9Sstevel@tonic-gate 	    if (cap->cdr_write) {
13477c478bd9Sstevel@tonic-gate 		return (DM_DT_CDR);
13487c478bd9Sstevel@tonic-gate 	    }
13497c478bd9Sstevel@tonic-gate 	    if (cap->cdr_read) {
13507c478bd9Sstevel@tonic-gate 		return (DM_DT_CDROM);
13517c478bd9Sstevel@tonic-gate 	    }
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	/* everything failed, so this is an older CD-ROM */
13557c478bd9Sstevel@tonic-gate 	if (dm_debug > 1) {
13567c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "INFO: uscsi failed\n");
13577c478bd9Sstevel@tonic-gate 	}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	return (DM_DT_CDROM);
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate static uint64_t
convnum(uchar_t * nptr,int len)13637c478bd9Sstevel@tonic-gate convnum(uchar_t *nptr, int len)
13647c478bd9Sstevel@tonic-gate {
13657c478bd9Sstevel@tonic-gate 	uint64_t value;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	for (value = 0; len > 0; len--, nptr++)
13687c478bd9Sstevel@tonic-gate 		value = (value << 8) | *nptr;
13697c478bd9Sstevel@tonic-gate 	return (value);
13707c478bd9Sstevel@tonic-gate }
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate static void
fill_command_g1(struct uscsi_cmd * cmd,union scsi_cdb * cdb,caddr_t buff,int blen)13737c478bd9Sstevel@tonic-gate fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb,
13747c478bd9Sstevel@tonic-gate 	caddr_t buff, int blen)
13757c478bd9Sstevel@tonic-gate {
13767c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cmd, sizeof (struct uscsi_cmd));
13777c478bd9Sstevel@tonic-gate 	bzero(buff, blen);
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdb = (caddr_t)cdb;
13807c478bd9Sstevel@tonic-gate 	cmd->uscsi_cdblen = CDB_GROUP1;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	cmd->uscsi_bufaddr = buff;
13837c478bd9Sstevel@tonic-gate 	cmd->uscsi_buflen = blen;
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ;
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate static void
fill_general_page_cdb_g1(union scsi_cdb * cdb,int command,int lun,uchar_t c0,uchar_t c1)13897c478bd9Sstevel@tonic-gate fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun,
13907c478bd9Sstevel@tonic-gate 	uchar_t c0, uchar_t c1)
13917c478bd9Sstevel@tonic-gate {
13927c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
13937c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = command;
13947c478bd9Sstevel@tonic-gate 	cdb->scc_lun = lun;
13957c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = c0; /* max length for page */
13967c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = c1; /* max length for page */
13977c478bd9Sstevel@tonic-gate }
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate static void
fill_mode_page_cdb(union scsi_cdb * cdb,int page)14007c478bd9Sstevel@tonic-gate fill_mode_page_cdb(union scsi_cdb *cdb, int page)
14017c478bd9Sstevel@tonic-gate {
14027c478bd9Sstevel@tonic-gate 	/* group 1 mode page */
14037c478bd9Sstevel@tonic-gate 	bzero((caddr_t)cdb, sizeof (union scsi_cdb));
14047c478bd9Sstevel@tonic-gate 	cdb->scc_cmd = SCMD_MODE_SENSE_G1;
14057c478bd9Sstevel@tonic-gate 	cdb->g1_count0 = 0xff; /* max length for mode page */
14067c478bd9Sstevel@tonic-gate 	cdb->g1_count1 = 0xff; /* max length for mode page */
14077c478bd9Sstevel@tonic-gate 	cdb->g1_addr3 = page;
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate static int
uscsi_mode_sense(int fd,int page_code,int page_control,caddr_t page_data,int page_size,struct scsi_ms_header * header)14117c478bd9Sstevel@tonic-gate uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
14127c478bd9Sstevel@tonic-gate 	int page_size, struct  scsi_ms_header *header)
14137c478bd9Sstevel@tonic-gate {
14147c478bd9Sstevel@tonic-gate 	caddr_t			mode_sense_buf;
14157c478bd9Sstevel@tonic-gate 	struct mode_header	*hdr;
14167c478bd9Sstevel@tonic-gate 	struct mode_page	*pg;
14177c478bd9Sstevel@tonic-gate 	int			nbytes;
14187c478bd9Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
14197c478bd9Sstevel@tonic-gate 	union scsi_cdb		cdb;
14207c478bd9Sstevel@tonic-gate 	int			status;
14217c478bd9Sstevel@tonic-gate 	int			maximum;
14227c478bd9Sstevel@tonic-gate 	char			rqbuf[255];
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	/*
14257c478bd9Sstevel@tonic-gate 	 * Allocate a buffer for the mode sense headers
14267c478bd9Sstevel@tonic-gate 	 * and mode sense data itself.
14277c478bd9Sstevel@tonic-gate 	 */
14287c478bd9Sstevel@tonic-gate 	nbytes = sizeof (struct block_descriptor) +
14297c478bd9Sstevel@tonic-gate 				sizeof (struct mode_header) + page_size;
14307c478bd9Sstevel@tonic-gate 	nbytes = page_size;
14317c478bd9Sstevel@tonic-gate 	if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
14327c478bd9Sstevel@tonic-gate 	    return (-1);
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	/*
14367c478bd9Sstevel@tonic-gate 	 * Build and execute the uscsi ioctl
14377c478bd9Sstevel@tonic-gate 	 */
14387c478bd9Sstevel@tonic-gate 	(void) memset(mode_sense_buf, 0, nbytes);
14397c478bd9Sstevel@tonic-gate 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
14407c478bd9Sstevel@tonic-gate 	(void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
14437c478bd9Sstevel@tonic-gate 	FORMG0COUNT(&cdb, (uchar_t)nbytes);
14447c478bd9Sstevel@tonic-gate 	cdb.cdb_opaque[2] = page_control | page_code;
14457c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
14467c478bd9Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
14477c478bd9Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = mode_sense_buf;
14487c478bd9Sstevel@tonic-gate 	ucmd.uscsi_buflen = nbytes;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_SILENT;
14517c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_READ;
14527c478bd9Sstevel@tonic-gate 	ucmd.uscsi_timeout = 30;
14537c478bd9Sstevel@tonic-gate 	ucmd.uscsi_flags |= USCSI_RQENABLE;
14547c478bd9Sstevel@tonic-gate 	if (ucmd.uscsi_rqbuf == NULL)  {
14557c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqbuf = rqbuf;
14567c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqlen = sizeof (rqbuf);
14577c478bd9Sstevel@tonic-gate 	    ucmd.uscsi_rqresid = sizeof (rqbuf);
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 	ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	status = ioctl(fd, USCSICMD, &ucmd);
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if (status || ucmd.uscsi_status != 0) {
14647c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14657c478bd9Sstevel@tonic-gate 	    return (-1);
14667c478bd9Sstevel@tonic-gate 	}
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	/*
14697c478bd9Sstevel@tonic-gate 	 * Verify that the returned data looks reasonabled,
14707c478bd9Sstevel@tonic-gate 	 * find the actual page data, and copy it into the
14717c478bd9Sstevel@tonic-gate 	 * user's buffer.  Copy the mode_header and block_descriptor
14727c478bd9Sstevel@tonic-gate 	 * into the header structure, which can then be used to
14737c478bd9Sstevel@tonic-gate 	 * return the same data to the drive when issuing a mode select.
14747c478bd9Sstevel@tonic-gate 	 */
14757c478bd9Sstevel@tonic-gate 	hdr = (struct mode_header *)mode_sense_buf;
14767c478bd9Sstevel@tonic-gate 	(void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
14777c478bd9Sstevel@tonic-gate 	if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
14787c478bd9Sstevel@tonic-gate 	    hdr->bdesc_length != 0) {
14797c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14807c478bd9Sstevel@tonic-gate 	    return (-1);
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 	(void) memcpy((caddr_t)header, mode_sense_buf,
14837c478bd9Sstevel@tonic-gate 	    (int) (sizeof (struct mode_header) + hdr->bdesc_length));
14847c478bd9Sstevel@tonic-gate 	pg = (struct mode_page *)((ulong_t)mode_sense_buf +
14857c478bd9Sstevel@tonic-gate 	    sizeof (struct mode_header) + hdr->bdesc_length);
14867c478bd9Sstevel@tonic-gate 	if (pg->code != page_code) {
14877c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
14887c478bd9Sstevel@tonic-gate 	    return (-1);
14897c478bd9Sstevel@tonic-gate 	}
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	/*
14927c478bd9Sstevel@tonic-gate 	 * Accept up to "page_size" bytes of mode sense data.
14937c478bd9Sstevel@tonic-gate 	 * This allows us to accept both CCS and SCSI-2
14947c478bd9Sstevel@tonic-gate 	 * structures, as long as we request the greater
14957c478bd9Sstevel@tonic-gate 	 * of the two.
14967c478bd9Sstevel@tonic-gate 	 */
14977c478bd9Sstevel@tonic-gate 	maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
14987c478bd9Sstevel@tonic-gate 	if (((int)pg->length) > maximum) {
14997c478bd9Sstevel@tonic-gate 	    free(mode_sense_buf);
15007c478bd9Sstevel@tonic-gate 	    return (-1);
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	(void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	free(mode_sense_buf);
15067c478bd9Sstevel@tonic-gate 	return (0);
15077c478bd9Sstevel@tonic-gate }
1508