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