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