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