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/cam/scsi/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 /*-
    2  * Copyright (c) 2000 Matthew Jacob
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. The name of the author may not be used to endorse or promote products
   12  *    derived from this software without specific prior written permission.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/queue.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/types.h>
   35 #include <sys/malloc.h>
   36 #include <sys/fcntl.h>
   37 #include <sys/conf.h>
   38 #include <sys/errno.h>
   39 #include <machine/stdarg.h>
   40 
   41 #include <cam/cam.h>
   42 #include <cam/cam_ccb.h>
   43 #include <cam/cam_periph.h>
   44 #include <cam/cam_xpt_periph.h>
   45 #include <cam/cam_debug.h>
   46 #include <cam/cam_sim.h>
   47 
   48 #include <cam/scsi/scsi_all.h>
   49 #include <cam/scsi/scsi_message.h>
   50 #include <sys/ioccom.h>
   51 #include <cam/scsi/scsi_ses.h>
   52 
   53 #include <opt_ses.h>
   54 
   55 MALLOC_DEFINE(M_SCSISES, "SCSI SES", "SCSI SES buffers");
   56 
   57 /*
   58  * Platform Independent Driver Internal Definitions for SES devices.
   59  */
   60 typedef enum {
   61         SES_NONE,
   62         SES_SES_SCSI2,
   63         SES_SES,
   64         SES_SES_PASSTHROUGH,
   65         SES_SEN,
   66         SES_SAFT
   67 } enctyp;
   68 
   69 struct ses_softc;
   70 typedef struct ses_softc ses_softc_t;
   71 typedef struct {
   72         int (*softc_init)(ses_softc_t *, int);
   73         int (*init_enc)(ses_softc_t *);
   74         int (*get_encstat)(ses_softc_t *, int);
   75         int (*set_encstat)(ses_softc_t *, ses_encstat, int);
   76         int (*get_objstat)(ses_softc_t *, ses_objstat *, int);
   77         int (*set_objstat)(ses_softc_t *, ses_objstat *, int);
   78 } encvec;
   79 
   80 #define ENCI_SVALID     0x80
   81 
   82 typedef struct {
   83         uint32_t
   84                 enctype : 8,            /* enclosure type */
   85                 subenclosure : 8,       /* subenclosure id */
   86                 svalid  : 1,            /* enclosure information valid */
   87                 priv    : 15;           /* private data, per object */
   88         uint8_t encstat[4];     /* state && stats */
   89 } encobj;
   90 
   91 #define SEN_ID          "UNISYS           SUN_SEN"
   92 #define SEN_ID_LEN      24
   93 
   94 
   95 static enctyp ses_type(void *, int);
   96 
   97 
   98 /* Forward reference to Enclosure Functions */
   99 static int ses_softc_init(ses_softc_t *, int);
  100 static int ses_init_enc(ses_softc_t *);
  101 static int ses_get_encstat(ses_softc_t *, int);
  102 static int ses_set_encstat(ses_softc_t *, uint8_t, int);
  103 static int ses_get_objstat(ses_softc_t *, ses_objstat *, int);
  104 static int ses_set_objstat(ses_softc_t *, ses_objstat *, int);
  105 
  106 static int safte_softc_init(ses_softc_t *, int);
  107 static int safte_init_enc(ses_softc_t *);
  108 static int safte_get_encstat(ses_softc_t *, int);
  109 static int safte_set_encstat(ses_softc_t *, uint8_t, int);
  110 static int safte_get_objstat(ses_softc_t *, ses_objstat *, int);
  111 static int safte_set_objstat(ses_softc_t *, ses_objstat *, int);
  112 
  113 /*
  114  * Platform implementation defines/functions for SES internal kernel stuff
  115  */
  116 
  117 #define STRNCMP                 strncmp
  118 #define PRINTF                  printf
  119 #define SES_LOG                 ses_log
  120 #ifdef  DEBUG
  121 #define SES_DLOG                ses_log
  122 #else
  123 #define SES_DLOG                if (0) ses_log
  124 #endif
  125 #define SES_VLOG                if (bootverbose) ses_log
  126 #define SES_MALLOC(amt)         malloc(amt, M_SCSISES, M_NOWAIT)
  127 #define SES_FREE(ptr, amt)      free(ptr, M_SCSISES)
  128 #define MEMZERO                 bzero
  129 #define MEMCPY(dest, src, amt)  bcopy(src, dest, amt)
  130 
  131 static int ses_runcmd(struct ses_softc *, char *, int, char *, int *);
  132 static void ses_log(struct ses_softc *, const char *, ...);
  133 
  134 /*
  135  * Gerenal FreeBSD kernel stuff.
  136  */
  137 
  138 
  139 #define ccb_state       ppriv_field0
  140 #define ccb_bp          ppriv_ptr1
  141 
  142 struct ses_softc {
  143         enctyp          ses_type;       /* type of enclosure */
  144         encvec          ses_vec;        /* vector to handlers */
  145         void *          ses_private;    /* per-type private data */
  146         encobj *        ses_objmap;     /* objects */
  147         uint32_t        ses_nobjects;   /* number of objects */
  148         ses_encstat     ses_encstat;    /* overall status */
  149         uint8_t ses_flags;
  150         union ccb       ses_saved_ccb;
  151         struct cdev *ses_dev;
  152         struct cam_periph *periph;
  153 };
  154 #define SES_FLAG_INVALID        0x01
  155 #define SES_FLAG_OPEN           0x02
  156 #define SES_FLAG_INITIALIZED    0x04
  157 
  158 #define SESUNIT(x)       (minor((x)))
  159 
  160 static  d_open_t        sesopen;
  161 static  d_close_t       sesclose;
  162 static  d_ioctl_t       sesioctl;
  163 static  periph_init_t   sesinit;
  164 static  periph_ctor_t   sesregister;
  165 static  periph_oninv_t  sesoninvalidate;
  166 static  periph_dtor_t   sescleanup;
  167 static  periph_start_t  sesstart;
  168 
  169 static void sesasync(void *, uint32_t, struct cam_path *, void *);
  170 static void sesdone(struct cam_periph *, union ccb *);
  171 static int seserror(union ccb *, uint32_t, uint32_t);
  172 
  173 static struct periph_driver sesdriver = {
  174         sesinit, "ses",
  175         TAILQ_HEAD_INITIALIZER(sesdriver.units), /* generation */ 0
  176 };
  177 
  178 PERIPHDRIVER_DECLARE(ses, sesdriver);
  179 
  180 static struct cdevsw ses_cdevsw = {
  181         .d_version =    D_VERSION,
  182         .d_open =       sesopen,
  183         .d_close =      sesclose,
  184         .d_ioctl =      sesioctl,
  185         .d_name =       "ses",
  186         .d_flags =      0,
  187 };
  188 
  189 static void
  190 sesinit(void)
  191 {
  192         cam_status status;
  193 
  194         /*
  195          * Install a global async callback.  This callback will
  196          * receive async callbacks like "new device found".
  197          */
  198         status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL);
  199 
  200         if (status != CAM_REQ_CMP) {
  201                 printf("ses: Failed to attach master async callback "
  202                        "due to status 0x%x!\n", status);
  203         }
  204 }
  205 
  206 static void
  207 sesoninvalidate(struct cam_periph *periph)
  208 {
  209         struct ses_softc *softc;
  210 
  211         softc = (struct ses_softc *)periph->softc;
  212 
  213         /*
  214          * Unregister any async callbacks.
  215          */
  216         xpt_register_async(0, sesasync, periph, periph->path);
  217 
  218         softc->ses_flags |= SES_FLAG_INVALID;
  219 
  220         xpt_print(periph->path, "lost device\n");
  221 }
  222 
  223 static void
  224 sescleanup(struct cam_periph *periph)
  225 {
  226         struct ses_softc *softc;
  227 
  228         softc = (struct ses_softc *)periph->softc;
  229 
  230         destroy_dev(softc->ses_dev);
  231 
  232         xpt_print(periph->path, "removing device entry\n");
  233         free(softc, M_SCSISES);
  234 }
  235 
  236 static void
  237 sesasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
  238 {
  239         struct cam_periph *periph;
  240 
  241         periph = (struct cam_periph *)callback_arg;
  242 
  243         switch(code) {
  244         case AC_FOUND_DEVICE:
  245         {
  246                 cam_status status;
  247                 struct ccb_getdev *cgd;
  248                 int inq_len;
  249 
  250                 cgd = (struct ccb_getdev *)arg;
  251                 if (arg == NULL) {
  252                         break;
  253                 }
  254 
  255                 inq_len = cgd->inq_data.additional_length + 4;
  256 
  257                 /*
  258                  * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS
  259                  * PROBLEM: IS A SAF-TE DEVICE.
  260                  */
  261                 switch (ses_type(&cgd->inq_data, inq_len)) {
  262                 case SES_SES:
  263                 case SES_SES_SCSI2:
  264                 case SES_SES_PASSTHROUGH:
  265                 case SES_SEN:
  266                 case SES_SAFT:
  267                         break;
  268                 default:
  269                         return;
  270                 }
  271 
  272                 status = cam_periph_alloc(sesregister, sesoninvalidate,
  273                     sescleanup, sesstart, "ses", CAM_PERIPH_BIO,
  274                     cgd->ccb_h.path, sesasync, AC_FOUND_DEVICE, cgd);
  275 
  276                 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
  277                         printf("sesasync: Unable to probe new device due to "
  278                             "status 0x%x\n", status);
  279                 }
  280                 break;
  281         }
  282         default:
  283                 cam_periph_async(periph, code, path, arg);
  284                 break;
  285         }
  286 }
  287 
  288 static cam_status
  289 sesregister(struct cam_periph *periph, void *arg)
  290 {
  291         struct ses_softc *softc;
  292         struct ccb_getdev *cgd;
  293         char *tname;
  294 
  295         cgd = (struct ccb_getdev *)arg;
  296         if (periph == NULL) {
  297                 printf("sesregister: periph was NULL!!\n");
  298                 return (CAM_REQ_CMP_ERR);
  299         }
  300 
  301         if (cgd == NULL) {
  302                 printf("sesregister: no getdev CCB, can't register device\n");
  303                 return (CAM_REQ_CMP_ERR);
  304         }
  305 
  306         softc = SES_MALLOC(sizeof (struct ses_softc));
  307         if (softc == NULL) {
  308                 printf("sesregister: Unable to probe new device. "
  309                        "Unable to allocate softc\n");                           
  310                 return (CAM_REQ_CMP_ERR);
  311         }
  312         bzero(softc, sizeof (struct ses_softc));
  313         periph->softc = softc;
  314         softc->periph = periph;
  315 
  316         softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data));
  317 
  318         switch (softc->ses_type) {
  319         case SES_SES:
  320         case SES_SES_SCSI2:
  321         case SES_SES_PASSTHROUGH:
  322                 softc->ses_vec.softc_init = ses_softc_init;
  323                 softc->ses_vec.init_enc = ses_init_enc;
  324                 softc->ses_vec.get_encstat = ses_get_encstat;
  325                 softc->ses_vec.set_encstat = ses_set_encstat;
  326                 softc->ses_vec.get_objstat = ses_get_objstat;
  327                 softc->ses_vec.set_objstat = ses_set_objstat;
  328                 break;
  329         case SES_SAFT:
  330                 softc->ses_vec.softc_init = safte_softc_init;
  331                 softc->ses_vec.init_enc = safte_init_enc;
  332                 softc->ses_vec.get_encstat = safte_get_encstat;
  333                 softc->ses_vec.set_encstat = safte_set_encstat;
  334                 softc->ses_vec.get_objstat = safte_get_objstat;
  335                 softc->ses_vec.set_objstat = safte_set_objstat;
  336                 break;
  337         case SES_SEN:
  338                 break;
  339         case SES_NONE:
  340         default:
  341                 free(softc, M_SCSISES);
  342                 return (CAM_REQ_CMP_ERR);
  343         }
  344 
  345         cam_periph_unlock(periph);
  346         softc->ses_dev = make_dev(&ses_cdevsw, unit2minor(periph->unit_number),
  347             UID_ROOT, GID_OPERATOR, 0600, "%s%d",
  348             periph->periph_name, periph->unit_number);
  349         cam_periph_lock(periph);
  350         softc->ses_dev->si_drv1 = periph;
  351 
  352         /*
  353          * Add an async callback so that we get
  354          * notified if this device goes away.
  355          */
  356         xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path);
  357 
  358         switch (softc->ses_type) {
  359         default:
  360         case SES_NONE:
  361                 tname = "No SES device";
  362                 break;
  363         case SES_SES_SCSI2:
  364                 tname = "SCSI-2 SES Device";
  365                 break;
  366         case SES_SES:
  367                 tname = "SCSI-3 SES Device";
  368                 break;
  369         case SES_SES_PASSTHROUGH:
  370                 tname = "SES Passthrough Device";
  371                 break;
  372         case SES_SEN:
  373                 tname = "UNISYS SEN Device (NOT HANDLED YET)";
  374                 break;
  375         case SES_SAFT:
  376                 tname = "SAF-TE Compliant Device";
  377                 break;
  378         }
  379         xpt_announce_periph(periph, tname);
  380         return (CAM_REQ_CMP);
  381 }
  382 
  383 static int
  384 sesopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  385 {
  386         struct cam_periph *periph;
  387         struct ses_softc *softc;
  388         int error = 0;
  389 
  390         periph = (struct cam_periph *)dev->si_drv1;
  391         if (periph == NULL) {
  392                 return (ENXIO);
  393         }
  394 
  395         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  396                 cam_periph_unlock(periph);
  397                 return (ENXIO);
  398         }
  399 
  400         cam_periph_lock(periph);
  401 
  402         softc = (struct ses_softc *)periph->softc;
  403 
  404         if (softc->ses_flags & SES_FLAG_INVALID) {
  405                 error = ENXIO;
  406                 goto out;
  407         }
  408         if (softc->ses_flags & SES_FLAG_OPEN) {
  409                 error = EBUSY;
  410                 goto out;
  411         }
  412         if (softc->ses_vec.softc_init == NULL) {
  413                 error = ENXIO;
  414                 goto out;
  415         }
  416 
  417         softc->ses_flags |= SES_FLAG_OPEN;
  418         if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
  419                 error = (*softc->ses_vec.softc_init)(softc, 1);
  420                 if (error)
  421                         softc->ses_flags &= ~SES_FLAG_OPEN;
  422                 else
  423                         softc->ses_flags |= SES_FLAG_INITIALIZED;
  424         }
  425 
  426 out:
  427         cam_periph_unlock(periph);
  428         if (error) {
  429                 cam_periph_release(periph);
  430         }
  431         return (error);
  432 }
  433 
  434 static int
  435 sesclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  436 {
  437         struct cam_periph *periph;
  438         struct ses_softc *softc;
  439         int error;
  440 
  441         error = 0;
  442 
  443         periph = (struct cam_periph *)dev->si_drv1;
  444         if (periph == NULL)
  445                 return (ENXIO);
  446 
  447         cam_periph_lock(periph);
  448 
  449         softc = (struct ses_softc *)periph->softc;
  450         softc->ses_flags &= ~SES_FLAG_OPEN;
  451 
  452         cam_periph_unlock(periph);
  453         cam_periph_release(periph);
  454 
  455         return (0);
  456 }
  457 
  458 static void
  459 sesstart(struct cam_periph *p, union ccb *sccb)
  460 {
  461         if (p->immediate_priority <= p->pinfo.priority) {
  462                 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
  463                 p->immediate_priority = CAM_PRIORITY_NONE;
  464                 wakeup(&p->ccb_list);
  465         }
  466 }
  467 
  468 static void
  469 sesdone(struct cam_periph *periph, union ccb *dccb)
  470 {
  471         wakeup(&dccb->ccb_h.cbfcnp);
  472 }
  473 
  474 static int
  475 seserror(union ccb *ccb, uint32_t cflags, uint32_t sflags)
  476 {
  477         struct ses_softc *softc;
  478         struct cam_periph *periph;
  479 
  480         periph = xpt_path_periph(ccb->ccb_h.path);
  481         softc = (struct ses_softc *)periph->softc;
  482 
  483         return (cam_periph_error(ccb, cflags, sflags, &softc->ses_saved_ccb));
  484 }
  485 
  486 static int
  487 sesioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, struct thread *td)
  488 {
  489         struct cam_periph *periph;
  490         ses_encstat tmp;
  491         ses_objstat objs;
  492         ses_object *uobj;
  493         struct ses_softc *ssc;
  494         void *addr;
  495         int error, i;
  496 
  497 
  498         if (arg_addr)
  499                 addr = *((caddr_t *) arg_addr);
  500         else
  501                 addr = NULL;
  502 
  503         periph = (struct cam_periph *)dev->si_drv1;
  504         if (periph == NULL)
  505                 return (ENXIO);
  506 
  507         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n"));
  508 
  509         cam_periph_lock(periph);
  510         ssc = (struct ses_softc *)periph->softc;
  511 
  512         /*
  513          * Now check to see whether we're initialized or not.
  514          * This actually should never fail as we're not supposed
  515          * to get past ses_open w/o successfully initializing
  516          * things.
  517          */
  518         if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
  519                 cam_periph_unlock(periph);
  520                 return (ENXIO);
  521         }
  522         cam_periph_unlock(periph);
  523 
  524         error = 0;
  525 
  526         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  527             ("trying to do ioctl %#lx\n", cmd));
  528 
  529         /*
  530          * If this command can change the device's state,
  531          * we must have the device open for writing.
  532          *
  533          * For commands that get information about the
  534          * device- we don't need to lock the peripheral
  535          * if we aren't running a command. The number
  536          * of objects and the contents will stay stable
  537          * after the first open that does initialization.
  538          * The periph also can't go away while a user
  539          * process has it open.
  540          */
  541         switch (cmd) {
  542         case SESIOC_GETNOBJ:
  543         case SESIOC_GETOBJMAP:
  544         case SESIOC_GETENCSTAT:
  545         case SESIOC_GETOBJSTAT:
  546                 break;
  547         default:
  548                 if ((flag & FWRITE) == 0) {
  549                         return (EBADF);
  550                 }
  551         }
  552 
  553         switch (cmd) {
  554         case SESIOC_GETNOBJ:
  555                 error = copyout(&ssc->ses_nobjects, addr,
  556                     sizeof (ssc->ses_nobjects));
  557                 break;
  558                 
  559         case SESIOC_GETOBJMAP:
  560                 for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++) {
  561                         ses_object kobj;
  562                         kobj.obj_id = i;
  563                         kobj.subencid = ssc->ses_objmap[i].subenclosure;
  564                         kobj.object_type = ssc->ses_objmap[i].enctype;
  565                         error = copyout(&kobj, &uobj[i], sizeof (ses_object));
  566                         if (error) {
  567                                 break;
  568                         }
  569                 }
  570                 break;
  571 
  572         case SESIOC_GETENCSTAT:
  573                 cam_periph_lock(periph);
  574                 error = (*ssc->ses_vec.get_encstat)(ssc, 1);
  575                 if (error) {
  576                         cam_periph_unlock(periph);
  577                         break;
  578                 }
  579                 tmp = ssc->ses_encstat & ~ENCI_SVALID;
  580                 cam_periph_unlock(periph);
  581                 error = copyout(&tmp, addr, sizeof (ses_encstat));
  582                 ssc->ses_encstat = tmp;
  583                 break;
  584 
  585         case SESIOC_SETENCSTAT:
  586                 error = copyin(addr, &tmp, sizeof (ses_encstat));
  587                 if (error)
  588                         break;
  589                 cam_periph_lock(periph);
  590                 error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
  591                 cam_periph_unlock(periph);
  592                 break;
  593 
  594         case SESIOC_GETOBJSTAT:
  595                 error = copyin(addr, &objs, sizeof (ses_objstat));
  596                 if (error)
  597                         break;
  598                 if (objs.obj_id >= ssc->ses_nobjects) {
  599                         error = EINVAL;
  600                         break;
  601                 }
  602                 cam_periph_lock(periph);
  603                 error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
  604                 cam_periph_unlock(periph);
  605                 if (error)
  606                         break;
  607                 error = copyout(&objs, addr, sizeof (ses_objstat));
  608                 /*
  609                  * Always (for now) invalidate entry.
  610                  */
  611                 ssc->ses_objmap[objs.obj_id].svalid = 0;
  612                 break;
  613 
  614         case SESIOC_SETOBJSTAT:
  615                 error = copyin(addr, &objs, sizeof (ses_objstat));
  616                 if (error)
  617                         break;
  618 
  619                 if (objs.obj_id >= ssc->ses_nobjects) {
  620                         error = EINVAL;
  621                         break;
  622                 }
  623                 cam_periph_lock(periph);
  624                 error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
  625                 cam_periph_unlock(periph);
  626 
  627                 /*
  628                  * Always (for now) invalidate entry.
  629                  */
  630                 ssc->ses_objmap[objs.obj_id].svalid = 0;
  631                 break;
  632 
  633         case SESIOC_INIT:
  634 
  635                 cam_periph_lock(periph);
  636                 error = (*ssc->ses_vec.init_enc)(ssc);
  637                 cam_periph_unlock(periph);
  638                 break;
  639 
  640         default:
  641                 cam_periph_lock(periph);
  642                 error = cam_periph_ioctl(periph, cmd, arg_addr, seserror);
  643                 cam_periph_unlock(periph);
  644                 break;
  645         }
  646         return (error);
  647 }
  648 
  649 #define SES_CFLAGS      CAM_RETRY_SELTO
  650 #define SES_FLAGS       SF_NO_PRINT | SF_RETRY_UA
  651 static int
  652 ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp)
  653 {
  654         int error, dlen;
  655         ccb_flags ddf;
  656         union ccb *ccb;
  657 
  658         if (dptr) {
  659                 if ((dlen = *dlenp) < 0) {
  660                         dlen = -dlen;
  661                         ddf = CAM_DIR_OUT;
  662                 } else {
  663                         ddf = CAM_DIR_IN;
  664                 }
  665         } else {
  666                 dlen = 0;
  667                 ddf = CAM_DIR_NONE;
  668         }
  669 
  670         if (cdbl > IOCDBLEN) {
  671                 cdbl = IOCDBLEN;
  672         }
  673 
  674         ccb = cam_periph_getccb(ssc->periph, 1);
  675         cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, dptr,
  676             dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000);
  677         bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
  678 
  679         error = cam_periph_runccb(ccb, seserror, SES_CFLAGS, SES_FLAGS, NULL);
  680         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
  681                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
  682         if (error) {
  683                 if (dptr) {
  684                         *dlenp = dlen;
  685                 }
  686         } else {
  687                 if (dptr) {
  688                         *dlenp = ccb->csio.resid;
  689                 }
  690         }
  691         xpt_release_ccb(ccb);
  692         return (error);
  693 }
  694 
  695 static void
  696 ses_log(struct ses_softc *ssc, const char *fmt, ...)
  697 {
  698         va_list ap;
  699 
  700         printf("%s%d: ", ssc->periph->periph_name, ssc->periph->unit_number);
  701         va_start(ap, fmt);
  702         vprintf(fmt, ap);
  703         va_end(ap);
  704 }
  705 
  706 /*
  707  * The code after this point runs on many platforms,
  708  * so forgive the slightly awkward and nonconforming
  709  * appearance.
  710  */
  711 
  712 /*
  713  * Is this a device that supports enclosure services?
  714  *
  715  * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's
  716  * an SES device. If it happens to be an old UNISYS SEN device, we can
  717  * handle that too.
  718  */
  719 
  720 #define SAFTE_START     44
  721 #define SAFTE_END       50
  722 #define SAFTE_LEN       SAFTE_END-SAFTE_START
  723 
  724 static enctyp
  725 ses_type(void *buf, int buflen)
  726 {
  727         unsigned char *iqd = buf;
  728 
  729         if (buflen < 8+SEN_ID_LEN)
  730                 return (SES_NONE);
  731 
  732         if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
  733                 if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) {
  734                         return (SES_SEN);
  735                 } else if ((iqd[2] & 0x7) > 2) {
  736                         return (SES_SES);
  737                 } else {
  738                         return (SES_SES_SCSI2);
  739                 }
  740                 return (SES_NONE);
  741         }
  742 
  743 #ifdef  SES_ENABLE_PASSTHROUGH
  744         if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
  745                 /*
  746                  * PassThrough Device.
  747                  */
  748                 return (SES_SES_PASSTHROUGH);
  749         }
  750 #endif
  751 
  752         /*
  753          * The comparison is short for a reason-
  754          * some vendors were chopping it short.
  755          */
  756 
  757         if (buflen < SAFTE_END - 2) {
  758                 return (SES_NONE);
  759         }
  760 
  761         if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
  762                 return (SES_SAFT);
  763         }
  764         return (SES_NONE);
  765 }
  766 
  767 /*
  768  * SES Native Type Device Support
  769  */
  770 
  771 /*
  772  * SES Diagnostic Page Codes
  773  */
  774 
  775 typedef enum {
  776         SesConfigPage = 0x1,
  777         SesControlPage,
  778 #define SesStatusPage SesControlPage
  779         SesHelpTxt,
  780         SesStringOut,
  781 #define SesStringIn     SesStringOut
  782         SesThresholdOut,
  783 #define SesThresholdIn SesThresholdOut
  784         SesArrayControl,
  785 #define SesArrayStatus  SesArrayControl
  786         SesElementDescriptor,
  787         SesShortStatus
  788 } SesDiagPageCodes;
  789 
  790 /*
  791  * minimal amounts
  792  */
  793 
  794 /*
  795  * Minimum amount of data, starting from byte 0, to have
  796  * the config header.
  797  */
  798 #define SES_CFGHDR_MINLEN       12
  799 
  800 /*
  801  * Minimum amount of data, starting from byte 0, to have
  802  * the config header and one enclosure header.
  803  */
  804 #define SES_ENCHDR_MINLEN       48
  805 
  806 /*
  807  * Take this value, subtract it from VEnclen and you know
  808  * the length of the vendor unique bytes.
  809  */
  810 #define SES_ENCHDR_VMIN         36
  811 
  812 /*
  813  * SES Data Structures
  814  */
  815 
  816 typedef struct {
  817         uint32_t GenCode;       /* Generation Code */
  818         uint8_t Nsubenc;        /* Number of Subenclosures */
  819 } SesCfgHdr;
  820 
  821 typedef struct {
  822         uint8_t Subencid;       /* SubEnclosure Identifier */
  823         uint8_t Ntypes;         /* # of supported types */
  824         uint8_t VEnclen;        /* Enclosure Descriptor Length */
  825 } SesEncHdr;
  826 
  827 typedef struct {
  828         uint8_t encWWN[8];      /* XXX- Not Right Yet */
  829         uint8_t encVid[8];
  830         uint8_t encPid[16];
  831         uint8_t encRev[4];
  832         uint8_t encVen[1];
  833 } SesEncDesc;
  834 
  835 typedef struct {
  836         uint8_t enc_type;               /* type of element */
  837         uint8_t enc_maxelt;             /* maximum supported */
  838         uint8_t enc_subenc;             /* in SubEnc # N */
  839         uint8_t enc_tlen;               /* Type Descriptor Text Length */
  840 } SesThdr;
  841 
  842 typedef struct {
  843         uint8_t comstatus;
  844         uint8_t comstat[3];
  845 } SesComStat;
  846 
  847 struct typidx {
  848         int ses_tidx;
  849         int ses_oidx;
  850 };
  851 
  852 struct sscfg {
  853         uint8_t ses_ntypes;     /* total number of types supported */
  854 
  855         /*
  856          * We need to keep a type index as well as an
  857          * object index for each object in an enclosure.
  858          */
  859         struct typidx *ses_typidx;
  860 
  861         /*
  862          * We also need to keep track of the number of elements
  863          * per type of element. This is needed later so that we
  864          * can find precisely in the returned status data the
  865          * status for the Nth element of the Kth type.
  866          */
  867         uint8_t *       ses_eltmap;
  868 };
  869 
  870 
  871 /*
  872  * (de)canonicalization defines
  873  */
  874 #define sbyte(x, byte)          ((((uint32_t)(x)) >> (byte * 8)) & 0xff)
  875 #define sbit(x, bit)            (((uint32_t)(x)) << bit)
  876 #define sset8(outp, idx, sval)  (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  877 
  878 #define sset16(outp, idx, sval) \
  879         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  880         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  881 
  882 
  883 #define sset24(outp, idx, sval) \
  884         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
  885         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  886         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  887 
  888 
  889 #define sset32(outp, idx, sval) \
  890         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \
  891         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
  892         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  893         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  894 
  895 #define gbyte(x, byte)  ((((uint32_t)(x)) & 0xff) << (byte * 8))
  896 #define gbit(lv, in, idx, shft, mask)   lv = ((in[idx] >> shft) & mask)
  897 #define sget8(inp, idx, lval)   lval = (((uint8_t *)(inp))[idx++])
  898 #define gget8(inp, idx, lval)   lval = (((uint8_t *)(inp))[idx])
  899 
  900 #define sget16(inp, idx, lval)  \
  901         lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
  902                 (((uint8_t *)(inp))[idx+1]), idx += 2
  903 
  904 #define gget16(inp, idx, lval)  \
  905         lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
  906                 (((uint8_t *)(inp))[idx+1])
  907 
  908 #define sget24(inp, idx, lval)  \
  909         lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
  910                 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
  911                         (((uint8_t *)(inp))[idx+2]), idx += 3
  912 
  913 #define gget24(inp, idx, lval)  \
  914         lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
  915                 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
  916                         (((uint8_t *)(inp))[idx+2])
  917 
  918 #define sget32(inp, idx, lval)  \
  919         lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
  920                 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
  921                 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
  922                         (((uint8_t *)(inp))[idx+3]), idx += 4
  923 
  924 #define gget32(inp, idx, lval)  \
  925         lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
  926                 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
  927                 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
  928                         (((uint8_t *)(inp))[idx+3])
  929 
  930 #define SCSZ    0x2000
  931 #define CFLEN   (256 + SES_ENCHDR_MINLEN)
  932 
  933 /*
  934  * Routines specific && private to SES only
  935  */
  936 
  937 static int ses_getconfig(ses_softc_t *);
  938 static int ses_getputstat(ses_softc_t *, int, SesComStat *, int, int);
  939 static int ses_cfghdr(uint8_t *, int, SesCfgHdr *);
  940 static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr *);
  941 static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc *);
  942 static int ses_getthdr(uint8_t *, int,  int, SesThdr *);
  943 static int ses_decode(char *, int, uint8_t *, int, int, SesComStat *);
  944 static int ses_encode(char *, int, uint8_t *, int, int, SesComStat *);
  945 
  946 static int
  947 ses_softc_init(ses_softc_t *ssc, int doinit)
  948 {
  949         if (doinit == 0) {
  950                 struct sscfg *cc;
  951                 if (ssc->ses_nobjects) {
  952                         SES_FREE(ssc->ses_objmap,
  953                             ssc->ses_nobjects * sizeof (encobj));
  954                         ssc->ses_objmap = NULL;
  955                 }
  956                 if ((cc = ssc->ses_private) != NULL) {
  957                         if (cc->ses_eltmap && cc->ses_ntypes) {
  958                                 SES_FREE(cc->ses_eltmap, cc->ses_ntypes);
  959                                 cc->ses_eltmap = NULL;
  960                                 cc->ses_ntypes = 0;
  961                         }
  962                         if (cc->ses_typidx && ssc->ses_nobjects) {
  963                                 SES_FREE(cc->ses_typidx,
  964                                     ssc->ses_nobjects * sizeof (struct typidx));
  965                                 cc->ses_typidx = NULL;
  966                         }
  967                         SES_FREE(cc, sizeof (struct sscfg));
  968                         ssc->ses_private = NULL;
  969                 }
  970                 ssc->ses_nobjects = 0;
  971                 return (0);
  972         }
  973         if (ssc->ses_private == NULL) {
  974                 ssc->ses_private = SES_MALLOC(sizeof (struct sscfg));
  975         }
  976         if (ssc->ses_private == NULL) {
  977                 return (ENOMEM);
  978         }
  979         ssc->ses_nobjects = 0;
  980         ssc->ses_encstat = 0;
  981         return (ses_getconfig(ssc));
  982 }
  983 
  984 static int
  985 ses_init_enc(ses_softc_t *ssc)
  986 {
  987         return (0);
  988 }
  989 
  990 static int
  991 ses_get_encstat(ses_softc_t *ssc, int slpflag)
  992 {
  993         SesComStat ComStat;
  994         int status;
  995 
  996         if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) {
  997                 return (status);
  998         }
  999         ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID;
 1000         return (0);
 1001 }
 1002 
 1003 static int
 1004 ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag)
 1005 {
 1006         SesComStat ComStat;
 1007         int status;
 1008 
 1009         ComStat.comstatus = encstat & 0xf;
 1010         if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) {
 1011                 return (status);
 1012         }
 1013         ssc->ses_encstat = encstat & 0xf;       /* note no SVALID set */
 1014         return (0);
 1015 }
 1016 
 1017 static int
 1018 ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
 1019 {
 1020         int i = (int)obp->obj_id;
 1021 
 1022         if (ssc->ses_objmap[i].svalid == 0) {
 1023                 SesComStat ComStat;
 1024                 int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1);
 1025                 if (err)
 1026                         return (err);
 1027                 ssc->ses_objmap[i].encstat[0] = ComStat.comstatus;
 1028                 ssc->ses_objmap[i].encstat[1] = ComStat.comstat[0];
 1029                 ssc->ses_objmap[i].encstat[2] = ComStat.comstat[1];
 1030                 ssc->ses_objmap[i].encstat[3] = ComStat.comstat[2];
 1031                 ssc->ses_objmap[i].svalid = 1;
 1032         }
 1033         obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
 1034         obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
 1035         obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
 1036         obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
 1037         return (0);
 1038 }
 1039 
 1040 static int
 1041 ses_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
 1042 {
 1043         SesComStat ComStat;
 1044         int err;
 1045         /*
 1046          * If this is clear, we don't do diddly.
 1047          */
 1048         if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
 1049                 return (0);
 1050         }
 1051         ComStat.comstatus = obp->cstat[0];
 1052         ComStat.comstat[0] = obp->cstat[1];
 1053         ComStat.comstat[1] = obp->cstat[2];
 1054         ComStat.comstat[2] = obp->cstat[3];
 1055         err = ses_getputstat(ssc, (int)obp->obj_id, &ComStat, slpflag, 0);
 1056         ssc->ses_objmap[(int)obp->obj_id].svalid = 0;
 1057         return (err);
 1058 }
 1059 
 1060 static int
 1061 ses_getconfig(ses_softc_t *ssc)
 1062 {
 1063         struct sscfg *cc;
 1064         SesCfgHdr cf;
 1065         SesEncHdr hd;
 1066         SesEncDesc *cdp;
 1067         SesThdr thdr;
 1068         int err, amt, i, nobj, ntype, maxima;
 1069         char storage[CFLEN], *sdata;
 1070         static char cdb[6] = {
 1071             RECEIVE_DIAGNOSTIC, 0x1, SesConfigPage, SCSZ >> 8, SCSZ & 0xff, 0
 1072         };
 1073 
 1074         cc = ssc->ses_private;
 1075         if (cc == NULL) {
 1076                 return (ENXIO);
 1077         }
 1078 
 1079         sdata = SES_MALLOC(SCSZ);
 1080         if (sdata == NULL)
 1081                 return (ENOMEM);
 1082 
 1083         amt = SCSZ;
 1084         err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
 1085         if (err) {
 1086                 SES_FREE(sdata, SCSZ);
 1087                 return (err);
 1088         }
 1089         amt = SCSZ - amt;
 1090 
 1091         if (ses_cfghdr((uint8_t *) sdata, amt, &cf)) {
 1092                 SES_LOG(ssc, "Unable to parse SES Config Header\n");
 1093                 SES_FREE(sdata, SCSZ);
 1094                 return (EIO);
 1095         }
 1096         if (amt < SES_ENCHDR_MINLEN) {
 1097                 SES_LOG(ssc, "runt enclosure length (%d)\n", amt);
 1098                 SES_FREE(sdata, SCSZ);
 1099                 return (EIO);
 1100         }
 1101 
 1102         SES_VLOG(ssc, "GenCode %x %d Subenclosures\n", cf.GenCode, cf.Nsubenc);
 1103 
 1104         /*
 1105          * Now waltz through all the subenclosures toting up the
 1106          * number of types available in each. For this, we only
 1107          * really need the enclosure header. However, we get the
 1108          * enclosure descriptor for debug purposes, as well
 1109          * as self-consistency checking purposes.
 1110          */
 1111 
 1112         maxima = cf.Nsubenc + 1;
 1113         cdp = (SesEncDesc *) storage;
 1114         for (ntype = i = 0; i < maxima; i++) {
 1115                 MEMZERO((caddr_t)cdp, sizeof (*cdp));
 1116                 if (ses_enchdr((uint8_t *) sdata, amt, i, &hd)) {
 1117                         SES_LOG(ssc, "Cannot Extract Enclosure Header %d\n", i);
 1118                         SES_FREE(sdata, SCSZ);
 1119                         return (EIO);
 1120                 }
 1121                 SES_VLOG(ssc, " SubEnclosure ID %d, %d Types With this ID, En"
 1122                     "closure Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen);
 1123 
 1124                 if (ses_encdesc((uint8_t *)sdata, amt, i, cdp)) {
 1125                         SES_LOG(ssc, "Can't get Enclosure Descriptor %d\n", i);
 1126                         SES_FREE(sdata, SCSZ);
 1127                         return (EIO);
 1128                 }
 1129                 SES_VLOG(ssc, " WWN: %02x%02x%02x%02x%02x%02x%02x%02x\n",
 1130                     cdp->encWWN[0], cdp->encWWN[1], cdp->encWWN[2],
 1131                     cdp->encWWN[3], cdp->encWWN[4], cdp->encWWN[5],
 1132                     cdp->encWWN[6], cdp->encWWN[7]);
 1133                 ntype += hd.Ntypes;
 1134         }
 1135 
 1136         /*
 1137          * Now waltz through all the types that are available, getting
 1138          * the type header so we can start adding up the number of
 1139          * objects available.
 1140          */
 1141         for (nobj = i = 0; i < ntype; i++) {
 1142                 if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
 1143                         SES_LOG(ssc, "Can't get Enclosure Type Header %d\n", i);
 1144                         SES_FREE(sdata, SCSZ);
 1145                         return (EIO);
 1146                 }
 1147                 SES_LOG(ssc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
 1148                     "%d, Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt,
 1149                     thdr.enc_subenc, thdr.enc_tlen);
 1150                 nobj += thdr.enc_maxelt;
 1151         }
 1152 
 1153 
 1154         /*
 1155          * Now allocate the object array and type map.
 1156          */
 1157 
 1158         ssc->ses_objmap = SES_MALLOC(nobj * sizeof (encobj));
 1159         cc->ses_typidx = SES_MALLOC(nobj * sizeof (struct typidx));
 1160         cc->ses_eltmap = SES_MALLOC(ntype);
 1161 
 1162         if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL ||
 1163             cc->ses_eltmap == NULL) {
 1164                 if (ssc->ses_objmap) {
 1165                         SES_FREE(ssc->ses_objmap, (nobj * sizeof (encobj)));
 1166                         ssc->ses_objmap = NULL;
 1167                 }
 1168                 if (cc->ses_typidx) {
 1169                         SES_FREE(cc->ses_typidx,
 1170                             (nobj * sizeof (struct typidx)));
 1171                         cc->ses_typidx = NULL;
 1172                 }
 1173                 if (cc->ses_eltmap) {
 1174                         SES_FREE(cc->ses_eltmap, ntype);
 1175                         cc->ses_eltmap = NULL;
 1176                 }
 1177                 SES_FREE(sdata, SCSZ);
 1178                 return (ENOMEM);
 1179         }
 1180         MEMZERO(ssc->ses_objmap, nobj * sizeof (encobj));
 1181         MEMZERO(cc->ses_typidx, nobj * sizeof (struct typidx));
 1182         MEMZERO(cc->ses_eltmap, ntype);
 1183         cc->ses_ntypes = (uint8_t) ntype;
 1184         ssc->ses_nobjects = nobj;
 1185 
 1186         /*
 1187          * Now waltz through the # of types again to fill in the types
 1188          * (and subenclosure ids) of the allocated objects.
 1189          */
 1190         nobj = 0;
 1191         for (i = 0; i < ntype; i++) {
 1192                 int j;
 1193                 if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
 1194                         continue;
 1195                 }
 1196                 cc->ses_eltmap[i] = thdr.enc_maxelt;
 1197                 for (j = 0; j < thdr.enc_maxelt; j++) {
 1198                         cc->ses_typidx[nobj].ses_tidx = i;
 1199                         cc->ses_typidx[nobj].ses_oidx = j;
 1200                         ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc;
 1201                         ssc->ses_objmap[nobj++].enctype = thdr.enc_type;
 1202                 }
 1203         }
 1204         SES_FREE(sdata, SCSZ);
 1205         return (0);
 1206 }
 1207 
 1208 static int
 1209 ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, int in)
 1210 {
 1211         struct sscfg *cc;
 1212         int err, amt, bufsiz, tidx, oidx;
 1213         char cdb[6], *sdata;
 1214 
 1215         cc = ssc->ses_private;
 1216         if (cc == NULL) {
 1217                 return (ENXIO);
 1218         }
 1219 
 1220         /*
 1221          * If we're just getting overall enclosure status,
 1222          * we only need 2 bytes of data storage.
 1223          *
 1224          * If we're getting anything else, we know how much
 1225          * storage we need by noting that starting at offset
 1226          * 8 in returned data, all object status bytes are 4
 1227          * bytes long, and are stored in chunks of types(M)
 1228          * and nth+1 instances of type M.
 1229          */
 1230         if (objid == -1) {
 1231                 bufsiz = 2;
 1232         } else {
 1233                 bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8;
 1234         }
 1235         sdata = SES_MALLOC(bufsiz);
 1236         if (sdata == NULL)
 1237                 return (ENOMEM);
 1238 
 1239         cdb[0] = RECEIVE_DIAGNOSTIC;
 1240         cdb[1] = 1;
 1241         cdb[2] = SesStatusPage;
 1242         cdb[3] = bufsiz >> 8;
 1243         cdb[4] = bufsiz & 0xff;
 1244         cdb[5] = 0;
 1245         amt = bufsiz;
 1246         err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
 1247         if (err) {
 1248                 SES_FREE(sdata, bufsiz);
 1249                 return (err);
 1250         }
 1251         amt = bufsiz - amt;
 1252 
 1253         if (objid == -1) {
 1254                 tidx = -1;
 1255                 oidx = -1;
 1256         } else {
 1257                 tidx = cc->ses_typidx[objid].ses_tidx;
 1258                 oidx = cc->ses_typidx[objid].ses_oidx;
 1259         }
 1260         if (in) {
 1261                 if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
 1262                         err = ENODEV;
 1263                 }
 1264         } else {
 1265                 if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
 1266                         err = ENODEV;
 1267                 } else {
 1268                         cdb[0] = SEND_DIAGNOSTIC;
 1269                         cdb[1] = 0x10;
 1270                         cdb[2] = 0;
 1271                         cdb[3] = bufsiz >> 8;
 1272                         cdb[4] = bufsiz & 0xff;
 1273                         cdb[5] = 0;
 1274                         amt = -bufsiz;
 1275                         err = ses_runcmd(ssc, cdb, 6, sdata, &amt);   
 1276                 }
 1277         }
 1278         SES_FREE(sdata, bufsiz);
 1279         return (0);
 1280 }
 1281 
 1282 
 1283 /*
 1284  * Routines to parse returned SES data structures.
 1285  * Architecture and compiler independent.
 1286  */
 1287 
 1288 static int
 1289 ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp)
 1290 {
 1291         if (buflen < SES_CFGHDR_MINLEN) {
 1292                 return (-1);
 1293         }
 1294         gget8(buffer, 1, cfp->Nsubenc);
 1295         gget32(buffer, 4, cfp->GenCode);
 1296         return (0);
 1297 }
 1298 
 1299 static int
 1300 ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp)
 1301 {
 1302         int s, off = 8;
 1303         for (s = 0; s < SubEncId; s++) {
 1304                 if (off + 3 > amt)
 1305                         return (-1);
 1306                 off += buffer[off+3] + 4;
 1307         }
 1308         if (off + 3 > amt) {
 1309                 return (-1);
 1310         }
 1311         gget8(buffer, off+1, chp->Subencid);
 1312         gget8(buffer, off+2, chp->Ntypes);
 1313         gget8(buffer, off+3, chp->VEnclen);
 1314         return (0);
 1315 }
 1316 
 1317 static int
 1318 ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp)
 1319 {
 1320         int s, e, enclen, off = 8;
 1321         for (s = 0; s < SubEncId; s++) {
 1322                 if (off + 3 > amt)
 1323                         return (-1);
 1324                 off += buffer[off+3] + 4;
 1325         }
 1326         if (off + 3 > amt) {
 1327                 return (-1);
 1328         }
 1329         gget8(buffer, off+3, enclen);
 1330         off += 4;
 1331         if (off  >= amt)
 1332                 return (-1);
 1333 
 1334         e = off + enclen;
 1335         if (e > amt) {
 1336                 e = amt;
 1337         }
 1338         MEMCPY(cdp, &buffer[off], e - off);
 1339         return (0);
 1340 }
 1341 
 1342 static int
 1343 ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp)
 1344 {
 1345         int s, off = 8;
 1346 
 1347         if (amt < SES_CFGHDR_MINLEN) {
 1348                 return (-1);
 1349         }
 1350         for (s = 0; s < buffer[1]; s++) {
 1351                 if (off + 3 > amt)
 1352                         return (-1);
 1353                 off += buffer[off+3] + 4;
 1354         }
 1355         if (off + 3 > amt) {
 1356                 return (-1);
 1357         }
 1358         off += buffer[off+3] + 4 + (nth * 4);
 1359         if (amt < (off + 4))
 1360                 return (-1);
 1361 
 1362         gget8(buffer, off++, thp->enc_type);
 1363         gget8(buffer, off++, thp->enc_maxelt);
 1364         gget8(buffer, off++, thp->enc_subenc);
 1365         gget8(buffer, off, thp->enc_tlen);
 1366         return (0);
 1367 }
 1368 
 1369 /*
 1370  * This function needs a little explanation.
 1371  *
 1372  * The arguments are:
 1373  *
 1374  *
 1375  *      char *b, int amt
 1376  *
 1377  *              These describes the raw input SES status data and length.
 1378  *
 1379  *      uint8_t *ep
 1380  *
 1381  *              This is a map of the number of types for each element type
 1382  *              in the enclosure.
 1383  *
 1384  *      int elt
 1385  *
 1386  *              This is the element type being sought. If elt is -1,
 1387  *              then overall enclosure status is being sought.
 1388  *
 1389  *      int elm
 1390  *
 1391  *              This is the ordinal Mth element of type elt being sought.
 1392  *
 1393  *      SesComStat *sp
 1394  *
 1395  *              This is the output area to store the status for
 1396  *              the Mth element of type Elt.
 1397  */
 1398 
 1399 static int
 1400 ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
 1401 {
 1402         int idx, i;
 1403 
 1404         /*
 1405          * If it's overall enclosure status being sought, get that.
 1406          * We need at least 2 bytes of status data to get that.
 1407          */
 1408         if (elt == -1) {
 1409                 if (amt < 2)
 1410                         return (-1);
 1411                 gget8(b, 1, sp->comstatus);
 1412                 sp->comstat[0] = 0;
 1413                 sp->comstat[1] = 0;
 1414                 sp->comstat[2] = 0;
 1415                 return (0);
 1416         }
 1417 
 1418         /*
 1419          * Check to make sure that the Mth element is legal for type Elt.
 1420          */
 1421 
 1422         if (elm >= ep[elt])
 1423                 return (-1);
 1424 
 1425         /*
 1426          * Starting at offset 8, start skipping over the storage
 1427          * for the element types we're not interested in.
 1428          */
 1429         for (idx = 8, i = 0; i < elt; i++) {
 1430                 idx += ((ep[i] + 1) * 4);
 1431         }
 1432 
 1433         /*
 1434          * Skip over Overall status for this element type.
 1435          */
 1436         idx += 4;
 1437 
 1438         /*
 1439          * And skip to the index for the Mth element that we're going for.
 1440          */
 1441         idx += (4 * elm);
 1442 
 1443         /*
 1444          * Make sure we haven't overflowed the buffer.
 1445          */
 1446         if (idx+4 > amt)
 1447                 return (-1);
 1448 
 1449         /*
 1450          * Retrieve the status.
 1451          */
 1452         gget8(b, idx++, sp->comstatus);
 1453         gget8(b, idx++, sp->comstat[0]);
 1454         gget8(b, idx++, sp->comstat[1]);
 1455         gget8(b, idx++, sp->comstat[2]);
 1456 #if     0
 1457         PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4);
 1458 #endif
 1459         return (0);
 1460 }
 1461 
 1462 /*
 1463  * This is the mirror function to ses_decode, but we set the 'select'
 1464  * bit for the object which we're interested in. All other objects,
 1465  * after a status fetch, should have that bit off. Hmm. It'd be easy
 1466  * enough to ensure this, so we will.
 1467  */
 1468 
 1469 static int
 1470 ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
 1471 {
 1472         int idx, i;
 1473 
 1474         /*
 1475          * If it's overall enclosure status being sought, get that.
 1476          * We need at least 2 bytes of status data to get that.
 1477          */
 1478         if (elt == -1) {
 1479                 if (amt < 2)
 1480                         return (-1);
 1481                 i = 0;
 1482                 sset8(b, i, 0);
 1483                 sset8(b, i, sp->comstatus & 0xf);
 1484 #if     0
 1485                 PRINTF("set EncStat %x\n", sp->comstatus);
 1486 #endif
 1487                 return (0);
 1488         }
 1489 
 1490         /*
 1491          * Check to make sure that the Mth element is legal for type Elt.
 1492          */
 1493 
 1494         if (elm >= ep[elt])
 1495                 return (-1);
 1496 
 1497         /*
 1498          * Starting at offset 8, start skipping over the storage
 1499          * for the element types we're not interested in.
 1500          */
 1501         for (idx = 8, i = 0; i < elt; i++) {
 1502                 idx += ((ep[i] + 1) * 4);
 1503         }
 1504 
 1505         /*
 1506          * Skip over Overall status for this element type.
 1507          */
 1508         idx += 4;
 1509 
 1510         /*
 1511          * And skip to the index for the Mth element that we're going for.
 1512          */
 1513         idx += (4 * elm);
 1514 
 1515         /*
 1516          * Make sure we haven't overflowed the buffer.
 1517          */
 1518         if (idx+4 > amt)
 1519                 return (-1);
 1520 
 1521         /*
 1522          * Set the status.
 1523          */
 1524         sset8(b, idx, sp->comstatus);
 1525         sset8(b, idx, sp->comstat[0]);
 1526         sset8(b, idx, sp->comstat[1]);
 1527         sset8(b, idx, sp->comstat[2]);
 1528         idx -= 4;
 1529 
 1530 #if     0
 1531         PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n",
 1532             elt, elm, idx, sp->comstatus, sp->comstat[0],
 1533             sp->comstat[1], sp->comstat[2]);
 1534 #endif
 1535 
 1536         /*
 1537          * Now make sure all other 'Select' bits are off.
 1538          */
 1539         for (i = 8; i < amt; i += 4) {
 1540                 if (i != idx)
 1541                         b[i] &= ~0x80;
 1542         }
 1543         /*
 1544          * And make sure the INVOP bit is clear.
 1545          */
 1546         b[2] &= ~0x10;
 1547 
 1548         return (0);
 1549 }
 1550 
 1551 /*
 1552  * SAF-TE Type Device Emulation
 1553  */
 1554 
 1555 static int safte_getconfig(ses_softc_t *);
 1556 static int safte_rdstat(ses_softc_t *, int);;
 1557 static int set_objstat_sel(ses_softc_t *, ses_objstat *, int);
 1558 static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int);
 1559 static void wrslot_stat(ses_softc_t *, int);
 1560 static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int);
 1561 
 1562 #define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
 1563         SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
 1564 /*
 1565  * SAF-TE specific defines- Mandatory ones only...
 1566  */
 1567 
 1568 /*
 1569  * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
 1570  */
 1571 #define SAFTE_RD_RDCFG  0x00    /* read enclosure configuration */
 1572 #define SAFTE_RD_RDESTS 0x01    /* read enclosure status */
 1573 #define SAFTE_RD_RDDSTS 0x04    /* read drive slot status */
 1574 
 1575 /*
 1576  * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
 1577  */
 1578 #define SAFTE_WT_DSTAT  0x10    /* write device slot status */
 1579 #define SAFTE_WT_SLTOP  0x12    /* perform slot operation */
 1580 #define SAFTE_WT_FANSPD 0x13    /* set fan speed */
 1581 #define SAFTE_WT_ACTPWS 0x14    /* turn on/off power supply */
 1582 #define SAFTE_WT_GLOBAL 0x15    /* send global command */
 1583 
 1584 
 1585 #define SAFT_SCRATCH    64
 1586 #define NPSEUDO_THERM   16
 1587 #define NPSEUDO_ALARM   1
 1588 struct scfg {
 1589         /*
 1590          * Cached Configuration
 1591          */
 1592         uint8_t Nfans;          /* Number of Fans */
 1593         uint8_t Npwr;           /* Number of Power Supplies */
 1594         uint8_t Nslots;         /* Number of Device Slots */
 1595         uint8_t DoorLock;       /* Door Lock Installed */
 1596         uint8_t Ntherm;         /* Number of Temperature Sensors */
 1597         uint8_t Nspkrs;         /* Number of Speakers */
 1598         uint8_t Nalarm;         /* Number of Alarms (at least one) */
 1599         /*
 1600          * Cached Flag Bytes for Global Status
 1601          */
 1602         uint8_t flag1;
 1603         uint8_t flag2;
 1604         /*
 1605          * What object index ID is where various slots start.
 1606          */
 1607         uint8_t pwroff;
 1608         uint8_t slotoff;
 1609 #define SAFT_ALARM_OFFSET(cc)   (cc)->slotoff - 1
 1610 };
 1611 
 1612 #define SAFT_FLG1_ALARM         0x1
 1613 #define SAFT_FLG1_GLOBFAIL      0x2
 1614 #define SAFT_FLG1_GLOBWARN      0x4
 1615 #define SAFT_FLG1_ENCPWROFF     0x8
 1616 #define SAFT_FLG1_ENCFANFAIL    0x10
 1617 #define SAFT_FLG1_ENCPWRFAIL    0x20
 1618 #define SAFT_FLG1_ENCDRVFAIL    0x40
 1619 #define SAFT_FLG1_ENCDRVWARN    0x80
 1620 
 1621 #define SAFT_FLG2_LOCKDOOR      0x4
 1622 #define SAFT_PRIVATE            sizeof (struct scfg)
 1623 
 1624 static char *safte_2little = "Too Little Data Returned (%d) at line %d\n";
 1625 #define SAFT_BAIL(r, x, k, l)   \
 1626         if ((r) >= (x)) { \
 1627                 SES_LOG(ssc, safte_2little, x, __LINE__);\
 1628                 SES_FREE((k), (l)); \
 1629                 return (EIO); \
 1630         }
 1631 
 1632 
 1633 static int
 1634 safte_softc_init(ses_softc_t *ssc, int doinit)
 1635 {
 1636         int err, i, r;
 1637         struct scfg *cc;
 1638 
 1639         if (doinit == 0) {
 1640                 if (ssc->ses_nobjects) {
 1641                         if (ssc->ses_objmap) {
 1642                                 SES_FREE(ssc->ses_objmap,
 1643                                     ssc->ses_nobjects * sizeof (encobj));
 1644                                 ssc->ses_objmap = NULL;
 1645                         }
 1646                         ssc->ses_nobjects = 0;
 1647                 }
 1648                 if (ssc->ses_private) {
 1649                         SES_FREE(ssc->ses_private, SAFT_PRIVATE);
 1650                         ssc->ses_private = NULL;
 1651                 }
 1652                 return (0);
 1653         }
 1654 
 1655         if (ssc->ses_private == NULL) {
 1656                 ssc->ses_private = SES_MALLOC(SAFT_PRIVATE);
 1657                 if (ssc->ses_private == NULL) {
 1658                         return (ENOMEM);
 1659                 }
 1660                 MEMZERO(ssc->ses_private, SAFT_PRIVATE);
 1661         }
 1662 
 1663         ssc->ses_nobjects = 0;
 1664         ssc->ses_encstat = 0;
 1665 
 1666         if ((err = safte_getconfig(ssc)) != 0) {
 1667                 return (err);
 1668         }
 1669 
 1670         /*
 1671          * The number of objects here, as well as that reported by the
 1672          * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15)
 1673          * that get reported during READ_BUFFER/READ_ENC_STATUS.
 1674          */
 1675         cc = ssc->ses_private;
 1676         ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock +
 1677             cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM;
 1678         ssc->ses_objmap = (encobj *)
 1679             SES_MALLOC(ssc->ses_nobjects * sizeof (encobj));
 1680         if (ssc->ses_objmap == NULL) {
 1681                 return (ENOMEM);
 1682         }
 1683         MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj));
 1684 
 1685         r = 0;
 1686         /*
 1687          * Note that this is all arranged for the convenience
 1688          * in later fetches of status.
 1689          */
 1690         for (i = 0; i < cc->Nfans; i++)
 1691                 ssc->ses_objmap[r++].enctype = SESTYP_FAN;
 1692         cc->pwroff = (uint8_t) r;
 1693         for (i = 0; i < cc->Npwr; i++)
 1694                 ssc->ses_objmap[r++].enctype = SESTYP_POWER;
 1695         for (i = 0; i < cc->DoorLock; i++)
 1696                 ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK;
 1697         for (i = 0; i < cc->Nspkrs; i++)
 1698                 ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 1699         for (i = 0; i < cc->Ntherm; i++)
 1700                 ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 1701         for (i = 0; i < NPSEUDO_THERM; i++)
 1702                 ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 1703         ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 1704         cc->slotoff = (uint8_t) r;
 1705         for (i = 0; i < cc->Nslots; i++)
 1706                 ssc->ses_objmap[r++].enctype = SESTYP_DEVICE;
 1707         return (0);
 1708 }
 1709 
 1710 static int
 1711 safte_init_enc(ses_softc_t *ssc)
 1712 {
 1713         int err;
 1714         static char cdb0[6] = { SEND_DIAGNOSTIC };
 1715 
 1716         err = ses_runcmd(ssc, cdb0, 6, NULL, 0);
 1717         if (err) {
 1718                 return (err);
 1719         }
 1720         DELAY(5000);
 1721         err = wrbuf16(ssc, SAFTE_WT_GLOBAL, 0, 0, 0, 1);
 1722         return (err);
 1723 }
 1724 
 1725 static int
 1726 safte_get_encstat(ses_softc_t *ssc, int slpflg)
 1727 {
 1728         return (safte_rdstat(ssc, slpflg));
 1729 }
 1730 
 1731 static int
 1732 safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg)
 1733 {
 1734         struct scfg *cc = ssc->ses_private;
 1735         if (cc == NULL)
 1736                 return (0);
 1737         /*
 1738          * Since SAF-TE devices aren't necessarily sticky in terms
 1739          * of state, make our soft copy of enclosure status 'sticky'-
 1740          * that is, things set in enclosure status stay set (as implied
 1741          * by conditions set in reading object status) until cleared.
 1742          */
 1743         ssc->ses_encstat &= ~ALL_ENC_STAT;
 1744         ssc->ses_encstat |= (encstat & ALL_ENC_STAT);
 1745         ssc->ses_encstat |= ENCI_SVALID;
 1746         cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
 1747         if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) {
 1748                 cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL;
 1749         } else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) {
 1750                 cc->flag1 |= SAFT_FLG1_GLOBWARN;
 1751         }
 1752         return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
 1753 }
 1754 
 1755 static int
 1756 safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg)
 1757 {
 1758         int i = (int)obp->obj_id;
 1759 
 1760         if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
 1761             (ssc->ses_objmap[i].svalid) == 0) {
 1762                 int err = safte_rdstat(ssc, slpflg);
 1763                 if (err)
 1764                         return (err);
 1765         }
 1766         obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
 1767         obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
 1768         obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
 1769         obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
 1770         return (0);
 1771 }
 1772 
 1773 
 1774 static int
 1775 safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp)
 1776 {
 1777         int idx, err;
 1778         encobj *ep;
 1779         struct scfg *cc;
 1780 
 1781 
 1782         SES_DLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n",
 1783             (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2],
 1784             obp->cstat[3]);
 1785 
 1786         /*
 1787          * If this is clear, we don't do diddly.
 1788          */
 1789         if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
 1790                 return (0);
 1791         }
 1792 
 1793         err = 0;
 1794         /*
 1795          * Check to see if the common bits are set and do them first.
 1796          */
 1797         if (obp->cstat[0] & ~SESCTL_CSEL) {
 1798                 err = set_objstat_sel(ssc, obp, slp);
 1799                 if (err)
 1800                         return (err);
 1801         }
 1802 
 1803         cc = ssc->ses_private;
 1804         if (cc == NULL)
 1805                 return (0);
 1806 
 1807         idx = (int)obp->obj_id;
 1808         ep = &ssc->ses_objmap[idx];
 1809 
 1810         switch (ep->enctype) {
 1811         case SESTYP_DEVICE:
 1812         {
 1813                 uint8_t slotop = 0;
 1814                 /*
 1815                  * XXX: I should probably cache the previous state
 1816                  * XXX: of SESCTL_DEVOFF so that when it goes from
 1817                  * XXX: true to false I can then set PREPARE FOR OPERATION
 1818                  * XXX: flag in PERFORM SLOT OPERATION write buffer command.
 1819                  */
 1820                 if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
 1821                         slotop |= 0x2;
 1822                 }
 1823                 if (obp->cstat[2] & SESCTL_RQSID) {
 1824                         slotop |= 0x4;
 1825                 }
 1826                 err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff,
 1827                     slotop, slp);
 1828                 if (err)
 1829                         return (err);
 1830                 if (obp->cstat[3] & SESCTL_RQSFLT) {
 1831                         ep->priv |= 0x2;
 1832                 } else {
 1833                         ep->priv &= ~0x2;
 1834                 }
 1835                 if (ep->priv & 0xc6) {
 1836                         ep->priv &= ~0x1;
 1837                 } else {
 1838                         ep->priv |= 0x1;        /* no errors */
 1839                 }
 1840                 wrslot_stat(ssc, slp);
 1841                 break;
 1842         }
 1843         case SESTYP_POWER:
 1844                 if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 1845                         cc->flag1 |= SAFT_FLG1_ENCPWRFAIL;
 1846                 } else {
 1847                         cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
 1848                 }
 1849                 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1850                     cc->flag2, 0, slp);
 1851                 if (err)
 1852                         return (err);
 1853                 if (obp->cstat[3] & SESCTL_RQSTON) {
 1854                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 1855                                 idx - cc->pwroff, 0, 0, slp);
 1856                 } else {
 1857                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 1858                                 idx - cc->pwroff, 0, 1, slp);
 1859                 }
 1860                 break;
 1861         case SESTYP_FAN:
 1862                 if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 1863                         cc->flag1 |= SAFT_FLG1_ENCFANFAIL;
 1864                 } else {
 1865                         cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
 1866                 }
 1867                 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1868                     cc->flag2, 0, slp);
 1869                 if (err)
 1870                         return (err);
 1871                 if (obp->cstat[3] & SESCTL_RQSTON) {
 1872                         uint8_t fsp;
 1873                         if ((obp->cstat[3] & 0x7) == 7) {
 1874                                 fsp = 4;
 1875                         } else if ((obp->cstat[3] & 0x7) == 6) {
 1876                                 fsp = 3;
 1877                         } else if ((obp->cstat[3] & 0x7) == 4) {
 1878                                 fsp = 2;
 1879                         } else {
 1880                                 fsp = 1;
 1881                         }
 1882                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
 1883                 } else {
 1884                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 1885                 }
 1886                 break;
 1887         case SESTYP_DOORLOCK:
 1888                 if (obp->cstat[3] & 0x1) {
 1889                         cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
 1890                 } else {
 1891                         cc->flag2 |= SAFT_FLG2_LOCKDOOR;
 1892                 }
 1893                 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1894                     cc->flag2, 0, slp);
 1895                 break;
 1896         case SESTYP_ALARM:
 1897                 /*
 1898                  * On all nonzero but the 'muted' bit, we turn on the alarm,
 1899                  */
 1900                 obp->cstat[3] &= ~0xa;
 1901                 if (obp->cstat[3] & 0x40) {
 1902                         cc->flag2 &= ~SAFT_FLG1_ALARM;
 1903                 } else if (obp->cstat[3] != 0) {
 1904                         cc->flag2 |= SAFT_FLG1_ALARM;
 1905                 } else {
 1906                         cc->flag2 &= ~SAFT_FLG1_ALARM;
 1907                 }
 1908                 ep->priv = obp->cstat[3];
 1909                 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1910                         cc->flag2, 0, slp);
 1911                 break;
 1912         default:
 1913                 break;
 1914         }
 1915         ep->svalid = 0;
 1916         return (0);
 1917 }
 1918 
 1919 static int
 1920 safte_getconfig(ses_softc_t *ssc)
 1921 {
 1922         struct scfg *cfg;
 1923         int err, amt;
 1924         char *sdata;
 1925         static char cdb[10] =
 1926             { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
 1927 
 1928         cfg = ssc->ses_private;
 1929         if (cfg == NULL)
 1930                 return (ENXIO);
 1931 
 1932         sdata = SES_MALLOC(SAFT_SCRATCH);
 1933         if (sdata == NULL)
 1934                 return (ENOMEM);
 1935 
 1936         amt = SAFT_SCRATCH;
 1937         err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 1938         if (err) {
 1939                 SES_FREE(sdata, SAFT_SCRATCH);
 1940                 return (err);
 1941         }
 1942         amt = SAFT_SCRATCH - amt;
 1943         if (amt < 6) {
 1944                 SES_LOG(ssc, "too little data (%d) for configuration\n", amt);
 1945                 SES_FREE(sdata, SAFT_SCRATCH);
 1946                 return (EIO);
 1947         }
 1948         SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n",
 1949             sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]);
 1950         cfg->Nfans = sdata[0];
 1951         cfg->Npwr = sdata[1];
 1952         cfg->Nslots = sdata[2];
 1953         cfg->DoorLock = sdata[3];
 1954         cfg->Ntherm = sdata[4];
 1955         cfg->Nspkrs = sdata[5];
 1956         cfg->Nalarm = NPSEUDO_ALARM;
 1957         SES_FREE(sdata, SAFT_SCRATCH);
 1958         return (0);
 1959 }
 1960 
 1961 static int
 1962 safte_rdstat(ses_softc_t *ssc, int slpflg)
 1963 {
 1964         int err, oid, r, i, hiwater, nitems, amt;
 1965         uint16_t tempflags;
 1966         size_t buflen;
 1967         uint8_t status, oencstat;
 1968         char *sdata, cdb[10];
 1969         struct scfg *cc = ssc->ses_private;
 1970 
 1971 
 1972         /*
 1973          * The number of objects overstates things a bit,
 1974          * both for the bogus 'thermometer' entries and
 1975          * the drive status (which isn't read at the same
 1976          * time as the enclosure status), but that's okay.
 1977          */
 1978         buflen = 4 * cc->Nslots;
 1979         if (ssc->ses_nobjects > buflen)
 1980                 buflen = ssc->ses_nobjects;
 1981         sdata = SES_MALLOC(buflen);
 1982         if (sdata == NULL)
 1983                 return (ENOMEM);
 1984 
 1985         cdb[0] = READ_BUFFER;
 1986         cdb[1] = 1;
 1987         cdb[2] = SAFTE_RD_RDESTS;
 1988         cdb[3] = 0;
 1989         cdb[4] = 0;
 1990         cdb[5] = 0;
 1991         cdb[6] = 0;
 1992         cdb[7] = (buflen >> 8) & 0xff;
 1993         cdb[8] = buflen & 0xff;
 1994         cdb[9] = 0;
 1995         amt = buflen;
 1996         err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 1997         if (err) {
 1998                 SES_FREE(sdata, buflen);
 1999                 return (err);
 2000         }
 2001         hiwater = buflen - amt;
 2002 
 2003 
 2004         /*
 2005          * invalidate all status bits.
 2006          */
 2007         for (i = 0; i < ssc->ses_nobjects; i++)
 2008                 ssc->ses_objmap[i].svalid = 0;
 2009         oencstat = ssc->ses_encstat & ALL_ENC_STAT;
 2010         ssc->ses_encstat = 0;
 2011 
 2012 
 2013         /*
 2014          * Now parse returned buffer.
 2015          * If we didn't get enough data back,
 2016          * that's considered a fatal error.
 2017          */
 2018         oid = r = 0;
 2019 
 2020         for (nitems = i = 0; i < cc->Nfans; i++) {
 2021                 SAFT_BAIL(r, hiwater, sdata, buflen);
 2022                 /*
 2023                  * 0 = Fan Operational
 2024                  * 1 = Fan is malfunctioning
 2025                  * 2 = Fan is not present
 2026                  * 0x80 = Unknown or Not Reportable Status
 2027                  */
 2028                 ssc->ses_objmap[oid].encstat[1] = 0;    /* resvd */
 2029                 ssc->ses_objmap[oid].encstat[2] = 0;    /* resvd */
 2030                 switch ((int)(uint8_t)sdata[r]) {
 2031                 case 0:
 2032                         nitems++;
 2033                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2034                         /*
 2035                          * We could get fancier and cache
 2036                          * fan speeds that we have set, but
 2037                          * that isn't done now.
 2038                          */
 2039                         ssc->ses_objmap[oid].encstat[3] = 7;
 2040                         break;
 2041 
 2042                 case 1:
 2043                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2044                         /*
 2045                          * FAIL and FAN STOPPED synthesized
 2046                          */
 2047                         ssc->ses_objmap[oid].encstat[3] = 0x40;
 2048                         /*
 2049                          * Enclosure marked with CRITICAL error
 2050                          * if only one fan or no thermometers,
 2051                          * else the NONCRITICAL error is set.
 2052                          */
 2053                         if (cc->Nfans == 1 || cc->Ntherm == 0)
 2054                                 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2055                         else
 2056                                 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2057                         break;
 2058                 case 2:
 2059                         ssc->ses_objmap[oid].encstat[0] =
 2060                             SES_OBJSTAT_NOTINSTALLED;
 2061                         ssc->ses_objmap[oid].encstat[3] = 0;
 2062                         /*
 2063                          * Enclosure marked with CRITICAL error
 2064                          * if only one fan or no thermometers,
 2065                          * else the NONCRITICAL error is set.
 2066                          */
 2067                         if (cc->Nfans == 1)
 2068                                 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2069                         else
 2070                                 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2071                         break;
 2072                 case 0x80:
 2073                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2074                         ssc->ses_objmap[oid].encstat[3] = 0;
 2075                         ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2076                         break;
 2077                 default:
 2078                         ssc->ses_objmap[oid].encstat[0] =
 2079                             SES_OBJSTAT_UNSUPPORTED;
 2080                         SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i,
 2081                             sdata[r] & 0xff);
 2082                         break;
 2083                 }
 2084                 ssc->ses_objmap[oid++].svalid = 1;
 2085                 r++;
 2086         }
 2087 
 2088         /*
 2089          * No matter how you cut it, no cooling elements when there
 2090          * should be some there is critical.
 2091          */
 2092         if (cc->Nfans && nitems == 0) {
 2093                 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2094         }
 2095 
 2096 
 2097         for (i = 0; i < cc->Npwr; i++) {
 2098                 SAFT_BAIL(r, hiwater, sdata, buflen);
 2099                 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2100                 ssc->ses_objmap[oid].encstat[1] = 0;    /* resvd */
 2101                 ssc->ses_objmap[oid].encstat[2] = 0;    /* resvd */
 2102                 ssc->ses_objmap[oid].encstat[3] = 0x20; /* requested on */
 2103                 switch ((uint8_t)sdata[r]) {
 2104                 case 0x00:      /* pws operational and on */
 2105                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2106                         break;
 2107                 case 0x01:      /* pws operational and off */
 2108                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2109                         ssc->ses_objmap[oid].encstat[3] = 0x10;
 2110                         ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2111                         break;
 2112                 case 0x10:      /* pws is malfunctioning and commanded on */
 2113                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2114                         ssc->ses_objmap[oid].encstat[3] = 0x61;
 2115                         ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2116                         break;
 2117 
 2118                 case 0x11:      /* pws is malfunctioning and commanded off */
 2119                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
 2120                         ssc->ses_objmap[oid].encstat[3] = 0x51;
 2121                         ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2122                         break;
 2123                 case 0x20:      /* pws is not present */
 2124                         ssc->ses_objmap[oid].encstat[0] =
 2125                             SES_OBJSTAT_NOTINSTALLED;
 2126                         ssc->ses_objmap[oid].encstat[3] = 0;
 2127                         ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2128                         break;
 2129                 case 0x21:      /* pws is present */
 2130                         /*
 2131                          * This is for enclosures that cannot tell whether the
 2132                          * device is on or malfunctioning, but know that it is
 2133                          * present. Just fall through.
 2134                          */
 2135                         /* FALLTHROUGH */
 2136                 case 0x80:      /* Unknown or Not Reportable Status */
 2137                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2138                         ssc->ses_objmap[oid].encstat[3] = 0;
 2139                         ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2140                         break;
 2141                 default:
 2142                         SES_LOG(ssc, "unknown power supply %d status (0x%x)\n",
 2143                             i, sdata[r] & 0xff);
 2144                         break;
 2145                 }
 2146                 ssc->ses_objmap[oid++].svalid = 1;
 2147                 r++;
 2148         }
 2149 
 2150         /*
 2151          * Skip over Slot SCSI IDs
 2152          */
 2153         r += cc->Nslots;
 2154 
 2155         /*
 2156          * We always have doorlock status, no matter what,
 2157          * but we only save the status if we have one.
 2158          */
 2159         SAFT_BAIL(r, hiwater, sdata, buflen);
 2160         if (cc->DoorLock) {
 2161                 /*
 2162                  * 0 = Door Locked
 2163                  * 1 = Door Unlocked, or no Lock Installed
 2164                  * 0x80 = Unknown or Not Reportable Status
 2165                  */
 2166                 ssc->ses_objmap[oid].encstat[1] = 0;
 2167                 ssc->ses_objmap[oid].encstat[2] = 0;
 2168                 switch ((uint8_t)sdata[r]) {
 2169                 case 0:
 2170                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2171                         ssc->ses_objmap[oid].encstat[3] = 0;
 2172                         break;
 2173                 case 1:
 2174                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2175                         ssc->ses_objmap[oid].encstat[3] = 1;
 2176                         break;
 2177                 case 0x80:
 2178                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2179                         ssc->ses_objmap[oid].encstat[3] = 0;
 2180                         ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2181                         break;
 2182                 default:
 2183                         ssc->ses_objmap[oid].encstat[0] =
 2184                             SES_OBJSTAT_UNSUPPORTED;
 2185                         SES_LOG(ssc, "unknown lock status 0x%x\n",
 2186                             sdata[r] & 0xff);
 2187                         break;
 2188                 }
 2189                 ssc->ses_objmap[oid++].svalid = 1;
 2190         }
 2191         r++;
 2192 
 2193         /*
 2194          * We always have speaker status, no matter what,
 2195          * but we only save the status if we have one.
 2196          */
 2197         SAFT_BAIL(r, hiwater, sdata, buflen);
 2198         if (cc->Nspkrs) {
 2199                 ssc->ses_objmap[oid].encstat[1] = 0;
 2200                 ssc->ses_objmap[oid].encstat[2] = 0;
 2201                 if (sdata[r] == 1) {
 2202                         /*
 2203                          * We need to cache tone urgency indicators.
 2204                          * Someday.
 2205                          */
 2206                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
 2207                         ssc->ses_objmap[oid].encstat[3] = 0x8;
 2208                         ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2209                 } else if (sdata[r] == 0) {
 2210                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2211                         ssc->ses_objmap[oid].encstat[3] = 0;
 2212                 } else {
 2213                         ssc->ses_objmap[oid].encstat[0] =
 2214                             SES_OBJSTAT_UNSUPPORTED;
 2215                         ssc->ses_objmap[oid].encstat[3] = 0;
 2216                         SES_LOG(ssc, "unknown spkr status 0x%x\n",
 2217                             sdata[r] & 0xff);
 2218                 }
 2219                 ssc->ses_objmap[oid++].svalid = 1;
 2220         }
 2221         r++;
 2222 
 2223         for (i = 0; i < cc->Ntherm; i++) {
 2224                 SAFT_BAIL(r, hiwater, sdata, buflen);
 2225                 /*
 2226                  * Status is a range from -10 to 245 deg Celsius,
 2227                  * which we need to normalize to -20 to -245 according
 2228                  * to the latest SCSI spec, which makes little
 2229                  * sense since this would overflow an 8bit value.
 2230                  * Well, still, the base normalization is -20,
 2231                  * not -10, so we have to adjust.
 2232                  *
 2233                  * So what's over and under temperature?
 2234                  * Hmm- we'll state that 'normal' operating
 2235                  * is 10 to 40 deg Celsius.
 2236                  */
 2237 
 2238                 /*
 2239                  * Actually.... All of the units that people out in the world
 2240                  * seem to have do not come even close to setting a value that
 2241                  * complies with this spec.
 2242                  *
 2243                  * The closest explanation I could find was in an
 2244                  * LSI-Logic manual, which seemed to indicate that
 2245                  * this value would be set by whatever the I2C code
 2246                  * would interpolate from the output of an LM75
 2247                  * temperature sensor.
 2248                  *
 2249                  * This means that it is impossible to use the actual
 2250                  * numeric value to predict anything. But we don't want
 2251                  * to lose the value. So, we'll propagate the *uncorrected*
 2252                  * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
 2253                  * temperature flags for warnings.
 2254                  */
 2255                 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL;
 2256                 ssc->ses_objmap[oid].encstat[1] = 0;
 2257                 ssc->ses_objmap[oid].encstat[2] = sdata[r];
 2258                 ssc->ses_objmap[oid].encstat[3] = 0;;
 2259                 ssc->ses_objmap[oid++].svalid = 1;
 2260                 r++;
 2261         }
 2262 
 2263         /*
 2264          * Now, for "pseudo" thermometers, we have two bytes
 2265          * of information in enclosure status- 16 bits. Actually,
 2266          * the MSB is a single TEMP ALERT flag indicating whether
 2267          * any other bits are set, but, thanks to fuzzy thinking,
 2268          * in the SAF-TE spec, this can also be set even if no
 2269          * other bits are set, thus making this really another
 2270          * binary temperature sensor.
 2271          */
 2272 
 2273         SAFT_BAIL(r, hiwater, sdata, buflen);
 2274         tempflags = sdata[r++];
 2275         SAFT_BAIL(r, hiwater, sdata, buflen);
 2276         tempflags |= (tempflags << 8) | sdata[r++];
 2277 
 2278         for (i = 0; i < NPSEUDO_THERM; i++) {
 2279                 ssc->ses_objmap[oid].encstat[1] = 0;
 2280                 if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) {
 2281                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2282                         ssc->ses_objmap[4].encstat[2] = 0xff;
 2283                         /*
 2284                          * Set 'over temperature' failure.
 2285                          */
 2286                         ssc->ses_objmap[oid].encstat[3] = 8;
 2287                         ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2288                 } else {
 2289                         /*
 2290                          * We used to say 'not available' and synthesize a
 2291                          * nominal 30 deg (C)- that was wrong. Actually,
 2292                          * Just say 'OK', and use the reserved value of
 2293                          * zero.
 2294                          */
 2295                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2296                         ssc->ses_objmap[oid].encstat[2] = 0;
 2297                         ssc->ses_objmap[oid].encstat[3] = 0;
 2298                 }
 2299                 ssc->ses_objmap[oid++].svalid = 1;
 2300         }
 2301 
 2302         /*
 2303          * Get alarm status.
 2304          */
 2305         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2306         ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv;
 2307         ssc->ses_objmap[oid++].svalid = 1;
 2308 
 2309         /*
 2310          * Now get drive slot status
 2311          */
 2312         cdb[2] = SAFTE_RD_RDDSTS;
 2313         amt = buflen;
 2314         err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2315         if (err) {
 2316                 SES_FREE(sdata, buflen);
 2317                 return (err);
 2318         }
 2319         hiwater = buflen - amt;
 2320         for (r = i = 0; i < cc->Nslots; i++, r += 4) {
 2321                 SAFT_BAIL(r+3, hiwater, sdata, buflen);
 2322                 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
 2323                 ssc->ses_objmap[oid].encstat[1] = (uint8_t) i;
 2324                 ssc->ses_objmap[oid].encstat[2] = 0;
 2325                 ssc->ses_objmap[oid].encstat[3] = 0;
 2326                 status = sdata[r+3];
 2327                 if ((status & 0x1) == 0) {      /* no device */
 2328                         ssc->ses_objmap[oid].encstat[0] =
 2329                             SES_OBJSTAT_NOTINSTALLED;
 2330                 } else {
 2331                         ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2332                 }
 2333                 if (status & 0x2) {
 2334                         ssc->ses_objmap[oid].encstat[2] = 0x8;
 2335                 }
 2336                 if ((status & 0x4) == 0) {
 2337                         ssc->ses_objmap[oid].encstat[3] = 0x10;
 2338                 }
 2339                 ssc->ses_objmap[oid++].svalid = 1;
 2340         }
 2341         /* see comment below about sticky enclosure status */
 2342         ssc->ses_encstat |= ENCI_SVALID | oencstat;
 2343         SES_FREE(sdata, buflen);
 2344         return (0);
 2345 }
 2346 
 2347 static int
 2348 set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp)
 2349 {
 2350         int idx;
 2351         encobj *ep;
 2352         struct scfg *cc = ssc->ses_private;
 2353 
 2354         if (cc == NULL)
 2355                 return (0);
 2356 
 2357         idx = (int)obp->obj_id;
 2358         ep = &ssc->ses_objmap[idx];
 2359 
 2360         switch (ep->enctype) {
 2361         case SESTYP_DEVICE:
 2362                 if (obp->cstat[0] & SESCTL_PRDFAIL) {
 2363                         ep->priv |= 0x40;
 2364                 }
 2365                 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */
 2366                 if (obp->cstat[0] & SESCTL_DISABLE) {
 2367                         ep->priv |= 0x80;
 2368                         /*
 2369                          * Hmm. Try to set the 'No Drive' flag.
 2370                          * Maybe that will count as a 'disable'.
 2371                          */
 2372                 }
 2373                 if (ep->priv & 0xc6) {
 2374                         ep->priv &= ~0x1;
 2375                 } else {
 2376                         ep->priv |= 0x1;        /* no errors */
 2377                 }
 2378                 wrslot_stat(ssc, slp);
 2379                 break;
 2380         case SESTYP_POWER:
 2381                 /*
 2382                  * Okay- the only one that makes sense here is to
 2383                  * do the 'disable' for a power supply.
 2384                  */
 2385                 if (obp->cstat[0] & SESCTL_DISABLE) {
 2386                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 2387                                 idx - cc->pwroff, 0, 0, slp);
 2388                 }
 2389                 break;
 2390         case SESTYP_FAN:
 2391                 /*
 2392                  * Okay- the only one that makes sense here is to
 2393                  * set fan speed to zero on disable.
 2394                  */
 2395                 if (obp->cstat[0] & SESCTL_DISABLE) {
 2396                         /* remember- fans are the first items, so idx works */
 2397                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 2398                 }
 2399                 break;
 2400         case SESTYP_DOORLOCK:
 2401                 /*
 2402                  * Well, we can 'disable' the lock.
 2403                  */
 2404                 if (obp->cstat[0] & SESCTL_DISABLE) {
 2405                         cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
 2406                         (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 2407                                 cc->flag2, 0, slp);
 2408                 }
 2409                 break;
 2410         case SESTYP_ALARM:
 2411                 /*
 2412                  * Well, we can 'disable' the alarm.
 2413                  */
 2414                 if (obp->cstat[0] & SESCTL_DISABLE) {
 2415                         cc->flag2 &= ~SAFT_FLG1_ALARM;
 2416                         ep->priv |= 0x40;       /* Muted */
 2417                         (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 2418                                 cc->flag2, 0, slp);
 2419                 }
 2420                 break;
 2421         default:
 2422                 break;
 2423         }
 2424         ep->svalid = 0;
 2425         return (0);
 2426 }
 2427 
 2428 /*
 2429  * This function handles all of the 16 byte WRITE BUFFER commands.
 2430  */
 2431 static int
 2432 wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2,
 2433     uint8_t b3, int slp)
 2434 {
 2435         int err, amt;
 2436         char *sdata;
 2437         struct scfg *cc = ssc->ses_private;
 2438         static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
 2439 
 2440         if (cc == NULL)
 2441                 return (0);
 2442 
 2443         sdata = SES_MALLOC(16);
 2444         if (sdata == NULL)
 2445                 return (ENOMEM);
 2446 
 2447         SES_DLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3);
 2448 
 2449         sdata[0] = op;
 2450         sdata[1] = b1;
 2451         sdata[2] = b2;
 2452         sdata[3] = b3;
 2453         MEMZERO(&sdata[4], 12);
 2454         amt = -16;
 2455         err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2456         SES_FREE(sdata, 16);
 2457         return (err);
 2458 }
 2459 
 2460 /*
 2461  * This function updates the status byte for the device slot described.
 2462  *
 2463  * Since this is an optional SAF-TE command, there's no point in
 2464  * returning an error.
 2465  */
 2466 static void
 2467 wrslot_stat(ses_softc_t *ssc, int slp)
 2468 {
 2469         int i, amt;
 2470         encobj *ep;
 2471         char cdb[10], *sdata;
 2472         struct scfg *cc = ssc->ses_private;
 2473 
 2474         if (cc == NULL)
 2475                 return;
 2476 
 2477         SES_DLOG(ssc, "saf_wrslot\n");
 2478         cdb[0] = WRITE_BUFFER;
 2479         cdb[1] = 1;
 2480         cdb[2] = 0;
 2481         cdb[3] = 0;
 2482         cdb[4] = 0;
 2483         cdb[5] = 0;
 2484         cdb[6] = 0;
 2485         cdb[7] = 0;
 2486         cdb[8] = cc->Nslots * 3 + 1;
 2487         cdb[9] = 0;
 2488 
 2489         sdata = SES_MALLOC(cc->Nslots * 3 + 1);
 2490         if (sdata == NULL)
 2491                 return;
 2492         MEMZERO(sdata, cc->Nslots * 3 + 1);
 2493 
 2494         sdata[0] = SAFTE_WT_DSTAT;
 2495         for (i = 0; i < cc->Nslots; i++) {
 2496                 ep = &ssc->ses_objmap[cc->slotoff + i];
 2497                 SES_DLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff);
 2498                 sdata[1 + (3 * i)] = ep->priv & 0xff;
 2499         }
 2500         amt = -(cc->Nslots * 3 + 1);
 2501         (void) ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2502         SES_FREE(sdata, cc->Nslots * 3 + 1);
 2503 }
 2504 
 2505 /*
 2506  * This function issues the "PERFORM SLOT OPERATION" command.
 2507  */
 2508 static int
 2509 perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp)
 2510 {
 2511         int err, amt;
 2512         char *sdata;
 2513         struct scfg *cc = ssc->ses_private;
 2514         static char cdb[10] =
 2515             { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
 2516 
 2517         if (cc == NULL)
 2518                 return (0);
 2519 
 2520         sdata = SES_MALLOC(SAFT_SCRATCH);
 2521         if (sdata == NULL)
 2522                 return (ENOMEM);
 2523         MEMZERO(sdata, SAFT_SCRATCH);
 2524 
 2525         sdata[0] = SAFTE_WT_SLTOP;
 2526         sdata[1] = slot;
 2527         sdata[2] = opflag;
 2528         SES_DLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag);
 2529         amt = -SAFT_SCRATCH;
 2530         err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2531         SES_FREE(sdata, SAFT_SCRATCH);
 2532         return (err);
 2533 }

Cache object: 24befe710245514402c119bd779a307a


[ 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.