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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <libdevinfo.h>
33 #include <sys/sunddi.h>
34 #include <sys/types.h>
41 /* included for uscsi */
44 #include <sys/scsi/impl/types.h>
45 #include <sys/scsi/impl/uscsi.h>
46 #include <sys/scsi/generic/commands.h>
47 #include <sys/scsi/impl/commands.h>
48 #include <sys/scsi/generic/mode.h>
49 #include <sys/byteorder.h>
51 #include "libdiskmgt.h"
52 #include "disks_private.h"
54 #define KSTAT_CLASS_DISK "disk"
55 #define KSTAT_CLASS_ERROR "device_error"
57 #define SCSIBUFLEN 0xffff
60 #define b3(a) (((a)>>24) & 0xFF)
61 #define b2(a) (((a)>>16) & 0xFF)
62 #define b1(a) (((a)>>8) & 0xFF)
63 #define b0(a) (((a)>>0) & 0xFF)
65 static char *kstat_err_names
[] = {
74 "Predictive Failure Analysis",
78 static char *err_attr_names
[] = {
92 * **************** begin uscsi stuff ****************
95 #if defined(_BIT_FIELDS_LTOH)
96 #elif defined(_BIT_FIELDS_HTOL)
98 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
101 struct conf_feature
{
102 uchar_t feature
[2]; /* common to all */
103 #if defined(_BIT_FIELDS_LTOH)
113 #endif /* _BIT_FIELDS_LTOH */
120 struct profile_list
{
122 #if defined(_BIT_FIELDS_LTOH)
123 uchar_t current_p
: 1;
124 uchar_t reserved1
: 7;
126 uchar_t reserved1
: 7;
127 uchar_t current_p
: 1;
128 #endif /* _BIT_FIELDS_LTOH */
135 #if defined(_BIT_FIELDS_LTOH)
137 uchar_t reserved1
: 7;
139 uchar_t reserved1
: 7;
141 #endif /* _BIT_FIELDS_LTOH */
145 #if defined(_BIT_FIELDS_LTOH)
159 #endif /* _BIT_FIELDS_LTOH */
162 struct random_readable
{
165 #if defined(_BIT_FIELDS_LTOH)
167 uchar_t reserved1
: 7;
169 uchar_t reserved1
: 7;
171 #endif /* _BIT_FIELDS_LTOH */
175 #if defined(_BIT_FIELDS_LTOH)
178 uchar_t reserved1
: 6;
180 uchar_t reserved1
: 6;
183 #endif /* _BIT_FIELDS_LTOH */
186 #if defined(_BIT_FIELDS_LTOH)
196 #endif /* _BIT_FIELDS_LTOH */
198 uchar_t numlevels
[2];
207 #define PROF_NON_REMOVABLE 0x0001
208 #define PROF_REMOVABLE 0x0002
209 #define PROF_MAGNETO_OPTICAL 0x0003
210 #define PROF_OPTICAL_WO 0x0004
211 #define PROF_OPTICAL_ASMO 0x0005
212 #define PROF_CDROM 0x0008
213 #define PROF_CDR 0x0009
214 #define PROF_CDRW 0x000a
215 #define PROF_DVDROM 0x0010
216 #define PROF_DVDR 0x0011
217 #define PROF_DVDRAM 0x0012
218 #define PROF_DVDRW_REST 0x0013
219 #define PROF_DVDRW_SEQ 0x0014
220 #define PROF_DVDRW 0x001a
221 #define PROF_DDCD_ROM 0x0020
222 #define PROF_DDCD_R 0x0021
223 #define PROF_DDCD_RW 0x0022
224 #define PROF_NON_CONFORMING 0xffff
226 struct get_configuration
{
230 struct conf_feature feature
;
233 struct capabilities
{
234 #if defined(_BIT_FIELDS_LTOH)
235 uchar_t pagecode
: 6;
241 uchar_t pagecode
: 6;
242 #endif /* _BIT_FIELDS_LTOH */
244 #if defined(_BIT_FIELDS_LTOH)
245 /* read capabilities */
246 uchar_t cdr_read
: 1;
247 uchar_t cdrw_read
: 1;
249 uchar_t dvdrom_read
: 1;
250 uchar_t dvdr_read
: 1;
251 uchar_t dvdram_read
: 1;
255 uchar_t dvdram_read
: 1;
256 uchar_t dvdr_read
: 1;
257 uchar_t dvdrom_read
: 1;
259 uchar_t cdrw_read
: 1;
260 uchar_t cdr_read
: 1;
261 #endif /* _BIT_FIELDS_LTOH */
262 #if defined(_BIT_FIELDS_LTOH)
263 /* write capabilities */
264 uchar_t cdr_write
: 1;
265 uchar_t cdrw_write
: 1;
266 uchar_t testwrite
: 1;
268 uchar_t dvdr_write
: 1;
269 uchar_t dvdram_write
: 1;
272 /* write capabilities */
274 uchar_t dvdram_write
: 1;
275 uchar_t dvdr_write
: 1;
277 uchar_t testwrite
: 1;
278 uchar_t cdrw_write
: 1;
279 uchar_t cdr_write
: 1;
280 #endif /* _BIT_FIELDS_LTOH */
285 uchar_t obsolete0
[2];
286 uchar_t numvlevels
[2];
288 uchar_t obsolete1
[4];
293 /* there is more to this page, but nothing we care about */
296 struct mode_header_g2
{
304 * Mode sense/select page header information
306 struct scsi_ms_header
{
307 struct mode_header mode_header
;
308 struct block_descriptor block_descriptor
;
311 #define MODESENSE_PAGE_LEN(p) (((int)((struct mode_page *)p)->length) + \
312 sizeof (struct mode_page))
314 #define MODE_SENSE_PC_CURRENT (0 << 6)
315 #define MODE_SENSE_PC_DEFAULT (2 << 6)
316 #define MODE_SENSE_PC_SAVED (3 << 6)
318 #define MAX_MODE_SENSE_SIZE 255
319 #define IMPOSSIBLE_SCSI_STATUS 0xff
322 * ********** end of uscsi stuff ************
325 static descriptor_t
**apply_filter(descriptor_t
**drives
, int filter
[],
327 static int check_atapi(int fd
);
328 static int conv_drive_type(uint_t drive_type
);
329 static uint64_t convnum(uchar_t
*nptr
, int len
);
330 static void fill_command_g1(struct uscsi_cmd
*cmd
,
331 union scsi_cdb
*cdb
, caddr_t buff
, int blen
);
332 static void fill_general_page_cdb_g1(union scsi_cdb
*cdb
,
333 int command
, int lun
, uchar_t c0
, uchar_t c1
);
334 static void fill_mode_page_cdb(union scsi_cdb
*cdb
, int page
);
335 static descriptor_t
**get_assoc_alias(disk_t
*diskp
, int *errp
);
336 static descriptor_t
**get_assoc_controllers(descriptor_t
*dp
, int *errp
);
337 static descriptor_t
**get_assoc_paths(descriptor_t
*dp
, int *errp
);
338 static int get_attrs(disk_t
*diskp
, int fd
, char *opath
,
340 static int get_cdrom_drvtype(int fd
);
341 static int get_disk_kstats(kstat_ctl_t
*kc
, char *diskname
,
342 char *classname
, nvlist_t
*stats
);
343 static void get_drive_type(disk_t
*dp
, int fd
);
344 static int get_err_kstats(kstat_ctl_t
*kc
, char *diskname
,
346 static int get_io_kstats(kstat_ctl_t
*kc
, char *diskname
,
348 static int get_kstat_vals(kstat_t
*ksp
, nvlist_t
*stats
);
349 static char *get_err_attr_name(char *kstat_name
);
350 static int get_rpm(disk_t
*dp
, int fd
);
351 static int get_solidstate(disk_t
*dp
, int fd
);
352 static int update_stat64(nvlist_t
*stats
, char *attr
,
354 static int update_stat32(nvlist_t
*stats
, char *attr
,
356 static int uscsi_mode_sense(int fd
, int page_code
,
357 int page_control
, caddr_t page_data
, int page_size
,
358 struct scsi_ms_header
*header
);
361 drive_get_assoc_descriptors(descriptor_t
*dp
, dm_desc_type_t type
,
366 return (get_assoc_controllers(dp
, errp
));
368 return (get_assoc_paths(dp
, errp
));
370 return (get_assoc_alias(dp
->p
.disk
, errp
));
372 return (media_get_assocs(dp
, errp
));
380 * Get the drive descriptors for the given media/alias/devpath.
383 drive_get_assocs(descriptor_t
*desc
, int *errp
)
385 descriptor_t
**drives
;
387 /* at most one drive is associated with these descriptors */
389 drives
= (descriptor_t
**)calloc(2, sizeof (descriptor_t
*));
390 if (drives
== NULL
) {
395 drives
[0] = cache_get_desc(DM_DRIVE
, desc
->p
.disk
, NULL
, NULL
, errp
);
397 cache_free_descriptors(drives
);
407 drive_get_attributes(descriptor_t
*dp
, int *errp
)
409 nvlist_t
*attrs
= NULL
;
411 char opath
[MAXPATHLEN
];
413 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
419 fd
= drive_open_disk(dp
->p
.disk
, opath
, sizeof (opath
));
421 if ((*errp
= get_attrs(dp
->p
.disk
, fd
, opath
, attrs
)) != 0) {
434 * Check if we have the drive in our list, based upon the device id.
435 * We got the device id from the dev tree walk. This is encoded
436 * using devid_str_encode(3DEVID). In order to check the device ids we need
437 * to use the devid_compare(3DEVID) function, so we need to decode the
438 * string representation of the device id.
441 drive_get_descriptor_by_name(char *name
, int *errp
)
444 descriptor_t
**drives
;
445 descriptor_t
*drive
= NULL
;
448 if (name
== NULL
|| devid_str_decode(name
, &devid
, NULL
) != 0) {
453 drives
= cache_get_descriptors(DM_DRIVE
, errp
);
460 * We have to loop through all of them, freeing the ones we don't
461 * want. Once drive is set, we don't need to compare any more.
463 for (i
= 0; drives
[i
]; i
++) {
464 if (drive
== NULL
&& drives
[i
]->p
.disk
->devid
!= NULL
&&
465 devid_compare(devid
, drives
[i
]->p
.disk
->devid
) == 0) {
469 /* clean up the unused descriptor */
470 cache_free_descriptor(drives
[i
]);
484 drive_get_descriptors(int filter
[], int *errp
)
486 descriptor_t
**drives
;
488 drives
= cache_get_descriptors(DM_DRIVE
, errp
);
493 if (filter
!= NULL
&& filter
[0] != DM_FILTER_END
) {
494 descriptor_t
**found
;
495 found
= apply_filter(drives
, filter
, errp
);
507 drive_get_name(descriptor_t
*dp
)
509 return (dp
->p
.disk
->device_id
);
513 drive_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
520 if (nvlist_alloc(&stats
, NVATTRS
, 0) != 0) {
525 if (stat_type
== DM_DRV_STAT_PERFORMANCE
||
526 stat_type
== DM_DRV_STAT_DIAGNOSTIC
) {
532 if (ap
== NULL
|| ap
->kstat_name
== NULL
) {
538 if ((kc
= kstat_open()) == NULL
) {
547 if (ap
->kstat_name
== NULL
) {
551 if (stat_type
== DM_DRV_STAT_PERFORMANCE
) {
552 status
= get_io_kstats(kc
, ap
->kstat_name
, stats
);
554 status
= get_err_kstats(kc
, ap
->kstat_name
, stats
);
559 (void) kstat_close(kc
);
567 (void) kstat_close(kc
);
573 if (stat_type
== DM_DRV_STAT_TEMPERATURE
) {
576 if ((fd
= drive_open_disk(diskp
, NULL
, 0)) >= 0) {
577 struct dk_temperature temp
;
579 if (ioctl(fd
, DKIOCGTEMPERATURE
, &temp
) >= 0) {
580 if (nvlist_add_uint32(stats
, DM_TEMPERATURE
,
581 temp
.dkt_cur_temp
) != 0) {
608 drive_make_descriptors()
613 dp
= cache_get_disklist();
615 cache_load_desc(DM_DRIVE
, dp
, NULL
, NULL
, &error
);
626 * This function opens the disk generically (any slice).
629 drive_open_disk(disk_t
*diskp
, char *opath
, int len
)
632 * Just open the first devpath.
634 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->devpaths
!= NULL
) {
636 (void) strlcpy(opath
, diskp
->aliases
->devpaths
->devpath
, len
);
638 return (open(diskp
->aliases
->devpaths
->devpath
, O_RDONLY
|O_NDELAY
));
644 static descriptor_t
**
645 apply_filter(descriptor_t
**drives
, int filter
[], int *errp
)
648 descriptor_t
**found
;
652 /* count the number of drives in the snapshot */
653 for (cnt
= 0; drives
[cnt
]; cnt
++);
655 found
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
658 cache_free_descriptors(drives
);
663 for (i
= 0; drives
[i
]; i
++) {
667 /* Make sure the drive type is set */
668 get_drive_type(drives
[i
]->p
.disk
, -1);
671 for (j
= 0; filter
[j
] != DM_FILTER_END
; j
++) {
672 if (drives
[i
]->p
.disk
->drv_type
== filter
[j
]) {
673 found
[pos
++] = drives
[i
];
680 cache_free_descriptor(drives
[i
]);
691 conv_drive_type(uint_t drive_type
)
693 switch (drive_type
) {
695 return (DM_DT_UNKNOWN
);
697 return (DM_DT_MO_ERASABLE
);
698 case DK_MO_WRITEONCE
:
699 return (DM_DT_MO_WRITEONCE
);
701 return (DM_DT_AS_MO
);
703 return (DM_DT_CDROM
);
709 return (DM_DT_DVDROM
);
713 return (DM_DT_DVDRAM
);
715 return (DM_DT_FIXED
);
717 return (DM_DT_FLOPPY
);
723 return (DM_DT_UNKNOWN
);
727 static descriptor_t
**
728 get_assoc_alias(disk_t
*diskp
, int *errp
)
732 descriptor_t
**out_array
;
737 aliasp
= diskp
->aliases
;
740 while (aliasp
!= NULL
) {
741 if (aliasp
->alias
!= NULL
) {
744 aliasp
= aliasp
->next
;
747 /* set up the new array */
748 out_array
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
));
749 if (out_array
== NULL
) {
754 aliasp
= diskp
->aliases
;
756 while (aliasp
!= NULL
) {
757 if (aliasp
->alias
!= NULL
) {
758 out_array
[pos
++] = cache_get_desc(DM_ALIAS
, diskp
,
759 aliasp
->alias
, NULL
, errp
);
761 cache_free_descriptors(out_array
);
766 aliasp
= aliasp
->next
;
769 out_array
[pos
] = NULL
;
774 static descriptor_t
**
775 get_assoc_controllers(descriptor_t
*dp
, int *errp
)
779 descriptor_t
**controllers
;
784 /* Count how many we have. */
785 for (cnt
= 0; diskp
->controllers
[cnt
]; cnt
++);
787 /* make the snapshot */
788 controllers
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
789 if (controllers
== NULL
) {
794 for (i
= 0; diskp
->controllers
[i
]; i
++) {
795 controllers
[i
] = cache_get_desc(DM_CONTROLLER
,
796 diskp
->controllers
[i
], NULL
, NULL
, errp
);
798 cache_free_descriptors(controllers
);
803 controllers
[i
] = NULL
;
806 return (controllers
);
809 static descriptor_t
**
810 get_assoc_paths(descriptor_t
*dp
, int *errp
)
814 descriptor_t
**paths
;
817 pp
= dp
->p
.disk
->paths
;
819 /* Count how many we have. */
822 for (; pp
[cnt
]; cnt
++);
825 /* make the snapshot */
826 paths
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
833 * We fill in the name field of the descriptor with the device_id
834 * when we deal with path descriptors originating from a drive.
835 * In that way we can use the device id within the path code to
836 * lookup the path state for this drive.
838 for (i
= 0; i
< cnt
; i
++) {
839 paths
[i
] = cache_get_desc(DM_PATH
, pp
[i
], dp
->p
.disk
->device_id
,
842 cache_free_descriptors(paths
);
854 get_attrs(disk_t
*diskp
, int fd
, char *opath
, nvlist_t
*attrs
)
856 if (diskp
->removable
) {
857 struct dk_minfo minfo
;
859 if (nvlist_add_boolean(attrs
, DM_REMOVABLE
) != 0) {
863 /* Make sure media is inserted and spun up. */
864 if (fd
>= 0 && media_read_info(fd
, &minfo
)) {
865 if (nvlist_add_boolean(attrs
, DM_LOADED
) != 0) {
870 /* can't tell diff between dead & no media on removable drives */
871 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_UP
) != 0) {
875 get_drive_type(diskp
, fd
);
878 struct dk_minfo minfo
;
880 /* check if the fixed drive is up or not */
881 if (fd
>= 0 && media_read_info(fd
, &minfo
)) {
882 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_UP
) != 0) {
886 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_DOWN
) != 0) {
891 get_drive_type(diskp
, fd
);
894 if (nvlist_add_uint32(attrs
, DM_DRVTYPE
, diskp
->drv_type
) != 0) {
898 if (diskp
->product_id
!= NULL
) {
899 if (nvlist_add_string(attrs
, DM_PRODUCT_ID
, diskp
->product_id
)
904 if (diskp
->vendor_id
!= NULL
) {
905 if (nvlist_add_string(attrs
, DM_VENDOR_ID
, diskp
->vendor_id
) != 0) {
910 if (diskp
->sync_speed
!= -1) {
911 if (nvlist_add_uint32(attrs
, DM_SYNC_SPEED
, diskp
->sync_speed
)
917 if (diskp
->wide
== 1) {
918 if (nvlist_add_boolean(attrs
, DM_WIDE
) != 0) {
923 if (diskp
->rpm
== 0) {
924 diskp
->rpm
= get_rpm(diskp
, fd
);
927 if (diskp
->rpm
> 0) {
928 if (nvlist_add_uint32(attrs
, DM_RPM
, diskp
->rpm
) != 0) {
933 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->cluster
) {
934 if (nvlist_add_boolean(attrs
, DM_CLUSTERED
) != 0) {
939 if (strlen(opath
) > 0) {
940 if (nvlist_add_string(attrs
, DM_OPATH
, opath
) != 0) {
945 if (diskp
->solid_state
< 0) {
946 diskp
->solid_state
= get_solidstate(diskp
, fd
);
949 if (diskp
->solid_state
> 0) {
950 if (nvlist_add_boolean(attrs
, DM_SOLIDSTATE
) != 0) {
959 get_disk_kstats(kstat_ctl_t
*kc
, char *diskname
, char *classname
,
966 class_len
= strlen(classname
);
967 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
968 if (strncmp(ksp
->ks_class
, classname
, class_len
) == 0) {
969 char kstat_name
[KSTAT_STRLEN
];
970 char *dname
= kstat_name
;
971 char *ename
= ksp
->ks_name
;
973 /* names are format: "sd0,err" - copy chars up to comma */
974 while (*ename
&& *ename
!= ',') {
979 if (libdiskmgt_str_eq(diskname
, kstat_name
)) {
980 (void) kstat_read(kc
, ksp
, NULL
);
981 err
= get_kstat_vals(ksp
, stats
);
991 * Getting the drive type depends on if the dev tree walk indicated that the
992 * drive was a CD-ROM or not. The kernal lumps all of the removable multi-media
993 * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
994 * a uscsi cmd to check the drive type.
997 get_drive_type(disk_t
*dp
, int fd
)
999 if (dp
->drv_type
== DM_DT_UNKNOWN
) {
1000 int opened_here
= 0;
1002 /* We may have already opened the device. */
1004 fd
= drive_open_disk(dp
, NULL
, 0);
1010 /* use uscsi to determine drive type */
1011 dp
->drv_type
= get_cdrom_drvtype(fd
);
1013 /* if uscsi fails, just call it a cd-rom */
1014 if (dp
->drv_type
== DM_DT_UNKNOWN
) {
1015 dp
->drv_type
= DM_DT_CDROM
;
1019 struct dk_minfo minfo
;
1021 if (media_read_info(fd
, &minfo
)) {
1022 dp
->drv_type
= conv_drive_type(minfo
.dki_media_type
);
1033 dp
->drv_type
= DM_DT_CDROM
;
1040 get_err_attr_name(char *kstat_name
)
1044 for (i
= 0; kstat_err_names
[i
] != NULL
; i
++) {
1045 if (libdiskmgt_str_eq(kstat_name
, kstat_err_names
[i
])) {
1046 return (err_attr_names
[i
]);
1054 get_err_kstats(kstat_ctl_t
*kc
, char *diskname
, nvlist_t
*stats
)
1056 return (get_disk_kstats(kc
, diskname
, KSTAT_CLASS_ERROR
, stats
));
1060 get_io_kstats(kstat_ctl_t
*kc
, char *diskname
, nvlist_t
*stats
)
1062 return (get_disk_kstats(kc
, diskname
, KSTAT_CLASS_DISK
, stats
));
1066 get_kstat_vals(kstat_t
*ksp
, nvlist_t
*stats
)
1068 if (ksp
->ks_type
== KSTAT_TYPE_IO
) {
1071 kiop
= KSTAT_IO_PTR(ksp
);
1073 /* see sys/kstat.h kstat_io_t struct for more fields */
1075 if (update_stat64(stats
, DM_NBYTESREAD
, kiop
->nread
) != 0) {
1078 if (update_stat64(stats
, DM_NBYTESWRITTEN
, kiop
->nwritten
) != 0) {
1081 if (update_stat64(stats
, DM_NREADOPS
, kiop
->reads
) != 0) {
1084 if (update_stat64(stats
, DM_NWRITEOPS
, kiop
->writes
) != 0) {
1088 } else if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
1092 knp
= KSTAT_NAMED_PTR(ksp
);
1093 for (i
= 0; i
< ksp
->ks_ndata
; i
++) {
1096 if (knp
[i
].name
[0] == 0)
1099 if ((attr_name
= get_err_attr_name(knp
[i
].name
)) == NULL
) {
1104 switch (knp
[i
].data_type
) {
1105 case KSTAT_DATA_UINT32
:
1106 if (update_stat32(stats
, attr_name
, knp
[i
].value
.ui32
)
1113 /* Right now all of the error types are uint32 */
1122 update_stat32(nvlist_t
*stats
, char *attr
, uint32_t value
)
1126 if (nvlist_lookup_int32(stats
, attr
, &currval
) == 0) {
1130 return (nvlist_add_uint32(stats
, attr
, value
));
1134 * There can be more than one kstat value when we have multi-path drives
1135 * that are not under mpxio (since there is more than one kstat name for
1136 * the drive in this case). So, we may have merge all of the kstat values
1137 * to give an accurate set of stats for the drive.
1140 update_stat64(nvlist_t
*stats
, char *attr
, uint64_t value
)
1144 if (nvlist_lookup_int64(stats
, attr
, &currval
) == 0) {
1147 return (nvlist_add_uint64(stats
, attr
, value
));
1151 * uscsi function to get the rpm of the drive
1154 get_rpm(disk_t
*dp
, int fd
)
1156 int opened_here
= 0;
1159 /* We may have already opened the device. */
1161 fd
= drive_open_disk(dp
, NULL
, 0);
1167 struct mode_geometry
*page4
;
1168 struct scsi_ms_header header
;
1170 struct mode_geometry page4
;
1171 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1174 page4
= &u_page4
.page4
;
1175 (void) memset(&u_page4
, 0, sizeof (u_page4
));
1177 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1178 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1182 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1183 MODE_SENSE_PC_SAVED
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1188 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1189 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1194 #ifdef _LITTLE_ENDIAN
1195 page4
->rpm
= ntohs(page4
->rpm
);
1196 #endif /* _LITTLE_ENDIAN */
1210 get_solidstate(disk_t
*dp
, int fd
)
1212 int opened_here
= 0;
1213 int solid_state
= -1;
1215 /* We may have already opened the device. */
1217 fd
= drive_open_disk(dp
, NULL
, 0);
1222 if (ioctl(fd
, DKIOCSOLIDSTATE
, &solid_state
) < 0) {
1231 return (solid_state
);
1235 * ******** the rest of this is uscsi stuff for the drv type ********
1239 * We try a get_configuration uscsi cmd. If that fails, try a
1240 * atapi_capabilities cmd. If both fail then this is an older CD-ROM.
1243 get_cdrom_drvtype(int fd
)
1246 struct uscsi_cmd cmd
;
1247 uchar_t buff
[SCSIBUFLEN
];
1249 fill_general_page_cdb_g1(&cdb
, SCMD_GET_CONFIGURATION
, 0,
1250 b0(sizeof (buff
)), b1(sizeof (buff
)));
1251 fill_command_g1(&cmd
, &cdb
, (caddr_t
)buff
, sizeof (buff
));
1253 if (ioctl(fd
, USCSICMD
, &cmd
) >= 0) {
1254 struct get_configuration
*config
;
1255 struct conf_feature
*feature
;
1258 /* The first profile is the preferred one for the drive. */
1259 config
= (struct get_configuration
*)buff
;
1260 feature
= &config
->feature
;
1261 flen
= feature
->len
/ sizeof (struct profile_list
);
1265 prof_num
= (int)convnum(feature
->features
.plist
[0].profile
, 2);
1268 (void) fprintf(stderr
, "INFO: uscsi get_configuration %d\n",
1273 case PROF_MAGNETO_OPTICAL
:
1274 return (DM_DT_MO_ERASABLE
);
1275 case PROF_OPTICAL_WO
:
1276 return (DM_DT_MO_WRITEONCE
);
1277 case PROF_OPTICAL_ASMO
:
1278 return (DM_DT_AS_MO
);
1280 return (DM_DT_CDROM
);
1284 return (DM_DT_CDRW
);
1286 return (DM_DT_DVDROM
);
1288 return (DM_DT_DVDRAM
);
1289 case PROF_DVDRW_REST
:
1290 return (DM_DT_DVDRW
);
1291 case PROF_DVDRW_SEQ
:
1292 return (DM_DT_DVDRW
);
1294 return (DM_DT_DVDRW
);
1296 return (DM_DT_DDCDROM
);
1298 return (DM_DT_DDCDR
);
1300 return (DM_DT_DDCDRW
);
1305 /* see if the atapi capabilities give anything */
1306 return (check_atapi(fd
));
1313 struct uscsi_cmd cmd
;
1314 uchar_t buff
[SCSIBUFLEN
];
1316 fill_mode_page_cdb(&cdb
, ATAPI_CAPABILITIES
);
1317 fill_command_g1(&cmd
, &cdb
, (caddr_t
)buff
, sizeof (buff
));
1319 if (ioctl(fd
, USCSICMD
, &cmd
) >= 0) {
1321 struct capabilities
*cap
;
1322 struct mode_header_g2
*mode
;
1324 mode
= (struct mode_header_g2
*)buff
;
1326 bdesclen
= (int)convnum(mode
->desclen
, 2);
1327 cap
= (struct capabilities
*)
1328 &buff
[sizeof (struct mode_header_g2
) + bdesclen
];
1331 (void) fprintf(stderr
, "INFO: uscsi atapi capabilities\n");
1334 /* These are in order of how we want to report the drv type. */
1335 if (cap
->dvdram_write
) {
1336 return (DM_DT_DVDRAM
);
1338 if (cap
->dvdr_write
) {
1339 return (DM_DT_DVDR
);
1341 if (cap
->dvdrom_read
) {
1342 return (DM_DT_DVDROM
);
1344 if (cap
->cdrw_write
) {
1345 return (DM_DT_CDRW
);
1347 if (cap
->cdr_write
) {
1350 if (cap
->cdr_read
) {
1351 return (DM_DT_CDROM
);
1355 /* everything failed, so this is an older CD-ROM */
1357 (void) fprintf(stderr
, "INFO: uscsi failed\n");
1360 return (DM_DT_CDROM
);
1364 convnum(uchar_t
*nptr
, int len
)
1368 for (value
= 0; len
> 0; len
--, nptr
++)
1369 value
= (value
<< 8) | *nptr
;
1374 fill_command_g1(struct uscsi_cmd
*cmd
, union scsi_cdb
*cdb
,
1375 caddr_t buff
, int blen
)
1377 bzero((caddr_t
)cmd
, sizeof (struct uscsi_cmd
));
1380 cmd
->uscsi_cdb
= (caddr_t
)cdb
;
1381 cmd
->uscsi_cdblen
= CDB_GROUP1
;
1383 cmd
->uscsi_bufaddr
= buff
;
1384 cmd
->uscsi_buflen
= blen
;
1386 cmd
->uscsi_flags
= USCSI_DIAGNOSE
|USCSI_ISOLATE
|USCSI_READ
;
1390 fill_general_page_cdb_g1(union scsi_cdb
*cdb
, int command
, int lun
,
1391 uchar_t c0
, uchar_t c1
)
1393 bzero((caddr_t
)cdb
, sizeof (union scsi_cdb
));
1394 cdb
->scc_cmd
= command
;
1396 cdb
->g1_count0
= c0
; /* max length for page */
1397 cdb
->g1_count1
= c1
; /* max length for page */
1401 fill_mode_page_cdb(union scsi_cdb
*cdb
, int page
)
1403 /* group 1 mode page */
1404 bzero((caddr_t
)cdb
, sizeof (union scsi_cdb
));
1405 cdb
->scc_cmd
= SCMD_MODE_SENSE_G1
;
1406 cdb
->g1_count0
= 0xff; /* max length for mode page */
1407 cdb
->g1_count1
= 0xff; /* max length for mode page */
1408 cdb
->g1_addr3
= page
;
1412 uscsi_mode_sense(int fd
, int page_code
, int page_control
, caddr_t page_data
,
1413 int page_size
, struct scsi_ms_header
*header
)
1415 caddr_t mode_sense_buf
;
1416 struct mode_header
*hdr
;
1417 struct mode_page
*pg
;
1419 struct uscsi_cmd ucmd
;
1426 * Allocate a buffer for the mode sense headers
1427 * and mode sense data itself.
1429 nbytes
= sizeof (struct block_descriptor
) +
1430 sizeof (struct mode_header
) + page_size
;
1432 if ((mode_sense_buf
= malloc((uint_t
)nbytes
)) == NULL
) {
1437 * Build and execute the uscsi ioctl
1439 (void) memset(mode_sense_buf
, 0, nbytes
);
1440 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
1441 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
1443 cdb
.scc_cmd
= SCMD_MODE_SENSE
;
1444 FORMG0COUNT(&cdb
, (uchar_t
)nbytes
);
1445 cdb
.cdb_opaque
[2] = page_control
| page_code
;
1446 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
1447 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
1448 ucmd
.uscsi_bufaddr
= mode_sense_buf
;
1449 ucmd
.uscsi_buflen
= nbytes
;
1451 ucmd
.uscsi_flags
|= USCSI_SILENT
;
1452 ucmd
.uscsi_flags
|= USCSI_READ
;
1453 ucmd
.uscsi_timeout
= 30;
1454 ucmd
.uscsi_flags
|= USCSI_RQENABLE
;
1455 if (ucmd
.uscsi_rqbuf
== NULL
) {
1456 ucmd
.uscsi_rqbuf
= rqbuf
;
1457 ucmd
.uscsi_rqlen
= sizeof (rqbuf
);
1458 ucmd
.uscsi_rqresid
= sizeof (rqbuf
);
1460 ucmd
.uscsi_rqstatus
= IMPOSSIBLE_SCSI_STATUS
;
1462 status
= ioctl(fd
, USCSICMD
, &ucmd
);
1464 if (status
|| ucmd
.uscsi_status
!= 0) {
1465 free(mode_sense_buf
);
1470 * Verify that the returned data looks reasonabled,
1471 * find the actual page data, and copy it into the
1472 * user's buffer. Copy the mode_header and block_descriptor
1473 * into the header structure, which can then be used to
1474 * return the same data to the drive when issuing a mode select.
1476 hdr
= (struct mode_header
*)mode_sense_buf
;
1477 (void) memset((caddr_t
)header
, 0, sizeof (struct scsi_ms_header
));
1478 if (hdr
->bdesc_length
!= sizeof (struct block_descriptor
) &&
1479 hdr
->bdesc_length
!= 0) {
1480 free(mode_sense_buf
);
1483 (void) memcpy((caddr_t
)header
, mode_sense_buf
,
1484 (int) (sizeof (struct mode_header
) + hdr
->bdesc_length
));
1485 pg
= (struct mode_page
*)((ulong_t
)mode_sense_buf
+
1486 sizeof (struct mode_header
) + hdr
->bdesc_length
);
1487 if (pg
->code
!= page_code
) {
1488 free(mode_sense_buf
);
1493 * Accept up to "page_size" bytes of mode sense data.
1494 * This allows us to accept both CCS and SCSI-2
1495 * structures, as long as we request the greater
1498 maximum
= page_size
- sizeof (struct mode_page
) - hdr
->bdesc_length
;
1499 if (((int)pg
->length
) > maximum
) {
1500 free(mode_sense_buf
);
1504 (void) memcpy(page_data
, (caddr_t
)pg
, MODESENSE_PAGE_LEN(pg
));
1506 free(mode_sense_buf
);