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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
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>
40
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>
50
51 #include "libdiskmgt.h"
52 #include "disks_private.h"
53
54 #define KSTAT_CLASS_DISK "disk"
55 #define KSTAT_CLASS_ERROR "device_error"
56
57 #define SCSIBUFLEN 0xffff
58
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)
64
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
76 };
77
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
89 };
90
91 /*
92 * **************** begin uscsi stuff ****************
93 */
94
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
100
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;
205 };
206
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
225
226 struct get_configuration {
227 uchar_t len[4];
228 uchar_t reserved[2];
229 uchar_t curprof[2];
230 struct conf_feature feature;
231 };
232
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 */
294 };
295
296 struct mode_header_g2 {
297 uchar_t modelen[2];
298 uchar_t obsolete;
299 uchar_t reserved[3];
300 uchar_t desclen[2];
301 };
302
303 /*
304 * Mode sense/select page header information
305 */
306 struct scsi_ms_header {
307 struct mode_header mode_header;
308 struct block_descriptor block_descriptor;
309 };
310
311 #define MODESENSE_PAGE_LEN(p) (((int)((struct mode_page *)p)->length) + \
312 sizeof (struct mode_page))
313
314 #define MODE_SENSE_PC_CURRENT (0 << 6)
315 #define MODE_SENSE_PC_DEFAULT (2 << 6)
316 #define MODE_SENSE_PC_SAVED (3 << 6)
317
318 #define MAX_MODE_SENSE_SIZE 255
319 #define IMPOSSIBLE_SCSI_STATUS 0xff
320
321 /*
322 * ********** end of uscsi stuff ************
323 */
324
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);
359
360 descriptor_t **
drive_get_assoc_descriptors(descriptor_t * dp,dm_desc_type_t type,int * errp)361 drive_get_assoc_descriptors(descriptor_t *dp, dm_desc_type_t type,
362 int *errp)
363 {
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));
373 }
374
375 *errp = EINVAL;
376 return (NULL);
377 }
378
379 /*
380 * Get the drive descriptors for the given media/alias/devpath.
381 */
382 descriptor_t **
drive_get_assocs(descriptor_t * desc,int * errp)383 drive_get_assocs(descriptor_t *desc, int *errp)
384 {
385 descriptor_t **drives;
386
387 /* at most one drive is associated with these descriptors */
388
389 drives = (descriptor_t **)calloc(2, sizeof (descriptor_t *));
390 if (drives == NULL) {
391 *errp = ENOMEM;
392 return (NULL);
393 }
394
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);
399 }
400
401 drives[1] = NULL;
402
403 return (drives);
404 }
405
406 nvlist_t *
drive_get_attributes(descriptor_t * dp,int * errp)407 drive_get_attributes(descriptor_t *dp, int *errp)
408 {
409 nvlist_t *attrs = NULL;
410 int fd;
411 char opath[MAXPATHLEN];
412
413 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
414 *errp = ENOMEM;
415 return (NULL);
416 }
417
418 opath[0] = 0;
419 fd = drive_open_disk(dp->p.disk, opath, sizeof (opath));
420
421 if ((*errp = get_attrs(dp->p.disk, fd, opath, attrs)) != 0) {
422 nvlist_free(attrs);
423 attrs = NULL;
424 }
425
426 if (fd >= 0) {
427 (void) close(fd);
428 }
429
430 return (attrs);
431 }
432
433 /*
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.
439 */
440 descriptor_t *
drive_get_descriptor_by_name(char * name,int * errp)441 drive_get_descriptor_by_name(char *name, int *errp)
442 {
443 ddi_devid_t devid;
444 descriptor_t **drives;
445 descriptor_t *drive = NULL;
446 int i;
447
448 if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
449 *errp = EINVAL;
450 return (NULL);
451 }
452
453 drives = cache_get_descriptors(DM_DRIVE, errp);
454 if (*errp != 0) {
455 devid_free(devid);
456 return (NULL);
457 }
458
459 /*
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.
462 */
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];
467
468 } else {
469 /* clean up the unused descriptor */
470 cache_free_descriptor(drives[i]);
471 }
472 }
473 free(drives);
474 devid_free(devid);
475
476 if (drive == NULL) {
477 *errp = ENODEV;
478 }
479
480 return (drive);
481 }
482
483 descriptor_t **
drive_get_descriptors(int filter[],int * errp)484 drive_get_descriptors(int filter[], int *errp)
485 {
486 descriptor_t **drives;
487
488 drives = cache_get_descriptors(DM_DRIVE, errp);
489 if (*errp != 0) {
490 return (NULL);
491 }
492
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;
500 }
501 }
502
503 return (drives);
504 }
505
506 char *
drive_get_name(descriptor_t * dp)507 drive_get_name(descriptor_t *dp)
508 {
509 return (dp->p.disk->device_id);
510 }
511
512 nvlist_t *
drive_get_stats(descriptor_t * dp,int stat_type,int * errp)513 drive_get_stats(descriptor_t *dp, int stat_type, int *errp)
514 {
515 disk_t *diskp;
516 nvlist_t *stats;
517
518 diskp = dp->p.disk;
519
520 if (nvlist_alloc(&stats, NVATTRS, 0) != 0) {
521 *errp = ENOMEM;
522 return (NULL);
523 }
524
525 if (stat_type == DM_DRV_STAT_PERFORMANCE ||
526 stat_type == DM_DRV_STAT_DIAGNOSTIC) {
527
528 alias_t *ap;
529 kstat_ctl_t *kc;
530
531 ap = diskp->aliases;
532 if (ap == NULL || ap->kstat_name == NULL) {
533 nvlist_free(stats);
534 *errp = EACCES;
535 return (NULL);
536 }
537
538 if ((kc = kstat_open()) == NULL) {
539 nvlist_free(stats);
540 *errp = EACCES;
541 return (NULL);
542 }
543
544 while (ap != NULL) {
545 int status;
546
547 if (ap->kstat_name == NULL) {
548 continue;
549 }
550
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);
555 }
556
557 if (status != 0) {
558 nvlist_free(stats);
559 (void) kstat_close(kc);
560 *errp = ENOMEM;
561 return (NULL);
562 }
563
564 ap = ap->next;
565 }
566
567 (void) kstat_close(kc);
568
569 *errp = 0;
570 return (stats);
571 }
572
573 if (stat_type == DM_DRV_STAT_TEMPERATURE) {
574 int fd;
575
576 if ((fd = drive_open_disk(diskp, NULL, 0)) >= 0) {
577 struct dk_temperature temp;
578
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);
585 }
586 } else {
587 *errp = errno;
588 nvlist_free(stats);
589 return (NULL);
590 }
591 (void) close(fd);
592 } else {
593 *errp = errno;
594 nvlist_free(stats);
595 return (NULL);
596 }
597
598 *errp = 0;
599 return (stats);
600 }
601
602 nvlist_free(stats);
603 *errp = EINVAL;
604 return (NULL);
605 }
606
607 int
drive_make_descriptors()608 drive_make_descriptors()
609 {
610 int error;
611 disk_t *dp;
612
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);
618 }
619 dp = dp->next;
620 }
621
622 return (0);
623 }
624
625 /*
626 * This function opens the disk generically (any slice).
627 */
628 int
drive_open_disk(disk_t * diskp,char * opath,int len)629 drive_open_disk(disk_t *diskp, char *opath, int len)
630 {
631 /*
632 * Just open the first devpath.
633 */
634 if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
635 if (opath != NULL) {
636 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
637 }
638 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
639 }
640
641 return (-1);
642 }
643
644 static descriptor_t **
apply_filter(descriptor_t ** drives,int filter[],int * errp)645 apply_filter(descriptor_t **drives, int filter[], int *errp)
646 {
647 int i;
648 descriptor_t **found;
649 int cnt;
650 int pos;
651
652 /* count the number of drives in the snapshot */
653 for (cnt = 0; drives[cnt]; cnt++);
654
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);
660 }
661
662 pos = 0;
663 for (i = 0; drives[i]; i++) {
664 int j;
665 int match;
666
667 /* Make sure the drive type is set */
668 get_drive_type(drives[i]->p.disk, -1);
669
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;
676 }
677 }
678
679 if (!match) {
680 cache_free_descriptor(drives[i]);
681 }
682 }
683 found[pos] = NULL;
684 free(drives);
685
686 *errp = 0;
687 return (found);
688 }
689
690 static int
conv_drive_type(uint_t drive_type)691 conv_drive_type(uint_t drive_type)
692 {
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);
724 }
725 }
726
727 static descriptor_t **
get_assoc_alias(disk_t * diskp,int * errp)728 get_assoc_alias(disk_t *diskp, int *errp)
729 {
730 alias_t *aliasp;
731 uint_t cnt;
732 descriptor_t **out_array;
733 int pos;
734
735 *errp = 0;
736
737 aliasp = diskp->aliases;
738 cnt = 0;
739
740 while (aliasp != NULL) {
741 if (aliasp->alias != NULL) {
742 cnt++;
743 }
744 aliasp = aliasp->next;
745 }
746
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);
752 }
753
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);
763 }
764 }
765
766 aliasp = aliasp->next;
767 }
768
769 out_array[pos] = NULL;
770
771 return (out_array);
772 }
773
774 static descriptor_t **
get_assoc_controllers(descriptor_t * dp,int * errp)775 get_assoc_controllers(descriptor_t *dp, int *errp)
776 {
777 disk_t *diskp;
778 int cnt;
779 descriptor_t **controllers;
780 int i;
781
782 diskp = dp->p.disk;
783
784 /* Count how many we have. */
785 for (cnt = 0; diskp->controllers[cnt]; cnt++);
786
787 /* make the snapshot */
788 controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
789 if (controllers == NULL) {
790 *errp = ENOMEM;
791 return (NULL);
792 }
793
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);
800 }
801 }
802
803 controllers[i] = NULL;
804
805 *errp = 0;
806 return (controllers);
807 }
808
809 static descriptor_t **
get_assoc_paths(descriptor_t * dp,int * errp)810 get_assoc_paths(descriptor_t *dp, int *errp)
811 {
812 path_t **pp;
813 int cnt;
814 descriptor_t **paths;
815 int i;
816
817 pp = dp->p.disk->paths;
818
819 /* Count how many we have. */
820 cnt = 0;
821 if (pp != NULL) {
822 for (; pp[cnt]; cnt++);
823 }
824
825 /* make the snapshot */
826 paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
827 if (paths == NULL) {
828 *errp = ENOMEM;
829 return (NULL);
830 }
831
832 /*
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.
837 */
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);
844 }
845 }
846
847 paths[i] = NULL;
848
849 *errp = 0;
850 return (paths);
851 }
852
853 static int
get_attrs(disk_t * diskp,int fd,char * opath,nvlist_t * attrs)854 get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs)
855 {
856 if (diskp->removable) {
857 struct dk_minfo minfo;
858
859 if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) {
860 return (ENOMEM);
861 }
862
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);
867 }
868 }
869
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);
873 }
874
875 get_drive_type(diskp, fd);
876
877 } else {
878 struct dk_minfo minfo;
879
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);
884 }
885 } else {
886 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) {
887 return (ENOMEM);
888 }
889 }
890
891 get_drive_type(diskp, fd);
892 }
893
894 if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) {
895 return (ENOMEM);
896 }
897
898 if (diskp->product_id != NULL) {
899 if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id)
900 != 0) {
901 return (ENOMEM);
902 }
903 }
904 if (diskp->vendor_id != NULL) {
905 if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) {
906 return (ENOMEM);
907 }
908 }
909
910 if (diskp->sync_speed != -1) {
911 if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed)
912 != 0) {
913 return (ENOMEM);
914 }
915 }
916
917 if (diskp->wide == 1) {
918 if (nvlist_add_boolean(attrs, DM_WIDE) != 0) {
919 return (ENOMEM);
920 }
921 }
922
923 if (diskp->rpm == 0) {
924 diskp->rpm = get_rpm(diskp, fd);
925 }
926
927 if (diskp->rpm > 0) {
928 if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) {
929 return (ENOMEM);
930 }
931 }
932
933 if (diskp->aliases != NULL && diskp->aliases->cluster) {
934 if (nvlist_add_boolean(attrs, DM_CLUSTERED) != 0) {
935 return (ENOMEM);
936 }
937 }
938
939 if (strlen(opath) > 0) {
940 if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) {
941 return (ENOMEM);
942 }
943 }
944
945 if (diskp->solid_state < 0) {
946 diskp->solid_state = get_solidstate(diskp, fd);
947 }
948
949 if (diskp->solid_state > 0) {
950 if (nvlist_add_boolean(attrs, DM_SOLIDSTATE) != 0) {
951 return (ENOMEM);
952 }
953 }
954
955 return (0);
956 }
957
958 static int
get_disk_kstats(kstat_ctl_t * kc,char * diskname,char * classname,nvlist_t * stats)959 get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname,
960 nvlist_t *stats)
961 {
962 kstat_t *ksp;
963 size_t class_len;
964 int err = 0;
965
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;
972
973 /* names are format: "sd0,err" - copy chars up to comma */
974 while (*ename && *ename != ',') {
975 *dname++ = *ename++;
976 }
977 *dname = NULL;
978
979 if (libdiskmgt_str_eq(diskname, kstat_name)) {
980 (void) kstat_read(kc, ksp, NULL);
981 err = get_kstat_vals(ksp, stats);
982 break;
983 }
984 }
985 }
986
987 return (err);
988 }
989
990 /*
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.
995 */
996 static void
get_drive_type(disk_t * dp,int fd)997 get_drive_type(disk_t *dp, int fd)
998 {
999 if (dp->drv_type == DM_DT_UNKNOWN) {
1000 int opened_here = 0;
1001
1002 /* We may have already opened the device. */
1003 if (fd < 0) {
1004 fd = drive_open_disk(dp, NULL, 0);
1005 opened_here = 1;
1006 }
1007
1008 if (fd >= 0) {
1009 if (dp->cd_rom) {
1010 /* use uscsi to determine drive type */
1011 dp->drv_type = get_cdrom_drvtype(fd);
1012
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;
1016 }
1017
1018 } else {
1019 struct dk_minfo minfo;
1020
1021 if (media_read_info(fd, &minfo)) {
1022 dp->drv_type = conv_drive_type(minfo.dki_media_type);
1023 }
1024 }
1025
1026 if (opened_here) {
1027 (void) close(fd);
1028 }
1029
1030 } else {
1031 /* couldn't open */
1032 if (dp->cd_rom) {
1033 dp->drv_type = DM_DT_CDROM;
1034 }
1035 }
1036 }
1037 }
1038
1039 static char *
get_err_attr_name(char * kstat_name)1040 get_err_attr_name(char *kstat_name)
1041 {
1042 int i;
1043
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]);
1047 }
1048 }
1049
1050 return (NULL);
1051 }
1052
1053 static int
get_err_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)1054 get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1055 {
1056 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats));
1057 }
1058
1059 static int
get_io_kstats(kstat_ctl_t * kc,char * diskname,nvlist_t * stats)1060 get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats)
1061 {
1062 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats));
1063 }
1064
1065 static int
get_kstat_vals(kstat_t * ksp,nvlist_t * stats)1066 get_kstat_vals(kstat_t *ksp, nvlist_t *stats)
1067 {
1068 if (ksp->ks_type == KSTAT_TYPE_IO) {
1069 kstat_io_t *kiop;
1070
1071 kiop = KSTAT_IO_PTR(ksp);
1072
1073 /* see sys/kstat.h kstat_io_t struct for more fields */
1074
1075 if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) {
1076 return (ENOMEM);
1077 }
1078 if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) {
1079 return (ENOMEM);
1080 }
1081 if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) {
1082 return (ENOMEM);
1083 }
1084 if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) {
1085 return (ENOMEM);
1086 }
1087
1088 } else if (ksp->ks_type == KSTAT_TYPE_NAMED) {
1089 kstat_named_t *knp;
1090 int i;
1091
1092 knp = KSTAT_NAMED_PTR(ksp);
1093 for (i = 0; i < ksp->ks_ndata; i++) {
1094 char *attr_name;
1095
1096 if (knp[i].name[0] == 0)
1097 continue;
1098
1099 if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) {
1100 continue;
1101
1102 }
1103
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);
1109 }
1110 break;
1111
1112 default:
1113 /* Right now all of the error types are uint32 */
1114 break;
1115 }
1116 }
1117 }
1118 return (0);
1119 }
1120
1121 static int
update_stat32(nvlist_t * stats,char * attr,uint32_t value)1122 update_stat32(nvlist_t *stats, char *attr, uint32_t value)
1123 {
1124 int32_t currval;
1125
1126 if (nvlist_lookup_int32(stats, attr, &currval) == 0) {
1127 value += currval;
1128 }
1129
1130 return (nvlist_add_uint32(stats, attr, value));
1131 }
1132
1133 /*
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.
1138 */
1139 static int
update_stat64(nvlist_t * stats,char * attr,uint64_t value)1140 update_stat64(nvlist_t *stats, char *attr, uint64_t value)
1141 {
1142 int64_t currval;
1143
1144 if (nvlist_lookup_int64(stats, attr, &currval) == 0) {
1145 value += currval;
1146 }
1147 return (nvlist_add_uint64(stats, attr, value));
1148 }
1149
1150 /*
1151 * uscsi function to get the rpm of the drive
1152 */
1153 static int
get_rpm(disk_t * dp,int fd)1154 get_rpm(disk_t *dp, int fd)
1155 {
1156 int opened_here = 0;
1157 int rpm = -1;
1158
1159 /* We may have already opened the device. */
1160 if (fd < 0) {
1161 fd = drive_open_disk(dp, NULL, 0);
1162 opened_here = 1;
1163 }
1164
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;
1173
1174 page4 = &u_page4.page4;
1175 (void) memset(&u_page4, 0, sizeof (u_page4));
1176
1177 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY,
1178 MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE,
1179 &header);
1180
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);
1185 }
1186
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);
1191 }
1192
1193 if (!status) {
1194 #ifdef _LITTLE_ENDIAN
1195 page4->rpm = ntohs(page4->rpm);
1196 #endif /* _LITTLE_ENDIAN */
1197
1198 rpm = page4->rpm;
1199 }
1200
1201 if (opened_here) {
1202 (void) close(fd);
1203 }
1204 }
1205
1206 return (rpm);
1207 }
1208
1209 static int
get_solidstate(disk_t * dp,int fd)1210 get_solidstate(disk_t *dp, int fd)
1211 {
1212 int opened_here = 0;
1213 int solid_state = -1;
1214
1215 /* We may have already opened the device. */
1216 if (fd < 0) {
1217 fd = drive_open_disk(dp, NULL, 0);
1218 opened_here = 1;
1219 }
1220
1221 if (fd >= 0) {
1222 if (ioctl(fd, DKIOCSOLIDSTATE, &solid_state) < 0) {
1223 solid_state = -1;
1224 }
1225 }
1226
1227 if (opened_here) {
1228 (void) close(fd);
1229 }
1230
1231 return (solid_state);
1232 }
1233
1234 /*
1235 * ******** the rest of this is uscsi stuff for the drv type ********
1236 */
1237
1238 /*
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.
1241 */
1242 static int
get_cdrom_drvtype(int fd)1243 get_cdrom_drvtype(int fd)
1244 {
1245 union scsi_cdb cdb;
1246 struct uscsi_cmd cmd;
1247 uchar_t buff[SCSIBUFLEN];
1248
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));
1252
1253 if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1254 struct get_configuration *config;
1255 struct conf_feature *feature;
1256 int flen;
1257
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;
1264
1265 prof_num = (int)convnum(feature->features.plist[0].profile, 2);
1266
1267 if (dm_debug > 1) {
1268 (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n",
1269 prof_num);
1270 }
1271
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);
1301 }
1302 }
1303 }
1304
1305 /* see if the atapi capabilities give anything */
1306 return (check_atapi(fd));
1307 }
1308
1309 static int
check_atapi(int fd)1310 check_atapi(int fd)
1311 {
1312 union scsi_cdb cdb;
1313 struct uscsi_cmd cmd;
1314 uchar_t buff[SCSIBUFLEN];
1315
1316 fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES);
1317 fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff));
1318
1319 if (ioctl(fd, USCSICMD, &cmd) >= 0) {
1320 int bdesclen;
1321 struct capabilities *cap;
1322 struct mode_header_g2 *mode;
1323
1324 mode = (struct mode_header_g2 *)buff;
1325
1326 bdesclen = (int)convnum(mode->desclen, 2);
1327 cap = (struct capabilities *)
1328 &buff[sizeof (struct mode_header_g2) + bdesclen];
1329
1330 if (dm_debug > 1) {
1331 (void) fprintf(stderr, "INFO: uscsi atapi capabilities\n");
1332 }
1333
1334 /* These are in order of how we want to report the drv type. */
1335 if (cap->dvdram_write) {
1336 return (DM_DT_DVDRAM);
1337 }
1338 if (cap->dvdr_write) {
1339 return (DM_DT_DVDR);
1340 }
1341 if (cap->dvdrom_read) {
1342 return (DM_DT_DVDROM);
1343 }
1344 if (cap->cdrw_write) {
1345 return (DM_DT_CDRW);
1346 }
1347 if (cap->cdr_write) {
1348 return (DM_DT_CDR);
1349 }
1350 if (cap->cdr_read) {
1351 return (DM_DT_CDROM);
1352 }
1353 }
1354
1355 /* everything failed, so this is an older CD-ROM */
1356 if (dm_debug > 1) {
1357 (void) fprintf(stderr, "INFO: uscsi failed\n");
1358 }
1359
1360 return (DM_DT_CDROM);
1361 }
1362
1363 static uint64_t
convnum(uchar_t * nptr,int len)1364 convnum(uchar_t *nptr, int len)
1365 {
1366 uint64_t value;
1367
1368 for (value = 0; len > 0; len--, nptr++)
1369 value = (value << 8) | *nptr;
1370 return (value);
1371 }
1372
1373 static void
fill_command_g1(struct uscsi_cmd * cmd,union scsi_cdb * cdb,caddr_t buff,int blen)1374 fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb,
1375 caddr_t buff, int blen)
1376 {
1377 bzero((caddr_t)cmd, sizeof (struct uscsi_cmd));
1378 bzero(buff, blen);
1379
1380 cmd->uscsi_cdb = (caddr_t)cdb;
1381 cmd->uscsi_cdblen = CDB_GROUP1;
1382
1383 cmd->uscsi_bufaddr = buff;
1384 cmd->uscsi_buflen = blen;
1385
1386 cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ;
1387 }
1388
1389 static void
fill_general_page_cdb_g1(union scsi_cdb * cdb,int command,int lun,uchar_t c0,uchar_t c1)1390 fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun,
1391 uchar_t c0, uchar_t c1)
1392 {
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 */
1398 }
1399
1400 static void
fill_mode_page_cdb(union scsi_cdb * cdb,int page)1401 fill_mode_page_cdb(union scsi_cdb *cdb, int page)
1402 {
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;
1409 }
1410
1411 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)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)
1414 {
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];
1424
1425 /*
1426 * Allocate a buffer for the mode sense headers
1427 * and mode sense data itself.
1428 */
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);
1434 }
1435
1436 /*
1437 * Build and execute the uscsi ioctl
1438 */
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));
1442
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;
1450
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);
1459 }
1460 ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS;
1461
1462 status = ioctl(fd, USCSICMD, &ucmd);
1463
1464 if (status || ucmd.uscsi_status != 0) {
1465 free(mode_sense_buf);
1466 return (-1);
1467 }
1468
1469 /*
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.
1475 */
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);
1482 }
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);
1490 }
1491
1492 /*
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.
1497 */
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);
1502 }
1503
1504 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg));
1505
1506 free(mode_sense_buf);
1507 return (0);
1508 }
1509