The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scsi/ses.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: ses.c,v 1.64 2021/10/24 16:57:30 mpi Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include "bio.h"
   20 
   21 #include <sys/param.h>
   22 #include <sys/systm.h>
   23 #include <sys/device.h>
   24 #include <sys/scsiio.h>
   25 #include <sys/malloc.h>
   26 #include <sys/pool.h>
   27 #include <sys/rwlock.h>
   28 #include <sys/queue.h>
   29 #include <sys/sensors.h>
   30 
   31 #if NBIO > 0
   32 #include <dev/biovar.h>
   33 #endif /* NBIO > 0 */
   34 
   35 #include <scsi/scsi_all.h>
   36 #include <scsi/scsiconf.h>
   37 
   38 #include <scsi/ses.h>
   39 
   40 #ifdef SES_DEBUG
   41 #define DPRINTF(x...)           do { if (sesdebug) printf(x); } while (0)
   42 #define DPRINTFN(n, x...)       do { if (sesdebug > (n)) printf(x); } while (0)
   43 int     sesdebug = 2;
   44 #else
   45 #define DPRINTF(x...)           /* x */
   46 #define DPRINTFN(n,x...)        /* n: x */
   47 #endif /* SES_DEBUG */
   48 
   49 int     ses_match(struct device *, void *, void *);
   50 void    ses_attach(struct device *, struct device *, void *);
   51 int     ses_detach(struct device *, int);
   52 
   53 struct ses_sensor {
   54         struct ksensor           se_sensor;
   55         u_int8_t                 se_type;
   56         struct ses_status       *se_stat;
   57 
   58         TAILQ_ENTRY(ses_sensor) se_entry;
   59 };
   60 
   61 #if NBIO > 0
   62 struct ses_slot {
   63         struct ses_status       *sl_stat;
   64 
   65         TAILQ_ENTRY(ses_slot)    sl_entry;
   66 };
   67 #endif /* NBIO > 0 */
   68 
   69 struct ses_softc {
   70         struct device            sc_dev;
   71         struct scsi_link        *sc_link;
   72         struct rwlock            sc_lock;
   73 
   74         enum {
   75                 SES_ENC_STD,
   76                 SES_ENC_DELL
   77         }                        sc_enctype;
   78 
   79         u_char                  *sc_buf;
   80         ssize_t                  sc_buflen;
   81 
   82 #if NBIO > 0
   83         TAILQ_HEAD(, ses_slot)   sc_slots;
   84 #endif /* NBIO > 0 */
   85         TAILQ_HEAD(, ses_sensor) sc_sensors;
   86         struct ksensordev        sc_sensordev;
   87         struct sensor_task      *sc_sensortask;
   88 };
   89 
   90 const struct cfattach ses_ca = {
   91         sizeof(struct ses_softc), ses_match, ses_attach, ses_detach
   92 };
   93 
   94 struct cfdriver ses_cd = {
   95         NULL, "ses", DV_DULL
   96 };
   97 
   98 #define DEVNAME(s)      ((s)->sc_dev.dv_xname)
   99 
  100 #define SES_BUFLEN      2048 /* XXX Is this enough? */
  101 
  102 int     ses_read_config(struct ses_softc *);
  103 int     ses_read_status(struct ses_softc *);
  104 int     ses_make_sensors(struct ses_softc *, struct ses_type_desc *, int);
  105 void    ses_refresh_sensors(void *);
  106 
  107 #if NBIO > 0
  108 int     ses_ioctl(struct device *, u_long, caddr_t);
  109 int     ses_write_config(struct ses_softc *);
  110 int     ses_bio_blink(struct ses_softc *, struct bioc_blink *);
  111 #endif /* NBIO > 0 */
  112 
  113 void    ses_psu2sensor(struct ses_softc *, struct ses_sensor *);
  114 void    ses_cool2sensor(struct ses_softc *, struct ses_sensor *);
  115 void    ses_temp2sensor(struct ses_softc *, struct ses_sensor *);
  116 
  117 #ifdef SES_DEBUG
  118 void     ses_dump_enc_desc(struct ses_enc_desc *);
  119 char    *ses_dump_enc_string(u_char *, ssize_t);
  120 #endif /* SES_DEBUG */
  121 
  122 int
  123 ses_match(struct device *parent, void *match, void *aux)
  124 {
  125         struct scsi_attach_args         *sa = aux;
  126         struct scsi_inquiry_data        *inq = &sa->sa_sc_link->inqdata;
  127 
  128         if ((inq->device & SID_TYPE) == T_ENCLOSURE &&
  129             SID_ANSII_REV(inq) >= SCSI_REV_2)
  130                 return 2;
  131 
  132         /* Match on Dell enclosures. */
  133         if ((inq->device & SID_TYPE) == T_PROCESSOR &&
  134             SID_ANSII_REV(inq) == SCSI_REV_SPC)
  135                 return 3;
  136 
  137         return 0;
  138 }
  139 
  140 void
  141 ses_attach(struct device *parent, struct device *self, void *aux)
  142 {
  143         char                             vendor[33];
  144         struct ses_softc                *sc = (struct ses_softc *)self;
  145         struct scsi_attach_args         *sa = aux;
  146         struct ses_sensor               *sensor;
  147 #if NBIO > 0
  148         struct ses_slot                 *slot;
  149 #endif /* NBIO > 0 */
  150 
  151         sc->sc_link = sa->sa_sc_link;
  152         sa->sa_sc_link->device_softc = sc;
  153         rw_init(&sc->sc_lock, DEVNAME(sc));
  154 
  155         scsi_strvis(vendor, sc->sc_link->inqdata.vendor,
  156             sizeof(sc->sc_link->inqdata.vendor));
  157         if (strncasecmp(vendor, "Dell", sizeof(vendor)) == 0)
  158                 sc->sc_enctype = SES_ENC_DELL;
  159         else
  160                 sc->sc_enctype = SES_ENC_STD;
  161 
  162         printf("\n");
  163 
  164         if (ses_read_config(sc) != 0) {
  165                 printf("%s: unable to read enclosure configuration\n",
  166                     DEVNAME(sc));
  167                 return;
  168         }
  169 
  170         if (!TAILQ_EMPTY(&sc->sc_sensors)) {
  171                 sc->sc_sensortask = sensor_task_register(sc,
  172                     ses_refresh_sensors, 10);
  173                 if (sc->sc_sensortask == NULL) {
  174                         printf("%s: unable to register update task\n",
  175                             DEVNAME(sc));
  176                         while (!TAILQ_EMPTY(&sc->sc_sensors)) {
  177                                 sensor = TAILQ_FIRST(&sc->sc_sensors);
  178                                 TAILQ_REMOVE(&sc->sc_sensors, sensor,
  179                                     se_entry);
  180                                 free(sensor, M_DEVBUF, sizeof(*sensor));
  181                         }
  182                 } else {
  183                         TAILQ_FOREACH(sensor, &sc->sc_sensors, se_entry)
  184                                 sensor_attach(&sc->sc_sensordev,
  185                                     &sensor->se_sensor);
  186                         sensordev_install(&sc->sc_sensordev);
  187                 }
  188         }
  189 
  190 #if NBIO > 0
  191         if (!TAILQ_EMPTY(&sc->sc_slots) &&
  192             bio_register(self, ses_ioctl) != 0) {
  193                 printf("%s: unable to register ioctl\n", DEVNAME(sc));
  194                 while (!TAILQ_EMPTY(&sc->sc_slots)) {
  195                         slot = TAILQ_FIRST(&sc->sc_slots);
  196                         TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
  197                         free(slot, M_DEVBUF, sizeof(*slot));
  198                 }
  199         }
  200 #endif /* NBIO > 0 */
  201 
  202         if (TAILQ_EMPTY(&sc->sc_sensors)
  203 #if NBIO > 0
  204             && TAILQ_EMPTY(&sc->sc_slots)
  205 #endif /* NBIO > 0 */
  206             ) {
  207                 dma_free(sc->sc_buf, sc->sc_buflen);
  208                 sc->sc_buf = NULL;
  209         }
  210 }
  211 
  212 int
  213 ses_detach(struct device *self, int flags)
  214 {
  215         struct ses_softc                *sc = (struct ses_softc *)self;
  216         struct ses_sensor               *sensor;
  217 #if NBIO > 0
  218         struct ses_slot                 *slot;
  219 #endif /* NBIO > 0 */
  220 
  221         rw_enter_write(&sc->sc_lock);
  222 
  223 #if NBIO > 0
  224         if (!TAILQ_EMPTY(&sc->sc_slots)) {
  225                 bio_unregister(self);
  226                 while (!TAILQ_EMPTY(&sc->sc_slots)) {
  227                         slot = TAILQ_FIRST(&sc->sc_slots);
  228                         TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
  229                         free(slot, M_DEVBUF, sizeof(*slot));
  230                 }
  231         }
  232 #endif /* NBIO > 0 */
  233 
  234         if (!TAILQ_EMPTY(&sc->sc_sensors)) {
  235                 sensordev_deinstall(&sc->sc_sensordev);
  236                 sensor_task_unregister(sc->sc_sensortask);
  237 
  238                 while (!TAILQ_EMPTY(&sc->sc_sensors)) {
  239                         sensor = TAILQ_FIRST(&sc->sc_sensors);
  240                         sensor_detach(&sc->sc_sensordev, &sensor->se_sensor);
  241                         TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry);
  242                         free(sensor, M_DEVBUF, sizeof(*sensor));
  243                 }
  244         }
  245 
  246         if (sc->sc_buf != NULL)
  247                 dma_free(sc->sc_buf, sc->sc_buflen);
  248 
  249         rw_exit_write(&sc->sc_lock);
  250 
  251         return 0;
  252 }
  253 
  254 int
  255 ses_read_config(struct ses_softc *sc)
  256 {
  257         struct ses_scsi_diag            *cmd;
  258         struct ses_config_hdr           *cfg;
  259         struct ses_type_desc            *tdh, *tdlist;
  260 #ifdef SES_DEBUG
  261         struct ses_enc_desc             *desc;
  262 #endif /* SES_DEBUG */
  263         struct ses_enc_hdr              *enc;
  264         struct scsi_xfer                *xs;
  265         u_char                          *buf, *p;
  266         int                              error = 0, i;
  267         int                              flags = 0, ntypes = 0, nelems = 0;
  268 
  269         buf = dma_alloc(SES_BUFLEN, PR_NOWAIT | PR_ZERO);
  270         if (buf == NULL)
  271                 return 1;
  272 
  273         if (cold)
  274                 SET(flags, SCSI_AUTOCONF);
  275         xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
  276         if (xs == NULL) {
  277                 error = 1;
  278                 goto done;
  279         }
  280         xs->cmdlen = sizeof(*cmd);
  281         xs->data = buf;
  282         xs->datalen = SES_BUFLEN;
  283         xs->retries = 2;
  284         xs->timeout = 3000;
  285 
  286         cmd = (struct ses_scsi_diag *)&xs->cmd;
  287         cmd->opcode = RECEIVE_DIAGNOSTIC;
  288         SET(cmd->flags, SES_DIAG_PCV);
  289         cmd->pgcode = SES_PAGE_CONFIG;
  290         cmd->length = htobe16(SES_BUFLEN);
  291 
  292         error = scsi_xs_sync(xs);
  293         scsi_xs_put(xs);
  294 
  295         if (error) {
  296                 error = 1;
  297                 goto done;
  298         }
  299 
  300         cfg = (struct ses_config_hdr *)buf;
  301         if (cfg->pgcode != SES_PAGE_CONFIG || betoh16(cfg->length) >
  302             SES_BUFLEN) {
  303                 error = 1;
  304                 goto done;
  305         }
  306 
  307         DPRINTF("%s: config: n_subenc: %d length: %d\n", DEVNAME(sc),
  308             cfg->n_subenc, betoh16(cfg->length));
  309 
  310         p = buf + SES_CFG_HDRLEN;
  311         for (i = 0; i <= cfg->n_subenc; i++) {
  312                 enc = (struct ses_enc_hdr *)p;
  313 #ifdef SES_DEBUG
  314                 DPRINTF("%s: enclosure %d enc_id: 0x%02x n_types: %d\n",
  315                     DEVNAME(sc), i, enc->enc_id, enc->n_types);
  316                 desc = (struct ses_enc_desc *)(p + SES_ENC_HDRLEN);
  317                 ses_dump_enc_desc(desc);
  318 #endif /* SES_DEBUG */
  319 
  320                 ntypes += enc->n_types;
  321 
  322                 p += SES_ENC_HDRLEN + enc->vendor_len;
  323         }
  324 
  325         tdlist = (struct ses_type_desc *)p; /* Stash this for later. */
  326 
  327         for (i = 0; i < ntypes; i++) {
  328                 tdh = (struct ses_type_desc *)p;
  329                 DPRINTF("%s: td %d subenc_id: %d type 0x%02x n_elem: %d\n",
  330                     DEVNAME(sc), i, tdh->subenc_id, tdh->type, tdh->n_elem);
  331 
  332                 nelems += tdh->n_elem;
  333 
  334                 p += SES_TYPE_DESCLEN;
  335         }
  336 
  337 #ifdef SES_DEBUG
  338         for (i = 0; i < ntypes; i++) {
  339                 DPRINTF("%s: td %d '%s'\n", DEVNAME(sc), i,
  340                     ses_dump_enc_string(p, tdlist[i].desc_len));
  341 
  342                 p += tdlist[i].desc_len;
  343         }
  344 #endif /* SES_DEBUG */
  345 
  346         sc->sc_buflen = SES_STAT_LEN(ntypes, nelems);
  347         sc->sc_buf = dma_alloc(sc->sc_buflen, PR_NOWAIT);
  348         if (sc->sc_buf == NULL) {
  349                 error = 1;
  350                 goto done;
  351         }
  352 
  353         /* Get the status page and then use it to generate a list of sensors. */
  354         if (ses_make_sensors(sc, tdlist, ntypes) != 0) {
  355                 dma_free(sc->sc_buf, sc->sc_buflen);
  356                 error = 1;
  357                 goto done;
  358         }
  359 
  360 done:
  361         if (buf)
  362                 dma_free(buf, SES_BUFLEN);
  363         return error;
  364 }
  365 
  366 int
  367 ses_read_status(struct ses_softc *sc)
  368 {
  369         struct ses_scsi_diag            *cmd;
  370         struct scsi_xfer                *xs;
  371         int                              error, flags = 0;
  372 
  373         if (cold)
  374                 SET(flags, SCSI_AUTOCONF);
  375         xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT);
  376         if (xs == NULL)
  377                 return 1;
  378         xs->cmdlen = sizeof(*cmd);
  379         xs->data = sc->sc_buf;
  380         xs->datalen = sc->sc_buflen;
  381         xs->retries = 2;
  382         xs->timeout = 3000;
  383 
  384         cmd = (struct ses_scsi_diag *)&xs->cmd;
  385         cmd->opcode = RECEIVE_DIAGNOSTIC;
  386         SET(cmd->flags, SES_DIAG_PCV);
  387         cmd->pgcode = SES_PAGE_STATUS;
  388         cmd->length = htobe16(sc->sc_buflen);
  389 
  390         error = scsi_xs_sync(xs);
  391         scsi_xs_put(xs);
  392 
  393         if (error != 0)
  394                 return 1;
  395 
  396         return 0;
  397 }
  398 
  399 int
  400 ses_make_sensors(struct ses_softc *sc, struct ses_type_desc *types, int ntypes)
  401 {
  402         struct ses_status               *status;
  403         struct ses_sensor               *sensor;
  404         char                            *fmt;
  405 #if NBIO > 0
  406         struct ses_slot                 *slot;
  407 #endif /* NBIO > 0 */
  408         enum sensor_type                 stype;
  409         int                              i, j;
  410 
  411         if (ses_read_status(sc) != 0)
  412                 return 1;
  413 
  414         strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
  415             sizeof(sc->sc_sensordev.xname));
  416 
  417         TAILQ_INIT(&sc->sc_sensors);
  418 #if NBIO > 0
  419         TAILQ_INIT(&sc->sc_slots);
  420 #endif /* NBIO > 0 */
  421 
  422         status = (struct ses_status *)(sc->sc_buf + SES_STAT_HDRLEN);
  423         for (i = 0; i < ntypes; i++) {
  424                 /* Ignore the overall status element for this type. */
  425                 DPRINTFN(1, "%s: %3d:-   0x%02x 0x%02x%02x%02x type: 0x%02x\n",
  426                      DEVNAME(sc), i, status->com, status->f1, status->f2,
  427                     status->f3, types[i].type);
  428 
  429                 for (j = 0; j < types[i].n_elem; j++) {
  430                         /* Move to the current status element. */
  431                         status++;
  432 
  433                         DPRINTFN(1, "%s: %3d:%-3d 0x%02x 0x%02x%02x%02x\n",
  434                             DEVNAME(sc), i, j, status->com, status->f1,
  435                             status->f2, status->f3);
  436 
  437                         if (SES_STAT_CODE(status->com) == SES_STAT_CODE_NOTINST)
  438                                 continue;
  439 
  440                         switch (types[i].type) {
  441 #if NBIO > 0
  442                         case SES_T_DEVICE:
  443                                 slot = malloc(sizeof(*slot), M_DEVBUF,
  444                                     M_NOWAIT | M_ZERO);
  445                                 if (slot == NULL)
  446                                         goto error;
  447 
  448                                 slot->sl_stat = status;
  449 
  450                                 TAILQ_INSERT_TAIL(&sc->sc_slots, slot,
  451                                     sl_entry);
  452 
  453                                 continue;
  454 #endif /* NBIO > 0 */
  455 
  456                         case SES_T_POWERSUPPLY:
  457                                 stype = SENSOR_INDICATOR;
  458                                 fmt = "PSU";
  459                                 break;
  460 
  461                         case SES_T_COOLING:
  462                                 stype = SENSOR_PERCENT;
  463                                 fmt = "Fan";
  464                                 break;
  465 
  466                         case SES_T_TEMP:
  467                                 stype = SENSOR_TEMP;
  468                                 fmt = "";
  469                                 break;
  470 
  471                         default:
  472                                 continue;
  473                         }
  474 
  475                         sensor = malloc(sizeof(*sensor), M_DEVBUF,
  476                             M_NOWAIT | M_ZERO);
  477                         if (sensor == NULL)
  478                                 goto error;
  479 
  480                         sensor->se_type = types[i].type;
  481                         sensor->se_stat = status;
  482                         sensor->se_sensor.type = stype;
  483                         strlcpy(sensor->se_sensor.desc, fmt,
  484                             sizeof(sensor->se_sensor.desc));
  485 
  486                         TAILQ_INSERT_TAIL(&sc->sc_sensors, sensor, se_entry);
  487                 }
  488 
  489                 /* Move to the overall status element of the next type. */
  490                 status++;
  491         }
  492 
  493         return 0;
  494 error:
  495 #if NBIO > 0
  496         while (!TAILQ_EMPTY(&sc->sc_slots)) {
  497                 slot = TAILQ_FIRST(&sc->sc_slots);
  498                 TAILQ_REMOVE(&sc->sc_slots, slot, sl_entry);
  499                 free(slot, M_DEVBUF, sizeof(*slot));
  500         }
  501 #endif /* NBIO > 0 */
  502         while (!TAILQ_EMPTY(&sc->sc_sensors)) {
  503                 sensor = TAILQ_FIRST(&sc->sc_sensors);
  504                 TAILQ_REMOVE(&sc->sc_sensors, sensor, se_entry);
  505                 free(sensor, M_DEVBUF, sizeof(*sensor));
  506         }
  507         return 1;
  508 }
  509 
  510 void
  511 ses_refresh_sensors(void *arg)
  512 {
  513         struct ses_softc                *sc = (struct ses_softc *)arg;
  514         struct ses_sensor               *sensor;
  515         int                              ret = 0;
  516 
  517         rw_enter_write(&sc->sc_lock);
  518 
  519         if (ses_read_status(sc) != 0) {
  520                 rw_exit_write(&sc->sc_lock);
  521                 return;
  522         }
  523 
  524         TAILQ_FOREACH(sensor, &sc->sc_sensors, se_entry) {
  525                 DPRINTFN(10, "%s: %s 0x%02x 0x%02x%02x%02x\n", DEVNAME(sc),
  526                     sensor->se_sensor.desc, sensor->se_stat->com,
  527                     sensor->se_stat->f1, sensor->se_stat->f2,
  528                     sensor->se_stat->f3);
  529 
  530                 switch (SES_STAT_CODE(sensor->se_stat->com)) {
  531                 case SES_STAT_CODE_OK:
  532                         sensor->se_sensor.status = SENSOR_S_OK;
  533                         break;
  534 
  535                 case SES_STAT_CODE_CRIT:
  536                 case SES_STAT_CODE_UNREC:
  537                         sensor->se_sensor.status = SENSOR_S_CRIT;
  538                         break;
  539 
  540                 case SES_STAT_CODE_NONCRIT:
  541                         sensor->se_sensor.status = SENSOR_S_WARN;
  542                         break;
  543 
  544                 case SES_STAT_CODE_NOTINST:
  545                 case SES_STAT_CODE_UNKNOWN:
  546                 case SES_STAT_CODE_NOTAVAIL:
  547                         sensor->se_sensor.status = SENSOR_S_UNKNOWN;
  548                         break;
  549                 }
  550 
  551                 switch (sensor->se_type) {
  552                 case SES_T_POWERSUPPLY:
  553                         ses_psu2sensor(sc, sensor);
  554                         break;
  555 
  556                 case SES_T_COOLING:
  557                         ses_cool2sensor(sc, sensor);
  558                         break;
  559 
  560                 case SES_T_TEMP:
  561                         ses_temp2sensor(sc, sensor);
  562                         break;
  563 
  564                 default:
  565                         ret = 1;
  566                         break;
  567                 }
  568         }
  569 
  570         rw_exit_write(&sc->sc_lock);
  571 
  572         if (ret)
  573                 printf("%s: error in sensor data\n", DEVNAME(sc));
  574 }
  575 
  576 #if NBIO > 0
  577 int
  578 ses_ioctl(struct device *dev, u_long cmd, caddr_t addr)
  579 {
  580         struct ses_softc                *sc = (struct ses_softc *)dev;
  581         int                              error = 0;
  582 
  583         switch (cmd) {
  584         case BIOCBLINK:
  585                 error = ses_bio_blink(sc, (struct bioc_blink *)addr);
  586                 break;
  587 
  588         default:
  589                 error = EINVAL;
  590                 break;
  591         }
  592 
  593         return error;
  594 }
  595 
  596 int
  597 ses_write_config(struct ses_softc *sc)
  598 {
  599         struct ses_scsi_diag            *cmd;
  600         struct scsi_xfer                *xs;
  601         int                              error, flags = 0;
  602 
  603         if (cold)
  604                 SET(flags, SCSI_AUTOCONF);
  605 
  606         xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT);
  607         if (xs == NULL)
  608                 return 1;
  609         xs->cmdlen = sizeof(*cmd);
  610         xs->data = sc->sc_buf;
  611         xs->datalen = sc->sc_buflen;
  612         xs->retries = 2;
  613         xs->timeout = 3000;
  614 
  615         cmd = (struct ses_scsi_diag *)&xs->cmd;
  616         cmd->opcode = SEND_DIAGNOSTIC;
  617         SET(cmd->flags, SES_DIAG_PF);
  618         cmd->length = htobe16(sc->sc_buflen);
  619 
  620         error = scsi_xs_sync(xs);
  621         scsi_xs_put(xs);
  622 
  623         if (error != 0)
  624                 return 1;
  625 
  626         return 0;
  627 }
  628 
  629 int
  630 ses_bio_blink(struct ses_softc *sc, struct bioc_blink *blink)
  631 {
  632         struct ses_slot                 *slot;
  633 
  634         rw_enter_write(&sc->sc_lock);
  635 
  636         if (ses_read_status(sc) != 0) {
  637                 rw_exit_write(&sc->sc_lock);
  638                 return EIO;
  639         }
  640 
  641         TAILQ_FOREACH(slot, &sc->sc_slots, sl_entry) {
  642                 if (slot->sl_stat->f1 == blink->bb_target)
  643                         break;
  644         }
  645 
  646         if (slot == NULL) {
  647                 rw_exit_write(&sc->sc_lock);
  648                 return EINVAL;
  649         }
  650 
  651         DPRINTFN(3, "%s: 0x%02x 0x%02x 0x%02x 0x%02x\n", DEVNAME(sc),
  652             slot->sl_stat->com, slot->sl_stat->f1, slot->sl_stat->f2,
  653             slot->sl_stat->f3);
  654 
  655         slot->sl_stat->com = SES_STAT_SELECT;
  656         slot->sl_stat->f2 &= SES_C_DEV_F2MASK;
  657         slot->sl_stat->f3 &= SES_C_DEV_F3MASK;
  658 
  659         switch (blink->bb_status) {
  660         case BIOC_SBUNBLINK:
  661                 slot->sl_stat->f2 &= ~SES_C_DEV_IDENT;
  662                 break;
  663 
  664         case BIOC_SBBLINK:
  665                 SET(slot->sl_stat->f2, SES_C_DEV_IDENT);
  666                 break;
  667 
  668         default:
  669                 rw_exit_write(&sc->sc_lock);
  670                 return EINVAL;
  671         }
  672 
  673         DPRINTFN(3, "%s: 0x%02x 0x%02x 0x%02x 0x%02x\n", DEVNAME(sc),
  674             slot->sl_stat->com, slot->sl_stat->f1, slot->sl_stat->f2,
  675             slot->sl_stat->f3);
  676 
  677         if (ses_write_config(sc) != 0) {
  678                 rw_exit_write(&sc->sc_lock);
  679                 return EIO;
  680         }
  681 
  682         rw_exit_write(&sc->sc_lock);
  683 
  684         return 0;
  685 }
  686 #endif /* NBIO > 0 */
  687 
  688 void
  689 ses_psu2sensor(struct ses_softc *sc, struct ses_sensor *s)
  690 {
  691         s->se_sensor.value = SES_S_PSU_OFF(s->se_stat) ? 0 : 1;
  692 }
  693 
  694 void
  695 ses_cool2sensor(struct ses_softc *sc, struct ses_sensor *s)
  696 {
  697         switch (sc->sc_enctype) {
  698         case SES_ENC_STD:
  699                 switch (SES_S_COOL_CODE(s->se_stat)) {
  700                 case SES_S_COOL_C_STOPPED:
  701                         s->se_sensor.value = 0;
  702                         break;
  703                 case SES_S_COOL_C_LOW1:
  704                 case SES_S_COOL_C_LOW2:
  705                 case SES_S_COOL_C_LOW3:
  706                         s->se_sensor.value = 33333;
  707                         break;
  708                 case SES_S_COOL_C_INTER:
  709                 case SES_S_COOL_C_HI3:
  710                 case SES_S_COOL_C_HI2:
  711                         s->se_sensor.value = 66666;
  712                         break;
  713                 case SES_S_COOL_C_HI1:
  714                         s->se_sensor.value = 100000;
  715                         break;
  716                 }
  717                 break;
  718 
  719         /* Dell only use the first three codes to represent speed */
  720         case SES_ENC_DELL:
  721                 switch (SES_S_COOL_CODE(s->se_stat)) {
  722                 case SES_S_COOL_C_STOPPED:
  723                         s->se_sensor.value = 0;
  724                         break;
  725                 case SES_S_COOL_C_LOW1:
  726                         s->se_sensor.value = 33333;
  727                         break;
  728                 case SES_S_COOL_C_LOW2:
  729                         s->se_sensor.value = 66666;
  730                         break;
  731                 case SES_S_COOL_C_LOW3:
  732                 case SES_S_COOL_C_INTER:
  733                 case SES_S_COOL_C_HI3:
  734                 case SES_S_COOL_C_HI2:
  735                 case SES_S_COOL_C_HI1:
  736                         s->se_sensor.value = 100000;
  737                         break;
  738                 }
  739                 break;
  740         }
  741 }
  742 
  743 void
  744 ses_temp2sensor(struct ses_softc *sc, struct ses_sensor *s)
  745 {
  746         s->se_sensor.value = (int64_t)SES_S_TEMP(s->se_stat);
  747         s->se_sensor.value += SES_S_TEMP_OFFSET;
  748         s->se_sensor.value *= 1000000;          /* Convert to micro degrees. */
  749         s->se_sensor.value += 273150000;        /* Convert to kelvin. */
  750 }
  751 
  752 #ifdef SES_DEBUG
  753 void
  754 ses_dump_enc_desc(struct ses_enc_desc *desc)
  755 {
  756         char                            str[32];
  757 
  758 #if 0
  759         /* XXX not a string. wwn? */
  760         memset(str, 0, sizeof(str));
  761         memcpy(str, desc->logical_id, sizeof(desc->logical_id));
  762         DPRINTF("logical_id: %s", str);
  763 #endif /* 0 */
  764 
  765         memset(str, 0, sizeof(str));
  766         memcpy(str, desc->vendor_id, sizeof(desc->vendor_id));
  767         DPRINTF(" vendor_id: %s", str);
  768 
  769         memset(str, 0, sizeof(str));
  770         memcpy(str, desc->prod_id, sizeof(desc->prod_id));
  771         DPRINTF(" prod_id: %s", str);
  772 
  773         memset(str, 0, sizeof(str));
  774         memcpy(str, desc->prod_rev, sizeof(desc->prod_rev));
  775         DPRINTF(" prod_rev: %s\n", str);
  776 }
  777 
  778 char *
  779 ses_dump_enc_string(u_char *buf, ssize_t len)
  780 {
  781         static char                     str[256];
  782 
  783         memset(str, 0, sizeof(str));
  784         if (len > 0)
  785                 memcpy(str, buf, len);
  786 
  787         return str;
  788 }
  789 #endif /* SES_DEBUG */

Cache object: d63c779ceb5c99eb3f6094468f905015


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.