Line data Source code
1 : /* $OpenBSD: ses.c,v 1.55 2015/08/23 01:55:39 tedu 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
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 0 : ses_match(struct device *parent, void *match, void *aux)
124 : {
125 0 : struct scsi_attach_args *sa = aux;
126 0 : struct scsi_inquiry_data *inq = sa->sa_inqbuf;
127 :
128 0 : if (inq == NULL)
129 0 : return (0);
130 :
131 0 : if ((inq->device & SID_TYPE) == T_ENCLOSURE &&
132 0 : SCSISPC(inq->version) >= 2)
133 0 : return (2);
134 :
135 : /* match on dell enclosures */
136 0 : if ((inq->device & SID_TYPE) == T_PROCESSOR &&
137 0 : SCSISPC(inq->version) == 3)
138 0 : return (3);
139 :
140 0 : return (0);
141 0 : }
142 :
143 : void
144 0 : ses_attach(struct device *parent, struct device *self, void *aux)
145 : {
146 0 : struct ses_softc *sc = (struct ses_softc *)self;
147 0 : struct scsi_attach_args *sa = aux;
148 0 : char vendor[33];
149 : struct ses_sensor *sensor;
150 : #if NBIO > 0
151 : struct ses_slot *slot;
152 : #endif
153 :
154 0 : sc->sc_link = sa->sa_sc_link;
155 0 : sa->sa_sc_link->device_softc = sc;
156 0 : rw_init(&sc->sc_lock, DEVNAME(sc));
157 :
158 0 : scsi_strvis(vendor, sc->sc_link->inqdata.vendor,
159 : sizeof(sc->sc_link->inqdata.vendor));
160 0 : if (strncasecmp(vendor, "Dell", sizeof(vendor)) == 0)
161 0 : sc->sc_enctype = SES_ENC_DELL;
162 : else
163 0 : sc->sc_enctype = SES_ENC_STD;
164 :
165 0 : printf("\n");
166 :
167 0 : if (ses_read_config(sc) != 0) {
168 0 : printf("%s: unable to read enclosure configuration\n",
169 : DEVNAME(sc));
170 0 : return;
171 : }
172 :
173 0 : if (!TAILQ_EMPTY(&sc->sc_sensors)) {
174 0 : sc->sc_sensortask = sensor_task_register(sc,
175 : ses_refresh_sensors, 10);
176 0 : if (sc->sc_sensortask == NULL) {
177 0 : printf("%s: unable to register update task\n",
178 : DEVNAME(sc));
179 0 : while (!TAILQ_EMPTY(&sc->sc_sensors)) {
180 : sensor = TAILQ_FIRST(&sc->sc_sensors);
181 0 : TAILQ_REMOVE(&sc->sc_sensors, sensor,
182 : se_entry);
183 0 : free(sensor, M_DEVBUF, sizeof(*sensor));
184 : }
185 : } else {
186 0 : TAILQ_FOREACH(sensor, &sc->sc_sensors, se_entry)
187 0 : sensor_attach(&sc->sc_sensordev,
188 0 : &sensor->se_sensor);
189 0 : sensordev_install(&sc->sc_sensordev);
190 : }
191 : }
192 :
193 : #if NBIO > 0
194 0 : if (!TAILQ_EMPTY(&sc->sc_slots) &&
195 0 : bio_register(self, ses_ioctl) != 0) {
196 0 : printf("%s: unable to register ioctl\n", DEVNAME(sc));
197 0 : while (!TAILQ_EMPTY(&sc->sc_slots)) {
198 : slot = TAILQ_FIRST(&sc->sc_slots);
199 0 : TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
200 0 : free(slot, M_DEVBUF, sizeof(*slot));
201 : }
202 : }
203 : #endif
204 :
205 0 : if (TAILQ_EMPTY(&sc->sc_sensors)
206 : #if NBIO > 0
207 0 : && TAILQ_EMPTY(&sc->sc_slots)
208 : #endif
209 : ) {
210 0 : dma_free(sc->sc_buf, sc->sc_buflen);
211 0 : sc->sc_buf = NULL;
212 0 : }
213 0 : }
214 :
215 : int
216 0 : ses_detach(struct device *self, int flags)
217 : {
218 0 : 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 0 : rw_enter_write(&sc->sc_lock);
225 :
226 : #if NBIO > 0
227 0 : if (!TAILQ_EMPTY(&sc->sc_slots)) {
228 0 : bio_unregister(self);
229 0 : while (!TAILQ_EMPTY(&sc->sc_slots)) {
230 : slot = TAILQ_FIRST(&sc->sc_slots);
231 0 : TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
232 0 : free(slot, M_DEVBUF, sizeof(*slot));
233 : }
234 : }
235 : #endif
236 :
237 0 : if (!TAILQ_EMPTY(&sc->sc_sensors)) {
238 0 : sensordev_deinstall(&sc->sc_sensordev);
239 0 : sensor_task_unregister(sc->sc_sensortask);
240 :
241 0 : while (!TAILQ_EMPTY(&sc->sc_sensors)) {
242 : sensor = TAILQ_FIRST(&sc->sc_sensors);
243 0 : sensor_detach(&sc->sc_sensordev, &sensor->se_sensor);
244 0 : TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry);
245 0 : free(sensor, M_DEVBUF, sizeof(*sensor));
246 : }
247 : }
248 :
249 0 : if (sc->sc_buf != NULL)
250 0 : dma_free(sc->sc_buf, sc->sc_buflen);
251 :
252 0 : rw_exit_write(&sc->sc_lock);
253 :
254 0 : return (0);
255 : }
256 :
257 : int
258 0 : 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
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 0 : buf = dma_alloc(SES_BUFLEN, PR_NOWAIT | PR_ZERO);
273 0 : if (buf == NULL)
274 0 : return (1);
275 :
276 0 : if (cold)
277 0 : flags |= SCSI_AUTOCONF;
278 0 : xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
279 0 : if (xs == NULL) {
280 : error = 1;
281 0 : goto done;
282 : }
283 0 : xs->cmdlen = sizeof(*cmd);
284 0 : xs->data = buf;
285 0 : xs->datalen = SES_BUFLEN;
286 0 : xs->retries = 2;
287 0 : xs->timeout = 3000;
288 :
289 0 : cmd = (struct ses_scsi_diag *)xs->cmd;
290 0 : cmd->opcode = RECEIVE_DIAGNOSTIC;
291 0 : cmd->flags |= SES_DIAG_PCV;
292 0 : cmd->pgcode = SES_PAGE_CONFIG;
293 0 : cmd->length = htobe16(SES_BUFLEN);
294 :
295 0 : error = scsi_xs_sync(xs);
296 0 : scsi_xs_put(xs);
297 :
298 0 : if (error) {
299 : error = 1;
300 0 : goto done;
301 : }
302 :
303 0 : cfg = (struct ses_config_hdr *)buf;
304 0 : if (cfg->pgcode != SES_PAGE_CONFIG || betoh16(cfg->length) >
305 : SES_BUFLEN) {
306 : error = 1;
307 0 : 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 0 : p = buf + SES_CFG_HDRLEN;
314 0 : for (i = 0; i <= cfg->n_subenc; i++) {
315 0 : 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 0 : ntypes += enc->n_types;
324 :
325 0 : p += SES_ENC_HDRLEN + enc->vendor_len;
326 : }
327 :
328 0 : tdlist = (struct ses_type_desc *)p; /* stash this for later */
329 :
330 0 : for (i = 0; i < ntypes; i++) {
331 0 : 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 0 : nelems += tdh->n_elem;
336 :
337 0 : 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 0 : sc->sc_buflen = SES_STAT_LEN(ntypes, nelems);
350 0 : sc->sc_buf = dma_alloc(sc->sc_buflen, PR_NOWAIT);
351 0 : if (sc->sc_buf == NULL) {
352 : error = 1;
353 0 : goto done;
354 : }
355 :
356 : /* get the status page and then use it to generate a list of sensors */
357 0 : if (ses_make_sensors(sc, tdlist, ntypes) != 0) {
358 0 : dma_free(sc->sc_buf, sc->sc_buflen);
359 : error = 1;
360 0 : goto done;
361 : }
362 :
363 : done:
364 0 : if (buf)
365 0 : dma_free(buf, SES_BUFLEN);
366 0 : return (error);
367 0 : }
368 :
369 : int
370 0 : 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 0 : if (cold)
377 0 : flags |= SCSI_AUTOCONF;
378 0 : xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
379 0 : if (xs == NULL)
380 0 : return (1);
381 0 : xs->cmdlen = sizeof(*cmd);
382 0 : xs->data = sc->sc_buf;
383 0 : xs->datalen = sc->sc_buflen;
384 0 : xs->retries = 2;
385 0 : xs->timeout = 3000;
386 :
387 0 : cmd = (struct ses_scsi_diag *)xs->cmd;
388 0 : cmd->opcode = RECEIVE_DIAGNOSTIC;
389 0 : cmd->flags |= SES_DIAG_PCV;
390 0 : cmd->pgcode = SES_PAGE_STATUS;
391 0 : cmd->length = htobe16(sc->sc_buflen);
392 :
393 0 : error = scsi_xs_sync(xs);
394 0 : scsi_xs_put(xs);
395 :
396 0 : if (error != 0)
397 0 : return (1);
398 :
399 0 : return (0);
400 0 : }
401 :
402 : int
403 0 : 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 : #if NBIO > 0
408 : struct ses_slot *slot;
409 : #endif
410 : enum sensor_type stype;
411 : char *fmt;
412 : int i, j;
413 :
414 0 : if (ses_read_status(sc) != 0)
415 0 : return (1);
416 :
417 0 : strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
418 : sizeof(sc->sc_sensordev.xname));
419 :
420 0 : TAILQ_INIT(&sc->sc_sensors);
421 : #if NBIO > 0
422 0 : TAILQ_INIT(&sc->sc_slots);
423 : #endif
424 :
425 0 : status = (struct ses_status *)(sc->sc_buf + SES_STAT_HDRLEN);
426 0 : 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 0 : 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 0 : if (SES_STAT_CODE(status->com) == SES_STAT_CODE_NOTINST)
441 : continue;
442 :
443 0 : switch (types[i].type) {
444 : #if NBIO > 0
445 : case SES_T_DEVICE:
446 0 : slot = malloc(sizeof(*slot), M_DEVBUF,
447 : M_NOWAIT | M_ZERO);
448 0 : if (slot == NULL)
449 : goto error;
450 :
451 0 : slot->sl_stat = status;
452 :
453 0 : TAILQ_INSERT_TAIL(&sc->sc_slots, slot,
454 : sl_entry);
455 :
456 0 : continue;
457 : #endif
458 :
459 : case SES_T_POWERSUPPLY:
460 : stype = SENSOR_INDICATOR;
461 : fmt = "PSU";
462 0 : break;
463 :
464 : case SES_T_COOLING:
465 : stype = SENSOR_PERCENT;
466 : fmt = "Fan";
467 0 : break;
468 :
469 : case SES_T_TEMP:
470 : stype = SENSOR_TEMP;
471 : fmt = "";
472 0 : break;
473 :
474 : default:
475 : continue;
476 : }
477 :
478 0 : sensor = malloc(sizeof(*sensor), M_DEVBUF,
479 : M_NOWAIT | M_ZERO);
480 0 : if (sensor == NULL)
481 : goto error;
482 :
483 0 : sensor->se_type = types[i].type;
484 0 : sensor->se_stat = status;
485 0 : sensor->se_sensor.type = stype;
486 0 : strlcpy(sensor->se_sensor.desc, fmt,
487 : sizeof(sensor->se_sensor.desc));
488 :
489 0 : TAILQ_INSERT_TAIL(&sc->sc_sensors, sensor, se_entry);
490 0 : }
491 :
492 : /* move to the overall status element of the next type */
493 : status++;
494 : }
495 :
496 0 : return (0);
497 : error:
498 : #if NBIO > 0
499 0 : while (!TAILQ_EMPTY(&sc->sc_slots)) {
500 : slot = TAILQ_FIRST(&sc->sc_slots);
501 0 : TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
502 0 : free(slot, M_DEVBUF, sizeof(*slot));
503 : }
504 : #endif
505 0 : while (!TAILQ_EMPTY(&sc->sc_sensors)) {
506 : sensor = TAILQ_FIRST(&sc->sc_sensors);
507 0 : TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry);
508 0 : free(sensor, M_DEVBUF, sizeof(*sensor));
509 : }
510 0 : return (1);
511 0 : }
512 :
513 : void
514 0 : ses_refresh_sensors(void *arg)
515 : {
516 0 : struct ses_softc *sc = (struct ses_softc *)arg;
517 : struct ses_sensor *sensor;
518 : int ret = 0;
519 :
520 0 : rw_enter_write(&sc->sc_lock);
521 :
522 0 : if (ses_read_status(sc) != 0) {
523 0 : rw_exit_write(&sc->sc_lock);
524 0 : return;
525 : }
526 :
527 0 : 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 0 : switch (SES_STAT_CODE(sensor->se_stat->com)) {
534 : case SES_STAT_CODE_OK:
535 0 : sensor->se_sensor.status = SENSOR_S_OK;
536 0 : break;
537 :
538 : case SES_STAT_CODE_CRIT:
539 : case SES_STAT_CODE_UNREC:
540 0 : sensor->se_sensor.status = SENSOR_S_CRIT;
541 0 : break;
542 :
543 : case SES_STAT_CODE_NONCRIT:
544 0 : sensor->se_sensor.status = SENSOR_S_WARN;
545 0 : break;
546 :
547 : case SES_STAT_CODE_NOTINST:
548 : case SES_STAT_CODE_UNKNOWN:
549 : case SES_STAT_CODE_NOTAVAIL:
550 0 : sensor->se_sensor.status = SENSOR_S_UNKNOWN;
551 0 : break;
552 : }
553 :
554 0 : switch (sensor->se_type) {
555 : case SES_T_POWERSUPPLY:
556 0 : ses_psu2sensor(sc, sensor);
557 0 : break;
558 :
559 : case SES_T_COOLING:
560 0 : ses_cool2sensor(sc, sensor);
561 0 : break;
562 :
563 : case SES_T_TEMP:
564 0 : ses_temp2sensor(sc, sensor);
565 0 : break;
566 :
567 : default:
568 : ret = 1;
569 0 : break;
570 : }
571 : }
572 :
573 0 : rw_exit_write(&sc->sc_lock);
574 :
575 0 : if (ret)
576 0 : printf("%s: error in sensor data\n", DEVNAME(sc));
577 0 : }
578 :
579 : #if NBIO > 0
580 : int
581 0 : ses_ioctl(struct device *dev, u_long cmd, caddr_t addr)
582 : {
583 0 : struct ses_softc *sc = (struct ses_softc *)dev;
584 : int error = 0;
585 :
586 0 : switch (cmd) {
587 : case BIOCBLINK:
588 0 : error = ses_bio_blink(sc, (struct bioc_blink *)addr);
589 0 : break;
590 :
591 : default:
592 : error = EINVAL;
593 0 : break;
594 : }
595 :
596 0 : return (error);
597 : }
598 :
599 : int
600 0 : 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 0 : if (cold)
607 0 : flags |= SCSI_AUTOCONF;
608 :
609 0 : xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
610 0 : if (xs == NULL)
611 0 : return (1);
612 0 : xs->cmdlen = sizeof(*cmd);
613 0 : xs->data = sc->sc_buf;
614 0 : xs->datalen = sc->sc_buflen;
615 0 : xs->retries = 2;
616 0 : xs->timeout = 3000;
617 :
618 0 : cmd = (struct ses_scsi_diag *)xs->cmd;
619 0 : cmd->opcode = SEND_DIAGNOSTIC;
620 0 : cmd->flags |= SES_DIAG_PF;
621 0 : cmd->length = htobe16(sc->sc_buflen);
622 :
623 0 : error = scsi_xs_sync(xs);
624 0 : scsi_xs_put(xs);
625 :
626 0 : if (error != 0)
627 0 : return (1);
628 :
629 0 : return (0);
630 0 : }
631 :
632 : int
633 0 : ses_bio_blink(struct ses_softc *sc, struct bioc_blink *blink)
634 : {
635 : struct ses_slot *slot;
636 :
637 0 : rw_enter_write(&sc->sc_lock);
638 :
639 0 : if (ses_read_status(sc) != 0) {
640 0 : rw_exit_write(&sc->sc_lock);
641 0 : return (EIO);
642 : }
643 :
644 0 : TAILQ_FOREACH(slot, &sc->sc_slots, sl_entry) {
645 0 : if (slot->sl_stat->f1 == blink->bb_target)
646 : break;
647 : }
648 :
649 0 : if (slot == NULL) {
650 0 : rw_exit_write(&sc->sc_lock);
651 0 : 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 0 : slot->sl_stat->com = SES_STAT_SELECT;
659 0 : slot->sl_stat->f2 &= SES_C_DEV_F2MASK;
660 0 : slot->sl_stat->f3 &= SES_C_DEV_F3MASK;
661 :
662 0 : switch (blink->bb_status) {
663 : case BIOC_SBUNBLINK:
664 0 : slot->sl_stat->f2 &= ~SES_C_DEV_IDENT;
665 0 : break;
666 :
667 : case BIOC_SBBLINK:
668 0 : slot->sl_stat->f2 |= SES_C_DEV_IDENT;
669 0 : break;
670 :
671 : default:
672 0 : rw_exit_write(&sc->sc_lock);
673 0 : 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 0 : if (ses_write_config(sc) != 0) {
681 : rw_exit_write(&sc->sc_lock);
682 0 : return (EIO);
683 : }
684 :
685 : rw_exit_write(&sc->sc_lock);
686 :
687 0 : return (0);
688 0 : }
689 : #endif
690 :
691 : void
692 0 : ses_psu2sensor(struct ses_softc *sc, struct ses_sensor *s)
693 : {
694 0 : s->se_sensor.value = SES_S_PSU_OFF(s->se_stat) ? 0 : 1;
695 0 : }
696 :
697 : void
698 0 : ses_cool2sensor(struct ses_softc *sc, struct ses_sensor *s)
699 : {
700 0 : switch (sc->sc_enctype) {
701 : case SES_ENC_STD:
702 0 : switch (SES_S_COOL_CODE(s->se_stat)) {
703 : case SES_S_COOL_C_STOPPED:
704 0 : s->se_sensor.value = 0;
705 0 : break;
706 : case SES_S_COOL_C_LOW1:
707 : case SES_S_COOL_C_LOW2:
708 : case SES_S_COOL_C_LOW3:
709 0 : s->se_sensor.value = 33333;
710 0 : break;
711 : case SES_S_COOL_C_INTER:
712 : case SES_S_COOL_C_HI3:
713 : case SES_S_COOL_C_HI2:
714 0 : s->se_sensor.value = 66666;
715 0 : break;
716 : case SES_S_COOL_C_HI1:
717 0 : s->se_sensor.value = 100000;
718 0 : break;
719 : }
720 : break;
721 :
722 : /* Dell only use the first three codes to represent speed */
723 : case SES_ENC_DELL:
724 0 : switch (SES_S_COOL_CODE(s->se_stat)) {
725 : case SES_S_COOL_C_STOPPED:
726 0 : s->se_sensor.value = 0;
727 0 : break;
728 : case SES_S_COOL_C_LOW1:
729 0 : s->se_sensor.value = 33333;
730 0 : break;
731 : case SES_S_COOL_C_LOW2:
732 0 : s->se_sensor.value = 66666;
733 0 : 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 0 : s->se_sensor.value = 100000;
740 0 : break;
741 : }
742 : break;
743 : }
744 0 : }
745 :
746 : void
747 0 : ses_temp2sensor(struct ses_softc *sc, struct ses_sensor *s)
748 : {
749 0 : s->se_sensor.value = (int64_t)SES_S_TEMP(s->se_stat);
750 0 : s->se_sensor.value += SES_S_TEMP_OFFSET;
751 0 : s->se_sensor.value *= 1000000; /* convert to micro (mu) degrees */
752 0 : s->se_sensor.value += 273150000; /* convert to kelvin */
753 0 : }
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
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 */
|