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