1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2017 Nexenta Systems, Inc.
29 * Copyright 2024 Sebastian Wiedenroth
30 */
31
32 #include <fcntl.h>
33 #include <libdevinfo.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stropts.h>
38 #include <sys/dkio.h>
39 #include <sys/sunddi.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 #include <kstat.h>
43 #include <errno.h>
44 #include <devid.h>
45 #include <dirent.h>
46
47 /* included for uscsi */
48 #include <strings.h>
49 #include <sys/stat.h>
50 #include <sys/scsi/impl/types.h>
51 #include <sys/scsi/impl/uscsi.h>
52 #include <sys/scsi/generic/commands.h>
53 #include <sys/scsi/impl/commands.h>
54 #include <sys/scsi/generic/mode.h>
55 #include <sys/byteorder.h>
56
57 #include "libdiskmgt.h"
58 #include "disks_private.h"
59
60 #define KSTAT_CLASS_DISK "disk"
61 #define KSTAT_CLASS_ERROR "device_error"
62
63 #define SCSIBUFLEN 0xffff
64
65 /* byte get macros */
66 #define b3(a) (((a)>>24) & 0xFF)
67 #define b2(a) (((a)>>16) & 0xFF)
68 #define b1(a) (((a)>>8) & 0xFF)
69 #define b0(a) (((a)>>0) & 0xFF)
70
71 static char *kstat_err_names[] = {
72 "Soft Errors",
73 "Hard Errors",
74 "Transport Errors",
75 "Media Error",
76 "Device Not Ready",
77 "No Device",
78 "Recoverable",
79 "Illegal Request",
80 "Predictive Failure Analysis",
81 NULL
82 };
83
84 static char *err_attr_names[] = {
85 DM_NSOFTERRS,
86 DM_NHARDERRS,
87 DM_NTRANSERRS,
88 DM_NMEDIAERRS,
89 DM_NDNRERRS,
90 DM_NNODEVERRS,
91 DM_NRECOVERRS,
92 DM_NILLREQERRS,
93 DM_FAILING,
94 NULL
95 };
96
97 /*
98 * **************** begin uscsi stuff ****************
99 */
100
101 #if defined(_BIT_FIELDS_LTOH)
102 #elif defined(_BIT_FIELDS_HTOL)
103 #else
104 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
105 #endif
106
107 struct conf_feature {
108 uchar_t feature[2]; /* common to all */
109 #if defined(_BIT_FIELDS_LTOH)
110 uchar_t current : 1;
111 uchar_t persist : 1;
112 uchar_t version : 4;
113 uchar_t reserved: 2;
114 #else
115 uchar_t reserved: 2;
116 uchar_t version : 4;
117 uchar_t persist : 1;
118 uchar_t current : 1;
119 #endif /* _BIT_FIELDS_LTOH */
120 uchar_t len;
121 union features {
122 struct generic {
123 uchar_t data[1];
124 } gen;
125 uchar_t data[1];
126 struct profile_list {
127 uchar_t profile[2];
128 #if defined(_BIT_FIELDS_LTOH)
129 uchar_t current_p : 1;
130 uchar_t reserved1 : 7;
131 #else
132 uchar_t reserved1 : 7;
133 uchar_t current_p : 1;
134 #endif /* _BIT_FIELDS_LTOH */
135 uchar_t reserved2;
136 } plist[1];
137 struct core {
138 uchar_t phys[4];
139 } core;
140 struct morphing {
141 #if defined(_BIT_FIELDS_LTOH)
142 uchar_t async : 1;
143 uchar_t reserved1 : 7;
144 #else
145 uchar_t reserved1 : 7;
146 uchar_t async : 1;
147 #endif /* _BIT_FIELDS_LTOH */
148 uchar_t reserved[3];
149 } morphing;
150 struct removable {
151 #if defined(_BIT_FIELDS_LTOH)
152 uchar_t lock : 1;
153 uchar_t resv1 : 1;
154 uchar_t pvnt : 1;
155 uchar_t eject : 1;
156 uchar_t resv2 : 1;
157 uchar_t loading : 3;
158 #else
159 uchar_t loading : 3;
160 uchar_t resv2 : 1;
161 uchar_t eject : 1;
162 uchar_t pvnt : 1;
163 uchar_t resv1 : 1;
164 uchar_t lock : 1;
165 #endif /* _BIT_FIELDS_LTOH */
166 uchar_t reserved[3];
167 } removable;
168 struct random_readable {
169 uchar_t lbsize[4];
170 uchar_t blocking[2];
171 #if defined(_BIT_FIELDS_LTOH)
172 uchar_t pp : 1;
173 uchar_t reserved1 : 7;
174 #else
175 uchar_t reserved1 : 7;
176 uchar_t pp : 1;
177 #endif /* _BIT_FIELDS_LTOH */
178 uchar_t reserved;
179 } rread;
180 struct cd_read {
181 #if defined(_BIT_FIELDS_LTOH)
182 uchar_t cdtext : 1;
183 uchar_t c2flag : 1;
184 uchar_t reserved1 : 6;
185 #else
186 uchar_t reserved1 : 6;
187 uchar_t c2flag : 1;
188 uchar_t cdtext : 1;
189 #endif /* _BIT_FIELDS_LTOH */
190 } cdread;
191 struct cd_audio {
192 #if defined(_BIT_FIELDS_LTOH)
193 uchar_t sv : 1;
194 uchar_t scm : 1;
195 uchar_t scan : 1;
196 uchar_t resv : 5;
197 #else
198 uchar_t resv : 5;
199 uchar_t scan : 1;
200 uchar_t scm : 1;
201 uchar_t sv : 1;
202 #endif /* _BIT_FIELDS_LTOH */
203 uchar_t reserved;
204 uchar_t numlevels[2];
205 } audio;
206 struct dvd_css {
207 uchar_t reserved[3];
208 uchar_t version;
209 } dvdcss;
210 } features;
211 };
212
213 #define PROF_NON_REMOVABLE 0x0001
214 #define PROF_REMOVABLE 0x0002
215 #define PROF_MAGNETO_OPTICAL 0x0003
216 #define PROF_OPTICAL_WO 0x0004
217 #define PROF_OPTICAL_ASMO 0x0005
218 #define PROF_CDROM 0x0008
219 #define PROF_CDR 0x0009
220 #define PROF_CDRW 0x000a
221 #define PROF_DVDROM 0x0010
222 #define PROF_DVDR 0x0011
223 #define PROF_DVDRAM 0x0012
224 #define PROF_DVDRW_REST 0x0013
225 #define PROF_DVDRW_SEQ 0x0014
226 #define PROF_DVDRW 0x001a
227 #define PROF_DDCD_ROM 0x0020
228 #define PROF_DDCD_R 0x0021
229 #define PROF_DDCD_RW 0x0022
230 #define PROF_NON_CONFORMING 0xffff
231
232 struct get_configuration {
233 uchar_t len[4];
234 uchar_t reserved[2];
235 uchar_t curprof[2];
236 struct conf_feature feature;
237 };
238
239 struct capabilities {
240 #if defined(_BIT_FIELDS_LTOH)
241 uchar_t pagecode : 6;
242 uchar_t resv1 : 1;
243 uchar_t ps : 1;
244 #else
245 uchar_t ps : 1;
246 uchar_t resv1 : 1;
247 uchar_t pagecode : 6;
248 #endif /* _BIT_FIELDS_LTOH */
249 uchar_t pagelen;
250 #if defined(_BIT_FIELDS_LTOH)
251 /* read capabilities */
252 uchar_t cdr_read : 1;
253 uchar_t cdrw_read : 1;
254 uchar_t method2 : 1;
255 uchar_t dvdrom_read : 1;
256 uchar_t dvdr_read : 1;
257 uchar_t dvdram_read : 1;
258 uchar_t resv2 : 2;
259 #else
260 uchar_t resv2 : 2;
261 uchar_t dvdram_read : 1;
262 uchar_t dvdr_read : 1;
263 uchar_t dvdrom_read : 1;
264 uchar_t method2 : 1;
265 uchar_t cdrw_read : 1;
266 uchar_t cdr_read : 1;
267 #endif /* _BIT_FIELDS_LTOH */
268 #if defined(_BIT_FIELDS_LTOH)
269 /* write capabilities */
270 uchar_t cdr_write : 1;
271 uchar_t cdrw_write : 1;
272 uchar_t testwrite : 1;
273 uchar_t resv3 : 1;
274 uchar_t dvdr_write : 1;
275 uchar_t dvdram_write : 1;
276 uchar_t resv4 : 2;
277 #else
278 /* write capabilities */
279 uchar_t resv4 : 2;
280 uchar_t dvdram_write : 1;
281 uchar_t dvdr_write : 1;
282 uchar_t resv3 : 1;
283 uchar_t testwrite : 1;
284 uchar_t cdrw_write : 1;
285 uchar_t cdr_write : 1;
286 #endif /* _BIT_FIELDS_LTOH */
287 uchar_t misc0;
288 uchar_t misc1;
289 uchar_t misc2;
290 uchar_t misc3;
291 uchar_t obsolete0[2];
292 uchar_t numvlevels[2];
293 uchar_t bufsize[2];
294 uchar_t obsolete1[4];
295 uchar_t resv5;
296 uchar_t misc4;
297 uchar_t obsolete2;
298 uchar_t copymgt[2];
299 /* there is more to this page, but nothing we care about */
300 };
301
302 struct mode_header_g2 {
303 uchar_t modelen[2];
304 uchar_t obsolete;
305 uchar_t reserved[3];
306 uchar_t desclen[2];
307 };
308
309 /*
310 * Mode sense/select page header information
311 */
312 struct scsi_ms_header {
313 struct mode_header mode_header;
314 struct block_descriptor block_descriptor;
315 };
316
317 #define MODESENSE_PAGE_LEN(p) (((int)((struct mode_page *)p)->length) + \
318 sizeof (struct mode_page))
319
320 #define MODE_SENSE_PC_CURRENT (0 << 6)
321 #define MODE_SENSE_PC_DEFAULT (2 << 6)
322 #define MODE_SENSE_PC_SAVED (3 << 6)
323
324 #define MAX_MODE_SENSE_SIZE 255
325 #define IMPOSSIBLE_SCSI_STATUS 0xff
326
327 /*
328 * ********** end of uscsi stuff ************
329 */
330
331 static descriptor_t **apply_filter(descriptor_t **drives, int filter[],
332 int *errp);
333 static int check_atapi(int fd);
334 static int conv_drive_type(uint_t drive_type);
335 static uint64_t convnum(uchar_t *nptr, int len);
336 static void fill_command_g1(struct uscsi_cmd *cmd,
337 union scsi_cdb *cdb, caddr_t buff, int blen);
338 static void fill_general_page_cdb_g1(union scsi_cdb *cdb,
339 int command, int lun, uchar_t c0, uchar_t c1);
340 static void fill_mode_page_cdb(union scsi_cdb *cdb, int page);
341 static descriptor_t **get_assoc_alias(disk_t *diskp, int *errp);
342 static descriptor_t **get_assoc_controllers(descriptor_t *dp, int *errp);
343 static descriptor_t **get_assoc_paths(descriptor_t *dp, int *errp);
344 static int get_attrs(disk_t *diskp, int fd, char *opath,
345 nvlist_t *nvp);
346 static int get_cdrom_drvtype(int fd);
347 static int get_disk_kstats(kstat_ctl_t *kc, char *diskname,
348 char *classname, nvlist_t *stats);
349 static void get_drive_type(disk_t *dp, int fd);
350 static int get_err_kstats(kstat_ctl_t *kc, char *diskname,
351 nvlist_t *stats);
352 static int get_io_kstats(kstat_ctl_t *kc, char *diskname,
353 nvlist_t *stats);
354 static int get_kstat_vals(kstat_t *ksp, nvlist_t *stats);
355 static char *get_err_attr_name(char *kstat_name);
356 static int get_rpm(disk_t *dp, int fd);
357 static int get_solidstate(disk_t *dp, int fd);
358 static int update_stat64(nvlist_t *stats, char *attr,
359 uint64_t value);
360 static int update_stat32(nvlist_t *stats, char *attr,
361 uint32_t value);
362 static int uscsi_mode_sense(int fd, int page_code,
363 int page_control, caddr_t page_data, int page_size,
364 struct scsi_ms_header *header);
365
366 descriptor_t **
drive_get_assoc_descriptors(descriptor_t * dp,dm_desc_type_t type,int * errp)367 drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
368 int *errp)
369 {
370 switch (type) {
371 case DM_CONTROLLER:
372 return (get_assoc_controllers(dp, errp));
373 case DM_PATH:
374 return (get_assoc_paths(dp, errp));
375 case DM_ALIAS:
376 return (get_assoc_alias(dp->p.disk, errp));
377 case DM_MEDIA:
378 return (media_get_assocs(dp, errp));
379 }
380
381 *errp = EINVAL;
382 return (NULL);
383 }
384
385 /*
386 * Get the drive descriptors for the given media/alias/devpath.
387 */
388 descriptor_t **
drive_get_assocs(descriptor_t * desc,int * errp)389 drive_get_assocs(descriptor_t *desc, int *errp)
390 {
391 descriptor_t **drives;
392
393 /* at most one drive is associated with these descriptors */
394
395 drives = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
396 if (drives == NULL) {
397 *errp = ENOMEM;
398 return (NULL);
399 }
400
401 drives[0] = cache_get_desc(DM_DRIVE, desc->p.disk, NULL, NULL, errp);
402 if (*errp != 0) {
403 cache_free_descriptors(drives);
404 return (NULL);
405 }
406
407 drives[1] = NULL;
408
409 return (drives);
410 }
411
412 nvlist_t *
drive_get_attributes(descriptor_t * dp,int * errp)413 drive_get_attributes(descriptor_t *dp, int *errp)
414 {
415 nvlist_t *attrs = NULL;
416 int fd;
417 char opath[MAXPATHLEN];
418
419 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
420 *errp = ENOMEM;
421 return (NULL);
422 }
423
424 opath[0] = 0;
425 fd = drive_open_disk(dp->p.disk, opath, sizeof (opath));
426
427 if ((*errp = get_attrs(dp->p.disk, fd, opath, attrs)) != 0) {
428 nvlist_free(attrs);
429 attrs = NULL;
430 }
431
432 if (fd >= 0) {
433 (void) close(fd);
434 }
435
436 return (attrs);
437 }
438
439 /*
440 * Check if we have the drive in our list, based upon the device id.
441 * We got the device id from the dev tree walk. This is encoded
442 * using devid_str_encode(3DEVID). In order to check the device ids we need
443 * to use the devid_compare(3DEVID) function, so we need to decode the
444 * string representation of the device id.
445 */
446 descriptor_t *
drive_get_descriptor_by_name(char * name,int * errp)447 drive_get_descriptor_by_name(char *name, int *errp)
448 {
449 ddi_devid_t devid;
450 descriptor_t **drives;
451 descriptor_t *drive = NULL;
452 int i;
453
454 if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
455 *errp = EINVAL;
456 return (NULL);
457 }
458
459 drives = cache_get_descriptors(DM_DRIVE, errp);
460 if (*errp != 0) {
461 devid_free(devid);
462 return (NULL);
463 }
464
465 /*
466 * We have to loop through all of them, freeing the ones we don't
467 * want. Once drive is set, we don't need to compare any more.
468 */
469 for (i = 0; drives[i]; i++) {
470 if (drive == NULL && drives[i]->p.disk->devid != NULL &&
471 devid_compare(devid, drives[i]->p.disk->devid) == 0) {
472 drive = drives[i];
473 } else {
474 /* clean up the unused descriptor */
475 cache_free_descriptor(drives[i]);
476 }
477 }
478 free(drives);
479 devid_free(devid);
480
481 if (drive == NULL) {
482 *errp = ENODEV;
483 }
484
485 return (drive);
486 }
487
488 descriptor_t **
drive_get_descriptors(int filter[],int * errp)489 drive_get_descriptors(int filter[], int *errp)
490 {
491 descriptor_t **drives;
492
493 drives = cache_get_descriptors(DM_DRIVE, errp);
494 if (*errp != 0) {
495 return (NULL);
496 }
497
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;
505 }
506 }
507
508 return (drives);
509 }
510
511 char *
drive_get_name(descriptor_t * dp)512 drive_get_name(descriptor_t *dp)
513 {
514 return (dp->p.disk->device_id);
515 }
516
517 nvlist_t *
drive_get_stats(descriptor_t * dp,int stat_type,int * errp)518 drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
519 {
520 disk_t *diskp;
521 nvlist_t *stats;
522
523 diskp = dp->p.disk;
524
525 if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
526 *errp = ENOMEM;
527 return (NULL);
528 }
529
530 if (stat_type == DM_DRV_STAT_PERFORMANCE ||
531 stat_type == DM_DRV_STAT_DIAGNOSTIC) {
532
533 alias_t *ap;
534 kstat_ctl_t *kc;
535
536 ap = diskp->aliases;
537 if (ap == NULL || ap->kstat_name == NULL) {
538 nvlist_free(stats);
539 *errp = EACCES;
540 return (NULL);
541 }
542
543 if ((kc = kstat_open()) == NULL) {
544 nvlist_free(stats);
545 *errp = EACCES;
546 return (NULL);
547 }
548
549 while (ap != NULL) {
550 int status;
551
552 if (ap->kstat_name == NULL) {
553 continue;
554 }
555
556 if (stat_type == DM_DRV_STAT_PERFORMANCE) {
557 status = get_io_kstats(kc, ap->kstat_name,
558 stats);
559 } else {
560 status = get_err_kstats(kc, ap->kstat_name,
561 stats);
562 }
563
564 if (status != 0) {
565 nvlist_free(stats);
566 (void) kstat_close(kc);
567 *errp = ENOMEM;
568 return (NULL);
569 }
570
571 ap = ap->next;
572 }
573
574 (void) kstat_close(kc);
575
576 *errp = 0;
577 return (stats);
578 }
579
580 if (stat_type == DM_DRV_STAT_TEMPERATURE) {
581 int fd;
582
583 if ((fd = drive_open_disk(diskp, NULL, 0)) >= 0) {
584 struct dk_temperature temp;
585
586 if (ioctl(fd, DKIOCGTEMPERATURE, &temp) >= 0) {
587 if (nvlist_add_uint32(stats, DM_TEMPERATURE,
588 temp.dkt_cur_temp) != 0) {
589 *errp = ENOMEM;
590 nvlist_free(stats);
591 return (NULL);
592 }
593 } else {
594 *errp = errno;
595 nvlist_free(stats);
596 return (NULL);
597 }
598 (void) close(fd);
599 } else {
600 *errp = errno;
601 nvlist_free(stats);
602 return (NULL);
603 }
604
605 *errp = 0;
606 return (stats);
607 }
608
609 nvlist_free(stats);
610 *errp = EINVAL;
611 return (NULL);
612 }
613
614 int
drive_make_descriptors()615 drive_make_descriptors()
616 {
617 int error;
618 disk_t *dp;
619
620 dp = cache_get_disklist();
621 while (dp != NULL) {
622 cache_load_desc(DM_DRIVE, dp, NULL, NULL, &error);
623 if (error != 0) {
624 return (error);
625 }
626 dp = dp->next;
627 }
628
629 return (0);
630 }
631
632 /*
633 * This function opens the disk generically (any slice).
634 */
635 int
drive_open_disk(disk_t * diskp,char * opath,int len)636 drive_open_disk(disk_t *diskp, char *opath, int len)
637 {
638 /*
639 * Just open the first devpath.
640 */
641 if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
642 char *devpath = diskp->aliases->devpaths->devpath;
643 if (opath != NULL) {
644 (void) strlcpy(opath, devpath, len);
645 }
646 return (open(devpath, O_RDONLY | O_NDELAY));
647 }
648
649 return (-1);
650 }
651
652 static descriptor_t **
apply_filter(descriptor_t ** drives,int filter[],int * errp)653 apply_filter(descriptor_t **drives, int filter[], int *errp)
654 {
655 int i;
656 descriptor_t **found;
657 int cnt;
658 int pos;
659
660 /* count the number of drives in the snapshot */
661 for (cnt = 0; drives[cnt]; cnt++)
662 ;
663
664 found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
665 if (found == NULL) {
666 *errp = ENOMEM;
667 cache_free_descriptors(drives);
668 return (NULL);
669 }
670
671 pos = 0;
672 for (i = 0; drives[i]; i++) {
673 int j;
674 int match;
675
676 /* Make sure the drive type is set */
677 get_drive_type(drives[i]->p.disk, -1);
678
679 match = 0;
680 for (j = 0; filter[j] != DM_FILTER_END; j++) {
681 if (drives[i]->p.disk->drv_type == filter[j]) {
682 found[pos++] = drives[i];
683 match = 1;
684 break;
685 }
686 }
687
688 if (!match) {
689 cache_free_descriptor(drives[i]);
690 }
691 }
692 found[pos] = NULL;
693 free(drives);
694
695 *errp = 0;
696 return (found);
697 }
698
699 static int
conv_drive_type(uint_t drive_type)700 conv_drive_type(uint_t drive_type)
701 {
702 switch (drive_type) {
703 case DK_UNKNOWN:
704 return (DM_DT_UNKNOWN);
705 case DK_MO_ERASABLE:
706 return (DM_DT_MO_ERASABLE);
707 case DK_MO_WRITEONCE:
708 return (DM_DT_MO_WRITEONCE);
709 case DK_AS_MO:
710 return (DM_DT_AS_MO);
711 case DK_CDROM:
712 return (DM_DT_CDROM);
713 case DK_CDR:
714 return (DM_DT_CDR);
715 case DK_CDRW:
716 return (DM_DT_CDRW);
717 case DK_DVDROM:
718 return (DM_DT_DVDROM);
719 case DK_DVDR:
720 return (DM_DT_DVDR);
721 case DK_DVDRAM:
722 return (DM_DT_DVDRAM);
723 case DK_FIXED_DISK:
724 return (DM_DT_FIXED);
725 case DK_FLOPPY:
726 return (DM_DT_FLOPPY);
727 case DK_ZIP:
728 return (DM_DT_ZIP);
729 case DK_JAZ:
730 return (DM_DT_JAZ);
731 default:
732 return (DM_DT_UNKNOWN);
733 }
734 }
735
736 static descriptor_t **
get_assoc_alias(disk_t * diskp,int * errp)737 get_assoc_alias(disk_t *diskp, int *errp)
738 {
739 alias_t *aliasp;
740 uint_t cnt;
741 descriptor_t **out_array;
742 int pos;
743
744 *errp = 0;
745
746 aliasp = diskp->aliases;
747 cnt = 0;
748
749 while (aliasp != NULL) {
750 if (aliasp->alias != NULL) {
751 cnt++;
752 }
753 aliasp = aliasp->next;
754 }
755
756 /* set up the new array */
757 out_array = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t));
758 if (out_array == NULL) {
759 *errp = ENOMEM;
760 return (NULL);
761 }
762
763 aliasp = diskp->aliases;
764 pos = 0;
765 while (aliasp != NULL) {
766 if (aliasp->alias != NULL) {
767 out_array[pos++] = cache_get_desc(DM_ALIAS, diskp,
768 aliasp->alias, NULL, errp);
769 if (*errp != 0) {
770 cache_free_descriptors(out_array);
771 return (NULL);
772 }
773 }
774
775 aliasp = aliasp->next;
776 }
777
778 out_array[pos] = NULL;
779
780 return (out_array);
781 }
782
783 static descriptor_t **
get_assoc_controllers(descriptor_t * dp,int * errp)784 get_assoc_controllers(descriptor_t *dp, int *errp)
785 {
786 disk_t *diskp;
787 int cnt;
788 descriptor_t **controllers;
789 int i;
790
791 diskp = dp->p.disk;
792
793 /* Count how many we have. */
794 for (cnt = 0; diskp->controllers[cnt]; cnt++)
795 ;
796
797 /* make the snapshot */
798 controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
799 if (controllers == NULL) {
800 *errp = ENOMEM;
801 return (NULL);
802 }
803
804 for (i = 0; diskp->controllers[i]; i++) {
805 controllers[i] = cache_get_desc(DM_CONTROLLER,
806 diskp->controllers[i], NULL, NULL, errp);
807 if (*errp != 0) {
808 cache_free_descriptors(controllers);
809 return (NULL);
810 }
811 }
812
813 controllers[i] = NULL;
814
815 *errp = 0;
816 return (controllers);
817 }
818
819 static descriptor_t **
get_assoc_paths(descriptor_t * dp,int * errp)820 get_assoc_paths(descriptor_t *dp, int *errp)
821 {
822 path_t **pp;
823 int cnt;
824 descriptor_t **paths;
825 int i;
826
827 pp = dp->p.disk->paths;
828
829 /* Count how many we have. */
830 cnt = 0;
831 if (pp != NULL) {
832 for (; pp[cnt]; cnt++)
833 ;
834 }
835
836 /* make the snapshot */
837 paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
838 if (paths == NULL) {
839 *errp = ENOMEM;
840 return (NULL);
841 }
842
843 /*
844 * We fill in the name field of the descriptor with the device_id
845 * when we deal with path descriptors originating from a drive.
846 * In that way we can use the device id within the path code to
847 * lookup the path state for this drive.
848 */
849 for (i = 0; i < cnt; i++) {
850 paths[i] = cache_get_desc(DM_PATH, pp[i], dp->p.disk->device_id,
851 NULL, errp);
852 if (*errp != 0) {
853 cache_free_descriptors(paths);
854 return (NULL);
855 }
856 }
857
858 paths[i] = NULL;
859
860 *errp = 0;
861 return (paths);
862 }
863
864 static int
get_attrs(disk_t * diskp,int fd,char * opath,nvlist_t * attrs)865 get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs)
866 {
867 if (diskp->removable) {
868 struct dk_minfo minfo;
869
870 if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
871 return (ENOMEM);
872 }
873
874 /* Make sure media is inserted and spun up. */
875 if (fd >= 0 && media_read_info(fd, &minfo)) {
876 if (nvlist_add_boolean(attrs, DM_LOADED) != 0) {
877 return (ENOMEM);
878 }
879 }
880
881 /*
882 * can't tell diff between dead & no media on removable drives
883 */
884 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) {
885 return (ENOMEM);
886 }
887
888 get_drive_type(diskp, fd);
889
890 } else {
891 struct dk_minfo minfo;
892
893 /* check if the fixed drive is up or not */
894 if (fd >= 0 && media_read_info(fd, &minfo)) {
895 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP)
896 != 0) {
897 return (ENOMEM);
898 }
899 } else {
900 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN)
901 != 0) {
902 return (ENOMEM);
903 }
904 }
905
906 get_drive_type(diskp, fd);
907 }
908
909 if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
910 return (ENOMEM);
911 }
912
913 if (diskp->product_id != NULL) {
914 if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
915 != 0) {
916 return (ENOMEM);
917 }
918 }
919 if (diskp->vendor_id != NULL) {
920 if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id)
921 != 0) {
922 return (ENOMEM);
923 }
924 }
925 if (diskp->serial != NULL) {
926 if (nvlist_add_string(attrs, DM_SERIAL, diskp->serial) != 0) {
927 return (ENOMEM);
928 }
929 }
930
931 if (diskp->sync_speed != -1) {
932 if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
933 != 0) {
934 return (ENOMEM);
935 }
936 }
937
938 if (diskp->wide == 1) {
939 if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
940 return (ENOMEM);
941 }
942 }
943
944 if (diskp->rpm == 0) {
945 diskp->rpm = get_rpm(diskp, fd);
946 }
947
948 if (diskp->rpm > 0) {
949 if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) {
950 return (ENOMEM);
951 }
952 }
953
954 if (strlen(opath) > 0) {
955 if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
956 return (ENOMEM);
957 }
958 }
959
960 if (diskp->solid_state < 0) {
961 diskp->solid_state = get_solidstate(diskp, fd);
962 }
963
964 if (diskp->solid_state > 0) {
965 if (nvlist_add_boolean(attrs, DM_SOLIDSTATE) != 0) {
966 return (ENOMEM);
967 }
968 }
969
970 return (0);
971 }
972
973 static int
get_disk_kstats(kstat_ctl_t * kc,char * diskname,char * classname,nvlist_t * stats)974 get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
975 nvlist_t *stats)
976 {
977 kstat_t *ksp;
978 size_t class_len;
979 int err = 0;
980
981 class_len = strlen(classname);
982 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
983 if (strncmp(ksp->ks_class, classname, class_len) == 0) {
984 char kstat_name[KSTAT_STRLEN];
985 char *dname = kstat_name;
986 char *ename = ksp->ks_name;
987
988 /*
989 * names are format: "sd0,err" - copy chars up to comma
990 */
991 while (*ename && *ename != ',') {
992 *dname++ = *ename++;
993 }
994 *dname = '\0';
995
996 if (libdiskmgt_str_eq(diskname, kstat_name)) {
997 (void) kstat_read(kc, ksp, NULL);
998 err = get_kstat_vals(ksp, stats);
999 break;
1000 }
1001 }
1002 }
1003
1004 return (err);
1005 }
1006
1007 /*
1008 * Getting the drive type depends on if the dev tree walk indicated that the
1009 * drive was a CD-ROM or not. The kernal lumps all of the removable multi-media
1010 * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use
1011 * a uscsi cmd to check the drive type.
1012 */
1013 static void
get_drive_type(disk_t * dp,int fd)1014 get_drive_type(disk_t *dp, int fd)
1015 {
1016 if (dp->drv_type == DM_DT_UNKNOWN) {
1017 int opened_here = 0;
1018
1019 /* We may have already opened the device. */
1020 if (fd < 0) {
1021 fd = drive_open_disk(dp, NULL, 0);
1022 opened_here = 1;
1023 }
1024
1025 if (fd >= 0) {
1026 if (dp->cd_rom) {
1027 /* use uscsi to determine drive type */
1028 dp->drv_type = get_cdrom_drvtype(fd);
1029
1030 /* if uscsi fails, just call it a cd-rom */
1031 if (dp->drv_type == DM_DT_UNKNOWN) {
1032 dp->drv_type = DM_DT_CDROM;
1033 }
1034
1035 } else {
1036 struct dk_minfo minfo;
1037
1038 if (media_read_info(fd, &minfo)) {
1039 dp->drv_type = conv_drive_type(
1040 minfo.dki_media_type);
1041 }
1042 }
1043
1044 if (opened_here) {
1045 (void) close(fd);
1046 }
1047
1048 } else {
1049 /* couldn't open */
1050 if (dp->cd_rom) {
1051 dp->drv_type = DM_DT_CDROM;
1052 }
1053 }
1054 }
1055 }
1056
1057 static char *
get_err_attr_name(char * kstat_name)1058 get_err_attr_name(char *kstat_name)
1059 {
1060 int i;
1061
1062 for (i = 0; kstat_err_names[i] != NULL; i++) {
1063 if (libdiskmgt_str_eq(kstat_name, kstat_err_names[i])) {
1064 return (err_attr_names[i]);
1065 }
1066 }
1067
1068 return (NULL);
1069 }
1070
1071 static int
get_err_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)1072 get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1073 {
1074 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
1075 }
1076
1077 static int
get_io_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)1078 get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1079 {
1080 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
1081 }
1082
1083 static int
get_kstat_vals(kstat_t * ksp,nvlist_t * stats)1084 get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
1085 {
1086 if (ksp->ks_type == KSTAT_TYPE_IO) {
1087 kstat_io_t *kiop;
1088
1089 kiop = KSTAT_IO_PTR(ksp);
1090
1091 /* see sys/kstat.h kstat_io_t struct for more fields */
1092
1093 if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) {
1094 return (ENOMEM);
1095 }
1096 if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten)
1097 != 0) {
1098 return (ENOMEM);
1099 }
1100 if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
1101 return (ENOMEM);
1102 }
1103 if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
1104 return (ENOMEM);
1105 }
1106
1107 } else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
1108 kstat_named_t *knp;
1109 int i;
1110
1111 knp = KSTAT_NAMED_PTR(ksp);
1112 for (i = 0; i < ksp->ks_ndata; i++) {
1113 char *attr_name;
1114
1115 if (knp[i].name[0] == 0)
1116 continue;
1117
1118 if ((attr_name = get_err_attr_name(knp[i].name))
1119 == NULL) {
1120 continue;
1121 }
1122
1123 switch (knp[i].data_type) {
1124 case KSTAT_DATA_UINT32:
1125 if (update_stat32(stats, attr_name,
1126 knp[i].value.ui32) != 0) {
1127 return (ENOMEM);
1128 }
1129 break;
1130
1131 default:
1132 /*
1133 * Right now all of the error types are uint32
1134 */
1135 break;
1136 }
1137 }
1138 }
1139 return (0);
1140 }
1141
1142 static int
update_stat32(nvlist_t * stats,char * attr,uint32_t value)1143 update_stat32(nvlist_t *stats, char *attr, uint32_t value)
1144 {
1145 int32_t currval;
1146
1147 if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
1148 value += currval;
1149 }
1150
1151 return (nvlist_add_uint32(stats, attr, value));
1152 }
1153
1154 /*
1155 * There can be more than one kstat value when we have multi-path drives
1156 * that are not under mpxio (since there is more than one kstat name for
1157 * the drive in this case). So, we may have merge all of the kstat values
1158 * to give an accurate set of stats for the drive.
1159 */
1160 static int
update_stat64(nvlist_t * stats,char * attr,uint64_t value)1161 update_stat64(nvlist_t *stats, char *attr, uint64_t value)
1162 {
1163 int64_t currval;
1164
1165 if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
1166 value += currval;
1167 }
1168 return (nvlist_add_uint64(stats, attr, value));
1169 }
1170
1171 /*
1172 * uscsi function to get the rpm of the drive
1173 */
1174 static int
get_rpm(disk_t * dp,int fd)1175 get_rpm(disk_t *dp, int fd)
1176 {
1177 int opened_here = 0;
1178 int rpm = -1;
1179
1180 /* We may have already opened the device. */
1181 if (fd < 0) {
1182 fd = drive_open_disk(dp, NULL, 0);
1183 opened_here = 1;
1184 }
1185
1186 if (fd >= 0) {
1187 int status;
1188 struct mode_geometry *page4;
1189 struct scsi_ms_header header;
1190 union {
1191 struct mode_geometry page4;
1192 char rawbuf[MAX_MODE_SENSE_SIZE];
1193 } u_page4;
1194
1195 page4 = &u_page4.page4;
1196 (void) memset(&u_page4, 0, sizeof (u_page4));
1197
1198 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1199 MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1200 &header);
1201
1202 if (status) {
1203 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1204 MODE_SENSE_PC_SAVED, (caddr_t)page4,
1205 MAX_MODE_SENSE_SIZE, &header);
1206 }
1207
1208 if (status) {
1209 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1210 MODE_SENSE_PC_CURRENT, (caddr_t)page4,
1211 MAX_MODE_SENSE_SIZE, &header);
1212 }
1213
1214 if (!status) {
1215 #ifdef _LITTLE_ENDIAN
1216 page4->rpm = ntohs(page4->rpm);
1217 #endif /* _LITTLE_ENDIAN */
1218
1219 rpm = page4->rpm;
1220 }
1221
1222 if (opened_here) {
1223 (void) close(fd);
1224 }
1225 }
1226
1227 return (rpm);
1228 }
1229
1230 static int
get_solidstate(disk_t * dp,int fd)1231 get_solidstate(disk_t *dp, int fd)
1232 {
1233 int opened_here = 0;
1234 int solid_state = -1;
1235
1236 /* We may have already opened the device. */
1237 if (fd < 0) {
1238 fd = drive_open_disk(dp, NULL, 0);
1239 opened_here = 1;
1240 }
1241
1242 if (fd >= 0) {
1243 if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
1244 solid_state = -1;
1245 }
1246 }
1247
1248 if (opened_here) {
1249 (void) close(fd);
1250 }
1251
1252 return (solid_state);
1253 }
1254
1255 /*
1256 * ******** the rest of this is uscsi stuff for the drv type ********
1257 */
1258
1259 /*
1260 * We try a get_configuration uscsi cmd. If that fails, try a
1261 * atapi_capabilities cmd. If both fail then this is an older CD-ROM.
1262 */
1263 static int
get_cdrom_drvtype(int fd)1264 get_cdrom_drvtype(int fd)
1265 {
1266 union scsi_cdb cdb;
1267 struct uscsi_cmd cmd;
1268 uchar_t buff[SCSIBUFLEN];
1269
1270 fill_general_page_cdb_g1(&cdb, SCMD_GET_CONFIGURATION, 0,
1271 b0(sizeof (buff)), b1(sizeof (buff)));
1272 fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
1273
1274 if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1275 struct get_configuration *config;
1276 struct conf_feature *feature;
1277 int flen;
1278
1279 /* The first profile is the preferred one for the drive. */
1280 config = (struct get_configuration *)buff;
1281 feature = &config->feature;
1282 flen = feature->len / sizeof (struct profile_list);
1283 if (flen > 0) {
1284 int prof_num;
1285
1286 prof_num = (int)convnum(
1287 feature->features.plist[0].profile, 2);
1288
1289 if (dm_debug > 1) {
1290 (void) fprintf(stderr,
1291 "INFO: uscsi get_configuration %d\n",
1292 prof_num);
1293 }
1294
1295 switch (prof_num) {
1296 case PROF_MAGNETO_OPTICAL:
1297 return (DM_DT_MO_ERASABLE);
1298 case PROF_OPTICAL_WO:
1299 return (DM_DT_MO_WRITEONCE);
1300 case PROF_OPTICAL_ASMO:
1301 return (DM_DT_AS_MO);
1302 case PROF_CDROM:
1303 return (DM_DT_CDROM);
1304 case PROF_CDR:
1305 return (DM_DT_CDR);
1306 case PROF_CDRW:
1307 return (DM_DT_CDRW);
1308 case PROF_DVDROM:
1309 return (DM_DT_DVDROM);
1310 case PROF_DVDRAM:
1311 return (DM_DT_DVDRAM);
1312 case PROF_DVDRW_REST:
1313 return (DM_DT_DVDRW);
1314 case PROF_DVDRW_SEQ:
1315 return (DM_DT_DVDRW);
1316 case PROF_DVDRW:
1317 return (DM_DT_DVDRW);
1318 case PROF_DDCD_ROM:
1319 return (DM_DT_DDCDROM);
1320 case PROF_DDCD_R:
1321 return (DM_DT_DDCDR);
1322 case PROF_DDCD_RW:
1323 return (DM_DT_DDCDRW);
1324 }
1325 }
1326 }
1327
1328 /* see if the atapi capabilities give anything */
1329 return (check_atapi(fd));
1330 }
1331
1332 static int
check_atapi(int fd)1333 check_atapi(int fd)
1334 {
1335 union scsi_cdb cdb;
1336 struct uscsi_cmd cmd;
1337 uchar_t buff[SCSIBUFLEN];
1338
1339 fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES);
1340 fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
1341
1342 if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1343 int bdesclen;
1344 struct capabilities *cap;
1345 struct mode_header_g2 *mode;
1346
1347 mode = (struct mode_header_g2 *)buff;
1348
1349 bdesclen = (int)convnum(mode->desclen, 2);
1350 cap = (struct capabilities *)
1351 &buff[sizeof (struct mode_header_g2) + bdesclen];
1352
1353 if (dm_debug > 1) {
1354 (void) fprintf(stderr,
1355 "INFO: uscsi atapi capabilities\n");
1356 }
1357
1358 /* These are in order of how we want to report the drv type. */
1359 if (cap->dvdram_write) {
1360 return (DM_DT_DVDRAM);
1361 }
1362 if (cap->dvdr_write) {
1363 return (DM_DT_DVDR);
1364 }
1365 if (cap->dvdrom_read) {
1366 return (DM_DT_DVDROM);
1367 }
1368 if (cap->cdrw_write) {
1369 return (DM_DT_CDRW);
1370 }
1371 if (cap->cdr_write) {
1372 return (DM_DT_CDR);
1373 }
1374 if (cap->cdr_read) {
1375 return (DM_DT_CDROM);
1376 }
1377 }
1378
1379 /* everything failed, so this is an older CD-ROM */
1380 if (dm_debug > 1) {
1381 (void) fprintf(stderr, "INFO: uscsi failed\n");
1382 }
1383
1384 return (DM_DT_CDROM);
1385 }
1386
1387 static uint64_t
convnum(uchar_t * nptr,int len)1388 convnum(uchar_t *nptr, int len)
1389 {
1390 uint64_t value;
1391
1392 for (value = 0; len > 0; len--, nptr++)
1393 value = (value << 8) | *nptr;
1394 return (value);
1395 }
1396
1397 static void
fill_command_g1(struct uscsi_cmd * cmd,union scsi_cdb * cdb,caddr_t buff,int blen)1398 fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb,
1399 caddr_t buff, int blen)
1400 {
1401 bzero((caddr_t)cmd, sizeof (struct uscsi_cmd));
1402 bzero(buff, blen);
1403
1404 cmd->uscsi_cdb = (caddr_t)cdb;
1405 cmd->uscsi_cdblen = CDB_GROUP1;
1406
1407 cmd->uscsi_bufaddr = buff;
1408 cmd->uscsi_buflen = blen;
1409
1410 cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ;
1411 }
1412
1413 static void
fill_general_page_cdb_g1(union scsi_cdb * cdb,int command,int lun,uchar_t c0,uchar_t c1)1414 fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun,
1415 uchar_t c0, uchar_t c1)
1416 {
1417 bzero((caddr_t)cdb, sizeof (union scsi_cdb));
1418 cdb->scc_cmd = command;
1419 cdb->scc_lun = lun;
1420 cdb->g1_count0 = c0; /* max length for page */
1421 cdb->g1_count1 = c1; /* max length for page */
1422 }
1423
1424 static void
fill_mode_page_cdb(union scsi_cdb * cdb,int page)1425 fill_mode_page_cdb(union scsi_cdb *cdb, int page)
1426 {
1427 /* group 1 mode page */
1428 bzero((caddr_t)cdb, sizeof (union scsi_cdb));
1429 cdb->scc_cmd = SCMD_MODE_SENSE_G1;
1430 cdb->g1_count0 = 0xff; /* max length for mode page */
1431 cdb->g1_count1 = 0xff; /* max length for mode page */
1432 cdb->g1_addr3 = page;
1433 }
1434
1435 static int
uscsi_mode_sense(int fd,int page_code,int page_control,caddr_t page_data,int page_size,struct scsi_ms_header * header)1436 uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data,
1437 int page_size, struct scsi_ms_header *header)
1438 {
1439 caddr_t mode_sense_buf;
1440 struct mode_header *hdr;
1441 struct mode_page *pg;
1442 int nbytes;
1443 struct uscsi_cmd ucmd;
1444 union scsi_cdb cdb;
1445 int status;
1446 int maximum;
1447 char rqbuf[255];
1448
1449 /*
1450 * Allocate a buffer for the mode sense headers
1451 * and mode sense data itself.
1452 */
1453 nbytes = sizeof (struct block_descriptor) +
1454 sizeof (struct mode_header) + page_size;
1455 nbytes = page_size;
1456 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) {
1457 return (-1);
1458 }
1459
1460 /*
1461 * Build and execute the uscsi ioctl
1462 */
1463 (void) memset(mode_sense_buf, 0, nbytes);
1464 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
1465 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb));
1466
1467 cdb.scc_cmd = SCMD_MODE_SENSE;
1468 FORMG0COUNT(&cdb, (uchar_t)nbytes);
1469 cdb.cdb_opaque[2] = page_control | page_code;
1470 ucmd.uscsi_cdb = (caddr_t)&cdb;
1471 ucmd.uscsi_cdblen = CDB_GROUP0;
1472 ucmd.uscsi_bufaddr = mode_sense_buf;
1473 ucmd.uscsi_buflen = nbytes;
1474
1475 ucmd.uscsi_flags |= USCSI_SILENT;
1476 ucmd.uscsi_flags |= USCSI_READ;
1477 ucmd.uscsi_timeout = 30;
1478 ucmd.uscsi_flags |= USCSI_RQENABLE;
1479 if (ucmd.uscsi_rqbuf == NULL) {
1480 ucmd.uscsi_rqbuf = rqbuf;
1481 ucmd.uscsi_rqlen = sizeof (rqbuf);
1482 ucmd.uscsi_rqresid = sizeof (rqbuf);
1483 }
1484 ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
1485
1486 status = ioctl(fd, USCSICMD, &ucmd);
1487
1488 if (status || ucmd.uscsi_status != 0) {
1489 free(mode_sense_buf);
1490 return (-1);
1491 }
1492
1493 /*
1494 * Verify that the returned data looks reasonabled,
1495 * find the actual page data, and copy it into the
1496 * user's buffer. Copy the mode_header and block_descriptor
1497 * into the header structure, which can then be used to
1498 * return the same data to the drive when issuing a mode select.
1499 */
1500 hdr = (struct mode_header *)mode_sense_buf;
1501 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header));
1502 if (hdr->bdesc_length != sizeof (struct block_descriptor) &&
1503 hdr->bdesc_length != 0) {
1504 free(mode_sense_buf);
1505 return (-1);
1506 }
1507 (void) memcpy((caddr_t)header, mode_sense_buf,
1508 (int) (sizeof (struct mode_header) + hdr->bdesc_length));
1509 pg = (struct mode_page *)((ulong_t)mode_sense_buf +
1510 sizeof (struct mode_header) + hdr->bdesc_length);
1511 if (pg->code != page_code) {
1512 free(mode_sense_buf);
1513 return (-1);
1514 }
1515
1516 /*
1517 * Accept up to "page_size" bytes of mode sense data.
1518 * This allows us to accept both CCS and SCSI-2
1519 * structures, as long as we request the greater
1520 * of the two.
1521 */
1522 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length;
1523 if (((int)pg->length) > maximum) {
1524 free(mode_sense_buf);
1525 return (-1);
1526 }
1527
1528 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1529
1530 free(mode_sense_buf);
1531 return (0);
1532 }
1533