LCOV - code coverage report
Current view: top level - scsi - ses.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 285 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13