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 2005 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 (S_ISCHR(buf.st_mode)) { 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 (S_ISDIR(buf.st_mode)) { 669 /* disk w/ slices so handle the directory */ 670 DIR *dirp; 671 struct dirent *dentp; 672 int dfd; 673 674 /* each device file in the dir represents a slice */ 675 676 if ((dirp = fdopendir(fd)) == NULL) { 677 (void) close(fd); 678 return (-1); 679 } 680 681 while ((dentp = readdir(dirp)) != NULL) { 682 char slice_path[MAXPATHLEN]; 683 684 if (libdiskmgt_str_eq(".", dentp->d_name) || 685 libdiskmgt_str_eq("..", dentp->d_name)) { 686 continue; 687 } 688 689 (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", 690 rmmedia_devpath, dentp->d_name); 691 692 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) < 0) { 693 continue; 694 } 695 696 if (fstat(dfd, &buf) == 0 && S_ISCHR(buf.st_mode)) { 697 /* opened, is device, so done */ 698 (void) closedir(dirp); 699 if (opath != NULL) { 700 (void) strlcpy(opath, slice_path, len); 701 } 702 return (dfd); 703 } 704 705 /* not a device, keep looking */ 706 (void) close(dfd); 707 } 708 709 /* did not find a device under the rmmedia_path */ 710 (void) closedir(dirp); 711 return (-1); 712 } 713 714 /* didn't find a device under volume management control */ 715 (void) close(fd); 716 return (-1); 717 } 718 719 /* 720 * Not removable media under volume management control so just open the 721 * first devpath. 722 */ 723 if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) { 724 if (opath != NULL) { 725 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len); 726 } 727 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY)); 728 } 729 730 return (-1); 731 } 732 733 static descriptor_t ** 734 apply_filter(descriptor_t **drives, int filter[], int *errp) 735 { 736 int i; 737 descriptor_t **found; 738 int cnt; 739 int pos; 740 741 /* count the number of drives in the snapshot */ 742 for (cnt = 0; drives[cnt]; cnt++); 743 744 found = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 745 if (found == NULL) { 746 *errp = ENOMEM; 747 cache_free_descriptors(drives); 748 return (NULL); 749 } 750 751 pos = 0; 752 for (i = 0; drives[i]; i++) { 753 int j; 754 int match; 755 756 /* Make sure the drive type is set */ 757 get_drive_type(drives[i]->p.disk, -1); 758 759 match = 0; 760 for (j = 0; filter[j] != DM_FILTER_END; j++) { 761 if (drives[i]->p.disk->drv_type == filter[j]) { 762 found[pos++] = drives[i]; 763 match = 1; 764 break; 765 } 766 } 767 768 if (!match) { 769 cache_free_descriptor(drives[i]); 770 } 771 } 772 found[pos] = NULL; 773 free(drives); 774 775 *errp = 0; 776 return (found); 777 } 778 779 static int 780 conv_drive_type(uint_t drive_type) 781 { 782 switch (drive_type) { 783 case DK_UNKNOWN: 784 return (DM_DT_UNKNOWN); 785 case DK_MO_ERASABLE: 786 return (DM_DT_MO_ERASABLE); 787 case DK_MO_WRITEONCE: 788 return (DM_DT_MO_WRITEONCE); 789 case DK_AS_MO: 790 return (DM_DT_AS_MO); 791 case DK_CDROM: 792 return (DM_DT_CDROM); 793 case DK_CDR: 794 return (DM_DT_CDR); 795 case DK_CDRW: 796 return (DM_DT_CDRW); 797 case DK_DVDROM: 798 return (DM_DT_DVDROM); 799 case DK_DVDR: 800 return (DM_DT_DVDR); 801 case DK_DVDRAM: 802 return (DM_DT_DVDRAM); 803 case DK_FIXED_DISK: 804 return (DM_DT_FIXED); 805 case DK_FLOPPY: 806 return (DM_DT_FLOPPY); 807 case DK_ZIP: 808 return (DM_DT_ZIP); 809 case DK_JAZ: 810 return (DM_DT_JAZ); 811 default: 812 return (DM_DT_UNKNOWN); 813 } 814 } 815 816 static descriptor_t ** 817 get_assoc_alias(disk_t *diskp, int *errp) 818 { 819 alias_t *aliasp; 820 uint_t cnt; 821 descriptor_t **out_array; 822 int pos; 823 824 *errp = 0; 825 826 aliasp = diskp->aliases; 827 cnt = 0; 828 829 while (aliasp != NULL) { 830 if (aliasp->alias != NULL) { 831 cnt++; 832 } 833 aliasp = aliasp->next; 834 } 835 836 /* set up the new array */ 837 out_array = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t)); 838 if (out_array == NULL) { 839 *errp = ENOMEM; 840 return (NULL); 841 } 842 843 aliasp = diskp->aliases; 844 pos = 0; 845 while (aliasp != NULL) { 846 if (aliasp->alias != NULL) { 847 out_array[pos++] = cache_get_desc(DM_ALIAS, diskp, 848 aliasp->alias, NULL, errp); 849 if (*errp != 0) { 850 cache_free_descriptors(out_array); 851 return (NULL); 852 } 853 } 854 855 aliasp = aliasp->next; 856 } 857 858 out_array[pos] = NULL; 859 860 return (out_array); 861 } 862 863 static descriptor_t ** 864 get_assoc_controllers(descriptor_t *dp, int *errp) 865 { 866 disk_t *diskp; 867 int cnt; 868 descriptor_t **controllers; 869 int i; 870 871 diskp = dp->p.disk; 872 873 /* Count how many we have. */ 874 for (cnt = 0; diskp->controllers[cnt]; cnt++); 875 876 /* make the snapshot */ 877 controllers = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 878 if (controllers == NULL) { 879 *errp = ENOMEM; 880 return (NULL); 881 } 882 883 for (i = 0; diskp->controllers[i]; i++) { 884 controllers[i] = cache_get_desc(DM_CONTROLLER, 885 diskp->controllers[i], NULL, NULL, errp); 886 if (*errp != 0) { 887 cache_free_descriptors(controllers); 888 return (NULL); 889 } 890 } 891 892 controllers[i] = NULL; 893 894 *errp = 0; 895 return (controllers); 896 } 897 898 static descriptor_t ** 899 get_assoc_paths(descriptor_t *dp, int *errp) 900 { 901 path_t **pp; 902 int cnt; 903 descriptor_t **paths; 904 int i; 905 906 pp = dp->p.disk->paths; 907 908 /* Count how many we have. */ 909 cnt = 0; 910 if (pp != NULL) { 911 for (; pp[cnt]; cnt++); 912 } 913 914 /* make the snapshot */ 915 paths = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 916 if (paths == NULL) { 917 *errp = ENOMEM; 918 return (NULL); 919 } 920 921 /* 922 * We fill in the name field of the descriptor with the device_id 923 * when we deal with path descriptors originating from a drive. 924 * In that way we can use the device id within the path code to 925 * lookup the path state for this drive. 926 */ 927 for (i = 0; i < cnt; i++) { 928 paths[i] = cache_get_desc(DM_PATH, pp[i], dp->p.disk->device_id, 929 NULL, errp); 930 if (*errp != 0) { 931 cache_free_descriptors(paths); 932 return (NULL); 933 } 934 } 935 936 paths[i] = NULL; 937 938 *errp = 0; 939 return (paths); 940 } 941 942 static int 943 get_attrs(disk_t *diskp, int fd, char *opath, nvlist_t *attrs) 944 { 945 if (diskp->removable) { 946 struct dk_minfo minfo; 947 948 if (nvlist_add_boolean(attrs, DM_REMOVABLE) != 0) { 949 return (ENOMEM); 950 } 951 952 /* Make sure media is inserted and spun up. */ 953 if (fd >= 0 && media_read_info(fd, &minfo)) { 954 if (nvlist_add_boolean(attrs, DM_LOADED) != 0) { 955 return (ENOMEM); 956 } 957 } 958 959 /* can't tell diff between dead & no media on removable drives */ 960 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) { 961 return (ENOMEM); 962 } 963 964 get_drive_type(diskp, fd); 965 966 } else { 967 struct dk_minfo minfo; 968 969 /* check if the fixed drive is up or not */ 970 if (fd >= 0 && media_read_info(fd, &minfo)) { 971 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_UP) != 0) { 972 return (ENOMEM); 973 } 974 } else { 975 if (nvlist_add_uint32(attrs, DM_STATUS, DM_DISK_DOWN) != 0) { 976 return (ENOMEM); 977 } 978 } 979 980 get_drive_type(diskp, fd); 981 } 982 983 if (nvlist_add_uint32(attrs, DM_DRVTYPE, diskp->drv_type) != 0) { 984 return (ENOMEM); 985 } 986 987 if (diskp->product_id != NULL) { 988 if (nvlist_add_string(attrs, DM_PRODUCT_ID, diskp->product_id) 989 != 0) { 990 return (ENOMEM); 991 } 992 } 993 if (diskp->vendor_id != NULL) { 994 if (nvlist_add_string(attrs, DM_VENDOR_ID, diskp->vendor_id) != 0) { 995 return (ENOMEM); 996 } 997 } 998 999 if (diskp->sync_speed != -1) { 1000 if (nvlist_add_uint32(attrs, DM_SYNC_SPEED, diskp->sync_speed) 1001 != 0) { 1002 return (ENOMEM); 1003 } 1004 } 1005 1006 if (diskp->wide == 1) { 1007 if (nvlist_add_boolean(attrs, DM_WIDE) != 0) { 1008 return (ENOMEM); 1009 } 1010 } 1011 1012 if (diskp->rpm == 0) { 1013 diskp->rpm = get_rpm(diskp, fd); 1014 } 1015 1016 if (diskp->rpm > 0) { 1017 if (nvlist_add_uint32(attrs, DM_RPM, diskp->rpm) != 0) { 1018 return (ENOMEM); 1019 } 1020 } 1021 1022 if (diskp->aliases != NULL && diskp->aliases->cluster) { 1023 if (nvlist_add_boolean(attrs, DM_CLUSTERED) != 0) { 1024 return (ENOMEM); 1025 } 1026 } 1027 1028 if (strlen(opath) > 0) { 1029 if (nvlist_add_string(attrs, DM_OPATH, opath) != 0) { 1030 return (ENOMEM); 1031 } 1032 } 1033 1034 return (0); 1035 } 1036 1037 static int 1038 get_disk_kstats(kstat_ctl_t *kc, char *diskname, char *classname, 1039 nvlist_t *stats) 1040 { 1041 kstat_t *ksp; 1042 size_t class_len; 1043 int err = 0; 1044 1045 class_len = strlen(classname); 1046 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1047 if (strncmp(ksp->ks_class, classname, class_len) == 0) { 1048 char kstat_name[KSTAT_STRLEN]; 1049 char *dname = kstat_name; 1050 char *ename = ksp->ks_name; 1051 1052 /* names are format: "sd0,err" - copy chars up to comma */ 1053 while (*ename && *ename != ',') { 1054 *dname++ = *ename++; 1055 } 1056 *dname = NULL; 1057 1058 if (libdiskmgt_str_eq(diskname, kstat_name)) { 1059 (void) kstat_read(kc, ksp, NULL); 1060 err = get_kstat_vals(ksp, stats); 1061 break; 1062 } 1063 } 1064 } 1065 1066 return (err); 1067 } 1068 1069 /* 1070 * Getting the drive type depends on if the dev tree walk indicated that the 1071 * drive was a CD-ROM or not. The kernal lumps all of the removable multi-media 1072 * drives (e.g. CD, DVD, MO, etc.) together as CD-ROMS, so we need to use 1073 * a uscsi cmd to check the drive type. 1074 */ 1075 static void 1076 get_drive_type(disk_t *dp, int fd) 1077 { 1078 if (dp->drv_type == DM_DT_UNKNOWN) { 1079 int opened_here = 0; 1080 1081 /* We may have already opened the device. */ 1082 if (fd < 0) { 1083 fd = drive_open_disk(dp, NULL, 0); 1084 opened_here = 1; 1085 } 1086 1087 if (fd >= 0) { 1088 if (dp->cd_rom) { 1089 /* use uscsi to determine drive type */ 1090 dp->drv_type = get_cdrom_drvtype(fd); 1091 1092 /* if uscsi fails, just call it a cd-rom */ 1093 if (dp->drv_type == DM_DT_UNKNOWN) { 1094 dp->drv_type = DM_DT_CDROM; 1095 } 1096 1097 } else { 1098 struct dk_minfo minfo; 1099 1100 if (media_read_info(fd, &minfo)) { 1101 dp->drv_type = conv_drive_type(minfo.dki_media_type); 1102 } 1103 } 1104 1105 if (opened_here) { 1106 (void) close(fd); 1107 } 1108 1109 } else { 1110 /* couldn't open */ 1111 if (dp->cd_rom) { 1112 dp->drv_type = DM_DT_CDROM; 1113 } 1114 } 1115 } 1116 } 1117 1118 static char * 1119 get_err_attr_name(char *kstat_name) 1120 { 1121 int i; 1122 1123 for (i = 0; kstat_err_names[i] != NULL; i++) { 1124 if (libdiskmgt_str_eq(kstat_name, kstat_err_names[i])) { 1125 return (err_attr_names[i]); 1126 } 1127 } 1128 1129 return (NULL); 1130 } 1131 1132 static int 1133 get_err_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats) 1134 { 1135 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_ERROR, stats)); 1136 } 1137 1138 static int 1139 get_io_kstats(kstat_ctl_t *kc, char *diskname, nvlist_t *stats) 1140 { 1141 return (get_disk_kstats(kc, diskname, KSTAT_CLASS_DISK, stats)); 1142 } 1143 1144 static int 1145 get_kstat_vals(kstat_t *ksp, nvlist_t *stats) 1146 { 1147 if (ksp->ks_type == KSTAT_TYPE_IO) { 1148 kstat_io_t *kiop; 1149 1150 kiop = KSTAT_IO_PTR(ksp); 1151 1152 /* see sys/kstat.h kstat_io_t struct for more fields */ 1153 1154 if (update_stat64(stats, DM_NBYTESREAD, kiop->nread) != 0) { 1155 return (ENOMEM); 1156 } 1157 if (update_stat64(stats, DM_NBYTESWRITTEN, kiop->nwritten) != 0) { 1158 return (ENOMEM); 1159 } 1160 if (update_stat64(stats, DM_NREADOPS, kiop->reads) != 0) { 1161 return (ENOMEM); 1162 } 1163 if (update_stat64(stats, DM_NWRITEOPS, kiop->writes) != 0) { 1164 return (ENOMEM); 1165 } 1166 1167 } else if (ksp->ks_type == KSTAT_TYPE_NAMED) { 1168 kstat_named_t *knp; 1169 int i; 1170 1171 knp = KSTAT_NAMED_PTR(ksp); 1172 for (i = 0; i < ksp->ks_ndata; i++) { 1173 char *attr_name; 1174 1175 if (knp[i].name[0] == 0) 1176 continue; 1177 1178 if ((attr_name = get_err_attr_name(knp[i].name)) == NULL) { 1179 continue; 1180 1181 } 1182 1183 switch (knp[i].data_type) { 1184 case KSTAT_DATA_UINT32: 1185 if (update_stat32(stats, attr_name, knp[i].value.ui32) 1186 != 0) { 1187 return (ENOMEM); 1188 } 1189 break; 1190 1191 default: 1192 /* Right now all of the error types are uint32 */ 1193 break; 1194 } 1195 } 1196 } 1197 return (0); 1198 } 1199 1200 static int 1201 update_stat32(nvlist_t *stats, char *attr, uint32_t value) 1202 { 1203 int32_t currval; 1204 1205 if (nvlist_lookup_int32(stats, attr, &currval) == 0) { 1206 value += currval; 1207 } 1208 1209 return (nvlist_add_uint32(stats, attr, value)); 1210 } 1211 1212 /* 1213 * There can be more than one kstat value when we have multi-path drives 1214 * that are not under mpxio (since there is more than one kstat name for 1215 * the drive in this case). So, we may have merge all of the kstat values 1216 * to give an accurate set of stats for the drive. 1217 */ 1218 static int 1219 update_stat64(nvlist_t *stats, char *attr, uint64_t value) 1220 { 1221 int64_t currval; 1222 1223 if (nvlist_lookup_int64(stats, attr, &currval) == 0) { 1224 value += currval; 1225 } 1226 return (nvlist_add_uint64(stats, attr, value)); 1227 } 1228 1229 /* 1230 * uscsi function to get the rpm of the drive 1231 */ 1232 static int 1233 get_rpm(disk_t *dp, int fd) 1234 { 1235 int opened_here = 0; 1236 int rpm = -1; 1237 1238 /* We may have already opened the device. */ 1239 if (fd < 0) { 1240 fd = drive_open_disk(dp, NULL, 0); 1241 opened_here = 1; 1242 } 1243 1244 if (fd >= 0) { 1245 int status; 1246 struct mode_geometry *page4; 1247 struct scsi_ms_header header; 1248 union { 1249 struct mode_geometry page4; 1250 char rawbuf[MAX_MODE_SENSE_SIZE]; 1251 } u_page4; 1252 1253 page4 = &u_page4.page4; 1254 (void) memset(&u_page4, 0, sizeof (u_page4)); 1255 1256 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY, 1257 MODE_SENSE_PC_DEFAULT, (caddr_t)page4, MAX_MODE_SENSE_SIZE, 1258 &header); 1259 1260 if (status) { 1261 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY, 1262 MODE_SENSE_PC_SAVED, (caddr_t)page4, MAX_MODE_SENSE_SIZE, 1263 &header); 1264 } 1265 1266 if (status) { 1267 status = uscsi_mode_sense(fd, DAD_MODE_GEOMETRY, 1268 MODE_SENSE_PC_CURRENT, (caddr_t)page4, MAX_MODE_SENSE_SIZE, 1269 &header); 1270 } 1271 1272 if (!status) { 1273 #ifdef _LITTLE_ENDIAN 1274 page4->rpm = ntohs(page4->rpm); 1275 #endif /* _LITTLE_ENDIAN */ 1276 1277 rpm = page4->rpm; 1278 } 1279 1280 if (opened_here) { 1281 (void) close(fd); 1282 } 1283 } 1284 1285 return (rpm); 1286 } 1287 1288 /* 1289 * ******** the rest of this is uscsi stuff for the drv type ******** 1290 */ 1291 1292 /* 1293 * We try a get_configuration uscsi cmd. If that fails, try a 1294 * atapi_capabilities cmd. If both fail then this is an older CD-ROM. 1295 */ 1296 static int 1297 get_cdrom_drvtype(int fd) 1298 { 1299 union scsi_cdb cdb; 1300 struct uscsi_cmd cmd; 1301 uchar_t buff[SCSIBUFLEN]; 1302 1303 fill_general_page_cdb_g1(&cdb, SCMD_GET_CONFIGURATION, 0, 1304 b0(sizeof (buff)), b1(sizeof (buff))); 1305 fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff)); 1306 1307 if (ioctl(fd, USCSICMD, &cmd) >= 0) { 1308 struct get_configuration *config; 1309 struct conf_feature *feature; 1310 int flen; 1311 1312 /* The first profile is the preferred one for the drive. */ 1313 config = (struct get_configuration *)buff; 1314 feature = &config->feature; 1315 flen = feature->len / sizeof (struct profile_list); 1316 if (flen > 0) { 1317 int prof_num; 1318 1319 prof_num = (int)convnum(feature->features.plist[0].profile, 2); 1320 1321 if (dm_debug > 1) { 1322 (void) fprintf(stderr, "INFO: uscsi get_configuration %d\n", 1323 prof_num); 1324 } 1325 1326 switch (prof_num) { 1327 case PROF_MAGNETO_OPTICAL: 1328 return (DM_DT_MO_ERASABLE); 1329 case PROF_OPTICAL_WO: 1330 return (DM_DT_MO_WRITEONCE); 1331 case PROF_OPTICAL_ASMO: 1332 return (DM_DT_AS_MO); 1333 case PROF_CDROM: 1334 return (DM_DT_CDROM); 1335 case PROF_CDR: 1336 return (DM_DT_CDR); 1337 case PROF_CDRW: 1338 return (DM_DT_CDRW); 1339 case PROF_DVDROM: 1340 return (DM_DT_DVDROM); 1341 case PROF_DVDRAM: 1342 return (DM_DT_DVDRAM); 1343 case PROF_DVDRW_REST: 1344 return (DM_DT_DVDRW); 1345 case PROF_DVDRW_SEQ: 1346 return (DM_DT_DVDRW); 1347 case PROF_DVDRW: 1348 return (DM_DT_DVDRW); 1349 case PROF_DDCD_ROM: 1350 return (DM_DT_DDCDROM); 1351 case PROF_DDCD_R: 1352 return (DM_DT_DDCDR); 1353 case PROF_DDCD_RW: 1354 return (DM_DT_DDCDRW); 1355 } 1356 } 1357 } 1358 1359 /* see if the atapi capabilities give anything */ 1360 return (check_atapi(fd)); 1361 } 1362 1363 static int 1364 check_atapi(int fd) 1365 { 1366 union scsi_cdb cdb; 1367 struct uscsi_cmd cmd; 1368 uchar_t buff[SCSIBUFLEN]; 1369 1370 fill_mode_page_cdb(&cdb, ATAPI_CAPABILITIES); 1371 fill_command_g1(&cmd, &cdb, (caddr_t)buff, sizeof (buff)); 1372 1373 if (ioctl(fd, USCSICMD, &cmd) >= 0) { 1374 int bdesclen; 1375 struct capabilities *cap; 1376 struct mode_header_g2 *mode; 1377 1378 mode = (struct mode_header_g2 *)buff; 1379 1380 bdesclen = (int)convnum(mode->desclen, 2); 1381 cap = (struct capabilities *) 1382 &buff[sizeof (struct mode_header_g2) + bdesclen]; 1383 1384 if (dm_debug > 1) { 1385 (void) fprintf(stderr, "INFO: uscsi atapi capabilities\n"); 1386 } 1387 1388 /* These are in order of how we want to report the drv type. */ 1389 if (cap->dvdram_write) { 1390 return (DM_DT_DVDRAM); 1391 } 1392 if (cap->dvdr_write) { 1393 return (DM_DT_DVDR); 1394 } 1395 if (cap->dvdrom_read) { 1396 return (DM_DT_DVDROM); 1397 } 1398 if (cap->cdrw_write) { 1399 return (DM_DT_CDRW); 1400 } 1401 if (cap->cdr_write) { 1402 return (DM_DT_CDR); 1403 } 1404 if (cap->cdr_read) { 1405 return (DM_DT_CDROM); 1406 } 1407 } 1408 1409 /* everything failed, so this is an older CD-ROM */ 1410 if (dm_debug > 1) { 1411 (void) fprintf(stderr, "INFO: uscsi failed\n"); 1412 } 1413 1414 return (DM_DT_CDROM); 1415 } 1416 1417 static uint64_t 1418 convnum(uchar_t *nptr, int len) 1419 { 1420 uint64_t value; 1421 1422 for (value = 0; len > 0; len--, nptr++) 1423 value = (value << 8) | *nptr; 1424 return (value); 1425 } 1426 1427 static void 1428 fill_command_g1(struct uscsi_cmd *cmd, union scsi_cdb *cdb, 1429 caddr_t buff, int blen) 1430 { 1431 bzero((caddr_t)cmd, sizeof (struct uscsi_cmd)); 1432 bzero(buff, blen); 1433 1434 cmd->uscsi_cdb = (caddr_t)cdb; 1435 cmd->uscsi_cdblen = CDB_GROUP1; 1436 1437 cmd->uscsi_bufaddr = buff; 1438 cmd->uscsi_buflen = blen; 1439 1440 cmd->uscsi_flags = USCSI_DIAGNOSE|USCSI_ISOLATE|USCSI_READ; 1441 } 1442 1443 static void 1444 fill_general_page_cdb_g1(union scsi_cdb *cdb, int command, int lun, 1445 uchar_t c0, uchar_t c1) 1446 { 1447 bzero((caddr_t)cdb, sizeof (union scsi_cdb)); 1448 cdb->scc_cmd = command; 1449 cdb->scc_lun = lun; 1450 cdb->g1_count0 = c0; /* max length for page */ 1451 cdb->g1_count1 = c1; /* max length for page */ 1452 } 1453 1454 static void 1455 fill_mode_page_cdb(union scsi_cdb *cdb, int page) 1456 { 1457 /* group 1 mode page */ 1458 bzero((caddr_t)cdb, sizeof (union scsi_cdb)); 1459 cdb->scc_cmd = SCMD_MODE_SENSE_G1; 1460 cdb->g1_count0 = 0xff; /* max length for mode page */ 1461 cdb->g1_count1 = 0xff; /* max length for mode page */ 1462 cdb->g1_addr3 = page; 1463 } 1464 1465 static int 1466 uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data, 1467 int page_size, struct scsi_ms_header *header) 1468 { 1469 caddr_t mode_sense_buf; 1470 struct mode_header *hdr; 1471 struct mode_page *pg; 1472 int nbytes; 1473 struct uscsi_cmd ucmd; 1474 union scsi_cdb cdb; 1475 int status; 1476 int maximum; 1477 char rqbuf[255]; 1478 1479 /* 1480 * Allocate a buffer for the mode sense headers 1481 * and mode sense data itself. 1482 */ 1483 nbytes = sizeof (struct block_descriptor) + 1484 sizeof (struct mode_header) + page_size; 1485 nbytes = page_size; 1486 if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) { 1487 return (-1); 1488 } 1489 1490 /* 1491 * Build and execute the uscsi ioctl 1492 */ 1493 (void) memset(mode_sense_buf, 0, nbytes); 1494 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 1495 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 1496 1497 cdb.scc_cmd = SCMD_MODE_SENSE; 1498 FORMG0COUNT(&cdb, (uchar_t)nbytes); 1499 cdb.cdb_opaque[2] = page_control | page_code; 1500 ucmd.uscsi_cdb = (caddr_t)&cdb; 1501 ucmd.uscsi_cdblen = CDB_GROUP0; 1502 ucmd.uscsi_bufaddr = mode_sense_buf; 1503 ucmd.uscsi_buflen = nbytes; 1504 1505 ucmd.uscsi_flags |= USCSI_SILENT; 1506 ucmd.uscsi_flags |= USCSI_READ; 1507 ucmd.uscsi_timeout = 30; 1508 ucmd.uscsi_flags |= USCSI_RQENABLE; 1509 if (ucmd.uscsi_rqbuf == NULL) { 1510 ucmd.uscsi_rqbuf = rqbuf; 1511 ucmd.uscsi_rqlen = sizeof (rqbuf); 1512 ucmd.uscsi_rqresid = sizeof (rqbuf); 1513 } 1514 ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS; 1515 1516 status = ioctl(fd, USCSICMD, &ucmd); 1517 1518 if (status || ucmd.uscsi_status != 0) { 1519 free(mode_sense_buf); 1520 return (-1); 1521 } 1522 1523 /* 1524 * Verify that the returned data looks reasonabled, 1525 * find the actual page data, and copy it into the 1526 * user's buffer. Copy the mode_header and block_descriptor 1527 * into the header structure, which can then be used to 1528 * return the same data to the drive when issuing a mode select. 1529 */ 1530 hdr = (struct mode_header *)mode_sense_buf; 1531 (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header)); 1532 if (hdr->bdesc_length != sizeof (struct block_descriptor) && 1533 hdr->bdesc_length != 0) { 1534 free(mode_sense_buf); 1535 return (-1); 1536 } 1537 (void) memcpy((caddr_t)header, mode_sense_buf, 1538 (int) (sizeof (struct mode_header) + hdr->bdesc_length)); 1539 pg = (struct mode_page *)((ulong_t)mode_sense_buf + 1540 sizeof (struct mode_header) + hdr->bdesc_length); 1541 if (pg->code != page_code) { 1542 free(mode_sense_buf); 1543 return (-1); 1544 } 1545 1546 /* 1547 * Accept up to "page_size" bytes of mode sense data. 1548 * This allows us to accept both CCS and SCSI-2 1549 * structures, as long as we request the greater 1550 * of the two. 1551 */ 1552 maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length; 1553 if (((int)pg->length) > maximum) { 1554 free(mode_sense_buf); 1555 return (-1); 1556 } 1557 1558 (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg)); 1559 1560 free(mode_sense_buf); 1561 return (0); 1562 } 1563