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