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