Merge commit '9276b3991ba20d5a5660887ba81b0bc7bed25a0c'
[unleashed.git] / usr / src / lib / libdiskmgt / common / drive.c
blob9d68f2b34acb557ac98b8377589eefca774cd140
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2017 Nexenta Systems, Inc.
31 #include <fcntl.h>
32 #include <libdevinfo.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stropts.h>
37 #include <sys/dkio.h>
38 #include <sys/sunddi.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <kstat.h>
42 #include <errno.h>
43 #include <devid.h>
44 #include <dirent.h>
46 /* included for uscsi */
47 #include <strings.h>
48 #include <sys/stat.h>
49 #include <sys/scsi/impl/types.h>
50 #include <sys/scsi/impl/uscsi.h>
51 #include <sys/scsi/generic/commands.h>
52 #include <sys/scsi/impl/commands.h>
53 #include <sys/scsi/generic/mode.h>
54 #include <sys/byteorder.h>
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
64 /* byte get macros */
65 #define b3(a) (((a)>>24) & 0xFF)
66 #define b2(a) (((a)>>16) & 0xFF)
67 #define b1(a) (((a)>>8) & 0xFF)
68 #define b0(a) (((a)>>0) & 0xFF)
70 static char *kstat_err_names[] = {
71 "Soft Errors",
72 "Hard Errors",
73 "Transport Errors",
74 "Media Error",
75 "Device Not Ready",
76 "No Device",
77 "Recoverable",
78 "Illegal Request",
79 "Predictive Failure Analysis",
80 NULL
83 static char *err_attr_names[] = {
84 DM_NSOFTERRS,
85 DM_NHARDERRS,
86 DM_NTRANSERRS,
87 DM_NMEDIAERRS,
88 DM_NDNRERRS,
89 DM_NNODEVERRS,
90 DM_NRECOVERRS,
91 DM_NILLREQERRS,
92 DM_FAILING,
93 NULL
97 * **************** begin uscsi stuff ****************
100 #if defined(_BIT_FIELDS_LTOH)
101 #elif defined(_BIT_FIELDS_HTOL)
102 #else
103 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
104 #endif
106 struct conf_feature {
107 uchar_t feature[2]; /* common to all */
108 #if defined(_BIT_FIELDS_LTOH)
109 uchar_t current : 1;
110 uchar_t persist : 1;
111 uchar_t version : 4;
112 uchar_t reserved: 2;
113 #else
114 uchar_t reserved: 2;
115 uchar_t version : 4;
116 uchar_t persist : 1;
117 uchar_t current : 1;
118 #endif /* _BIT_FIELDS_LTOH */
119 uchar_t len;
120 union features {
121 struct generic {
122 uchar_t data[1];
123 } gen;
124 uchar_t data[1];
125 struct profile_list {
126 uchar_t profile[2];
127 #if defined(_BIT_FIELDS_LTOH)
128 uchar_t current_p : 1;
129 uchar_t reserved1 : 7;
130 #else
131 uchar_t reserved1 : 7;
132 uchar_t current_p : 1;
133 #endif /* _BIT_FIELDS_LTOH */
134 uchar_t reserved2;
135 } plist[1];
136 struct core {
137 uchar_t phys[4];
138 } core;
139 struct morphing {
140 #if defined(_BIT_FIELDS_LTOH)
141 uchar_t async : 1;
142 uchar_t reserved1 : 7;
143 #else
144 uchar_t reserved1 : 7;
145 uchar_t async : 1;
146 #endif /* _BIT_FIELDS_LTOH */
147 uchar_t reserved[3];
148 } morphing;
149 struct removable {
150 #if defined(_BIT_FIELDS_LTOH)
151 uchar_t lock : 1;
152 uchar_t resv1 : 1;
153 uchar_t pvnt : 1;
154 uchar_t eject : 1;
155 uchar_t resv2 : 1;
156 uchar_t loading : 3;
157 #else
158 uchar_t loading : 3;
159 uchar_t resv2 : 1;
160 uchar_t eject : 1;
161 uchar_t pvnt : 1;
162 uchar_t resv1 : 1;
163 uchar_t lock : 1;
164 #endif /* _BIT_FIELDS_LTOH */
165 uchar_t reserved[3];
166 } removable;
167 struct random_readable {
168 uchar_t lbsize[4];
169 uchar_t blocking[2];
170 #if defined(_BIT_FIELDS_LTOH)
171 uchar_t pp : 1;
172 uchar_t reserved1 : 7;
173 #else
174 uchar_t reserved1 : 7;
175 uchar_t pp : 1;
176 #endif /* _BIT_FIELDS_LTOH */
177 uchar_t reserved;
178 } rread;
179 struct cd_read {
180 #if defined(_BIT_FIELDS_LTOH)
181 uchar_t cdtext : 1;
182 uchar_t c2flag : 1;
183 uchar_t reserved1 : 6;
184 #else
185 uchar_t reserved1 : 6;
186 uchar_t c2flag : 1;
187 uchar_t cdtext : 1;
188 #endif /* _BIT_FIELDS_LTOH */
189 } cdread;
190 struct cd_audio {
191 #if defined(_BIT_FIELDS_LTOH)
192 uchar_t sv : 1;
193 uchar_t scm : 1;
194 uchar_t scan : 1;
195 uchar_t resv : 5;
196 #else
197 uchar_t resv : 5;
198 uchar_t scan : 1;
199 uchar_t scm : 1;
200 uchar_t sv : 1;
201 #endif /* _BIT_FIELDS_LTOH */
202 uchar_t reserved;
203 uchar_t numlevels[2];
204 } audio;
205 struct dvd_css {
206 uchar_t reserved[3];
207 uchar_t version;
208 } dvdcss;
209 } features;
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 {
232 uchar_t len[4];
233 uchar_t reserved[2];
234 uchar_t curprof[2];
235 struct conf_feature feature;
238 struct capabilities {
239 #if defined(_BIT_FIELDS_LTOH)
240 uchar_t pagecode : 6;
241 uchar_t resv1 : 1;
242 uchar_t ps : 1;
243 #else
244 uchar_t ps : 1;
245 uchar_t resv1 : 1;
246 uchar_t pagecode : 6;
247 #endif /* _BIT_FIELDS_LTOH */
248 uchar_t pagelen;
249 #if defined(_BIT_FIELDS_LTOH)
250 /* read capabilities */
251 uchar_t cdr_read : 1;
252 uchar_t cdrw_read : 1;
253 uchar_t method2 : 1;
254 uchar_t dvdrom_read : 1;
255 uchar_t dvdr_read : 1;
256 uchar_t dvdram_read : 1;
257 uchar_t resv2 : 2;
258 #else
259 uchar_t resv2 : 2;
260 uchar_t dvdram_read : 1;
261 uchar_t dvdr_read : 1;
262 uchar_t dvdrom_read : 1;
263 uchar_t method2 : 1;
264 uchar_t cdrw_read : 1;
265 uchar_t cdr_read : 1;
266 #endif /* _BIT_FIELDS_LTOH */
267 #if defined(_BIT_FIELDS_LTOH)
268 /* write capabilities */
269 uchar_t cdr_write : 1;
270 uchar_t cdrw_write : 1;
271 uchar_t testwrite : 1;
272 uchar_t resv3 : 1;
273 uchar_t dvdr_write : 1;
274 uchar_t dvdram_write : 1;
275 uchar_t resv4 : 2;
276 #else
277 /* write capabilities */
278 uchar_t resv4 : 2;
279 uchar_t dvdram_write : 1;
280 uchar_t dvdr_write : 1;
281 uchar_t resv3 : 1;
282 uchar_t testwrite : 1;
283 uchar_t cdrw_write : 1;
284 uchar_t cdr_write : 1;
285 #endif /* _BIT_FIELDS_LTOH */
286 uchar_t misc0;
287 uchar_t misc1;
288 uchar_t misc2;
289 uchar_t misc3;
290 uchar_t obsolete0[2];
291 uchar_t numvlevels[2];
292 uchar_t bufsize[2];
293 uchar_t obsolete1[4];
294 uchar_t resv5;
295 uchar_t misc4;
296 uchar_t obsolete2;
297 uchar_t copymgt[2];
298 /* there is more to this page, but nothing we care about */
301 struct mode_header_g2 {
302 uchar_t modelen[2];
303 uchar_t obsolete;
304 uchar_t reserved[3];
305 uchar_t desclen[2];
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[],
331 int *errp);
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,
344 nvlist_t *nvp);
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,
350 nvlist_t *stats);
351 static int get_io_kstats(kstat_ctl_t *kc, char *diskname,
352 nvlist_t *stats);
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,
358 uint64_t value);
359 static int update_stat32(nvlist_t *stats, char *attr,
360 uint32_t value);
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);
365 descriptor_t **
366 drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
367 int *errp)
369 switch (type) {
370 case DM_CONTROLLER:
371 return (get_assoc_controllers(dp, errp));
372 case DM_PATH:
373 return (get_assoc_paths(dp, errp));
374 case DM_ALIAS:
375 return (get_assoc_alias(dp->p.disk, errp));
376 case DM_MEDIA:
377 return (media_get_assocs(dp, errp));
380 *errp = EINVAL;
381 return (NULL);
385 * Get the drive descriptors for the given media/alias/devpath.
387 descriptor_t **
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) {
396 *errp = ENOMEM;
397 return (NULL);
400 drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
401 if (*errp != 0) {
402 cache_free_descriptors(drives);
403 return (NULL);
406 drives[1] = NULL;
408 return (drives);
411 nvlist_t *
412 drive_get_attributes(descriptor_t *dp, int *errp)
414 nvlist_t *attrs = NULL;
415 int fd;
416 char opath[MAXPATHLEN];
418 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
419 *errp = ENOMEM;
420 return (NULL);
423 opath[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) {
427 nvlist_free(attrs);
428 attrs = NULL;
431 if (fd >= 0) {
432 (void) close(fd);
435 return (attrs);
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.
445 descriptor_t *
446 drive_get_descriptor_by_name(char *name, int *errp)
448 ddi_devid_t devid;
449 descriptor_t **drives;
450 descriptor_t *drive = NULL;
451 int i;
453 if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
454 *errp = EINVAL;
455 return (NULL);
458 drives = cache_get_descriptors(DM_DRIVE, errp);
459 if (*errp != 0) {
460 devid_free(devid);
461 return (NULL);
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) {
471 drive = drives[i];
473 } else {
474 /* clean up the unused descriptor */
475 cache_free_descriptor(drives[i]);
478 free(drives);
479 devid_free(devid);
481 if (drive == NULL) {
482 *errp = ENODEV;
485 return (drive);
488 descriptor_t **
489 drive_get_descriptors(int filter[], int *errp)
491 descriptor_t **drives;
493 drives = cache_get_descriptors(DM_DRIVE, errp);
494 if (*errp != 0) {
495 return (NULL);
498 if (filter != NULL && filter[0] != DM_FILTER_END) {
499 descriptor_t **found;
500 found = apply_filter(drives, filter, errp);
501 if (*errp != 0) {
502 drives = NULL;
503 } else {
504 drives = found;
508 return (drives);
511 char *
512 drive_get_name(descriptor_t *dp)
514 return (dp->p.disk->device_id);
517 nvlist_t *
518 drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
520 disk_t *diskp;
521 nvlist_t *stats;
523 diskp = dp->p.disk;
525 if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
526 *errp = ENOMEM;
527 return (NULL);
530 if (stat_type == DM_DRV_STAT_PERFORMANCE ||
531 stat_type == DM_DRV_STAT_DIAGNOSTIC) {
533 alias_t *ap;
534 kstat_ctl_t *kc;
536 ap = diskp->aliases;
537 if (ap == NULL || ap->kstat_name == NULL) {
538 nvlist_free(stats);
539 *errp = EACCES;
540 return (NULL);
543 if ((kc = kstat_open()) == NULL) {
544 nvlist_free(stats);
545 *errp = EACCES;
546 return (NULL);
549 while (ap != NULL) {
550 int status;
552 if (ap->kstat_name == NULL) {
553 continue;
556 if (stat_type == DM_DRV_STAT_PERFORMANCE) {
557 status = get_io_kstats(kc, ap->kstat_name, stats);
558 } else {
559 status = get_err_kstats(kc, ap->kstat_name, stats);
562 if (status != 0) {
563 nvlist_free(stats);
564 (void) kstat_close(kc);
565 *errp = ENOMEM;
566 return (NULL);
569 ap = ap->next;
572 (void) kstat_close(kc);
574 *errp = 0;
575 return (stats);
578 if (stat_type == DM_DRV_STAT_TEMPERATURE) {
579 int fd;
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) {
587 *errp = ENOMEM;
588 nvlist_free(stats);
589 return (NULL);
591 } else {
592 *errp = errno;
593 nvlist_free(stats);
594 return (NULL);
596 (void) close(fd);
597 } else {
598 *errp = errno;
599 nvlist_free(stats);
600 return (NULL);
603 *errp = 0;
604 return (stats);
607 nvlist_free(stats);
608 *errp = EINVAL;
609 return (NULL);
613 drive_make_descriptors()
615 int error;
616 disk_t *dp;
618 dp = cache_get_disklist();
619 while (dp != NULL) {
620 cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
621 if (error != 0) {
622 return (error);
624 dp = dp->next;
627 return (0);
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) {
640 if (opath != NULL) {
641 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
643 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
646 return (-1);
649 static descriptor_t **
650 apply_filter(descriptor_t **drives, int filter[], int *errp)
652 int i;
653 descriptor_t **found;
654 int cnt;
655 int pos;
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 *));
661 if (found == NULL) {
662 *errp = ENOMEM;
663 cache_free_descriptors(drives);
664 return (NULL);
667 pos = 0;
668 for (i = 0; drives[i]; i++) {
669 int j;
670 int match;
672 /* Make sure the drive type is set */
673 get_drive_type(drives[i]->p.disk, -1);
675 match = 0;
676 for (j = 0; filter[j] != DM_FILTER_END; j++) {
677 if (drives[i]->p.disk->drv_type == filter[j]) {
678 found[pos++] = drives[i];
679 match = 1;
680 break;
684 if (!match) {
685 cache_free_descriptor(drives[i]);
688 found[pos] = NULL;
689 free(drives);
691 *errp = 0;
692 return (found);
695 static int
696 conv_drive_type(uint_t drive_type)
698 switch (drive_type) {
699 case DK_UNKNOWN:
700 return (DM_DT_UNKNOWN);
701 case DK_MO_ERASABLE:
702 return (DM_DT_MO_ERASABLE);
703 case DK_MO_WRITEONCE:
704 return (DM_DT_MO_WRITEONCE);
705 case DK_AS_MO:
706 return (DM_DT_AS_MO);
707 case DK_CDROM:
708 return (DM_DT_CDROM);
709 case DK_CDR:
710 return (DM_DT_CDR);
711 case DK_CDRW:
712 return (DM_DT_CDRW);
713 case DK_DVDROM:
714 return (DM_DT_DVDROM);
715 case DK_DVDR:
716 return (DM_DT_DVDR);
717 case DK_DVDRAM:
718 return (DM_DT_DVDRAM);
719 case DK_FIXED_DISK:
720 return (DM_DT_FIXED);
721 case DK_FLOPPY:
722 return (DM_DT_FLOPPY);
723 case DK_ZIP:
724 return (DM_DT_ZIP);
725 case DK_JAZ:
726 return (DM_DT_JAZ);
727 default:
728 return (DM_DT_UNKNOWN);
732 static descriptor_t **
733 get_assoc_alias(disk_t *diskp, int *errp)
735 alias_t *aliasp;
736 uint_t cnt;
737 descriptor_t **out_array;
738 int pos;
740 *errp = 0;
742 aliasp = diskp->aliases;
743 cnt = 0;
745 while (aliasp != NULL) {
746 if (aliasp->alias != NULL) {
747 cnt++;
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) {
755 *errp = ENOMEM;
756 return (NULL);
759 aliasp = diskp->aliases;
760 pos = 0;
761 while (aliasp != NULL) {
762 if (aliasp->alias != NULL) {
763 out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
764 aliasp->alias, NULL, errp);
765 if (*errp != 0) {
766 cache_free_descriptors(out_array);
767 return (NULL);
771 aliasp = aliasp->next;
774 out_array[pos] = NULL;
776 return (out_array);
779 static descriptor_t **
780 get_assoc_controllers(descriptor_t *dp, int *errp)
782 disk_t *diskp;
783 int cnt;
784 descriptor_t **controllers;
785 int i;
787 diskp = dp->p.disk;
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) {
795 *errp = ENOMEM;
796 return (NULL);
799 for (i = 0; diskp->controllers[i]; i++) {
800 controllers[i] = cache_get_desc(DM_CONTROLLER,
801 diskp->controllers[i], NULL, NULL, errp);
802 if (*errp != 0) {
803 cache_free_descriptors(controllers);
804 return (NULL);
808 controllers[i] = NULL;
810 *errp = 0;
811 return (controllers);
814 static descriptor_t **
815 get_assoc_paths(descriptor_t *dp, int *errp)
817 path_t **pp;
818 int cnt;
819 descriptor_t **paths;
820 int i;
822 pp = dp->p.disk->paths;
824 /* Count how many we have. */
825 cnt = 0;
826 if (pp != NULL) {
827 for (; pp[cnt]; cnt++);
830 /* make the snapshot */
831 paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
832 if (paths == NULL) {
833 *errp = ENOMEM;
834 return (NULL);
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,
845 NULL, errp);
846 if (*errp != 0) {
847 cache_free_descriptors(paths);
848 return (NULL);
852 paths[i] = NULL;
854 *errp = 0;
855 return (paths);
858 static int
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) {
865 return (ENOMEM);
868 /* Make sure media is inserted and spun up. */
869 if (fd >= 0 && media_read_info(fd, &minfo)) {
870 if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
871 return (ENOMEM);
875 /* can't tell diff between dead & no media on removable drives */
876 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
877 return (ENOMEM);
880 get_drive_type(diskp, fd);
882 } else {
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) {
888 return (ENOMEM);
890 } else {
891 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
892 return (ENOMEM);
896 get_drive_type(diskp, fd);
899 if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
900 return (ENOMEM);
903 if (diskp->product_id != NULL) {
904 if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
905 != 0) {
906 return (ENOMEM);
909 if (diskp->vendor_id != NULL) {
910 if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
911 return (ENOMEM);
915 if (diskp->sync_speed != -1) {
916 if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
917 != 0) {
918 return (ENOMEM);
922 if (diskp->wide == 1) {
923 if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
924 return (ENOMEM);
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) {
934 return (ENOMEM);
938 if (strlen(opath) > 0) {
939 if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
940 return (ENOMEM);
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) {
950 return (ENOMEM);
954 return (0);
957 static int
958 get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
959 nvlist_t *stats)
961 kstat_t *ksp;
962 size_t class_len;
963 int err = 0;
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 != ',') {
974 *dname++ = *ename++;
976 *dname = '\0';
978 if (libdiskmgt_str_eq(diskname, kstat_name)) {
979 (void) kstat_read(kc, ksp, NULL);
980 err = get_kstat_vals(ksp, stats);
981 break;
986 return (err);
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.
995 static void
996 get_drive_type(disk_t *dp, int fd)
998 if (dp->drv_type == DM_DT_UNKNOWN) {
999 int opened_here = 0;
1001 /* We may have already opened the device. */
1002 if (fd < 0) {
1003 fd = drive_open_disk(dp, NULL, 0);
1004 opened_here = 1;
1007 if (fd >= 0) {
1008 if (dp->cd_rom) {
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;
1017 } else {
1018 struct dk_minfo minfo;
1020 if (media_read_info(fd, &minfo)) {
1021 dp->drv_type = conv_drive_type(minfo.dki_media_type);
1025 if (opened_here) {
1026 (void) close(fd);
1029 } else {
1030 /* couldn't open */
1031 if (dp->cd_rom) {
1032 dp->drv_type = DM_DT_CDROM;
1038 static char *
1039 get_err_attr_name(char *kstat_name)
1041 int i;
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]);
1049 return (NULL);
1052 static int
1053 get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1055 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
1058 static int
1059 get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1061 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
1064 static int
1065 get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
1067 if (ksp->ks_type == KSTAT_TYPE_IO) {
1068 kstat_io_t *kiop;
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) {
1075 return (ENOMEM);
1077 if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
1078 return (ENOMEM);
1080 if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
1081 return (ENOMEM);
1083 if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
1084 return (ENOMEM);
1087 } else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
1088 kstat_named_t *knp;
1089 int i;
1091 knp = KSTAT_NAMED_PTR(ksp);
1092 for (i = 0; i < ksp->ks_ndata; i++) {
1093 char *attr_name;
1095 if (knp[i].name[0] == 0)
1096 continue;
1098 if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
1099 continue;
1103 switch (knp[i].data_type) {
1104 case KSTAT_DATA_UINT32:
1105 if (update_stat32(stats, attr_name, knp[i].value.ui32)
1106 != 0) {
1107 return (ENOMEM);
1109 break;
1111 default:
1112 /* Right now all of the error types are uint32 */
1113 break;
1117 return (0);
1120 static int
1121 update_stat32(nvlist_t *stats, char *attr, uint32_t value)
1123 int32_t currval;
1125 if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
1126 value += currval;
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.
1138 static int
1139 update_stat64(nvlist_t *stats, char *attr, uint64_t value)
1141 int64_t currval;
1143 if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
1144 value += currval;
1146 return (nvlist_add_uint64(stats, attr, value));
1150 * uscsi function to get the rpm of the drive
1152 static int
1153 get_rpm(disk_t *dp, int fd)
1155 int opened_here = 0;
1156 int rpm = -1;
1158 /* We may have already opened the device. */
1159 if (fd < 0) {
1160 fd = drive_open_disk(dp, NULL, 0);
1161 opened_here = 1;
1164 if (fd >= 0) {
1165 int status;
1166 struct mode_geometry *page4;
1167 struct scsi_ms_header header;
1168 union {
1169 struct mode_geometry page4;
1170 char rawbuf[MAX_MODE_SENSE_SIZE];
1171 } u_page4;
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,
1178 &header);
1180 if (status) {
1181 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1182 MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1183 &header);
1186 if (status) {
1187 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1188 MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1189 &header);
1192 if (!status) {
1193 #ifdef _LITTLE_ENDIAN
1194 page4->rpm = ntohs(page4->rpm);
1195 #endif /* _LITTLE_ENDIAN */
1197 rpm = page4->rpm;
1200 if (opened_here) {
1201 (void) close(fd);
1205 return (rpm);
1208 static int
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. */
1215 if (fd < 0) {
1216 fd = drive_open_disk(dp, NULL, 0);
1217 opened_here = 1;
1220 if (fd >= 0) {
1221 if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
1222 solid_state = -1;
1226 if (opened_here) {
1227 (void) close(fd);
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.
1241 static int
1242 get_cdrom_drvtype(int fd)
1244 union scsi_cdb cdb;
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;
1255 int flen;
1257 /* The first profile is the preferred one for the drive. */
1258 config = (struct get_configuration *)buff;
1259 feature = &config->feature;
1260 flen = feature->len / sizeof (struct profile_list);
1261 if (flen > 0) {
1262 int prof_num;
1264 prof_num = (int)convnum(feature->features.plist[0].profile, 2);
1266 if (dm_debug > 1) {
1267 (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
1268 prof_num);
1271 switch (prof_num) {
1272 case PROF_MAGNETO_OPTICAL:
1273 return (DM_DT_MO_ERASABLE);
1274 case PROF_OPTICAL_WO:
1275 return (DM_DT_MO_WRITEONCE);
1276 case PROF_OPTICAL_ASMO:
1277 return (DM_DT_AS_MO);
1278 case PROF_CDROM:
1279 return (DM_DT_CDROM);
1280 case PROF_CDR:
1281 return (DM_DT_CDR);
1282 case PROF_CDRW:
1283 return (DM_DT_CDRW);
1284 case PROF_DVDROM:
1285 return (DM_DT_DVDROM);
1286 case PROF_DVDRAM:
1287 return (DM_DT_DVDRAM);
1288 case PROF_DVDRW_REST:
1289 return (DM_DT_DVDRW);
1290 case PROF_DVDRW_SEQ:
1291 return (DM_DT_DVDRW);
1292 case PROF_DVDRW:
1293 return (DM_DT_DVDRW);
1294 case PROF_DDCD_ROM:
1295 return (DM_DT_DDCDROM);
1296 case PROF_DDCD_R:
1297 return (DM_DT_DDCDR);
1298 case PROF_DDCD_RW:
1299 return (DM_DT_DDCDRW);
1304 /* see if the atapi capabilities give anything */
1305 return (check_atapi(fd));
1308 static int
1309 check_atapi(int fd)
1311 union scsi_cdb cdb;
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) {
1319 int bdesclen;
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];
1329 if (dm_debug > 1) {
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) {
1347 return (DM_DT_CDR);
1349 if (cap->cdr_read) {
1350 return (DM_DT_CDROM);
1354 /* everything failed, so this is an older CD-ROM */
1355 if (dm_debug > 1) {
1356 (void) fprintf(stderr, "INFO: uscsi failed\n");
1359 return (DM_DT_CDROM);
1362 static uint64_t
1363 convnum(uchar_t *nptr, int len)
1365 uint64_t value;
1367 for (value = 0; len > 0; len--, nptr++)
1368 value = (value << 8) | *nptr;
1369 return (value);
1372 static void
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));
1377 bzero(buff, blen);
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;
1388 static void
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;
1394 cdb->scc_lun = lun;
1395 cdb->g1_count0 = c0; /* max length for page */
1396 cdb->g1_count1 = c1; /* max length for page */
1399 static void
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;
1410 static int
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;
1417 int nbytes;
1418 struct uscsi_cmd ucmd;
1419 union scsi_cdb cdb;
1420 int status;
1421 int maximum;
1422 char rqbuf[255];
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;
1430 nbytes = page_size;
1431 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
1432 return (-1);
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);
1465 return (-1);
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);
1480 return (-1);
1482 (void) memcpy((caddr_t)header, mode_sense_buf,
1483 (int) (sizeof (struct mode_header) + hdr->bdesc_length));
1484 pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1485 sizeof (struct mode_header) + hdr->bdesc_length);
1486 if (pg->code != page_code) {
1487 free(mode_sense_buf);
1488 return (-1);
1492 * Accept up to "page_size" bytes of mode sense data.
1493 * This allows us to accept both CCS and SCSI-2
1494 * structures, as long as we request the greater
1495 * of the two.
1497 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
1498 if (((int)pg->length) > maximum) {
1499 free(mode_sense_buf);
1500 return (-1);
1503 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1505 free(mode_sense_buf);
1506 return (0);