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