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
ses_match(struct device * parent,void * match,void * aux)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
ses_attach(struct device * parent,struct device * self,void * aux)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
ses_detach(struct device * self,int flags)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
ses_read_config(struct ses_softc * sc)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
ses_read_status(struct ses_softc * sc)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
ses_make_sensors(struct ses_softc * sc,struct ses_type_desc * types,int ntypes)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
ses_refresh_sensors(void * arg)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
ses_ioctl(struct device * dev,u_long cmd,caddr_t addr)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
ses_write_config(struct ses_softc * sc)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
ses_bio_blink(struct ses_softc * sc,struct bioc_blink * blink)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
ses_psu2sensor(struct ses_softc * sc,struct ses_sensor * s)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
ses_cool2sensor(struct ses_softc * sc,struct ses_sensor * s)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
ses_temp2sensor(struct ses_softc * sc,struct ses_sensor * s)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
ses_dump_enc_desc(struct ses_enc_desc * desc)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 *
ses_dump_enc_string(u_char * buf,ssize_t len)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