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]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2017 Nexenta Systems, Inc.
32 #include <libdevinfo.h>
38 #include <sys/sunddi.h>
39 #include <sys/types.h>
46 /* included for uscsi */
49 #include <sys/scsi/impl/types.h>
50 #include <sys/scsi/impl/uscsi.h>
51 #include <sys/scsi/generic/commands.h>
52 #include <sys/scsi/impl/commands.h>
53 #include <sys/scsi/generic/mode.h>
54 #include <sys/byteorder.h>
56 #include "libdiskmgt.h"
57 #include "disks_private.h"
59 #define KSTAT_CLASS_DISK "disk"
60 #define KSTAT_CLASS_ERROR "device_error"
62 #define SCSIBUFLEN 0xffff
65 #define b3(a) (((a)>>24) & 0xFF)
66 #define b2(a) (((a)>>16) & 0xFF)
67 #define b1(a) (((a)>>8) & 0xFF)
68 #define b0(a) (((a)>>0) & 0xFF)
70 static char *kstat_err_names
[] = {
79 "Predictive Failure Analysis",
83 static char *err_attr_names
[] = {
97 * **************** begin uscsi stuff ****************
100 #if defined(_BIT_FIELDS_LTOH)
101 #elif defined(_BIT_FIELDS_HTOL)
103 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
106 struct conf_feature
{
107 uchar_t feature
[2]; /* common to all */
108 #if defined(_BIT_FIELDS_LTOH)
118 #endif /* _BIT_FIELDS_LTOH */
125 struct profile_list
{
127 #if defined(_BIT_FIELDS_LTOH)
128 uchar_t current_p
: 1;
129 uchar_t reserved1
: 7;
131 uchar_t reserved1
: 7;
132 uchar_t current_p
: 1;
133 #endif /* _BIT_FIELDS_LTOH */
140 #if defined(_BIT_FIELDS_LTOH)
142 uchar_t reserved1
: 7;
144 uchar_t reserved1
: 7;
146 #endif /* _BIT_FIELDS_LTOH */
150 #if defined(_BIT_FIELDS_LTOH)
164 #endif /* _BIT_FIELDS_LTOH */
167 struct random_readable
{
170 #if defined(_BIT_FIELDS_LTOH)
172 uchar_t reserved1
: 7;
174 uchar_t reserved1
: 7;
176 #endif /* _BIT_FIELDS_LTOH */
180 #if defined(_BIT_FIELDS_LTOH)
183 uchar_t reserved1
: 6;
185 uchar_t reserved1
: 6;
188 #endif /* _BIT_FIELDS_LTOH */
191 #if defined(_BIT_FIELDS_LTOH)
201 #endif /* _BIT_FIELDS_LTOH */
203 uchar_t numlevels
[2];
212 #define PROF_NON_REMOVABLE 0x0001
213 #define PROF_REMOVABLE 0x0002
214 #define PROF_MAGNETO_OPTICAL 0x0003
215 #define PROF_OPTICAL_WO 0x0004
216 #define PROF_OPTICAL_ASMO 0x0005
217 #define PROF_CDROM 0x0008
218 #define PROF_CDR 0x0009
219 #define PROF_CDRW 0x000a
220 #define PROF_DVDROM 0x0010
221 #define PROF_DVDR 0x0011
222 #define PROF_DVDRAM 0x0012
223 #define PROF_DVDRW_REST 0x0013
224 #define PROF_DVDRW_SEQ 0x0014
225 #define PROF_DVDRW 0x001a
226 #define PROF_DDCD_ROM 0x0020
227 #define PROF_DDCD_R 0x0021
228 #define PROF_DDCD_RW 0x0022
229 #define PROF_NON_CONFORMING 0xffff
231 struct get_configuration
{
235 struct conf_feature feature
;
238 struct capabilities
{
239 #if defined(_BIT_FIELDS_LTOH)
240 uchar_t pagecode
: 6;
246 uchar_t pagecode
: 6;
247 #endif /* _BIT_FIELDS_LTOH */
249 #if defined(_BIT_FIELDS_LTOH)
250 /* read capabilities */
251 uchar_t cdr_read
: 1;
252 uchar_t cdrw_read
: 1;
254 uchar_t dvdrom_read
: 1;
255 uchar_t dvdr_read
: 1;
256 uchar_t dvdram_read
: 1;
260 uchar_t dvdram_read
: 1;
261 uchar_t dvdr_read
: 1;
262 uchar_t dvdrom_read
: 1;
264 uchar_t cdrw_read
: 1;
265 uchar_t cdr_read
: 1;
266 #endif /* _BIT_FIELDS_LTOH */
267 #if defined(_BIT_FIELDS_LTOH)
268 /* write capabilities */
269 uchar_t cdr_write
: 1;
270 uchar_t cdrw_write
: 1;
271 uchar_t testwrite
: 1;
273 uchar_t dvdr_write
: 1;
274 uchar_t dvdram_write
: 1;
277 /* write capabilities */
279 uchar_t dvdram_write
: 1;
280 uchar_t dvdr_write
: 1;
282 uchar_t testwrite
: 1;
283 uchar_t cdrw_write
: 1;
284 uchar_t cdr_write
: 1;
285 #endif /* _BIT_FIELDS_LTOH */
290 uchar_t obsolete0
[2];
291 uchar_t numvlevels
[2];
293 uchar_t obsolete1
[4];
298 /* there is more to this page, but nothing we care about */
301 struct mode_header_g2
{
309 * Mode sense/select page header information
311 struct scsi_ms_header
{
312 struct mode_header mode_header
;
313 struct block_descriptor block_descriptor
;
316 #define MODESENSE_PAGE_LEN(p) (((int)((struct mode_page *)p)->length) + \
317 sizeof (struct mode_page))
319 #define MODE_SENSE_PC_CURRENT (0 << 6)
320 #define MODE_SENSE_PC_DEFAULT (2 << 6)
321 #define MODE_SENSE_PC_SAVED (3 << 6)
323 #define MAX_MODE_SENSE_SIZE 255
324 #define IMPOSSIBLE_SCSI_STATUS 0xff
327 * ********** end of uscsi stuff ************
330 static descriptor_t
**apply_filter(descriptor_t
**drives
, int filter
[],
332 static int check_atapi(int fd
);
333 static int conv_drive_type(uint_t drive_type
);
334 static uint64_t convnum(uchar_t
*nptr
, int len
);
335 static void fill_command_g1(struct uscsi_cmd
*cmd
,
336 union scsi_cdb
*cdb
, caddr_t buff
, int blen
);
337 static void fill_general_page_cdb_g1(union scsi_cdb
*cdb
,
338 int command
, int lun
, uchar_t c0
, uchar_t c1
);
339 static void fill_mode_page_cdb(union scsi_cdb
*cdb
, int page
);
340 static descriptor_t
**get_assoc_alias(disk_t
*diskp
, int *errp
);
341 static descriptor_t
**get_assoc_controllers(descriptor_t
*dp
, int *errp
);
342 static descriptor_t
**get_assoc_paths(descriptor_t
*dp
, int *errp
);
343 static int get_attrs(disk_t
*diskp
, int fd
, char *opath
,
345 static int get_cdrom_drvtype(int fd
);
346 static int get_disk_kstats(kstat_ctl_t
*kc
, char *diskname
,
347 char *classname
, nvlist_t
*stats
);
348 static void get_drive_type(disk_t
*dp
, int fd
);
349 static int get_err_kstats(kstat_ctl_t
*kc
, char *diskname
,
351 static int get_io_kstats(kstat_ctl_t
*kc
, char *diskname
,
353 static int get_kstat_vals(kstat_t
*ksp
, nvlist_t
*stats
);
354 static char *get_err_attr_name(char *kstat_name
);
355 static int get_rpm(disk_t
*dp
, int fd
);
356 static int get_solidstate(disk_t
*dp
, int fd
);
357 static int update_stat64(nvlist_t
*stats
, char *attr
,
359 static int update_stat32(nvlist_t
*stats
, char *attr
,
361 static int uscsi_mode_sense(int fd
, int page_code
,
362 int page_control
, caddr_t page_data
, int page_size
,
363 struct scsi_ms_header
*header
);
366 drive_get_assoc_descriptors(descriptor_t
*dp
, dm_desc_type_t type
,
371 return (get_assoc_controllers(dp
, errp
));
373 return (get_assoc_paths(dp
, errp
));
375 return (get_assoc_alias(dp
->p
.disk
, errp
));
377 return (media_get_assocs(dp
, errp
));
385 * Get the drive descriptors for the given media/alias/devpath.
388 drive_get_assocs(descriptor_t
*desc
, int *errp
)
390 descriptor_t
**drives
;
392 /* at most one drive is associated with these descriptors */
394 drives
= (descriptor_t
**)calloc(2, sizeof (descriptor_t
*));
395 if (drives
== NULL
) {
400 drives
[0] = cache_get_desc(DM_DRIVE
, desc
->p
.disk
, NULL
, NULL
, errp
);
402 cache_free_descriptors(drives
);
412 drive_get_attributes(descriptor_t
*dp
, int *errp
)
414 nvlist_t
*attrs
= NULL
;
416 char opath
[MAXPATHLEN
];
418 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
424 fd
= drive_open_disk(dp
->p
.disk
, opath
, sizeof (opath
));
426 if ((*errp
= get_attrs(dp
->p
.disk
, fd
, opath
, attrs
)) != 0) {
439 * Check if we have the drive in our list, based upon the device id.
440 * We got the device id from the dev tree walk. This is encoded
441 * using devid_str_encode(3DEVID). In order to check the device ids we need
442 * to use the devid_compare(3DEVID) function, so we need to decode the
443 * string representation of the device id.
446 drive_get_descriptor_by_name(char *name
, int *errp
)
449 descriptor_t
**drives
;
450 descriptor_t
*drive
= NULL
;
453 if (name
== NULL
|| devid_str_decode(name
, &devid
, NULL
) != 0) {
458 drives
= cache_get_descriptors(DM_DRIVE
, errp
);
465 * We have to loop through all of them, freeing the ones we don't
466 * want. Once drive is set, we don't need to compare any more.
468 for (i
= 0; drives
[i
]; i
++) {
469 if (drive
== NULL
&& drives
[i
]->p
.disk
->devid
!= NULL
&&
470 devid_compare(devid
, drives
[i
]->p
.disk
->devid
) == 0) {
474 /* clean up the unused descriptor */
475 cache_free_descriptor(drives
[i
]);
489 drive_get_descriptors(int filter
[], int *errp
)
491 descriptor_t
**drives
;
493 drives
= cache_get_descriptors(DM_DRIVE
, errp
);
498 if (filter
!= NULL
&& filter
[0] != DM_FILTER_END
) {
499 descriptor_t
**found
;
500 found
= apply_filter(drives
, filter
, errp
);
512 drive_get_name(descriptor_t
*dp
)
514 return (dp
->p
.disk
->device_id
);
518 drive_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
525 if (nvlist_alloc(&stats
, NVATTRS
, 0) != 0) {
530 if (stat_type
== DM_DRV_STAT_PERFORMANCE
||
531 stat_type
== DM_DRV_STAT_DIAGNOSTIC
) {
537 if (ap
== NULL
|| ap
->kstat_name
== NULL
) {
543 if ((kc
= kstat_open()) == NULL
) {
552 if (ap
->kstat_name
== NULL
) {
556 if (stat_type
== DM_DRV_STAT_PERFORMANCE
) {
557 status
= get_io_kstats(kc
, ap
->kstat_name
, stats
);
559 status
= get_err_kstats(kc
, ap
->kstat_name
, stats
);
564 (void) kstat_close(kc
);
572 (void) kstat_close(kc
);
578 if (stat_type
== DM_DRV_STAT_TEMPERATURE
) {
581 if ((fd
= drive_open_disk(diskp
, NULL
, 0)) >= 0) {
582 struct dk_temperature temp
;
584 if (ioctl(fd
, DKIOCGTEMPERATURE
, &temp
) >= 0) {
585 if (nvlist_add_uint32(stats
, DM_TEMPERATURE
,
586 temp
.dkt_cur_temp
) != 0) {
613 drive_make_descriptors()
618 dp
= cache_get_disklist();
620 cache_load_desc(DM_DRIVE
, dp
, NULL
, NULL
, &error
);
631 * This function opens the disk generically (any slice).
634 drive_open_disk(disk_t
*diskp
, char *opath
, int len
)
637 * Just open the first devpath.
639 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->devpaths
!= NULL
) {
641 (void) strlcpy(opath
, diskp
->aliases
->devpaths
->devpath
, len
);
643 return (open(diskp
->aliases
->devpaths
->devpath
, O_RDONLY
|O_NDELAY
));
649 static descriptor_t
**
650 apply_filter(descriptor_t
**drives
, int filter
[], int *errp
)
653 descriptor_t
**found
;
657 /* count the number of drives in the snapshot */
658 for (cnt
= 0; drives
[cnt
]; cnt
++);
660 found
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
663 cache_free_descriptors(drives
);
668 for (i
= 0; drives
[i
]; i
++) {
672 /* Make sure the drive type is set */
673 get_drive_type(drives
[i
]->p
.disk
, -1);
676 for (j
= 0; filter
[j
] != DM_FILTER_END
; j
++) {
677 if (drives
[i
]->p
.disk
->drv_type
== filter
[j
]) {
678 found
[pos
++] = drives
[i
];
685 cache_free_descriptor(drives
[i
]);
696 conv_drive_type(uint_t drive_type
)
698 switch (drive_type
) {
700 return (DM_DT_UNKNOWN
);
702 return (DM_DT_MO_ERASABLE
);
703 case DK_MO_WRITEONCE
:
704 return (DM_DT_MO_WRITEONCE
);
706 return (DM_DT_AS_MO
);
708 return (DM_DT_CDROM
);
714 return (DM_DT_DVDROM
);
718 return (DM_DT_DVDRAM
);
720 return (DM_DT_FIXED
);
722 return (DM_DT_FLOPPY
);
728 return (DM_DT_UNKNOWN
);
732 static descriptor_t
**
733 get_assoc_alias(disk_t
*diskp
, int *errp
)
737 descriptor_t
**out_array
;
742 aliasp
= diskp
->aliases
;
745 while (aliasp
!= NULL
) {
746 if (aliasp
->alias
!= NULL
) {
749 aliasp
= aliasp
->next
;
752 /* set up the new array */
753 out_array
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
));
754 if (out_array
== NULL
) {
759 aliasp
= diskp
->aliases
;
761 while (aliasp
!= NULL
) {
762 if (aliasp
->alias
!= NULL
) {
763 out_array
[pos
++] = cache_get_desc(DM_ALIAS
, diskp
,
764 aliasp
->alias
, NULL
, errp
);
766 cache_free_descriptors(out_array
);
771 aliasp
= aliasp
->next
;
774 out_array
[pos
] = NULL
;
779 static descriptor_t
**
780 get_assoc_controllers(descriptor_t
*dp
, int *errp
)
784 descriptor_t
**controllers
;
789 /* Count how many we have. */
790 for (cnt
= 0; diskp
->controllers
[cnt
]; cnt
++);
792 /* make the snapshot */
793 controllers
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
794 if (controllers
== NULL
) {
799 for (i
= 0; diskp
->controllers
[i
]; i
++) {
800 controllers
[i
] = cache_get_desc(DM_CONTROLLER
,
801 diskp
->controllers
[i
], NULL
, NULL
, errp
);
803 cache_free_descriptors(controllers
);
808 controllers
[i
] = NULL
;
811 return (controllers
);
814 static descriptor_t
**
815 get_assoc_paths(descriptor_t
*dp
, int *errp
)
819 descriptor_t
**paths
;
822 pp
= dp
->p
.disk
->paths
;
824 /* Count how many we have. */
827 for (; pp
[cnt
]; cnt
++);
830 /* make the snapshot */
831 paths
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
838 * We fill in the name field of the descriptor with the device_id
839 * when we deal with path descriptors originating from a drive.
840 * In that way we can use the device id within the path code to
841 * lookup the path state for this drive.
843 for (i
= 0; i
< cnt
; i
++) {
844 paths
[i
] = cache_get_desc(DM_PATH
, pp
[i
], dp
->p
.disk
->device_id
,
847 cache_free_descriptors(paths
);
859 get_attrs(disk_t
*diskp
, int fd
, char *opath
, nvlist_t
*attrs
)
861 if (diskp
->removable
) {
862 struct dk_minfo minfo
;
864 if (nvlist_add_boolean(attrs
, DM_REMOVABLE
) != 0) {
868 /* Make sure media is inserted and spun up. */
869 if (fd
>= 0 && media_read_info(fd
, &minfo
)) {
870 if (nvlist_add_boolean(attrs
, DM_LOADED
) != 0) {
875 /* can't tell diff between dead & no media on removable drives */
876 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_UP
) != 0) {
880 get_drive_type(diskp
, fd
);
883 struct dk_minfo minfo
;
885 /* check if the fixed drive is up or not */
886 if (fd
>= 0 && media_read_info(fd
, &minfo
)) {
887 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_UP
) != 0) {
891 if (nvlist_add_uint32(attrs
, DM_STATUS
, DM_DISK_DOWN
) != 0) {
896 get_drive_type(diskp
, fd
);
899 if (nvlist_add_uint32(attrs
, DM_DRVTYPE
, diskp
->drv_type
) != 0) {
903 if (diskp
->product_id
!= NULL
) {
904 if (nvlist_add_string(attrs
, DM_PRODUCT_ID
, diskp
->product_id
)
909 if (diskp
->vendor_id
!= NULL
) {
910 if (nvlist_add_string(attrs
, DM_VENDOR_ID
, diskp
->vendor_id
) != 0) {
915 if (diskp
->sync_speed
!= -1) {
916 if (nvlist_add_uint32(attrs
, DM_SYNC_SPEED
, diskp
->sync_speed
)
922 if (diskp
->wide
== 1) {
923 if (nvlist_add_boolean(attrs
, DM_WIDE
) != 0) {
928 if (diskp
->rpm
== 0) {
929 diskp
->rpm
= get_rpm(diskp
, fd
);
932 if (diskp
->rpm
> 0) {
933 if (nvlist_add_uint32(attrs
, DM_RPM
, diskp
->rpm
) != 0) {
938 if (strlen(opath
) > 0) {
939 if (nvlist_add_string(attrs
, DM_OPATH
, opath
) != 0) {
944 if (diskp
->solid_state
< 0) {
945 diskp
->solid_state
= get_solidstate(diskp
, fd
);
948 if (diskp
->solid_state
> 0) {
949 if (nvlist_add_boolean(attrs
, DM_SOLIDSTATE
) != 0) {
958 get_disk_kstats(kstat_ctl_t
*kc
, char *diskname
, char *classname
,
965 class_len
= strlen(classname
);
966 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
967 if (strncmp(ksp
->ks_class
, classname
, class_len
) == 0) {
968 char kstat_name
[KSTAT_STRLEN
];
969 char *dname
= kstat_name
;
970 char *ename
= ksp
->ks_name
;
972 /* names are format: "sd0,err" - copy chars up to comma */
973 while (*ename
&& *ename
!= ',') {
978 if (libdiskmgt_str_eq(diskname
, kstat_name
)) {
979 (void) kstat_read(kc
, ksp
, NULL
);
980 err
= get_kstat_vals(ksp
, stats
);
990 * Getting the drive type depends on if the dev tree walk indicated that the
991 * drive was a CD-ROM or not. The kernal lumps all of the removable multi-media
992 * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
993 * a uscsi cmd to check the drive type.
996 get_drive_type(disk_t
*dp
, int fd
)
998 if (dp
->drv_type
== DM_DT_UNKNOWN
) {
1001 /* We may have already opened the device. */
1003 fd
= drive_open_disk(dp
, NULL
, 0);
1009 /* use uscsi to determine drive type */
1010 dp
->drv_type
= get_cdrom_drvtype(fd
);
1012 /* if uscsi fails, just call it a cd-rom */
1013 if (dp
->drv_type
== DM_DT_UNKNOWN
) {
1014 dp
->drv_type
= DM_DT_CDROM
;
1018 struct dk_minfo minfo
;
1020 if (media_read_info(fd
, &minfo
)) {
1021 dp
->drv_type
= conv_drive_type(minfo
.dki_media_type
);
1032 dp
->drv_type
= DM_DT_CDROM
;
1039 get_err_attr_name(char *kstat_name
)
1043 for (i
= 0; kstat_err_names
[i
] != NULL
; i
++) {
1044 if (libdiskmgt_str_eq(kstat_name
, kstat_err_names
[i
])) {
1045 return (err_attr_names
[i
]);
1053 get_err_kstats(kstat_ctl_t
*kc
, char *diskname
, nvlist_t
*stats
)
1055 return (get_disk_kstats(kc
, diskname
, KSTAT_CLASS_ERROR
, stats
));
1059 get_io_kstats(kstat_ctl_t
*kc
, char *diskname
, nvlist_t
*stats
)
1061 return (get_disk_kstats(kc
, diskname
, KSTAT_CLASS_DISK
, stats
));
1065 get_kstat_vals(kstat_t
*ksp
, nvlist_t
*stats
)
1067 if (ksp
->ks_type
== KSTAT_TYPE_IO
) {
1070 kiop
= KSTAT_IO_PTR(ksp
);
1072 /* see sys/kstat.h kstat_io_t struct for more fields */
1074 if (update_stat64(stats
, DM_NBYTESREAD
, kiop
->nread
) != 0) {
1077 if (update_stat64(stats
, DM_NBYTESWRITTEN
, kiop
->nwritten
) != 0) {
1080 if (update_stat64(stats
, DM_NREADOPS
, kiop
->reads
) != 0) {
1083 if (update_stat64(stats
, DM_NWRITEOPS
, kiop
->writes
) != 0) {
1087 } else if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
1091 knp
= KSTAT_NAMED_PTR(ksp
);
1092 for (i
= 0; i
< ksp
->ks_ndata
; i
++) {
1095 if (knp
[i
].name
[0] == 0)
1098 if ((attr_name
= get_err_attr_name(knp
[i
].name
)) == NULL
) {
1103 switch (knp
[i
].data_type
) {
1104 case KSTAT_DATA_UINT32
:
1105 if (update_stat32(stats
, attr_name
, knp
[i
].value
.ui32
)
1112 /* Right now all of the error types are uint32 */
1121 update_stat32(nvlist_t
*stats
, char *attr
, uint32_t value
)
1125 if (nvlist_lookup_int32(stats
, attr
, &currval
) == 0) {
1129 return (nvlist_add_uint32(stats
, attr
, value
));
1133 * There can be more than one kstat value when we have multi-path drives
1134 * that are not under mpxio (since there is more than one kstat name for
1135 * the drive in this case). So, we may have merge all of the kstat values
1136 * to give an accurate set of stats for the drive.
1139 update_stat64(nvlist_t
*stats
, char *attr
, uint64_t value
)
1143 if (nvlist_lookup_int64(stats
, attr
, &currval
) == 0) {
1146 return (nvlist_add_uint64(stats
, attr
, value
));
1150 * uscsi function to get the rpm of the drive
1153 get_rpm(disk_t
*dp
, int fd
)
1155 int opened_here
= 0;
1158 /* We may have already opened the device. */
1160 fd
= drive_open_disk(dp
, NULL
, 0);
1166 struct mode_geometry
*page4
;
1167 struct scsi_ms_header header
;
1169 struct mode_geometry page4
;
1170 char rawbuf
[MAX_MODE_SENSE_SIZE
];
1173 page4
= &u_page4
.page4
;
1174 (void) memset(&u_page4
, 0, sizeof (u_page4
));
1176 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1177 MODE_SENSE_PC_DEFAULT
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1181 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1182 MODE_SENSE_PC_SAVED
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1187 status
= uscsi_mode_sense(fd
, DAD_MODE_GEOMETRY
,
1188 MODE_SENSE_PC_CURRENT
, (caddr_t
)page4
, MAX_MODE_SENSE_SIZE
,
1193 #ifdef _LITTLE_ENDIAN
1194 page4
->rpm
= ntohs(page4
->rpm
);
1195 #endif /* _LITTLE_ENDIAN */
1209 get_solidstate(disk_t
*dp
, int fd
)
1211 int opened_here
= 0;
1212 int solid_state
= -1;
1214 /* We may have already opened the device. */
1216 fd
= drive_open_disk(dp
, NULL
, 0);
1221 if (ioctl(fd
, DKIOCSOLIDSTATE
, &solid_state
) < 0) {
1230 return (solid_state
);
1234 * ******** the rest of this is uscsi stuff for the drv type ********
1238 * We try a get_configuration uscsi cmd. If that fails, try a
1239 * atapi_capabilities cmd. If both fail then this is an older CD-ROM.
1242 get_cdrom_drvtype(int fd
)
1245 struct uscsi_cmd cmd
;
1246 uchar_t buff
[SCSIBUFLEN
];
1248 fill_general_page_cdb_g1(&cdb
, SCMD_GET_CONFIGURATION
, 0,
1249 b0(sizeof (buff
)), b1(sizeof (buff
)));
1250 fill_command_g1(&cmd
, &cdb
, (caddr_t
)buff
, sizeof (buff
));
1252 if (ioctl(fd
, USCSICMD
, &cmd
) >= 0) {
1253 struct get_configuration
*config
;
1254 struct conf_feature
*feature
;
1257 /* The first profile is the preferred one for the drive. */
1258 config
= (struct get_configuration
*)buff
;
1259 feature
= &config
->feature
;
1260 flen
= feature
->len
/ sizeof (struct profile_list
);
1264 prof_num
= (int)convnum(feature
->features
.plist
[0].profile
, 2);
1267 (void) fprintf(stderr
, "INFO: uscsi get_configuration %d\n",
1272 case PROF_MAGNETO_OPTICAL
:
1273 return (DM_DT_MO_ERASABLE
);
1274 case PROF_OPTICAL_WO
:
1275 return (DM_DT_MO_WRITEONCE
);
1276 case PROF_OPTICAL_ASMO
:
1277 return (DM_DT_AS_MO
);
1279 return (DM_DT_CDROM
);
1283 return (DM_DT_CDRW
);
1285 return (DM_DT_DVDROM
);
1287 return (DM_DT_DVDRAM
);
1288 case PROF_DVDRW_REST
:
1289 return (DM_DT_DVDRW
);
1290 case PROF_DVDRW_SEQ
:
1291 return (DM_DT_DVDRW
);
1293 return (DM_DT_DVDRW
);
1295 return (DM_DT_DDCDROM
);
1297 return (DM_DT_DDCDR
);
1299 return (DM_DT_DDCDRW
);
1304 /* see if the atapi capabilities give anything */
1305 return (check_atapi(fd
));
1312 struct uscsi_cmd cmd
;
1313 uchar_t buff
[SCSIBUFLEN
];
1315 fill_mode_page_cdb(&cdb
, ATAPI_CAPABILITIES
);
1316 fill_command_g1(&cmd
, &cdb
, (caddr_t
)buff
, sizeof (buff
));
1318 if (ioctl(fd
, USCSICMD
, &cmd
) >= 0) {
1320 struct capabilities
*cap
;
1321 struct mode_header_g2
*mode
;
1323 mode
= (struct mode_header_g2
*)buff
;
1325 bdesclen
= (int)convnum(mode
->desclen
, 2);
1326 cap
= (struct capabilities
*)
1327 &buff
[sizeof (struct mode_header_g2
) + bdesclen
];
1330 (void) fprintf(stderr
, "INFO: uscsi atapi capabilities\n");
1333 /* These are in order of how we want to report the drv type. */
1334 if (cap
->dvdram_write
) {
1335 return (DM_DT_DVDRAM
);
1337 if (cap
->dvdr_write
) {
1338 return (DM_DT_DVDR
);
1340 if (cap
->dvdrom_read
) {
1341 return (DM_DT_DVDROM
);
1343 if (cap
->cdrw_write
) {
1344 return (DM_DT_CDRW
);
1346 if (cap
->cdr_write
) {
1349 if (cap
->cdr_read
) {
1350 return (DM_DT_CDROM
);
1354 /* everything failed, so this is an older CD-ROM */
1356 (void) fprintf(stderr
, "INFO: uscsi failed\n");
1359 return (DM_DT_CDROM
);
1363 convnum(uchar_t
*nptr
, int len
)
1367 for (value
= 0; len
> 0; len
--, nptr
++)
1368 value
= (value
<< 8) | *nptr
;
1373 fill_command_g1(struct uscsi_cmd
*cmd
, union scsi_cdb
*cdb
,
1374 caddr_t buff
, int blen
)
1376 bzero((caddr_t
)cmd
, sizeof (struct uscsi_cmd
));
1379 cmd
->uscsi_cdb
= (caddr_t
)cdb
;
1380 cmd
->uscsi_cdblen
= CDB_GROUP1
;
1382 cmd
->uscsi_bufaddr
= buff
;
1383 cmd
->uscsi_buflen
= blen
;
1385 cmd
->uscsi_flags
= USCSI_DIAGNOSE
|USCSI_ISOLATE
|USCSI_READ
;
1389 fill_general_page_cdb_g1(union scsi_cdb
*cdb
, int command
, int lun
,
1390 uchar_t c0
, uchar_t c1
)
1392 bzero((caddr_t
)cdb
, sizeof (union scsi_cdb
));
1393 cdb
->scc_cmd
= command
;
1395 cdb
->g1_count0
= c0
; /* max length for page */
1396 cdb
->g1_count1
= c1
; /* max length for page */
1400 fill_mode_page_cdb(union scsi_cdb
*cdb
, int page
)
1402 /* group 1 mode page */
1403 bzero((caddr_t
)cdb
, sizeof (union scsi_cdb
));
1404 cdb
->scc_cmd
= SCMD_MODE_SENSE_G1
;
1405 cdb
->g1_count0
= 0xff; /* max length for mode page */
1406 cdb
->g1_count1
= 0xff; /* max length for mode page */
1407 cdb
->g1_addr3
= page
;
1411 uscsi_mode_sense(int fd
, int page_code
, int page_control
, caddr_t page_data
,
1412 int page_size
, struct scsi_ms_header
*header
)
1414 caddr_t mode_sense_buf
;
1415 struct mode_header
*hdr
;
1416 struct mode_page
*pg
;
1418 struct uscsi_cmd ucmd
;
1425 * Allocate a buffer for the mode sense headers
1426 * and mode sense data itself.
1428 nbytes
= sizeof (struct block_descriptor
) +
1429 sizeof (struct mode_header
) + page_size
;
1431 if ((mode_sense_buf
= malloc((uint_t
)nbytes
)) == NULL
) {
1436 * Build and execute the uscsi ioctl
1438 (void) memset(mode_sense_buf
, 0, nbytes
);
1439 (void) memset((char *)&ucmd
, 0, sizeof (ucmd
));
1440 (void) memset((char *)&cdb
, 0, sizeof (union scsi_cdb
));
1442 cdb
.scc_cmd
= SCMD_MODE_SENSE
;
1443 FORMG0COUNT(&cdb
, (uchar_t
)nbytes
);
1444 cdb
.cdb_opaque
[2] = page_control
| page_code
;
1445 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
1446 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
1447 ucmd
.uscsi_bufaddr
= mode_sense_buf
;
1448 ucmd
.uscsi_buflen
= nbytes
;
1450 ucmd
.uscsi_flags
|= USCSI_SILENT
;
1451 ucmd
.uscsi_flags
|= USCSI_READ
;
1452 ucmd
.uscsi_timeout
= 30;
1453 ucmd
.uscsi_flags
|= USCSI_RQENABLE
;
1454 if (ucmd
.uscsi_rqbuf
== NULL
) {
1455 ucmd
.uscsi_rqbuf
= rqbuf
;
1456 ucmd
.uscsi_rqlen
= sizeof (rqbuf
);
1457 ucmd
.uscsi_rqresid
= sizeof (rqbuf
);
1459 ucmd
.uscsi_rqstatus
= IMPOSSIBLE_SCSI_STATUS
;
1461 status
= ioctl(fd
, USCSICMD
, &ucmd
);
1463 if (status
|| ucmd
.uscsi_status
!= 0) {
1464 free(mode_sense_buf
);
1469 * Verify that the returned data looks reasonabled,
1470 * find the actual page data, and copy it into the
1471 * user's buffer. Copy the mode_header and block_descriptor
1472 * into the header structure, which can then be used to
1473 * return the same data to the drive when issuing a mode select.
1475 hdr
= (struct mode_header
*)mode_sense_buf
;
1476 (void) memset((caddr_t
)header
, 0, sizeof (struct scsi_ms_header
));
1477 if (hdr
->bdesc_length
!= sizeof (struct block_descriptor
) &&
1478 hdr
->bdesc_length
!= 0) {
1479 free(mode_sense_buf
);
1482 (void) memcpy((caddr_t
)header
, mode_sense_buf
,
1483 (int) (sizeof (struct mode_header
) + hdr
->bdesc_length
));
1484 pg
= (struct mode_page
*)((ulong_t
)mode_sense_buf
+
1485 sizeof (struct mode_header
) + hdr
->bdesc_length
);
1486 if (pg
->code
!= page_code
) {
1487 free(mode_sense_buf
);
1492 * Accept up to "page_size" bytes of mode sense data.
1493 * This allows us to accept both CCS and SCSI-2
1494 * structures, as long as we request the greater
1497 maximum
= page_size
- sizeof (struct mode_page
) - hdr
->bdesc_length
;
1498 if (((int)pg
->length
) > maximum
) {
1499 free(mode_sense_buf
);
1503 (void) memcpy(page_data
, (caddr_t
)pg
, MODESENSE_PAGE_LEN(pg
));
1505 free(mode_sense_buf
);