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