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