1 /* $NetBSD: ses.c,v 1.41 2009/05/12 13:20:33 cegger Exp $ */
3 * Copyright (C) 2000 National Aeronautics & Space Administration
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. The name of the author may not be used to endorse or promote products
12 * derived from this software without specific prior written permission
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * Author: mjacob@nas.nasa.gov
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: ses.c,v 1.41 2009/05/12 13:20:33 cegger Exp $");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
38 #include <sys/ioctl.h>
39 #include <sys/scsiio.h>
42 #include <sys/malloc.h>
43 #include <sys/errno.h>
44 #include <sys/device.h>
45 #include <sys/disklabel.h>
49 #include <sys/vnode.h>
50 #include <machine/stdarg.h>
52 #include <dev/scsipi/scsipi_all.h>
53 #include <dev/scsipi/scsipi_disk.h>
54 #include <dev/scsipi/scsi_all.h>
55 #include <dev/scsipi/scsi_disk.h>
56 #include <dev/scsipi/scsipiconf.h>
57 #include <dev/scsipi/scsipi_base.h>
58 #include <dev/scsipi/ses.h>
61 * Platform Independent Driver Internal Definitions for SES devices.
73 typedef struct ses_softc ses_softc_t
;
75 int (*softc_init
)(ses_softc_t
*, int);
76 int (*init_enc
)(ses_softc_t
*);
77 int (*get_encstat
)(ses_softc_t
*, int);
78 int (*set_encstat
)(ses_softc_t
*, ses_encstat
, int);
79 int (*get_objstat
)(ses_softc_t
*, ses_objstat
*, int);
80 int (*set_objstat
)(ses_softc_t
*, ses_objstat
*, int);
83 #define ENCI_SVALID 0x80
87 enctype
: 8, /* enclosure type */
88 subenclosure
: 8, /* subenclosure id */
89 svalid
: 1, /* enclosure information valid */
90 priv
: 15; /* private data, per object */
91 uint8_t encstat
[4]; /* state && stats */
94 #define SEN_ID "UNISYS SUN_SEN"
97 static enctyp
ses_type(struct scsipi_inquiry_data
*);
100 /* Forward reference to Enclosure Functions */
101 static int ses_softc_init(ses_softc_t
*, int);
102 static int ses_init_enc(ses_softc_t
*);
103 static int ses_get_encstat(ses_softc_t
*, int);
104 static int ses_set_encstat(ses_softc_t
*, uint8_t, int);
105 static int ses_get_objstat(ses_softc_t
*, ses_objstat
*, int);
106 static int ses_set_objstat(ses_softc_t
*, ses_objstat
*, int);
108 static int safte_softc_init(ses_softc_t
*, int);
109 static int safte_init_enc(ses_softc_t
*);
110 static int safte_get_encstat(ses_softc_t
*, int);
111 static int safte_set_encstat(ses_softc_t
*, uint8_t, int);
112 static int safte_get_objstat(ses_softc_t
*, ses_objstat
*, int);
113 static int safte_set_objstat(ses_softc_t
*, ses_objstat
*, int);
116 * Platform implementation defines/functions for SES internal kernel stuff
119 #define STRNCMP strncmp
120 #define PRINTF printf
121 #define SES_LOG ses_log
122 #if defined(DEBUG) || defined(SCSIDEBUG)
123 #define SES_VLOG ses_log
125 #define SES_VLOG if (0) ses_log
127 #define SES_MALLOC(amt) malloc(amt, M_DEVBUF, M_NOWAIT)
128 #define SES_FREE(ptr, amt) free(ptr, M_DEVBUF)
129 #define MEMZERO(dest, amt) memset(dest, 0, amt)
130 #define MEMCPY(dest, src, amt) memcpy(dest, src, amt)
131 #define RECEIVE_DIAGNOSTIC 0x1c
132 #define SEND_DIAGNOSTIC 0x1d
133 #define WRITE_BUFFER 0x3b
134 #define READ_BUFFER 0x3c
136 static dev_type_open(sesopen
);
137 static dev_type_close(sesclose
);
138 static dev_type_ioctl(sesioctl
);
140 const struct cdevsw ses_cdevsw
= {
141 sesopen
, sesclose
, noread
, nowrite
, sesioctl
,
142 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
145 static int ses_runcmd(struct ses_softc
*, char *, int, char *, int *);
146 static void ses_log(struct ses_softc
*, const char *, ...)
147 __attribute__((__format__(__printf__
, 2, 3)));
150 * General NetBSD kernel stuff.
154 struct device sc_device
;
155 struct scsipi_periph
*sc_periph
;
156 enctyp ses_type
; /* type of enclosure */
157 encvec ses_vec
; /* vector to handlers */
158 void * ses_private
; /* per-type private data */
159 encobj
* ses_objmap
; /* objects */
160 u_int32_t ses_nobjects
; /* number of objects */
161 ses_encstat ses_encstat
; /* overall status */
164 #define SES_FLAG_INVALID 0x01
165 #define SES_FLAG_OPEN 0x02
166 #define SES_FLAG_INITIALIZED 0x04
168 #define SESUNIT(x) (minor((x)))
170 static int ses_match(device_t
, cfdata_t
, void *);
171 static void ses_attach(device_t
, device_t
, void *);
172 static enctyp
ses_device_type(struct scsipibus_attach_args
*);
174 CFATTACH_DECL(ses
, sizeof (struct ses_softc
),
175 ses_match
, ses_attach
, NULL
, NULL
);
177 extern struct cfdriver ses_cd
;
179 static const struct scsipi_periphsw ses_switch
= {
187 ses_match(device_t parent
, cfdata_t match
,
190 struct scsipibus_attach_args
*sa
= aux
;
192 switch (ses_device_type(sa
)) {
197 case SES_SES_PASSTHROUGH
:
199 * For these devices, it's a perfect match.
209 * Complete the attachment.
211 * We have to repeat the rerun of INQUIRY data as above because
212 * it's not until the return from the match routine that we have
213 * the softc available to set stuff in.
216 ses_attach(device_t parent
, device_t self
, void *aux
)
219 struct ses_softc
*softc
= device_private(self
);
220 struct scsipibus_attach_args
*sa
= aux
;
221 struct scsipi_periph
*periph
= sa
->sa_periph
;
223 SC_DEBUG(periph
, SCSIPI_DB2
, ("ssattach: "));
224 softc
->sc_periph
= periph
;
225 periph
->periph_dev
= &softc
->sc_device
;
226 periph
->periph_switch
= &ses_switch
;
227 periph
->periph_openings
= 1;
229 softc
->ses_type
= ses_device_type(sa
);
230 switch (softc
->ses_type
) {
233 case SES_SES_PASSTHROUGH
:
234 softc
->ses_vec
.softc_init
= ses_softc_init
;
235 softc
->ses_vec
.init_enc
= ses_init_enc
;
236 softc
->ses_vec
.get_encstat
= ses_get_encstat
;
237 softc
->ses_vec
.set_encstat
= ses_set_encstat
;
238 softc
->ses_vec
.get_objstat
= ses_get_objstat
;
239 softc
->ses_vec
.set_objstat
= ses_set_objstat
;
242 softc
->ses_vec
.softc_init
= safte_softc_init
;
243 softc
->ses_vec
.init_enc
= safte_init_enc
;
244 softc
->ses_vec
.get_encstat
= safte_get_encstat
;
245 softc
->ses_vec
.set_encstat
= safte_set_encstat
;
246 softc
->ses_vec
.get_objstat
= safte_get_objstat
;
247 softc
->ses_vec
.set_objstat
= safte_set_objstat
;
256 switch (softc
->ses_type
) {
259 tname
= "No SES device";
262 tname
= "SCSI-2 SES Device";
265 tname
= "SCSI-3 SES Device";
267 case SES_SES_PASSTHROUGH
:
268 tname
= "SES Passthrough Device";
271 tname
= "UNISYS SEN Device (NOT HANDLED YET)";
274 tname
= "SAF-TE Compliant Device";
277 printf("\n%s: %s\n", device_xname(&softc
->sc_device
), tname
);
282 ses_device_type(struct scsipibus_attach_args
*sa
)
284 struct scsipi_inquiry_data
*inqp
= sa
->sa_inqptr
;
289 return (ses_type(inqp
));
293 sesopen(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
295 struct ses_softc
*softc
;
299 softc
= device_lookup_private(&ses_cd
, unit
);
303 if (softc
->ses_flags
& SES_FLAG_INVALID
) {
307 if (softc
->ses_flags
& SES_FLAG_OPEN
) {
311 if (softc
->ses_vec
.softc_init
== NULL
) {
315 error
= scsipi_adapter_addref(
316 softc
->sc_periph
->periph_channel
->chan_adapter
);
321 softc
->ses_flags
|= SES_FLAG_OPEN
;
322 if ((softc
->ses_flags
& SES_FLAG_INITIALIZED
) == 0) {
323 error
= (*softc
->ses_vec
.softc_init
)(softc
, 1);
325 softc
->ses_flags
&= ~SES_FLAG_OPEN
;
327 softc
->ses_flags
|= SES_FLAG_INITIALIZED
;
335 sesclose(dev_t dev
, int flags
, int fmt
,
338 struct ses_softc
*softc
;
342 softc
= device_lookup_private(&ses_cd
, unit
);
346 scsipi_wait_drain(softc
->sc_periph
);
347 scsipi_adapter_delref(softc
->sc_periph
->periph_channel
->chan_adapter
);
348 softc
->ses_flags
&= ~SES_FLAG_OPEN
;
353 sesioctl(dev_t dev
, u_long cmd
, void *arg_addr
, int flag
, struct lwp
*l
)
357 ses_object obj
, *uobj
;
358 struct ses_softc
*ssc
= device_lookup_private(&ses_cd
, SESUNIT(dev
));
364 addr
= *((void **) arg_addr
);
368 SC_DEBUG(ssc
->sc_periph
, SCSIPI_DB2
, ("sesioctl 0x%lx ", cmd
));
371 * Now check to see whether we're initialized or not.
373 if ((ssc
->ses_flags
& SES_FLAG_INITIALIZED
) == 0) {
380 * If this command can change the device's state,
381 * we must have the device open for writing.
385 case SESIOC_GETOBJMAP
:
386 case SESIOC_GETENCSTAT
:
387 case SESIOC_GETOBJSTAT
:
390 if ((flag
& FWRITE
) == 0) {
399 error
= copyout(&ssc
->ses_nobjects
, addr
,
400 sizeof (ssc
->ses_nobjects
));
403 case SESIOC_GETOBJMAP
:
406 for (uobj
= addr
, i
= 0; i
!= ssc
->ses_nobjects
; i
++, uobj
++) {
408 obj
.subencid
= ssc
->ses_objmap
[i
].subenclosure
;
409 obj
.object_type
= ssc
->ses_objmap
[i
].enctype
;
410 error
= copyout(&obj
, uobj
, sizeof (ses_object
));
417 case SESIOC_GETENCSTAT
:
420 error
= (*ssc
->ses_vec
.get_encstat
)(ssc
, 1);
423 tmp
= ssc
->ses_encstat
& ~ENCI_SVALID
;
424 error
= copyout(&tmp
, addr
, sizeof (ses_encstat
));
425 ssc
->ses_encstat
= tmp
;
428 case SESIOC_SETENCSTAT
:
431 error
= copyin(addr
, &tmp
, sizeof (ses_encstat
));
434 error
= (*ssc
->ses_vec
.set_encstat
)(ssc
, tmp
, 1);
437 case SESIOC_GETOBJSTAT
:
440 error
= copyin(addr
, &objs
, sizeof (ses_objstat
));
443 if (objs
.obj_id
>= ssc
->ses_nobjects
) {
447 error
= (*ssc
->ses_vec
.get_objstat
)(ssc
, &objs
, 1);
450 error
= copyout(&objs
, addr
, sizeof (ses_objstat
));
452 * Always (for now) invalidate entry.
454 ssc
->ses_objmap
[objs
.obj_id
].svalid
= 0;
457 case SESIOC_SETOBJSTAT
:
460 error
= copyin(addr
, &objs
, sizeof (ses_objstat
));
464 if (objs
.obj_id
>= ssc
->ses_nobjects
) {
468 error
= (*ssc
->ses_vec
.set_objstat
)(ssc
, &objs
, 1);
471 * Always (for now) invalidate entry.
473 ssc
->ses_objmap
[objs
.obj_id
].svalid
= 0;
478 error
= (*ssc
->ses_vec
.init_enc
)(ssc
);
482 error
= scsipi_do_ioctl(ssc
->sc_periph
,
483 dev
, cmd
, arg_addr
, flag
, l
);
490 ses_runcmd(struct ses_softc
*ssc
, char *cdb
, int cdbl
, char *dptr
, int *dlenp
)
492 struct scsipi_generic sgen
;
496 if ((dl
= *dlenp
) < 0) {
498 flg
= XS_CTL_DATA_OUT
;
500 flg
= XS_CTL_DATA_IN
;
507 if (cdbl
> sizeof (struct scsipi_generic
)) {
508 cdbl
= sizeof (struct scsipi_generic
);
510 memcpy(&sgen
, cdb
, cdbl
);
512 flg
|= XS_CTL_SILENT
;
514 error
= scsipi_command(ssc
->sc_periph
, &sgen
, cdbl
,
515 (u_char
*) dptr
, dl
, SCSIPIRETRIES
, 30000, NULL
, flg
);
517 if (error
== 0 && dptr
)
524 ses_log(struct ses_softc
*ssc
, const char *fmt
, ...)
528 printf("%s: ", device_xname(&ssc
->sc_device
));
535 * The code after this point runs on many platforms,
536 * so forgive the slightly awkward and nonconforming
541 * Is this a device that supports enclosure services?
543 * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's
544 * an SES device. If it happens to be an old UNISYS SEN device, we can
548 #define SAFTE_START 44
550 #define SAFTE_LEN SAFTE_END-SAFTE_START
553 ses_type(struct scsipi_inquiry_data
*inqp
)
555 size_t given_len
= inqp
->additional_length
+ 4;
557 if (given_len
< 8+SEN_ID_LEN
)
560 if ((inqp
->device
& SID_TYPE
) == T_ENCLOSURE
) {
561 if (STRNCMP(inqp
->vendor
, SEN_ID
, SEN_ID_LEN
) == 0) {
563 } else if ((inqp
->version
& SID_ANSII
) > 2) {
566 return (SES_SES_SCSI2
);
571 #ifdef SES_ENABLE_PASSTHROUGH
572 if ((inqp
->flags2
& SID_EncServ
) && (inqp
->version
& SID_ANSII
) >= 2) {
574 * PassThrough Device.
576 return (SES_SES_PASSTHROUGH
);
581 * The comparison is short for a reason-
582 * some vendors were chopping it short.
585 if (given_len
< SAFTE_END
- 2) {
589 if (STRNCMP((char *)&inqp
->vendor_specific
[8], "SAF-TE",
590 SAFTE_LEN
- 2) == 0) {
598 * SES Native Type Device Support
602 * SES Diagnostic Page Codes
608 #define SesStatusPage SesControlPage
611 #define SesStringIn SesStringOut
613 #define SesThresholdIn SesThresholdOut
615 #define SesArrayStatus SesArrayControl
616 SesElementDescriptor
,
625 * Minimum amount of data, starting from byte 0, to have
628 #define SES_CFGHDR_MINLEN 12
631 * Minimum amount of data, starting from byte 0, to have
632 * the config header and one enclosure header.
634 #define SES_ENCHDR_MINLEN 48
637 * Take this value, subtract it from VEnclen and you know
638 * the length of the vendor unique bytes.
640 #define SES_ENCHDR_VMIN 36
643 * SES Data Structures
647 uint32_t GenCode
; /* Generation Code */
648 uint8_t Nsubenc
; /* Number of Subenclosures */
652 uint8_t Subencid
; /* SubEnclosure Identifier */
653 uint8_t Ntypes
; /* # of supported types */
654 uint8_t VEnclen
; /* Enclosure Descriptor Length */
658 uint8_t encWWN
[8]; /* XXX- Not Right Yet */
666 uint8_t enc_type
; /* type of element */
667 uint8_t enc_maxelt
; /* maximum supported */
668 uint8_t enc_subenc
; /* in SubEnc # N */
669 uint8_t enc_tlen
; /* Type Descriptor Text Length */
683 uint8_t ses_ntypes
; /* total number of types supported */
686 * We need to keep a type index as well as an
687 * object index for each object in an enclosure.
689 struct typidx
*ses_typidx
;
692 * We also need to keep track of the number of elements
693 * per type of element. This is needed later so that we
694 * can find precisely in the returned status data the
695 * status for the Nth element of the Kth type.
697 uint8_t * ses_eltmap
;
702 * (de)canonicalization defines
704 #define sbyte(x, byte) ((((uint32_t)(x)) >> (byte * 8)) & 0xff)
705 #define sbit(x, bit) (((uint32_t)(x)) << bit)
706 #define sset8(outp, idx, sval) (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
708 #define sset16(outp, idx, sval) \
709 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
710 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
713 #define sset24(outp, idx, sval) \
714 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
715 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
716 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
719 #define sset32(outp, idx, sval) \
720 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \
721 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
722 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
723 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
725 #define gbyte(x, byte) ((((uint32_t)(x)) & 0xff) << (byte * 8))
726 #define gbit(lv, in, idx, shft, mask) lv = ((in[idx] >> shft) & mask)
727 #define sget8(inp, idx, lval) lval = (((uint8_t *)(inp))[idx++])
728 #define gget8(inp, idx, lval) lval = (((uint8_t *)(inp))[idx])
730 #define sget16(inp, idx, lval) \
731 lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
732 (((uint8_t *)(inp))[idx+1]), idx += 2
734 #define gget16(inp, idx, lval) \
735 lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
736 (((uint8_t *)(inp))[idx+1])
738 #define sget24(inp, idx, lval) \
739 lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
740 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
741 (((uint8_t *)(inp))[idx+2]), idx += 3
743 #define gget24(inp, idx, lval) \
744 lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
745 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
746 (((uint8_t *)(inp))[idx+2])
748 #define sget32(inp, idx, lval) \
749 lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
750 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
751 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
752 (((uint8_t *)(inp))[idx+3]), idx += 4
754 #define gget32(inp, idx, lval) \
755 lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
756 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
757 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
758 (((uint8_t *)(inp))[idx+3])
761 #define CFLEN (256 + SES_ENCHDR_MINLEN)
764 * Routines specific && private to SES only
767 static int ses_getconfig(ses_softc_t
*);
768 static int ses_getputstat(ses_softc_t
*, int, SesComStat
*, int, int);
769 static int ses_cfghdr(uint8_t *, int, SesCfgHdr
*);
770 static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr
*);
771 static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc
*);
772 static int ses_getthdr(uint8_t *, int, int, SesThdr
*);
773 static int ses_decode(char *, int, uint8_t *, int, int, SesComStat
*);
774 static int ses_encode(char *, int, uint8_t *, int, int, SesComStat
*);
777 ses_softc_init(ses_softc_t
*ssc
, int doinit
)
781 if (ssc
->ses_nobjects
) {
782 SES_FREE(ssc
->ses_objmap
,
783 ssc
->ses_nobjects
* sizeof (encobj
));
784 ssc
->ses_objmap
= NULL
;
786 if ((cc
= ssc
->ses_private
) != NULL
) {
787 if (cc
->ses_eltmap
&& cc
->ses_ntypes
) {
788 SES_FREE(cc
->ses_eltmap
, cc
->ses_ntypes
);
789 cc
->ses_eltmap
= NULL
;
792 if (cc
->ses_typidx
&& ssc
->ses_nobjects
) {
793 SES_FREE(cc
->ses_typidx
,
794 ssc
->ses_nobjects
* sizeof (struct typidx
));
795 cc
->ses_typidx
= NULL
;
797 SES_FREE(cc
, sizeof (struct sscfg
));
798 ssc
->ses_private
= NULL
;
800 ssc
->ses_nobjects
= 0;
803 if (ssc
->ses_private
== NULL
) {
804 ssc
->ses_private
= SES_MALLOC(sizeof (struct sscfg
));
806 if (ssc
->ses_private
== NULL
) {
809 ssc
->ses_nobjects
= 0;
810 ssc
->ses_encstat
= 0;
811 return (ses_getconfig(ssc
));
815 ses_init_enc(ses_softc_t
*ssc
)
821 ses_get_encstat(ses_softc_t
*ssc
, int slpflag
)
826 if ((status
= ses_getputstat(ssc
, -1, &ComStat
, slpflag
, 1)) != 0) {
829 ssc
->ses_encstat
= ComStat
.comstatus
| ENCI_SVALID
;
834 ses_set_encstat(ses_softc_t
*ssc
, uint8_t encstat
, int slpflag
)
839 ComStat
.comstatus
= encstat
& 0xf;
840 if ((status
= ses_getputstat(ssc
, -1, &ComStat
, slpflag
, 0)) != 0) {
843 ssc
->ses_encstat
= encstat
& 0xf; /* note no SVALID set */
848 ses_get_objstat(ses_softc_t
*ssc
, ses_objstat
*obp
, int slpflag
)
850 int i
= (int)obp
->obj_id
;
852 if (ssc
->ses_objmap
[i
].svalid
== 0) {
854 int err
= ses_getputstat(ssc
, i
, &ComStat
, slpflag
, 1);
857 ssc
->ses_objmap
[i
].encstat
[0] = ComStat
.comstatus
;
858 ssc
->ses_objmap
[i
].encstat
[1] = ComStat
.comstat
[0];
859 ssc
->ses_objmap
[i
].encstat
[2] = ComStat
.comstat
[1];
860 ssc
->ses_objmap
[i
].encstat
[3] = ComStat
.comstat
[2];
861 ssc
->ses_objmap
[i
].svalid
= 1;
863 obp
->cstat
[0] = ssc
->ses_objmap
[i
].encstat
[0];
864 obp
->cstat
[1] = ssc
->ses_objmap
[i
].encstat
[1];
865 obp
->cstat
[2] = ssc
->ses_objmap
[i
].encstat
[2];
866 obp
->cstat
[3] = ssc
->ses_objmap
[i
].encstat
[3];
871 ses_set_objstat(ses_softc_t
*ssc
, ses_objstat
*obp
, int slpflag
)
876 * If this is clear, we don't do diddly.
878 if ((obp
->cstat
[0] & SESCTL_CSEL
) == 0) {
881 ComStat
.comstatus
= obp
->cstat
[0];
882 ComStat
.comstat
[0] = obp
->cstat
[1];
883 ComStat
.comstat
[1] = obp
->cstat
[2];
884 ComStat
.comstat
[2] = obp
->cstat
[3];
885 err
= ses_getputstat(ssc
, (int)obp
->obj_id
, &ComStat
, slpflag
, 0);
886 ssc
->ses_objmap
[(int)obp
->obj_id
].svalid
= 0;
891 ses_getconfig(ses_softc_t
*ssc
)
898 int err
, amt
, i
, nobj
, ntype
, maxima
;
899 char storage
[CFLEN
], *sdata
;
900 static char cdb
[6] = {
901 RECEIVE_DIAGNOSTIC
, 0x1, SesConfigPage
, SCSZ
>> 8, SCSZ
& 0xff, 0
904 cc
= ssc
->ses_private
;
909 sdata
= SES_MALLOC(SCSZ
);
914 err
= ses_runcmd(ssc
, cdb
, 6, sdata
, &amt
);
916 SES_FREE(sdata
, SCSZ
);
921 if (ses_cfghdr((uint8_t *) sdata
, amt
, &cf
)) {
922 SES_LOG(ssc
, "Unable to parse SES Config Header\n");
923 SES_FREE(sdata
, SCSZ
);
926 if (amt
< SES_ENCHDR_MINLEN
) {
927 SES_LOG(ssc
, "runt enclosure length (%d)\n", amt
);
928 SES_FREE(sdata
, SCSZ
);
932 SES_VLOG(ssc
, "GenCode %x %d Subenclosures\n", cf
.GenCode
, cf
.Nsubenc
);
935 * Now waltz through all the subenclosures toting up the
936 * number of types available in each. For this, we only
937 * really need the enclosure header. However, we get the
938 * enclosure descriptor for debug purposes, as well
939 * as self-consistency checking purposes.
942 maxima
= cf
.Nsubenc
+ 1;
943 cdp
= (SesEncDesc
*) storage
;
944 for (ntype
= i
= 0; i
< maxima
; i
++) {
945 MEMZERO((void *)cdp
, sizeof (*cdp
));
946 if (ses_enchdr((uint8_t *) sdata
, amt
, i
, &hd
)) {
947 SES_LOG(ssc
, "Cannot Extract Enclosure Header %d\n", i
);
948 SES_FREE(sdata
, SCSZ
);
951 SES_VLOG(ssc
, " SubEnclosure ID %d, %d Types With this ID, En"
952 "closure Length %d\n", hd
.Subencid
, hd
.Ntypes
, hd
.VEnclen
);
954 if (ses_encdesc((uint8_t *)sdata
, amt
, i
, cdp
)) {
955 SES_LOG(ssc
, "Can't get Enclosure Descriptor %d\n", i
);
956 SES_FREE(sdata
, SCSZ
);
959 SES_VLOG(ssc
, " WWN: %02x%02x%02x%02x%02x%02x%02x%02x\n",
960 cdp
->encWWN
[0], cdp
->encWWN
[1], cdp
->encWWN
[2],
961 cdp
->encWWN
[3], cdp
->encWWN
[4], cdp
->encWWN
[5],
962 cdp
->encWWN
[6], cdp
->encWWN
[7]);
967 * Now waltz through all the types that are available, getting
968 * the type header so we can start adding up the number of
971 for (nobj
= i
= 0; i
< ntype
; i
++) {
972 if (ses_getthdr((uint8_t *)sdata
, amt
, i
, &thdr
)) {
973 SES_LOG(ssc
, "Can't get Enclosure Type Header %d\n", i
);
974 SES_FREE(sdata
, SCSZ
);
977 SES_LOG(ssc
, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
978 "%d, Text Length %d\n", i
, thdr
.enc_type
, thdr
.enc_maxelt
,
979 thdr
.enc_subenc
, thdr
.enc_tlen
);
980 nobj
+= thdr
.enc_maxelt
;
985 * Now allocate the object array and type map.
988 ssc
->ses_objmap
= SES_MALLOC(nobj
* sizeof (encobj
));
989 cc
->ses_typidx
= SES_MALLOC(nobj
* sizeof (struct typidx
));
990 cc
->ses_eltmap
= SES_MALLOC(ntype
);
992 if (ssc
->ses_objmap
== NULL
|| cc
->ses_typidx
== NULL
||
993 cc
->ses_eltmap
== NULL
) {
994 if (ssc
->ses_objmap
) {
995 SES_FREE(ssc
->ses_objmap
, (nobj
* sizeof (encobj
)));
996 ssc
->ses_objmap
= NULL
;
998 if (cc
->ses_typidx
) {
999 SES_FREE(cc
->ses_typidx
,
1000 (nobj
* sizeof (struct typidx
)));
1001 cc
->ses_typidx
= NULL
;
1003 if (cc
->ses_eltmap
) {
1004 SES_FREE(cc
->ses_eltmap
, ntype
);
1005 cc
->ses_eltmap
= NULL
;
1007 SES_FREE(sdata
, SCSZ
);
1010 MEMZERO(ssc
->ses_objmap
, nobj
* sizeof (encobj
));
1011 MEMZERO(cc
->ses_typidx
, nobj
* sizeof (struct typidx
));
1012 MEMZERO(cc
->ses_eltmap
, ntype
);
1013 cc
->ses_ntypes
= (uint8_t) ntype
;
1014 ssc
->ses_nobjects
= nobj
;
1017 * Now waltz through the # of types again to fill in the types
1018 * (and subenclosure ids) of the allocated objects.
1021 for (i
= 0; i
< ntype
; i
++) {
1023 if (ses_getthdr((uint8_t *)sdata
, amt
, i
, &thdr
)) {
1026 cc
->ses_eltmap
[i
] = thdr
.enc_maxelt
;
1027 for (j
= 0; j
< thdr
.enc_maxelt
; j
++) {
1028 cc
->ses_typidx
[nobj
].ses_tidx
= i
;
1029 cc
->ses_typidx
[nobj
].ses_oidx
= j
;
1030 ssc
->ses_objmap
[nobj
].subenclosure
= thdr
.enc_subenc
;
1031 ssc
->ses_objmap
[nobj
++].enctype
= thdr
.enc_type
;
1034 SES_FREE(sdata
, SCSZ
);
1039 ses_getputstat(ses_softc_t
*ssc
, int objid
, SesComStat
*sp
, int slp
,
1043 int err
, amt
, bufsiz
, tidx
, oidx
;
1044 char cdb
[6], *sdata
;
1046 cc
= ssc
->ses_private
;
1052 * If we're just getting overall enclosure status,
1053 * we only need 2 bytes of data storage.
1055 * If we're getting anything else, we know how much
1056 * storage we need by noting that starting at offset
1057 * 8 in returned data, all object status bytes are 4
1058 * bytes long, and are stored in chunks of types(M)
1059 * and nth+1 instances of type M.
1064 bufsiz
= (ssc
->ses_nobjects
* 4) + (cc
->ses_ntypes
* 4) + 8;
1066 sdata
= SES_MALLOC(bufsiz
);
1070 cdb
[0] = RECEIVE_DIAGNOSTIC
;
1072 cdb
[2] = SesStatusPage
;
1073 cdb
[3] = bufsiz
>> 8;
1074 cdb
[4] = bufsiz
& 0xff;
1077 err
= ses_runcmd(ssc
, cdb
, 6, sdata
, &amt
);
1079 SES_FREE(sdata
, bufsiz
);
1088 tidx
= cc
->ses_typidx
[objid
].ses_tidx
;
1089 oidx
= cc
->ses_typidx
[objid
].ses_oidx
;
1092 if (ses_decode(sdata
, amt
, cc
->ses_eltmap
, tidx
, oidx
, sp
)) {
1096 if (ses_encode(sdata
, amt
, cc
->ses_eltmap
, tidx
, oidx
, sp
)) {
1099 cdb
[0] = SEND_DIAGNOSTIC
;
1102 cdb
[3] = bufsiz
>> 8;
1103 cdb
[4] = bufsiz
& 0xff;
1106 err
= ses_runcmd(ssc
, cdb
, 6, sdata
, &amt
);
1109 SES_FREE(sdata
, bufsiz
);
1115 * Routines to parse returned SES data structures.
1116 * Architecture and compiler independent.
1120 ses_cfghdr(uint8_t *buffer
, int buflen
, SesCfgHdr
*cfp
)
1122 if (buflen
< SES_CFGHDR_MINLEN
) {
1125 gget8(buffer
, 1, cfp
->Nsubenc
);
1126 gget32(buffer
, 4, cfp
->GenCode
);
1131 ses_enchdr(uint8_t *buffer
, int amt
, uint8_t SubEncId
, SesEncHdr
*chp
)
1134 for (s
= 0; s
< SubEncId
; s
++) {
1137 off
+= buffer
[off
+3] + 4;
1139 if (off
+ 3 > amt
) {
1142 gget8(buffer
, off
+1, chp
->Subencid
);
1143 gget8(buffer
, off
+2, chp
->Ntypes
);
1144 gget8(buffer
, off
+3, chp
->VEnclen
);
1149 ses_encdesc(uint8_t *buffer
, int amt
, uint8_t SubEncId
, SesEncDesc
*cdp
)
1151 int s
, e
, enclen
, off
= 8;
1152 for (s
= 0; s
< SubEncId
; s
++) {
1155 off
+= buffer
[off
+3] + 4;
1157 if (off
+ 3 > amt
) {
1160 gget8(buffer
, off
+3, enclen
);
1169 MEMCPY(cdp
, &buffer
[off
], e
- off
);
1174 ses_getthdr(uint8_t *buffer
, int amt
, int nth
, SesThdr
*thp
)
1178 if (amt
< SES_CFGHDR_MINLEN
) {
1181 for (s
= 0; s
< buffer
[1]; s
++) {
1184 off
+= buffer
[off
+3] + 4;
1186 if (off
+ 3 > amt
) {
1189 off
+= buffer
[off
+3] + 4 + (nth
* 4);
1190 if (amt
< (off
+ 4))
1193 gget8(buffer
, off
++, thp
->enc_type
);
1194 gget8(buffer
, off
++, thp
->enc_maxelt
);
1195 gget8(buffer
, off
++, thp
->enc_subenc
);
1196 gget8(buffer
, off
, thp
->enc_tlen
);
1201 * This function needs a little explanation.
1203 * The arguments are:
1208 * These describes the raw input SES status data and length.
1212 * This is a map of the number of types for each element type
1217 * This is the element type being sought. If elt is -1,
1218 * then overall enclosure status is being sought.
1222 * This is the ordinal Mth element of type elt being sought.
1226 * This is the output area to store the status for
1227 * the Mth element of type Elt.
1231 ses_decode(char *b
, int amt
, uint8_t *ep
, int elt
, int elm
, SesComStat
*sp
)
1236 * If it's overall enclosure status being sought, get that.
1237 * We need at least 2 bytes of status data to get that.
1242 gget8(b
, 1, sp
->comstatus
);
1250 * Check to make sure that the Mth element is legal for type Elt.
1257 * Starting at offset 8, start skipping over the storage
1258 * for the element types we're not interested in.
1260 for (idx
= 8, i
= 0; i
< elt
; i
++) {
1261 idx
+= ((ep
[i
] + 1) * 4);
1265 * Skip over Overall status for this element type.
1270 * And skip to the index for the Mth element that we're going for.
1275 * Make sure we haven't overflowed the buffer.
1281 * Retrieve the status.
1283 gget8(b
, idx
++, sp
->comstatus
);
1284 gget8(b
, idx
++, sp
->comstat
[0]);
1285 gget8(b
, idx
++, sp
->comstat
[1]);
1286 gget8(b
, idx
++, sp
->comstat
[2]);
1288 PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt
, elm
, idx
-4);
1294 * This is the mirror function to ses_decode, but we set the 'select'
1295 * bit for the object which we're interested in. All other objects,
1296 * after a status fetch, should have that bit off. Hmm. It'd be easy
1297 * enough to ensure this, so we will.
1301 ses_encode(char *b
, int amt
, uint8_t *ep
, int elt
, int elm
, SesComStat
*sp
)
1306 * If it's overall enclosure status being sought, get that.
1307 * We need at least 2 bytes of status data to get that.
1314 sset8(b
, i
, sp
->comstatus
& 0xf);
1316 PRINTF("set EncStat %x\n", sp
->comstatus
);
1322 * Check to make sure that the Mth element is legal for type Elt.
1329 * Starting at offset 8, start skipping over the storage
1330 * for the element types we're not interested in.
1332 for (idx
= 8, i
= 0; i
< elt
; i
++) {
1333 idx
+= ((ep
[i
] + 1) * 4);
1337 * Skip over Overall status for this element type.
1342 * And skip to the index for the Mth element that we're going for.
1347 * Make sure we haven't overflowed the buffer.
1355 sset8(b
, idx
, sp
->comstatus
);
1356 sset8(b
, idx
, sp
->comstat
[0]);
1357 sset8(b
, idx
, sp
->comstat
[1]);
1358 sset8(b
, idx
, sp
->comstat
[2]);
1362 PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n",
1363 elt
, elm
, idx
, sp
->comstatus
, sp
->comstat
[0],
1364 sp
->comstat
[1], sp
->comstat
[2]);
1368 * Now make sure all other 'Select' bits are off.
1370 for (i
= 8; i
< amt
; i
+= 4) {
1375 * And make sure the INVOP bit is clear.
1383 * SAF-TE Type Device Emulation
1386 static int safte_getconfig(ses_softc_t
*);
1387 static int safte_rdstat(ses_softc_t
*, int);
1388 static int set_objstat_sel(ses_softc_t
*, ses_objstat
*, int);
1389 static int wrbuf16(ses_softc_t
*, uint8_t, uint8_t, uint8_t, uint8_t, int);
1390 static void wrslot_stat(ses_softc_t
*, int);
1391 static int perf_slotop(ses_softc_t
*, uint8_t, uint8_t, int);
1393 #define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
1394 SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
1396 * SAF-TE specific defines- Mandatory ones only...
1400 * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
1402 #define SAFTE_RD_RDCFG 0x00 /* read enclosure configuration */
1403 #define SAFTE_RD_RDESTS 0x01 /* read enclosure status */
1404 #define SAFTE_RD_RDDSTS 0x04 /* read drive slot status */
1407 * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
1409 #define SAFTE_WT_DSTAT 0x10 /* write device slot status */
1410 #define SAFTE_WT_SLTOP 0x12 /* perform slot operation */
1411 #define SAFTE_WT_FANSPD 0x13 /* set fan speed */
1412 #define SAFTE_WT_ACTPWS 0x14 /* turn on/off power supply */
1413 #define SAFTE_WT_GLOBAL 0x15 /* send global command */
1416 #define SAFT_SCRATCH 64
1417 #define NPSEUDO_THERM 16
1418 #define NPSEUDO_ALARM 1
1421 * Cached Configuration
1423 uint8_t Nfans
; /* Number of Fans */
1424 uint8_t Npwr
; /* Number of Power Supplies */
1425 uint8_t Nslots
; /* Number of Device Slots */
1426 uint8_t DoorLock
; /* Door Lock Installed */
1427 uint8_t Ntherm
; /* Number of Temperature Sensors */
1428 uint8_t Nspkrs
; /* Number of Speakers */
1429 uint8_t Nalarm
; /* Number of Alarms (at least one) */
1431 * Cached Flag Bytes for Global Status
1436 * What object index ID is where various slots start.
1440 #define SAFT_ALARM_OFFSET(cc) (cc)->slotoff - 1
1443 #define SAFT_FLG1_ALARM 0x1
1444 #define SAFT_FLG1_GLOBFAIL 0x2
1445 #define SAFT_FLG1_GLOBWARN 0x4
1446 #define SAFT_FLG1_ENCPWROFF 0x8
1447 #define SAFT_FLG1_ENCFANFAIL 0x10
1448 #define SAFT_FLG1_ENCPWRFAIL 0x20
1449 #define SAFT_FLG1_ENCDRVFAIL 0x40
1450 #define SAFT_FLG1_ENCDRVWARN 0x80
1452 #define SAFT_FLG2_LOCKDOOR 0x4
1453 #define SAFT_PRIVATE sizeof (struct scfg)
1455 static const char safte_2little
[] = "Too Little Data Returned (%d) at line %d\n";
1456 #define SAFT_BAIL(r, x, k, l) \
1458 SES_LOG(ssc, safte_2little, x, __LINE__);\
1465 safte_softc_init(ses_softc_t
*ssc
, int doinit
)
1471 if (ssc
->ses_nobjects
) {
1472 if (ssc
->ses_objmap
) {
1473 SES_FREE(ssc
->ses_objmap
,
1474 ssc
->ses_nobjects
* sizeof (encobj
));
1475 ssc
->ses_objmap
= NULL
;
1477 ssc
->ses_nobjects
= 0;
1479 if (ssc
->ses_private
) {
1480 SES_FREE(ssc
->ses_private
, SAFT_PRIVATE
);
1481 ssc
->ses_private
= NULL
;
1486 if (ssc
->ses_private
== NULL
) {
1487 ssc
->ses_private
= SES_MALLOC(SAFT_PRIVATE
);
1488 if (ssc
->ses_private
== NULL
) {
1491 MEMZERO(ssc
->ses_private
, SAFT_PRIVATE
);
1494 ssc
->ses_nobjects
= 0;
1495 ssc
->ses_encstat
= 0;
1497 if ((err
= safte_getconfig(ssc
)) != 0) {
1502 * The number of objects here, as well as that reported by the
1503 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15)
1504 * that get reported during READ_BUFFER/READ_ENC_STATUS.
1506 cc
= ssc
->ses_private
;
1507 ssc
->ses_nobjects
= cc
->Nfans
+ cc
->Npwr
+ cc
->Nslots
+ cc
->DoorLock
+
1508 cc
->Ntherm
+ cc
->Nspkrs
+ NPSEUDO_THERM
+ NPSEUDO_ALARM
;
1509 ssc
->ses_objmap
= (encobj
*)
1510 SES_MALLOC(ssc
->ses_nobjects
* sizeof (encobj
));
1511 if (ssc
->ses_objmap
== NULL
) {
1514 MEMZERO(ssc
->ses_objmap
, ssc
->ses_nobjects
* sizeof (encobj
));
1518 * Note that this is all arranged for the convenience
1519 * in later fetches of status.
1521 for (i
= 0; i
< cc
->Nfans
; i
++)
1522 ssc
->ses_objmap
[r
++].enctype
= SESTYP_FAN
;
1523 cc
->pwroff
= (uint8_t) r
;
1524 for (i
= 0; i
< cc
->Npwr
; i
++)
1525 ssc
->ses_objmap
[r
++].enctype
= SESTYP_POWER
;
1526 for (i
= 0; i
< cc
->DoorLock
; i
++)
1527 ssc
->ses_objmap
[r
++].enctype
= SESTYP_DOORLOCK
;
1528 for (i
= 0; i
< cc
->Nspkrs
; i
++)
1529 ssc
->ses_objmap
[r
++].enctype
= SESTYP_ALARM
;
1530 for (i
= 0; i
< cc
->Ntherm
; i
++)
1531 ssc
->ses_objmap
[r
++].enctype
= SESTYP_THERM
;
1532 for (i
= 0; i
< NPSEUDO_THERM
; i
++)
1533 ssc
->ses_objmap
[r
++].enctype
= SESTYP_THERM
;
1534 ssc
->ses_objmap
[r
++].enctype
= SESTYP_ALARM
;
1535 cc
->slotoff
= (uint8_t) r
;
1536 for (i
= 0; i
< cc
->Nslots
; i
++)
1537 ssc
->ses_objmap
[r
++].enctype
= SESTYP_DEVICE
;
1542 safte_init_enc(ses_softc_t
*ssc
)
1546 static char cdb0
[6] = { SEND_DIAGNOSTIC
};
1547 static char cdb
[10] =
1548 { WRITE_BUFFER
, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
1550 sdata
= SES_MALLOC(SAFT_SCRATCH
);
1554 err
= ses_runcmd(ssc
, cdb0
, 6, NULL
, 0);
1556 SES_FREE(sdata
, SAFT_SCRATCH
);
1559 sdata
[0] = SAFTE_WT_GLOBAL
;
1560 MEMZERO(&sdata
[1], 15);
1561 amt
= -SAFT_SCRATCH
;
1562 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
1563 SES_FREE(sdata
, SAFT_SCRATCH
);
1568 safte_get_encstat(ses_softc_t
*ssc
, int slpflg
)
1570 return (safte_rdstat(ssc
, slpflg
));
1574 safte_set_encstat(ses_softc_t
*ssc
, uint8_t encstat
, int slpflg
)
1576 struct scfg
*cc
= ssc
->ses_private
;
1580 * Since SAF-TE devices aren't necessarily sticky in terms
1581 * of state, make our soft copy of enclosure status 'sticky'-
1582 * that is, things set in enclosure status stay set (as implied
1583 * by conditions set in reading object status) until cleared.
1585 ssc
->ses_encstat
&= ~ALL_ENC_STAT
;
1586 ssc
->ses_encstat
|= (encstat
& ALL_ENC_STAT
);
1587 ssc
->ses_encstat
|= ENCI_SVALID
;
1588 cc
->flag1
&= ~(SAFT_FLG1_ALARM
|SAFT_FLG1_GLOBFAIL
|SAFT_FLG1_GLOBWARN
);
1589 if ((encstat
& (SES_ENCSTAT_CRITICAL
|SES_ENCSTAT_UNRECOV
)) != 0) {
1590 cc
->flag1
|= SAFT_FLG1_ALARM
|SAFT_FLG1_GLOBFAIL
;
1591 } else if ((encstat
& SES_ENCSTAT_NONCRITICAL
) != 0) {
1592 cc
->flag1
|= SAFT_FLG1_GLOBWARN
;
1594 return (wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
, cc
->flag2
, 0, slpflg
));
1598 safte_get_objstat(ses_softc_t
*ssc
, ses_objstat
*obp
, int slpflg
)
1600 int i
= (int)obp
->obj_id
;
1602 if ((ssc
->ses_encstat
& ENCI_SVALID
) == 0 ||
1603 (ssc
->ses_objmap
[i
].svalid
) == 0) {
1604 int err
= safte_rdstat(ssc
, slpflg
);
1608 obp
->cstat
[0] = ssc
->ses_objmap
[i
].encstat
[0];
1609 obp
->cstat
[1] = ssc
->ses_objmap
[i
].encstat
[1];
1610 obp
->cstat
[2] = ssc
->ses_objmap
[i
].encstat
[2];
1611 obp
->cstat
[3] = ssc
->ses_objmap
[i
].encstat
[3];
1617 safte_set_objstat(ses_softc_t
*ssc
, ses_objstat
*obp
, int slp
)
1624 SES_VLOG(ssc
, "safte_set_objstat(%d): %x %x %x %x\n",
1625 (int)obp
->obj_id
, obp
->cstat
[0], obp
->cstat
[1], obp
->cstat
[2],
1629 * If this is clear, we don't do diddly.
1631 if ((obp
->cstat
[0] & SESCTL_CSEL
) == 0) {
1637 * Check to see if the common bits are set and do them first.
1639 if (obp
->cstat
[0] & ~SESCTL_CSEL
) {
1640 err
= set_objstat_sel(ssc
, obp
, slp
);
1645 cc
= ssc
->ses_private
;
1649 idx
= (int)obp
->obj_id
;
1650 ep
= &ssc
->ses_objmap
[idx
];
1652 switch (ep
->enctype
) {
1657 * XXX: I should probably cache the previous state
1658 * XXX: of SESCTL_DEVOFF so that when it goes from
1659 * XXX: true to false I can then set PREPARE FOR OPERATION
1660 * XXX: flag in PERFORM SLOT OPERATION write buffer command.
1662 if (obp
->cstat
[2] & (SESCTL_RQSINS
|SESCTL_RQSRMV
)) {
1665 if (obp
->cstat
[2] & SESCTL_RQSID
) {
1668 err
= perf_slotop(ssc
, (uint8_t) idx
- (uint8_t) cc
->slotoff
,
1672 if (obp
->cstat
[3] & SESCTL_RQSFLT
) {
1677 if (ep
->priv
& 0xc6) {
1680 ep
->priv
|= 0x1; /* no errors */
1682 wrslot_stat(ssc
, slp
);
1686 if (obp
->cstat
[3] & SESCTL_RQSTFAIL
) {
1687 cc
->flag1
|= SAFT_FLG1_ENCPWRFAIL
;
1689 cc
->flag1
&= ~SAFT_FLG1_ENCPWRFAIL
;
1691 err
= wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
1695 if (obp
->cstat
[3] & SESCTL_RQSTON
) {
1696 (void) wrbuf16(ssc
, SAFTE_WT_ACTPWS
,
1697 idx
- cc
->pwroff
, 0, 0, slp
);
1699 (void) wrbuf16(ssc
, SAFTE_WT_ACTPWS
,
1700 idx
- cc
->pwroff
, 0, 1, slp
);
1704 if (obp
->cstat
[3] & SESCTL_RQSTFAIL
) {
1705 cc
->flag1
|= SAFT_FLG1_ENCFANFAIL
;
1707 cc
->flag1
&= ~SAFT_FLG1_ENCFANFAIL
;
1709 err
= wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
1713 if (obp
->cstat
[3] & SESCTL_RQSTON
) {
1715 if ((obp
->cstat
[3] & 0x7) == 7) {
1717 } else if ((obp
->cstat
[3] & 0x7) == 6) {
1719 } else if ((obp
->cstat
[3] & 0x7) == 4) {
1724 (void) wrbuf16(ssc
, SAFTE_WT_FANSPD
, idx
, fsp
, 0, slp
);
1726 (void) wrbuf16(ssc
, SAFTE_WT_FANSPD
, idx
, 0, 0, slp
);
1729 case SESTYP_DOORLOCK
:
1730 if (obp
->cstat
[3] & 0x1) {
1731 cc
->flag2
&= ~SAFT_FLG2_LOCKDOOR
;
1733 cc
->flag2
|= SAFT_FLG2_LOCKDOOR
;
1735 (void) wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
1740 * On all nonzero but the 'muted' bit, we turn on the alarm,
1742 obp
->cstat
[3] &= ~0xa;
1743 if (obp
->cstat
[3] & 0x40) {
1744 cc
->flag2
&= ~SAFT_FLG1_ALARM
;
1745 } else if (obp
->cstat
[3] != 0) {
1746 cc
->flag2
|= SAFT_FLG1_ALARM
;
1748 cc
->flag2
&= ~SAFT_FLG1_ALARM
;
1750 ep
->priv
= obp
->cstat
[3];
1751 (void) wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
1762 safte_getconfig(ses_softc_t
*ssc
)
1767 static char cdb
[10] =
1768 { READ_BUFFER
, 1, SAFTE_RD_RDCFG
, 0, 0, 0, 0, 0, SAFT_SCRATCH
, 0 };
1770 cfg
= ssc
->ses_private
;
1774 sdata
= SES_MALLOC(SAFT_SCRATCH
);
1779 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
1781 SES_FREE(sdata
, SAFT_SCRATCH
);
1784 amt
= SAFT_SCRATCH
- amt
;
1786 SES_LOG(ssc
, "too little data (%d) for configuration\n", amt
);
1787 SES_FREE(sdata
, SAFT_SCRATCH
);
1790 SES_VLOG(ssc
, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n",
1791 sdata
[0], sdata
[1], sdata
[2], sdata
[3], sdata
[4], sdata
[5]);
1792 cfg
->Nfans
= sdata
[0];
1793 cfg
->Npwr
= sdata
[1];
1794 cfg
->Nslots
= sdata
[2];
1795 cfg
->DoorLock
= sdata
[3];
1796 cfg
->Ntherm
= sdata
[4];
1797 cfg
->Nspkrs
= sdata
[5];
1798 cfg
->Nalarm
= NPSEUDO_ALARM
;
1799 SES_FREE(sdata
, SAFT_SCRATCH
);
1804 safte_rdstat(ses_softc_t
*ssc
, int slpflg
)
1806 int err
, oid
, r
, i
, hiwater
, nitems
, amt
;
1809 uint8_t status
, oencstat
;
1810 char *sdata
, cdb
[10];
1811 struct scfg
*cc
= ssc
->ses_private
;
1815 * The number of objects overstates things a bit,
1816 * both for the bogus 'thermometer' entries and
1817 * the drive status (which isn't read at the same
1818 * time as the enclosure status), but that's okay.
1820 buflen
= 4 * cc
->Nslots
;
1821 if (ssc
->ses_nobjects
> buflen
)
1822 buflen
= ssc
->ses_nobjects
;
1823 sdata
= SES_MALLOC(buflen
);
1827 cdb
[0] = READ_BUFFER
;
1829 cdb
[2] = SAFTE_RD_RDESTS
;
1834 cdb
[7] = (buflen
>> 8) & 0xff;
1835 cdb
[8] = buflen
& 0xff;
1838 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
1840 SES_FREE(sdata
, buflen
);
1843 hiwater
= buflen
- amt
;
1847 * invalidate all status bits.
1849 for (i
= 0; i
< ssc
->ses_nobjects
; i
++)
1850 ssc
->ses_objmap
[i
].svalid
= 0;
1851 oencstat
= ssc
->ses_encstat
& ALL_ENC_STAT
;
1852 ssc
->ses_encstat
= 0;
1856 * Now parse returned buffer.
1857 * If we didn't get enough data back,
1858 * that's considered a fatal error.
1862 for (nitems
= i
= 0; i
< cc
->Nfans
; i
++) {
1863 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
1865 * 0 = Fan Operational
1866 * 1 = Fan is malfunctioning
1867 * 2 = Fan is not present
1868 * 0x80 = Unknown or Not Reportable Status
1870 ssc
->ses_objmap
[oid
].encstat
[1] = 0; /* resvd */
1871 ssc
->ses_objmap
[oid
].encstat
[2] = 0; /* resvd */
1872 switch ((int)(uint8_t)sdata
[r
]) {
1875 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
1877 * We could get fancier and cache
1878 * fan speeds that we have set, but
1879 * that isn't done now.
1881 ssc
->ses_objmap
[oid
].encstat
[3] = 7;
1885 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_CRIT
;
1887 * FAIL and FAN STOPPED synthesized
1889 ssc
->ses_objmap
[oid
].encstat
[3] = 0x40;
1891 * Enclosure marked with CRITICAL error
1892 * if only one fan or no thermometers,
1893 * else the NONCRITICAL error is set.
1895 if (cc
->Nfans
== 1 || cc
->Ntherm
== 0)
1896 ssc
->ses_encstat
|= SES_ENCSTAT_CRITICAL
;
1898 ssc
->ses_encstat
|= SES_ENCSTAT_NONCRITICAL
;
1901 ssc
->ses_objmap
[oid
].encstat
[0] =
1902 SES_OBJSTAT_NOTINSTALLED
;
1903 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
1905 * Enclosure marked with CRITICAL error
1906 * if only one fan or no thermometers,
1907 * else the NONCRITICAL error is set.
1910 ssc
->ses_encstat
|= SES_ENCSTAT_CRITICAL
;
1912 ssc
->ses_encstat
|= SES_ENCSTAT_NONCRITICAL
;
1915 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_UNKNOWN
;
1916 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
1917 ssc
->ses_encstat
|= SES_ENCSTAT_INFO
;
1920 ssc
->ses_objmap
[oid
].encstat
[0] =
1921 SES_OBJSTAT_UNSUPPORTED
;
1922 SES_LOG(ssc
, "Unknown fan%d status 0x%x\n", i
,
1926 ssc
->ses_objmap
[oid
++].svalid
= 1;
1931 * No matter how you cut it, no cooling elements when there
1932 * should be some there is critical.
1934 if (cc
->Nfans
&& nitems
== 0) {
1935 ssc
->ses_encstat
|= SES_ENCSTAT_CRITICAL
;
1939 for (i
= 0; i
< cc
->Npwr
; i
++) {
1940 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
1941 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_UNKNOWN
;
1942 ssc
->ses_objmap
[oid
].encstat
[1] = 0; /* resvd */
1943 ssc
->ses_objmap
[oid
].encstat
[2] = 0; /* resvd */
1944 ssc
->ses_objmap
[oid
].encstat
[3] = 0x20; /* requested on */
1945 switch ((uint8_t)sdata
[r
]) {
1946 case 0x00: /* pws operational and on */
1947 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
1949 case 0x01: /* pws operational and off */
1950 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
1951 ssc
->ses_objmap
[oid
].encstat
[3] = 0x10;
1952 ssc
->ses_encstat
|= SES_ENCSTAT_INFO
;
1954 case 0x10: /* pws is malfunctioning and commanded on */
1955 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_CRIT
;
1956 ssc
->ses_objmap
[oid
].encstat
[3] = 0x61;
1957 ssc
->ses_encstat
|= SES_ENCSTAT_NONCRITICAL
;
1960 case 0x11: /* pws is malfunctioning and commanded off */
1961 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_NONCRIT
;
1962 ssc
->ses_objmap
[oid
].encstat
[3] = 0x51;
1963 ssc
->ses_encstat
|= SES_ENCSTAT_NONCRITICAL
;
1965 case 0x20: /* pws is not present */
1966 ssc
->ses_objmap
[oid
].encstat
[0] =
1967 SES_OBJSTAT_NOTINSTALLED
;
1968 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
1969 ssc
->ses_encstat
|= SES_ENCSTAT_INFO
;
1971 case 0x21: /* pws is present */
1973 * This is for enclosures that cannot tell whether the
1974 * device is on or malfunctioning, but know that it is
1975 * present. Just fall through.
1978 case 0x80: /* Unknown or Not Reportable Status */
1979 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_UNKNOWN
;
1980 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
1981 ssc
->ses_encstat
|= SES_ENCSTAT_INFO
;
1984 SES_LOG(ssc
, "unknown power supply %d status (0x%x)\n",
1985 i
, sdata
[r
] & 0xff);
1988 ssc
->ses_objmap
[oid
++].svalid
= 1;
1993 * Skip over Slot SCSI IDs
1998 * We always have doorlock status, no matter what,
1999 * but we only save the status if we have one.
2001 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
2005 * 1 = Door Unlocked, or no Lock Installed
2006 * 0x80 = Unknown or Not Reportable Status
2008 ssc
->ses_objmap
[oid
].encstat
[1] = 0;
2009 ssc
->ses_objmap
[oid
].encstat
[2] = 0;
2010 switch ((uint8_t)sdata
[r
]) {
2012 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2013 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2016 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2017 ssc
->ses_objmap
[oid
].encstat
[3] = 1;
2020 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_UNKNOWN
;
2021 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2022 ssc
->ses_encstat
|= SES_ENCSTAT_INFO
;
2025 ssc
->ses_objmap
[oid
].encstat
[0] =
2026 SES_OBJSTAT_UNSUPPORTED
;
2027 SES_LOG(ssc
, "unknown lock status 0x%x\n",
2031 ssc
->ses_objmap
[oid
++].svalid
= 1;
2036 * We always have speaker status, no matter what,
2037 * but we only save the status if we have one.
2039 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
2041 ssc
->ses_objmap
[oid
].encstat
[1] = 0;
2042 ssc
->ses_objmap
[oid
].encstat
[2] = 0;
2043 if (sdata
[r
] == 1) {
2045 * We need to cache tone urgency indicators.
2048 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_NONCRIT
;
2049 ssc
->ses_objmap
[oid
].encstat
[3] = 0x8;
2050 ssc
->ses_encstat
|= SES_ENCSTAT_NONCRITICAL
;
2051 } else if (sdata
[r
] == 0) {
2052 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2053 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2055 ssc
->ses_objmap
[oid
].encstat
[0] =
2056 SES_OBJSTAT_UNSUPPORTED
;
2057 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2058 SES_LOG(ssc
, "unknown spkr status 0x%x\n",
2061 ssc
->ses_objmap
[oid
++].svalid
= 1;
2065 for (i
= 0; i
< cc
->Ntherm
; i
++) {
2066 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
2068 * Status is a range from -10 to 245 deg Celsius,
2069 * which we need to normalize to -20 to -245 according
2070 * to the latest SCSI spec, which makes little
2071 * sense since this would overflow an 8bit value.
2072 * Well, still, the base normalization is -20,
2073 * not -10, so we have to adjust.
2075 * So what's over and under temperature?
2076 * Hmm- we'll state that 'normal' operating
2077 * is 10 to 40 deg Celsius.
2081 * Actually.... All of the units that people out in the world
2082 * seem to have do not come even close to setting a value that
2083 * complies with this spec.
2085 * The closest explanation I could find was in an
2086 * LSI-Logic manual, which seemed to indicate that
2087 * this value would be set by whatever the I2C code
2088 * would interpolate from the output of an LM75
2089 * temperature sensor.
2091 * This means that it is impossible to use the actual
2092 * numeric value to predict anything. But we don't want
2093 * to lose the value. So, we'll propagate the *uncorrected*
2094 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
2095 * temperature flags for warnings.
2097 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_NOTAVAIL
;
2098 ssc
->ses_objmap
[oid
].encstat
[1] = 0;
2099 ssc
->ses_objmap
[oid
].encstat
[2] = sdata
[r
];
2100 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2101 ssc
->ses_objmap
[oid
++].svalid
= 1;
2106 * Now, for "pseudo" thermometers, we have two bytes
2107 * of information in enclosure status- 16 bits. Actually,
2108 * the MSB is a single TEMP ALERT flag indicating whether
2109 * any other bits are set, but, thanks to fuzzy thinking,
2110 * in the SAF-TE spec, this can also be set even if no
2111 * other bits are set, thus making this really another
2112 * binary temperature sensor.
2115 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
2116 tempflags
= sdata
[r
++];
2117 SAFT_BAIL(r
, hiwater
, sdata
, buflen
);
2118 tempflags
|= (tempflags
<< 8) | sdata
[r
++];
2120 for (i
= 0; i
< NPSEUDO_THERM
; i
++) {
2121 ssc
->ses_objmap
[oid
].encstat
[1] = 0;
2122 if (tempflags
& (1 << (NPSEUDO_THERM
- i
- 1))) {
2123 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_CRIT
;
2124 ssc
->ses_objmap
[4].encstat
[2] = 0xff;
2126 * Set 'over temperature' failure.
2128 ssc
->ses_objmap
[oid
].encstat
[3] = 8;
2129 ssc
->ses_encstat
|= SES_ENCSTAT_CRITICAL
;
2132 * We used to say 'not available' and synthesize a
2133 * nominal 30 deg (C)- that was wrong. Actually,
2134 * Just say 'OK', and use the reserved value of
2137 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2138 ssc
->ses_objmap
[oid
].encstat
[2] = 0;
2139 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2141 ssc
->ses_objmap
[oid
++].svalid
= 1;
2147 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2148 ssc
->ses_objmap
[oid
].encstat
[3] = ssc
->ses_objmap
[oid
].priv
;
2149 ssc
->ses_objmap
[oid
++].svalid
= 1;
2152 * Now get drive slot status
2154 cdb
[2] = SAFTE_RD_RDDSTS
;
2156 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
2158 SES_FREE(sdata
, buflen
);
2161 hiwater
= buflen
- amt
;
2162 for (r
= i
= 0; i
< cc
->Nslots
; i
++, r
+= 4) {
2163 SAFT_BAIL(r
+3, hiwater
, sdata
, buflen
);
2164 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_UNSUPPORTED
;
2165 ssc
->ses_objmap
[oid
].encstat
[1] = (uint8_t) i
;
2166 ssc
->ses_objmap
[oid
].encstat
[2] = 0;
2167 ssc
->ses_objmap
[oid
].encstat
[3] = 0;
2168 status
= sdata
[r
+3];
2169 if ((status
& 0x1) == 0) { /* no device */
2170 ssc
->ses_objmap
[oid
].encstat
[0] =
2171 SES_OBJSTAT_NOTINSTALLED
;
2173 ssc
->ses_objmap
[oid
].encstat
[0] = SES_OBJSTAT_OK
;
2176 ssc
->ses_objmap
[oid
].encstat
[2] = 0x8;
2178 if ((status
& 0x4) == 0) {
2179 ssc
->ses_objmap
[oid
].encstat
[3] = 0x10;
2181 ssc
->ses_objmap
[oid
++].svalid
= 1;
2183 /* see comment below about sticky enclosure status */
2184 ssc
->ses_encstat
|= ENCI_SVALID
| oencstat
;
2185 SES_FREE(sdata
, buflen
);
2190 set_objstat_sel(ses_softc_t
*ssc
, ses_objstat
*obp
, int slp
)
2194 struct scfg
*cc
= ssc
->ses_private
;
2199 idx
= (int)obp
->obj_id
;
2200 ep
= &ssc
->ses_objmap
[idx
];
2202 switch (ep
->enctype
) {
2204 if (obp
->cstat
[0] & SESCTL_PRDFAIL
) {
2207 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */
2208 if (obp
->cstat
[0] & SESCTL_DISABLE
) {
2211 * Hmm. Try to set the 'No Drive' flag.
2212 * Maybe that will count as a 'disable'.
2215 if (ep
->priv
& 0xc6) {
2218 ep
->priv
|= 0x1; /* no errors */
2220 wrslot_stat(ssc
, slp
);
2224 * Okay- the only one that makes sense here is to
2225 * do the 'disable' for a power supply.
2227 if (obp
->cstat
[0] & SESCTL_DISABLE
) {
2228 (void) wrbuf16(ssc
, SAFTE_WT_ACTPWS
,
2229 idx
- cc
->pwroff
, 0, 0, slp
);
2234 * Okay- the only one that makes sense here is to
2235 * set fan speed to zero on disable.
2237 if (obp
->cstat
[0] & SESCTL_DISABLE
) {
2238 /* remember- fans are the first items, so idx works */
2239 (void) wrbuf16(ssc
, SAFTE_WT_FANSPD
, idx
, 0, 0, slp
);
2242 case SESTYP_DOORLOCK
:
2244 * Well, we can 'disable' the lock.
2246 if (obp
->cstat
[0] & SESCTL_DISABLE
) {
2247 cc
->flag2
&= ~SAFT_FLG2_LOCKDOOR
;
2248 (void) wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
2254 * Well, we can 'disable' the alarm.
2256 if (obp
->cstat
[0] & SESCTL_DISABLE
) {
2257 cc
->flag2
&= ~SAFT_FLG1_ALARM
;
2258 ep
->priv
|= 0x40; /* Muted */
2259 (void) wrbuf16(ssc
, SAFTE_WT_GLOBAL
, cc
->flag1
,
2271 * This function handles all of the 16 byte WRITE BUFFER commands.
2274 wrbuf16(ses_softc_t
*ssc
, uint8_t op
, uint8_t b1
, uint8_t b2
,
2275 uint8_t b3
, int slp
)
2279 struct scfg
*cc
= ssc
->ses_private
;
2280 static char cdb
[10] = { WRITE_BUFFER
, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
2285 sdata
= SES_MALLOC(16);
2289 SES_VLOG(ssc
, "saf_wrbuf16 %x %x %x %x\n", op
, b1
, b2
, b3
);
2295 MEMZERO(&sdata
[4], 12);
2297 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
2298 SES_FREE(sdata
, 16);
2303 * This function updates the status byte for the device slot described.
2305 * Since this is an optional SAF-TE command, there's no point in
2306 * returning an error.
2309 wrslot_stat(ses_softc_t
*ssc
, int slp
)
2313 char cdb
[10], *sdata
;
2314 struct scfg
*cc
= ssc
->ses_private
;
2319 SES_VLOG(ssc
, "saf_wrslot\n");
2320 cdb
[0] = WRITE_BUFFER
;
2328 cdb
[8] = cc
->Nslots
* 3 + 1;
2331 sdata
= SES_MALLOC(cc
->Nslots
* 3 + 1);
2334 MEMZERO(sdata
, cc
->Nslots
* 3 + 1);
2336 sdata
[0] = SAFTE_WT_DSTAT
;
2337 for (i
= 0; i
< cc
->Nslots
; i
++) {
2338 ep
= &ssc
->ses_objmap
[cc
->slotoff
+ i
];
2339 SES_VLOG(ssc
, "saf_wrslot %d <- %x\n", i
, ep
->priv
& 0xff);
2340 sdata
[1 + (3 * i
)] = ep
->priv
& 0xff;
2342 amt
= -(cc
->Nslots
* 3 + 1);
2343 (void) ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
2344 SES_FREE(sdata
, cc
->Nslots
* 3 + 1);
2348 * This function issues the "PERFORM SLOT OPERATION" command.
2351 perf_slotop(ses_softc_t
*ssc
, uint8_t slot
, uint8_t opflag
, int slp
)
2355 struct scfg
*cc
= ssc
->ses_private
;
2356 static char cdb
[10] =
2357 { WRITE_BUFFER
, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH
, 0 };
2362 sdata
= SES_MALLOC(SAFT_SCRATCH
);
2365 MEMZERO(sdata
, SAFT_SCRATCH
);
2367 sdata
[0] = SAFTE_WT_SLTOP
;
2370 SES_VLOG(ssc
, "saf_slotop slot %d op %x\n", slot
, opflag
);
2371 amt
= -SAFT_SCRATCH
;
2372 err
= ses_runcmd(ssc
, cdb
, 10, sdata
, &amt
);
2373 SES_FREE(sdata
, SAFT_SCRATCH
);