dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdiskmgt / common / drive.c
bloba4c489a9bcd4bddadc755fbe5a9089ac799acd21
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
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <fcntl.h>
27 #include <libdevinfo.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stropts.h>
32 #include <sys/dkio.h>
33 #include <sys/sunddi.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <kstat.h>
37 #include <errno.h>
38 #include <devid.h>
39 #include <dirent.h>
41 /* included for uscsi */
42 #include <strings.h>
43 #include <sys/stat.h>
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
59 /* byte get macros */
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[] = {
66 "Soft Errors",
67 "Hard Errors",
68 "Transport Errors",
69 "Media Error",
70 "Device Not Ready",
71 "No Device",
72 "Recoverable",
73 "Illegal Request",
74 "Predictive Failure Analysis",
75 NULL
78 static char *err_attr_names[] = {
79 DM_NSOFTERRS,
80 DM_NHARDERRS,
81 DM_NTRANSERRS,
82 DM_NMEDIAERRS,
83 DM_NDNRERRS,
84 DM_NNODEVERRS,
85 DM_NRECOVERRS,
86 DM_NILLREQERRS,
87 DM_FAILING,
88 NULL
92 * **************** begin uscsi stuff ****************
95 #if defined(_BIT_FIELDS_LTOH)
96 #elif defined(_BIT_FIELDS_HTOL)
97 #else
98 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
99 #endif
101 struct conf_feature {
102 uchar_t feature[2]; /* common to all */
103 #if defined(_BIT_FIELDS_LTOH)
104 uchar_t current : 1;
105 uchar_t persist : 1;
106 uchar_t version : 4;
107 uchar_t reserved: 2;
108 #else
109 uchar_t reserved: 2;
110 uchar_t version : 4;
111 uchar_t persist : 1;
112 uchar_t current : 1;
113 #endif /* _BIT_FIELDS_LTOH */
114 uchar_t len;
115 union features {
116 struct generic {
117 uchar_t data[1];
118 } gen;
119 uchar_t data[1];
120 struct profile_list {
121 uchar_t profile[2];
122 #if defined(_BIT_FIELDS_LTOH)
123 uchar_t current_p : 1;
124 uchar_t reserved1 : 7;
125 #else
126 uchar_t reserved1 : 7;
127 uchar_t current_p : 1;
128 #endif /* _BIT_FIELDS_LTOH */
129 uchar_t reserved2;
130 } plist[1];
131 struct core {
132 uchar_t phys[4];
133 } core;
134 struct morphing {
135 #if defined(_BIT_FIELDS_LTOH)
136 uchar_t async : 1;
137 uchar_t reserved1 : 7;
138 #else
139 uchar_t reserved1 : 7;
140 uchar_t async : 1;
141 #endif /* _BIT_FIELDS_LTOH */
142 uchar_t reserved[3];
143 } morphing;
144 struct removable {
145 #if defined(_BIT_FIELDS_LTOH)
146 uchar_t lock : 1;
147 uchar_t resv1 : 1;
148 uchar_t pvnt : 1;
149 uchar_t eject : 1;
150 uchar_t resv2 : 1;
151 uchar_t loading : 3;
152 #else
153 uchar_t loading : 3;
154 uchar_t resv2 : 1;
155 uchar_t eject : 1;
156 uchar_t pvnt : 1;
157 uchar_t resv1 : 1;
158 uchar_t lock : 1;
159 #endif /* _BIT_FIELDS_LTOH */
160 uchar_t reserved[3];
161 } removable;
162 struct random_readable {
163 uchar_t lbsize[4];
164 uchar_t blocking[2];
165 #if defined(_BIT_FIELDS_LTOH)
166 uchar_t pp : 1;
167 uchar_t reserved1 : 7;
168 #else
169 uchar_t reserved1 : 7;
170 uchar_t pp : 1;
171 #endif /* _BIT_FIELDS_LTOH */
172 uchar_t reserved;
173 } rread;
174 struct cd_read {
175 #if defined(_BIT_FIELDS_LTOH)
176 uchar_t cdtext : 1;
177 uchar_t c2flag : 1;
178 uchar_t reserved1 : 6;
179 #else
180 uchar_t reserved1 : 6;
181 uchar_t c2flag : 1;
182 uchar_t cdtext : 1;
183 #endif /* _BIT_FIELDS_LTOH */
184 } cdread;
185 struct cd_audio {
186 #if defined(_BIT_FIELDS_LTOH)
187 uchar_t sv : 1;
188 uchar_t scm : 1;
189 uchar_t scan : 1;
190 uchar_t resv : 5;
191 #else
192 uchar_t resv : 5;
193 uchar_t scan : 1;
194 uchar_t scm : 1;
195 uchar_t sv : 1;
196 #endif /* _BIT_FIELDS_LTOH */
197 uchar_t reserved;
198 uchar_t numlevels[2];
199 } audio;
200 struct dvd_css {
201 uchar_t reserved[3];
202 uchar_t version;
203 } dvdcss;
204 } features;
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 {
227 uchar_t len[4];
228 uchar_t reserved[2];
229 uchar_t curprof[2];
230 struct conf_feature feature;
233 struct capabilities {
234 #if defined(_BIT_FIELDS_LTOH)
235 uchar_t pagecode : 6;
236 uchar_t resv1 : 1;
237 uchar_t ps : 1;
238 #else
239 uchar_t ps : 1;
240 uchar_t resv1 : 1;
241 uchar_t pagecode : 6;
242 #endif /* _BIT_FIELDS_LTOH */
243 uchar_t pagelen;
244 #if defined(_BIT_FIELDS_LTOH)
245 /* read capabilities */
246 uchar_t cdr_read : 1;
247 uchar_t cdrw_read : 1;
248 uchar_t method2 : 1;
249 uchar_t dvdrom_read : 1;
250 uchar_t dvdr_read : 1;
251 uchar_t dvdram_read : 1;
252 uchar_t resv2 : 2;
253 #else
254 uchar_t resv2 : 2;
255 uchar_t dvdram_read : 1;
256 uchar_t dvdr_read : 1;
257 uchar_t dvdrom_read : 1;
258 uchar_t method2 : 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;
267 uchar_t resv3 : 1;
268 uchar_t dvdr_write : 1;
269 uchar_t dvdram_write : 1;
270 uchar_t resv4 : 2;
271 #else
272 /* write capabilities */
273 uchar_t resv4 : 2;
274 uchar_t dvdram_write : 1;
275 uchar_t dvdr_write : 1;
276 uchar_t resv3 : 1;
277 uchar_t testwrite : 1;
278 uchar_t cdrw_write : 1;
279 uchar_t cdr_write : 1;
280 #endif /* _BIT_FIELDS_LTOH */
281 uchar_t misc0;
282 uchar_t misc1;
283 uchar_t misc2;
284 uchar_t misc3;
285 uchar_t obsolete0[2];
286 uchar_t numvlevels[2];
287 uchar_t bufsize[2];
288 uchar_t obsolete1[4];
289 uchar_t resv5;
290 uchar_t misc4;
291 uchar_t obsolete2;
292 uchar_t copymgt[2];
293 /* there is more to this page, but nothing we care about */
296 struct mode_header_g2 {
297 uchar_t modelen[2];
298 uchar_t obsolete;
299 uchar_t reserved[3];
300 uchar_t desclen[2];
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[],
326 int *errp);
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,
339 nvlist_t *nvp);
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,
345 nvlist_t *stats);
346 static int get_io_kstats(kstat_ctl_t *kc, char *diskname,
347 nvlist_t *stats);
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,
353 uint64_t value);
354 static int update_stat32(nvlist_t *stats, char *attr,
355 uint32_t value);
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);
360 descriptor_t **
361 drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
362 int *errp)
364 switch (type) {
365 case DM_CONTROLLER:
366 return (get_assoc_controllers(dp, errp));
367 case DM_PATH:
368 return (get_assoc_paths(dp, errp));
369 case DM_ALIAS:
370 return (get_assoc_alias(dp->p.disk, errp));
371 case DM_MEDIA:
372 return (media_get_assocs(dp, errp));
375 *errp = EINVAL;
376 return (NULL);
380 * Get the drive descriptors for the given media/alias/devpath.
382 descriptor_t **
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) {
391 *errp = ENOMEM;
392 return (NULL);
395 drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
396 if (*errp != 0) {
397 cache_free_descriptors(drives);
398 return (NULL);
401 drives[1] = NULL;
403 return (drives);
406 nvlist_t *
407 drive_get_attributes(descriptor_t *dp, int *errp)
409 nvlist_t *attrs = NULL;
410 int fd;
411 char opath[MAXPATHLEN];
413 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
414 *errp = ENOMEM;
415 return (NULL);
418 opath[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) {
422 nvlist_free(attrs);
423 attrs = NULL;
426 if (fd >= 0) {
427 (void) close(fd);
430 return (attrs);
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.
440 descriptor_t *
441 drive_get_descriptor_by_name(char *name, int *errp)
443 ddi_devid_t devid;
444 descriptor_t **drives;
445 descriptor_t *drive = NULL;
446 int i;
448 if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
449 *errp = EINVAL;
450 return (NULL);
453 drives = cache_get_descriptors(DM_DRIVE, errp);
454 if (*errp != 0) {
455 devid_free(devid);
456 return (NULL);
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) {
466 drive = drives[i];
468 } else {
469 /* clean up the unused descriptor */
470 cache_free_descriptor(drives[i]);
473 free(drives);
474 devid_free(devid);
476 if (drive == NULL) {
477 *errp = ENODEV;
480 return (drive);
483 descriptor_t **
484 drive_get_descriptors(int filter[], int *errp)
486 descriptor_t **drives;
488 drives = cache_get_descriptors(DM_DRIVE, errp);
489 if (*errp != 0) {
490 return (NULL);
493 if (filter != NULL && filter[0] != DM_FILTER_END) {
494 descriptor_t **found;
495 found = apply_filter(drives, filter, errp);
496 if (*errp != 0) {
497 drives = NULL;
498 } else {
499 drives = found;
503 return (drives);
506 char *
507 drive_get_name(descriptor_t *dp)
509 return (dp->p.disk->device_id);
512 nvlist_t *
513 drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
515 disk_t *diskp;
516 nvlist_t *stats;
518 diskp = dp->p.disk;
520 if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
521 *errp = ENOMEM;
522 return (NULL);
525 if (stat_type == DM_DRV_STAT_PERFORMANCE ||
526 stat_type == DM_DRV_STAT_DIAGNOSTIC) {
528 alias_t *ap;
529 kstat_ctl_t *kc;
531 ap = diskp->aliases;
532 if (ap == NULL || ap->kstat_name == NULL) {
533 nvlist_free(stats);
534 *errp = EACCES;
535 return (NULL);
538 if ((kc = kstat_open()) == NULL) {
539 nvlist_free(stats);
540 *errp = EACCES;
541 return (NULL);
544 while (ap != NULL) {
545 int status;
547 if (ap->kstat_name == NULL) {
548 continue;
551 if (stat_type == DM_DRV_STAT_PERFORMANCE) {
552 status = get_io_kstats(kc, ap->kstat_name, stats);
553 } else {
554 status = get_err_kstats(kc, ap->kstat_name, stats);
557 if (status != 0) {
558 nvlist_free(stats);
559 (void) kstat_close(kc);
560 *errp = ENOMEM;
561 return (NULL);
564 ap = ap->next;
567 (void) kstat_close(kc);
569 *errp = 0;
570 return (stats);
573 if (stat_type == DM_DRV_STAT_TEMPERATURE) {
574 int fd;
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) {
582 *errp = ENOMEM;
583 nvlist_free(stats);
584 return (NULL);
586 } else {
587 *errp = errno;
588 nvlist_free(stats);
589 return (NULL);
591 (void) close(fd);
592 } else {
593 *errp = errno;
594 nvlist_free(stats);
595 return (NULL);
598 *errp = 0;
599 return (stats);
602 nvlist_free(stats);
603 *errp = EINVAL;
604 return (NULL);
608 drive_make_descriptors()
610 int error;
611 disk_t *dp;
613 dp = cache_get_disklist();
614 while (dp != NULL) {
615 cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
616 if (error != 0) {
617 return (error);
619 dp = dp->next;
622 return (0);
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) {
635 if (opath != NULL) {
636 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
638 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
641 return (-1);
644 static descriptor_t **
645 apply_filter(descriptor_t **drives, int filter[], int *errp)
647 int i;
648 descriptor_t **found;
649 int cnt;
650 int pos;
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 *));
656 if (found == NULL) {
657 *errp = ENOMEM;
658 cache_free_descriptors(drives);
659 return (NULL);
662 pos = 0;
663 for (i = 0; drives[i]; i++) {
664 int j;
665 int match;
667 /* Make sure the drive type is set */
668 get_drive_type(drives[i]->p.disk, -1);
670 match = 0;
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];
674 match = 1;
675 break;
679 if (!match) {
680 cache_free_descriptor(drives[i]);
683 found[pos] = NULL;
684 free(drives);
686 *errp = 0;
687 return (found);
690 static int
691 conv_drive_type(uint_t drive_type)
693 switch (drive_type) {
694 case DK_UNKNOWN:
695 return (DM_DT_UNKNOWN);
696 case DK_MO_ERASABLE:
697 return (DM_DT_MO_ERASABLE);
698 case DK_MO_WRITEONCE:
699 return (DM_DT_MO_WRITEONCE);
700 case DK_AS_MO:
701 return (DM_DT_AS_MO);
702 case DK_CDROM:
703 return (DM_DT_CDROM);
704 case DK_CDR:
705 return (DM_DT_CDR);
706 case DK_CDRW:
707 return (DM_DT_CDRW);
708 case DK_DVDROM:
709 return (DM_DT_DVDROM);
710 case DK_DVDR:
711 return (DM_DT_DVDR);
712 case DK_DVDRAM:
713 return (DM_DT_DVDRAM);
714 case DK_FIXED_DISK:
715 return (DM_DT_FIXED);
716 case DK_FLOPPY:
717 return (DM_DT_FLOPPY);
718 case DK_ZIP:
719 return (DM_DT_ZIP);
720 case DK_JAZ:
721 return (DM_DT_JAZ);
722 default:
723 return (DM_DT_UNKNOWN);
727 static descriptor_t **
728 get_assoc_alias(disk_t *diskp, int *errp)
730 alias_t *aliasp;
731 uint_t cnt;
732 descriptor_t **out_array;
733 int pos;
735 *errp = 0;
737 aliasp = diskp->aliases;
738 cnt = 0;
740 while (aliasp != NULL) {
741 if (aliasp->alias != NULL) {
742 cnt++;
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) {
750 *errp = ENOMEM;
751 return (NULL);
754 aliasp = diskp->aliases;
755 pos = 0;
756 while (aliasp != NULL) {
757 if (aliasp->alias != NULL) {
758 out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
759 aliasp->alias, NULL, errp);
760 if (*errp != 0) {
761 cache_free_descriptors(out_array);
762 return (NULL);
766 aliasp = aliasp->next;
769 out_array[pos] = NULL;
771 return (out_array);
774 static descriptor_t **
775 get_assoc_controllers(descriptor_t *dp, int *errp)
777 disk_t *diskp;
778 int cnt;
779 descriptor_t **controllers;
780 int i;
782 diskp = dp->p.disk;
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) {
790 *errp = ENOMEM;
791 return (NULL);
794 for (i = 0; diskp->controllers[i]; i++) {
795 controllers[i] = cache_get_desc(DM_CONTROLLER,
796 diskp->controllers[i], NULL, NULL, errp);
797 if (*errp != 0) {
798 cache_free_descriptors(controllers);
799 return (NULL);
803 controllers[i] = NULL;
805 *errp = 0;
806 return (controllers);
809 static descriptor_t **
810 get_assoc_paths(descriptor_t *dp, int *errp)
812 path_t **pp;
813 int cnt;
814 descriptor_t **paths;
815 int i;
817 pp = dp->p.disk->paths;
819 /* Count how many we have. */
820 cnt = 0;
821 if (pp != NULL) {
822 for (; pp[cnt]; cnt++);
825 /* make the snapshot */
826 paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
827 if (paths == NULL) {
828 *errp = ENOMEM;
829 return (NULL);
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,
840 NULL, errp);
841 if (*errp != 0) {
842 cache_free_descriptors(paths);
843 return (NULL);
847 paths[i] = NULL;
849 *errp = 0;
850 return (paths);
853 static int
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) {
860 return (ENOMEM);
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) {
866 return (ENOMEM);
870 /* can't tell diff between dead & no media on removable drives */
871 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
872 return (ENOMEM);
875 get_drive_type(diskp, fd);
877 } else {
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) {
883 return (ENOMEM);
885 } else {
886 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
887 return (ENOMEM);
891 get_drive_type(diskp, fd);
894 if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
895 return (ENOMEM);
898 if (diskp->product_id != NULL) {
899 if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
900 != 0) {
901 return (ENOMEM);
904 if (diskp->vendor_id != NULL) {
905 if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
906 return (ENOMEM);
910 if (diskp->sync_speed != -1) {
911 if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
912 != 0) {
913 return (ENOMEM);
917 if (diskp->wide == 1) {
918 if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
919 return (ENOMEM);
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) {
929 return (ENOMEM);
933 if (diskp->aliases != NULL && diskp->aliases->cluster) {
934 if (nvlist_add_boolean(attrs, DM_CLUSTERED) != 0) {
935 return (ENOMEM);
939 if (strlen(opath) > 0) {
940 if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
941 return (ENOMEM);
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) {
951 return (ENOMEM);
955 return (0);
958 static int
959 get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
960 nvlist_t *stats)
962 kstat_t *ksp;
963 size_t class_len;
964 int err = 0;
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 != ',') {
975 *dname++ = *ename++;
977 *dname = '\0';
979 if (libdiskmgt_str_eq(diskname, kstat_name)) {
980 (void) kstat_read(kc, ksp, NULL);
981 err = get_kstat_vals(ksp, stats);
982 break;
987 return (err);
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.
996 static void
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. */
1003 if (fd < 0) {
1004 fd = drive_open_disk(dp, NULL, 0);
1005 opened_here = 1;
1008 if (fd >= 0) {
1009 if (dp->cd_rom) {
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;
1018 } else {
1019 struct dk_minfo minfo;
1021 if (media_read_info(fd, &minfo)) {
1022 dp->drv_type = conv_drive_type(minfo.dki_media_type);
1026 if (opened_here) {
1027 (void) close(fd);
1030 } else {
1031 /* couldn't open */
1032 if (dp->cd_rom) {
1033 dp->drv_type = DM_DT_CDROM;
1039 static char *
1040 get_err_attr_name(char *kstat_name)
1042 int i;
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]);
1050 return (NULL);
1053 static int
1054 get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1056 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
1059 static int
1060 get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1062 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
1065 static int
1066 get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
1068 if (ksp->ks_type == KSTAT_TYPE_IO) {
1069 kstat_io_t *kiop;
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) {
1076 return (ENOMEM);
1078 if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
1079 return (ENOMEM);
1081 if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
1082 return (ENOMEM);
1084 if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
1085 return (ENOMEM);
1088 } else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
1089 kstat_named_t *knp;
1090 int i;
1092 knp = KSTAT_NAMED_PTR(ksp);
1093 for (i = 0; i < ksp->ks_ndata; i++) {
1094 char *attr_name;
1096 if (knp[i].name[0] == 0)
1097 continue;
1099 if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
1100 continue;
1104 switch (knp[i].data_type) {
1105 case KSTAT_DATA_UINT32:
1106 if (update_stat32(stats, attr_name, knp[i].value.ui32)
1107 != 0) {
1108 return (ENOMEM);
1110 break;
1112 default:
1113 /* Right now all of the error types are uint32 */
1114 break;
1118 return (0);
1121 static int
1122 update_stat32(nvlist_t *stats, char *attr, uint32_t value)
1124 int32_t currval;
1126 if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
1127 value += currval;
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.
1139 static int
1140 update_stat64(nvlist_t *stats, char *attr, uint64_t value)
1142 int64_t currval;
1144 if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
1145 value += currval;
1147 return (nvlist_add_uint64(stats, attr, value));
1151 * uscsi function to get the rpm of the drive
1153 static int
1154 get_rpm(disk_t *dp, int fd)
1156 int opened_here = 0;
1157 int rpm = -1;
1159 /* We may have already opened the device. */
1160 if (fd < 0) {
1161 fd = drive_open_disk(dp, NULL, 0);
1162 opened_here = 1;
1165 if (fd >= 0) {
1166 int status;
1167 struct mode_geometry *page4;
1168 struct scsi_ms_header header;
1169 union {
1170 struct mode_geometry page4;
1171 char rawbuf[MAX_MODE_SENSE_SIZE];
1172 } u_page4;
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,
1179 &header);
1181 if (status) {
1182 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1183 MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1184 &header);
1187 if (status) {
1188 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1189 MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1190 &header);
1193 if (!status) {
1194 #ifdef _LITTLE_ENDIAN
1195 page4->rpm = ntohs(page4->rpm);
1196 #endif /* _LITTLE_ENDIAN */
1198 rpm = page4->rpm;
1201 if (opened_here) {
1202 (void) close(fd);
1206 return (rpm);
1209 static int
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. */
1216 if (fd < 0) {
1217 fd = drive_open_disk(dp, NULL, 0);
1218 opened_here = 1;
1221 if (fd >= 0) {
1222 if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
1223 solid_state = -1;
1227 if (opened_here) {
1228 (void) close(fd);
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.
1242 static int
1243 get_cdrom_drvtype(int fd)
1245 union scsi_cdb cdb;
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;
1256 int flen;
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);
1262 if (flen > 0) {
1263 int prof_num;
1265 prof_num = (int)convnum(feature->features.plist[0].profile, 2);
1267 if (dm_debug > 1) {
1268 (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
1269 prof_num);
1272 switch (prof_num) {
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);
1279 case PROF_CDROM:
1280 return (DM_DT_CDROM);
1281 case PROF_CDR:
1282 return (DM_DT_CDR);
1283 case PROF_CDRW:
1284 return (DM_DT_CDRW);
1285 case PROF_DVDROM:
1286 return (DM_DT_DVDROM);
1287 case PROF_DVDRAM:
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);
1293 case PROF_DVDRW:
1294 return (DM_DT_DVDRW);
1295 case PROF_DDCD_ROM:
1296 return (DM_DT_DDCDROM);
1297 case PROF_DDCD_R:
1298 return (DM_DT_DDCDR);
1299 case PROF_DDCD_RW:
1300 return (DM_DT_DDCDRW);
1305 /* see if the atapi capabilities give anything */
1306 return (check_atapi(fd));
1309 static int
1310 check_atapi(int fd)
1312 union scsi_cdb cdb;
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) {
1320 int bdesclen;
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];
1330 if (dm_debug > 1) {
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) {
1348 return (DM_DT_CDR);
1350 if (cap->cdr_read) {
1351 return (DM_DT_CDROM);
1355 /* everything failed, so this is an older CD-ROM */
1356 if (dm_debug > 1) {
1357 (void) fprintf(stderr, "INFO: uscsi failed\n");
1360 return (DM_DT_CDROM);
1363 static uint64_t
1364 convnum(uchar_t *nptr, int len)
1366 uint64_t value;
1368 for (value = 0; len > 0; len--, nptr++)
1369 value = (value << 8) | *nptr;
1370 return (value);
1373 static void
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));
1378 bzero(buff, blen);
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;
1389 static void
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;
1395 cdb->scc_lun = lun;
1396 cdb->g1_count0 = c0; /* max length for page */
1397 cdb->g1_count1 = c1; /* max length for page */
1400 static void
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;
1411 static int
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;
1418 int nbytes;
1419 struct uscsi_cmd ucmd;
1420 union scsi_cdb cdb;
1421 int status;
1422 int maximum;
1423 char rqbuf[255];
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;
1431 nbytes = page_size;
1432 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
1433 return (-1);
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);
1466 return (-1);
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);
1481 return (-1);
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);
1489 return (-1);
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
1496 * of the two.
1498 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
1499 if (((int)pg->length) > maximum) {
1500 free(mode_sense_buf);
1501 return (-1);
1504 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1506 free(mode_sense_buf);
1507 return (0);