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