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