1 /* $OpenBSD: ses.c,v 1.51 2011/03/17 21:30:24 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "bio.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/device.h> 24 #include <sys/scsiio.h> 25 #include <sys/malloc.h> 26 #include <sys/pool.h> 27 #include <sys/proc.h> 28 #include <sys/rwlock.h> 29 #include <sys/queue.h> 30 #include <sys/sensors.h> 31 32 #if NBIO > 0 33 #include <dev/biovar.h> 34 #endif 35 36 #include <scsi/scsi_all.h> 37 #include <scsi/scsiconf.h> 38 39 #include <scsi/ses.h> 40 41 #ifdef SES_DEBUG 42 #define DPRINTF(x...) do { if (sesdebug) printf(x); } while (0) 43 #define DPRINTFN(n, x...) do { if (sesdebug > (n)) printf(x); } while (0) 44 int sesdebug = 2; 45 #else 46 #define DPRINTF(x...) /* x */ 47 #define DPRINTFN(n,x...) /* n: x */ 48 #endif 49 50 int ses_match(struct device *, void *, void *); 51 void ses_attach(struct device *, struct device *, void *); 52 int ses_detach(struct device *, int); 53 54 struct ses_sensor { 55 struct ksensor se_sensor; 56 u_int8_t se_type; 57 struct ses_status *se_stat; 58 59 TAILQ_ENTRY(ses_sensor) se_entry; 60 }; 61 62 #if NBIO > 0 63 struct ses_slot { 64 struct ses_status *sl_stat; 65 66 TAILQ_ENTRY(ses_slot) sl_entry; 67 }; 68 #endif 69 70 struct ses_softc { 71 struct device sc_dev; 72 struct scsi_link *sc_link; 73 struct rwlock sc_lock; 74 75 enum { 76 SES_ENC_STD, 77 SES_ENC_DELL 78 } sc_enctype; 79 80 u_char *sc_buf; 81 ssize_t sc_buflen; 82 83 #if NBIO > 0 84 TAILQ_HEAD(, ses_slot) sc_slots; 85 #endif 86 TAILQ_HEAD(, ses_sensor) sc_sensors; 87 struct ksensordev sc_sensordev; 88 struct sensor_task *sc_sensortask; 89 }; 90 91 struct cfattach ses_ca = { 92 sizeof(struct ses_softc), ses_match, ses_attach, ses_detach 93 }; 94 95 struct cfdriver ses_cd = { 96 NULL, "ses", DV_DULL 97 }; 98 99 #define DEVNAME(s) ((s)->sc_dev.dv_xname) 100 101 #define SES_BUFLEN 2048 /* XXX is this enough? */ 102 103 int ses_read_config(struct ses_softc *); 104 int ses_read_status(struct ses_softc *); 105 int ses_make_sensors(struct ses_softc *, struct ses_type_desc *, int); 106 void ses_refresh_sensors(void *); 107 108 #if NBIO > 0 109 int ses_ioctl(struct device *, u_long, caddr_t); 110 int ses_write_config(struct ses_softc *); 111 int ses_bio_blink(struct ses_softc *, struct bioc_blink *); 112 #endif 113 114 void ses_psu2sensor(struct ses_softc *, struct ses_sensor *); 115 void ses_cool2sensor(struct ses_softc *, struct ses_sensor *); 116 void ses_temp2sensor(struct ses_softc *, struct ses_sensor *); 117 118 #ifdef SES_DEBUG 119 void ses_dump_enc_desc(struct ses_enc_desc *); 120 char *ses_dump_enc_string(u_char *, ssize_t); 121 #endif 122 123 int 124 ses_match(struct device *parent, void *match, void *aux) 125 { 126 struct scsi_attach_args *sa = aux; 127 struct scsi_inquiry_data *inq = sa->sa_inqbuf; 128 129 if (inq == NULL) 130 return (0); 131 132 if ((inq->device & SID_TYPE) == T_ENCLOSURE && 133 SCSISPC(inq->version) >= 2) 134 return (2); 135 136 /* match on dell enclosures */ 137 if ((inq->device & SID_TYPE) == T_PROCESSOR && 138 SCSISPC(inq->version) == 3) 139 return (3); 140 141 return (0); 142 } 143 144 void 145 ses_attach(struct device *parent, struct device *self, void *aux) 146 { 147 struct ses_softc *sc = (struct ses_softc *)self; 148 struct scsi_attach_args *sa = aux; 149 char vendor[33]; 150 struct ses_sensor *sensor; 151 #if NBIO > 0 152 struct ses_slot *slot; 153 #endif 154 155 sc->sc_link = sa->sa_sc_link; 156 sa->sa_sc_link->device_softc = sc; 157 rw_init(&sc->sc_lock, DEVNAME(sc)); 158 159 scsi_strvis(vendor, sc->sc_link->inqdata.vendor, 160 sizeof(sc->sc_link->inqdata.vendor)); 161 if (strncasecmp(vendor, "Dell", sizeof(vendor)) == 0) 162 sc->sc_enctype = SES_ENC_DELL; 163 else 164 sc->sc_enctype = SES_ENC_STD; 165 166 printf("\n"); 167 168 if (ses_read_config(sc) != 0) { 169 printf("%s: unable to read enclosure configuration\n", 170 DEVNAME(sc)); 171 return; 172 } 173 174 if (!TAILQ_EMPTY(&sc->sc_sensors)) { 175 sc->sc_sensortask = sensor_task_register(sc, 176 ses_refresh_sensors, 10); 177 if (sc->sc_sensortask == NULL) { 178 printf("%s: unable to register update task\n", 179 DEVNAME(sc)); 180 while (!TAILQ_EMPTY(&sc->sc_sensors)) { 181 sensor = TAILQ_FIRST(&sc->sc_sensors); 182 TAILQ_REMOVE(&sc->sc_sensors, sensor, 183 se_entry); 184 free(sensor, M_DEVBUF); 185 } 186 } else { 187 TAILQ_FOREACH(sensor, &sc->sc_sensors, se_entry) 188 sensor_attach(&sc->sc_sensordev, 189 &sensor->se_sensor); 190 sensordev_install(&sc->sc_sensordev); 191 } 192 } 193 194 #if NBIO > 0 195 if (!TAILQ_EMPTY(&sc->sc_slots) && 196 bio_register(self, ses_ioctl) != 0) { 197 printf("%s: unable to register ioctl\n", DEVNAME(sc)); 198 while (!TAILQ_EMPTY(&sc->sc_slots)) { 199 slot = TAILQ_FIRST(&sc->sc_slots); 200 TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry); 201 free(slot, M_DEVBUF); 202 } 203 } 204 #endif 205 206 if (TAILQ_EMPTY(&sc->sc_sensors) 207 #if NBIO > 0 208 && TAILQ_EMPTY(&sc->sc_slots) 209 #endif 210 ) { 211 dma_free(sc->sc_buf, sc->sc_buflen); 212 sc->sc_buf = NULL; 213 } 214 } 215 216 int 217 ses_detach(struct device *self, int flags) 218 { 219 struct ses_softc *sc = (struct ses_softc *)self; 220 struct ses_sensor *sensor; 221 #if NBIO > 0 222 struct ses_slot *slot; 223 #endif 224 225 rw_enter_write(&sc->sc_lock); 226 227 #if NBIO > 0 228 if (!TAILQ_EMPTY(&sc->sc_slots)) { 229 bio_unregister(self); 230 while (!TAILQ_EMPTY(&sc->sc_slots)) { 231 slot = TAILQ_FIRST(&sc->sc_slots); 232 TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry); 233 free(slot, M_DEVBUF); 234 } 235 } 236 #endif 237 238 if (!TAILQ_EMPTY(&sc->sc_sensors)) { 239 sensordev_deinstall(&sc->sc_sensordev); 240 sensor_task_unregister(sc->sc_sensortask); 241 242 while (!TAILQ_EMPTY(&sc->sc_sensors)) { 243 sensor = TAILQ_FIRST(&sc->sc_sensors); 244 sensor_detach(&sc->sc_sensordev, &sensor->se_sensor); 245 TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry); 246 free(sensor, M_DEVBUF); 247 } 248 } 249 250 if (sc->sc_buf != NULL) 251 dma_free(sc->sc_buf, sc->sc_buflen); 252 253 rw_exit_write(&sc->sc_lock); 254 255 return (0); 256 } 257 258 int 259 ses_read_config(struct ses_softc *sc) 260 { 261 struct ses_scsi_diag *cmd; 262 struct ses_config_hdr *cfg; 263 struct ses_type_desc *tdh, *tdlist; 264 #ifdef SES_DEBUG 265 struct ses_enc_desc *desc; 266 #endif 267 struct ses_enc_hdr *enc; 268 struct scsi_xfer *xs; 269 u_char *buf, *p; 270 int error = 0, i; 271 int flags = 0, ntypes = 0, nelems = 0; 272 273 buf = dma_alloc(SES_BUFLEN, PR_NOWAIT | PR_ZERO); 274 if (buf == NULL) 275 return (1); 276 277 if (cold) 278 flags |= SCSI_AUTOCONF; 279 xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); 280 if (xs == NULL) { 281 error = 1; 282 goto done; 283 } 284 xs->cmdlen = sizeof(*cmd); 285 xs->data = buf; 286 xs->datalen = SES_BUFLEN; 287 xs->retries = 2; 288 xs->timeout = 3000; 289 290 cmd = (struct ses_scsi_diag *)xs->cmd; 291 cmd->opcode = RECEIVE_DIAGNOSTIC; 292 cmd->flags |= SES_DIAG_PCV; 293 cmd->pgcode = SES_PAGE_CONFIG; 294 cmd->length = htobe16(SES_BUFLEN); 295 296 error = scsi_xs_sync(xs); 297 scsi_xs_put(xs); 298 299 if (error) { 300 error = 1; 301 goto done; 302 } 303 304 cfg = (struct ses_config_hdr *)buf; 305 if (cfg->pgcode != SES_PAGE_CONFIG || betoh16(cfg->length) > 306 SES_BUFLEN) { 307 error = 1; 308 goto done; 309 } 310 311 DPRINTF("%s: config: n_subenc: %d length: %d\n", DEVNAME(sc), 312 cfg->n_subenc, betoh16(cfg->length)); 313 314 p = buf + SES_CFG_HDRLEN; 315 for (i = 0; i <= cfg->n_subenc; i++) { 316 enc = (struct ses_enc_hdr *)p; 317 #ifdef SES_DEBUG 318 DPRINTF("%s: enclosure %d enc_id: 0x%02x n_types: %d\n", 319 DEVNAME(sc), i, enc->enc_id, enc->n_types); 320 desc = (struct ses_enc_desc *)(p + SES_ENC_HDRLEN); 321 ses_dump_enc_desc(desc); 322 #endif /* SES_DEBUG */ 323 324 ntypes += enc->n_types; 325 326 p += SES_ENC_HDRLEN + enc->vendor_len; 327 } 328 329 tdlist = (struct ses_type_desc *)p; /* stash this for later */ 330 331 for (i = 0; i < ntypes; i++) { 332 tdh = (struct ses_type_desc *)p; 333 DPRINTF("%s: td %d subenc_id: %d type 0x%02x n_elem: %d\n", 334 DEVNAME(sc), i, tdh->subenc_id, tdh->type, tdh->n_elem); 335 336 nelems += tdh->n_elem; 337 338 p += SES_TYPE_DESCLEN; 339 } 340 341 #ifdef SES_DEBUG 342 for (i = 0; i < ntypes; i++) { 343 DPRINTF("%s: td %d '%s'\n", DEVNAME(sc), i, 344 ses_dump_enc_string(p, tdlist[i].desc_len)); 345 346 p += tdlist[i].desc_len; 347 } 348 #endif /* SES_DEBUG */ 349 350 sc->sc_buflen = SES_STAT_LEN(ntypes, nelems); 351 sc->sc_buf = dma_alloc(sc->sc_buflen, PR_NOWAIT); 352 if (sc->sc_buf == NULL) { 353 error = 1; 354 goto done; 355 } 356 357 /* get the status page and then use it to generate a list of sensors */ 358 if (ses_make_sensors(sc, tdlist, ntypes) != 0) { 359 dma_free(sc->sc_buf, sc->sc_buflen); 360 error = 1; 361 goto done; 362 } 363 364 done: 365 if (buf) 366 dma_free(buf, SES_BUFLEN); 367 return (error); 368 } 369 370 int 371 ses_read_status(struct ses_softc *sc) 372 { 373 struct ses_scsi_diag *cmd; 374 struct scsi_xfer *xs; 375 int error, flags = 0; 376 377 if (cold) 378 flags |= SCSI_AUTOCONF; 379 xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); 380 if (xs == NULL) 381 return (1); 382 xs->cmdlen = sizeof(*cmd); 383 xs->data = sc->sc_buf; 384 xs->datalen = sc->sc_buflen; 385 xs->retries = 2; 386 xs->timeout = 3000; 387 388 cmd = (struct ses_scsi_diag *)xs->cmd; 389 cmd->opcode = RECEIVE_DIAGNOSTIC; 390 cmd->flags |= SES_DIAG_PCV; 391 cmd->pgcode = SES_PAGE_STATUS; 392 cmd->length = htobe16(sc->sc_buflen); 393 394 error = scsi_xs_sync(xs); 395 scsi_xs_put(xs); 396 397 if (error != 0) 398 return (1); 399 400 return (0); 401 } 402 403 int 404 ses_make_sensors(struct ses_softc *sc, struct ses_type_desc *types, int ntypes) 405 { 406 struct ses_status *status; 407 struct ses_sensor *sensor; 408 #if NBIO > 0 409 struct ses_slot *slot; 410 #endif 411 enum sensor_type stype; 412 char *fmt; 413 int i, j; 414 415 if (ses_read_status(sc) != 0) 416 return (1); 417 418 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 419 sizeof(sc->sc_sensordev.xname)); 420 421 TAILQ_INIT(&sc->sc_sensors); 422 #if NBIO > 0 423 TAILQ_INIT(&sc->sc_slots); 424 #endif 425 426 status = (struct ses_status *)(sc->sc_buf + SES_STAT_HDRLEN); 427 for (i = 0; i < ntypes; i++) { 428 /* ignore the overall status element for this type */ 429 DPRINTFN(1, "%s: %3d:- 0x%02x 0x%02x%02x%02x type: 0x%02x\n", 430 DEVNAME(sc), i, status->com, status->f1, status->f2, 431 status->f3, types[i].type); 432 433 for (j = 0; j < types[i].n_elem; j++) { 434 /* move to the current status element */ 435 status++; 436 437 DPRINTFN(1, "%s: %3d:%-3d 0x%02x 0x%02x%02x%02x\n", 438 DEVNAME(sc), i, j, status->com, status->f1, 439 status->f2, status->f3); 440 441 if (SES_STAT_CODE(status->com) == SES_STAT_CODE_NOTINST) 442 continue; 443 444 switch (types[i].type) { 445 #if NBIO > 0 446 case SES_T_DEVICE: 447 slot = malloc(sizeof(*slot), M_DEVBUF, 448 M_NOWAIT | M_ZERO); 449 if (slot == NULL) 450 goto error; 451 452 slot->sl_stat = status; 453 454 TAILQ_INSERT_TAIL(&sc->sc_slots, slot, 455 sl_entry); 456 457 continue; 458 #endif 459 460 case SES_T_POWERSUPPLY: 461 stype = SENSOR_INDICATOR; 462 fmt = "PSU"; 463 break; 464 465 case SES_T_COOLING: 466 stype = SENSOR_PERCENT; 467 fmt = "Fan"; 468 break; 469 470 case SES_T_TEMP: 471 stype = SENSOR_TEMP; 472 fmt = ""; 473 break; 474 475 default: 476 continue; 477 } 478 479 sensor = malloc(sizeof(*sensor), M_DEVBUF, 480 M_NOWAIT | M_ZERO); 481 if (sensor == NULL) 482 goto error; 483 484 sensor->se_type = types[i].type; 485 sensor->se_stat = status; 486 sensor->se_sensor.type = stype; 487 strlcpy(sensor->se_sensor.desc, fmt, 488 sizeof(sensor->se_sensor.desc)); 489 490 TAILQ_INSERT_TAIL(&sc->sc_sensors, sensor, se_entry); 491 } 492 493 /* move to the overall status element of the next type */ 494 status++; 495 } 496 497 return (0); 498 error: 499 #if NBIO > 0 500 while (!TAILQ_EMPTY(&sc->sc_slots)) { 501 slot = TAILQ_FIRST(&sc->sc_slots); 502 TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry); 503 free(slot, M_DEVBUF); 504 } 505 #endif 506 while (!TAILQ_EMPTY(&sc->sc_sensors)) { 507 sensor = TAILQ_FIRST(&sc->sc_sensors); 508 TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry); 509 free(sensor, M_DEVBUF); 510 } 511 return (1); 512 } 513 514 void 515 ses_refresh_sensors(void *arg) 516 { 517 struct ses_softc *sc = (struct ses_softc *)arg; 518 struct ses_sensor *sensor; 519 int ret = 0; 520 521 rw_enter_write(&sc->sc_lock); 522 523 if (ses_read_status(sc) != 0) { 524 rw_exit_write(&sc->sc_lock); 525 return; 526 } 527 528 TAILQ_FOREACH(sensor, &sc->sc_sensors, se_entry) { 529 DPRINTFN(10, "%s: %s 0x%02x 0x%02x%02x%02x\n", DEVNAME(sc), 530 sensor->se_sensor.desc, sensor->se_stat->com, 531 sensor->se_stat->f1, sensor->se_stat->f2, 532 sensor->se_stat->f3); 533 534 switch (SES_STAT_CODE(sensor->se_stat->com)) { 535 case SES_STAT_CODE_OK: 536 sensor->se_sensor.status = SENSOR_S_OK; 537 break; 538 539 case SES_STAT_CODE_CRIT: 540 case SES_STAT_CODE_UNREC: 541 sensor->se_sensor.status = SENSOR_S_CRIT; 542 break; 543 544 case SES_STAT_CODE_NONCRIT: 545 sensor->se_sensor.status = SENSOR_S_WARN; 546 break; 547 548 case SES_STAT_CODE_NOTINST: 549 case SES_STAT_CODE_UNKNOWN: 550 case SES_STAT_CODE_NOTAVAIL: 551 sensor->se_sensor.status = SENSOR_S_UNKNOWN; 552 break; 553 } 554 555 switch (sensor->se_type) { 556 case SES_T_POWERSUPPLY: 557 ses_psu2sensor(sc, sensor); 558 break; 559 560 case SES_T_COOLING: 561 ses_cool2sensor(sc, sensor); 562 break; 563 564 case SES_T_TEMP: 565 ses_temp2sensor(sc, sensor); 566 break; 567 568 default: 569 ret = 1; 570 break; 571 } 572 } 573 574 rw_exit_write(&sc->sc_lock); 575 576 if (ret) 577 printf("%s: error in sensor data\n", DEVNAME(sc)); 578 } 579 580 #if NBIO > 0 581 int 582 ses_ioctl(struct device *dev, u_long cmd, caddr_t addr) 583 { 584 struct ses_softc *sc = (struct ses_softc *)dev; 585 int error = 0; 586 587 switch (cmd) { 588 case BIOCBLINK: 589 error = ses_bio_blink(sc, (struct bioc_blink *)addr); 590 break; 591 592 default: 593 error = EINVAL; 594 break; 595 } 596 597 return (error); 598 } 599 600 int 601 ses_write_config(struct ses_softc *sc) 602 { 603 struct ses_scsi_diag *cmd; 604 struct scsi_xfer *xs; 605 int error, flags = 0; 606 607 if (cold) 608 flags |= SCSI_AUTOCONF; 609 610 xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT); 611 if (xs == NULL) 612 return (1); 613 xs->cmdlen = sizeof(*cmd); 614 xs->data = sc->sc_buf; 615 xs->datalen = sc->sc_buflen; 616 xs->retries = 2; 617 xs->timeout = 3000; 618 619 cmd = (struct ses_scsi_diag *)xs->cmd; 620 cmd->opcode = SEND_DIAGNOSTIC; 621 cmd->flags |= SES_DIAG_PF; 622 cmd->length = htobe16(sc->sc_buflen); 623 624 error = scsi_xs_sync(xs); 625 scsi_xs_put(xs); 626 627 if (error != 0) 628 return (1); 629 630 return (0); 631 } 632 633 int 634 ses_bio_blink(struct ses_softc *sc, struct bioc_blink *blink) 635 { 636 struct ses_slot *slot; 637 638 rw_enter_write(&sc->sc_lock); 639 640 if (ses_read_status(sc) != 0) { 641 rw_exit_write(&sc->sc_lock); 642 return (EIO); 643 } 644 645 TAILQ_FOREACH(slot, &sc->sc_slots, sl_entry) { 646 if (slot->sl_stat->f1 == blink->bb_target) 647 break; 648 } 649 650 if (slot == TAILQ_END(&sc->sc_slots)) { 651 rw_exit_write(&sc->sc_lock); 652 return (EINVAL); 653 } 654 655 DPRINTFN(3, "%s: 0x%02x 0x%02x 0x%02x 0x%02x\n", DEVNAME(sc), 656 slot->sl_stat->com, slot->sl_stat->f1, slot->sl_stat->f2, 657 slot->sl_stat->f3); 658 659 slot->sl_stat->com = SES_STAT_SELECT; 660 slot->sl_stat->f2 &= SES_C_DEV_F2MASK; 661 slot->sl_stat->f3 &= SES_C_DEV_F3MASK; 662 663 switch (blink->bb_status) { 664 case BIOC_SBUNBLINK: 665 slot->sl_stat->f2 &= ~SES_C_DEV_IDENT; 666 break; 667 668 case BIOC_SBBLINK: 669 slot->sl_stat->f2 |= SES_C_DEV_IDENT; 670 break; 671 672 default: 673 rw_exit_write(&sc->sc_lock); 674 return (EINVAL); 675 } 676 677 DPRINTFN(3, "%s: 0x%02x 0x%02x 0x%02x 0x%02x\n", DEVNAME(sc), 678 slot->sl_stat->com, slot->sl_stat->f1, slot->sl_stat->f2, 679 slot->sl_stat->f3); 680 681 if (ses_write_config(sc) != 0) { 682 rw_exit_write(&sc->sc_lock); 683 return (EIO); 684 } 685 686 rw_exit_write(&sc->sc_lock); 687 688 return (0); 689 } 690 #endif 691 692 void 693 ses_psu2sensor(struct ses_softc *sc, struct ses_sensor *s) 694 { 695 s->se_sensor.value = SES_S_PSU_OFF(s->se_stat) ? 0 : 1; 696 } 697 698 void 699 ses_cool2sensor(struct ses_softc *sc, struct ses_sensor *s) 700 { 701 switch (sc->sc_enctype) { 702 case SES_ENC_STD: 703 switch (SES_S_COOL_CODE(s->se_stat)) { 704 case SES_S_COOL_C_STOPPED: 705 s->se_sensor.value = 0; 706 break; 707 case SES_S_COOL_C_LOW1: 708 case SES_S_COOL_C_LOW2: 709 case SES_S_COOL_C_LOW3: 710 s->se_sensor.value = 33333; 711 break; 712 case SES_S_COOL_C_INTER: 713 case SES_S_COOL_C_HI3: 714 case SES_S_COOL_C_HI2: 715 s->se_sensor.value = 66666; 716 break; 717 case SES_S_COOL_C_HI1: 718 s->se_sensor.value = 100000; 719 break; 720 } 721 break; 722 723 /* Dell only use the first three codes to represent speed */ 724 case SES_ENC_DELL: 725 switch (SES_S_COOL_CODE(s->se_stat)) { 726 case SES_S_COOL_C_STOPPED: 727 s->se_sensor.value = 0; 728 break; 729 case SES_S_COOL_C_LOW1: 730 s->se_sensor.value = 33333; 731 break; 732 case SES_S_COOL_C_LOW2: 733 s->se_sensor.value = 66666; 734 break; 735 case SES_S_COOL_C_LOW3: 736 case SES_S_COOL_C_INTER: 737 case SES_S_COOL_C_HI3: 738 case SES_S_COOL_C_HI2: 739 case SES_S_COOL_C_HI1: 740 s->se_sensor.value = 100000; 741 break; 742 } 743 break; 744 } 745 } 746 747 void 748 ses_temp2sensor(struct ses_softc *sc, struct ses_sensor *s) 749 { 750 s->se_sensor.value = (int64_t)SES_S_TEMP(s->se_stat); 751 s->se_sensor.value += SES_S_TEMP_OFFSET; 752 s->se_sensor.value *= 1000000; /* convert to micro (mu) degrees */ 753 s->se_sensor.value += 273150000; /* convert to kelvin */ 754 } 755 756 #ifdef SES_DEBUG 757 void 758 ses_dump_enc_desc(struct ses_enc_desc *desc) 759 { 760 char str[32]; 761 762 #if 0 763 /* XXX not a string. wwn? */ 764 memset(str, 0, sizeof(str)); 765 memcpy(str, desc->logical_id, sizeof(desc->logical_id)); 766 DPRINTF("logical_id: %s", str); 767 #endif 768 769 memset(str, 0, sizeof(str)); 770 memcpy(str, desc->vendor_id, sizeof(desc->vendor_id)); 771 DPRINTF(" vendor_id: %s", str); 772 773 memset(str, 0, sizeof(str)); 774 memcpy(str, desc->prod_id, sizeof(desc->prod_id)); 775 DPRINTF(" prod_id: %s", str); 776 777 memset(str, 0, sizeof(str)); 778 memcpy(str, desc->prod_rev, sizeof(desc->prod_rev)); 779 DPRINTF(" prod_rev: %s\n", str); 780 } 781 782 char * 783 ses_dump_enc_string(u_char *buf, ssize_t len) 784 { 785 static char str[256]; 786 787 memset(str, 0, sizeof(str)); 788 if (len > 0) 789 memcpy(str, buf, len); 790 791 return (str); 792 } 793 #endif /* SES_DEBUG */ 794