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

Cache object: 83fb02d5f245473af79bb620e8875338


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