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

Cache object: 41a2eab86df647583c5274e0386b7a86


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