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