root/scsi/ses.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ses_match
  2. ses_attach
  3. ses_detach
  4. ses_read_config
  5. ses_read_status
  6. ses_make_sensors
  7. ses_refresh_sensors
  8. ses_ioctl
  9. ses_write_config
  10. ses_bio_blink
  11. ses_psu2sensor
  12. ses_cool2sensor
  13. ses_temp2sensor
  14. ses_dump_enc_desc
  15. ses_dump_enc_string

    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 */

/* [<][>][^][v][top][bottom][index][help] */