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