xref: /netbsd-src/sys/dev/scsipi/ses.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: ses.c,v 1.42 2009/05/12 14:44:31 cegger Exp $ */
2 /*
3  * Copyright (C) 2000 National Aeronautics & Space Administration
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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
13  *
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.
24  *
25  * Author:	mjacob@nas.nasa.gov
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: ses.c,v 1.42 2009/05/12 14:44:31 cegger Exp $");
30 
31 #include "opt_scsi.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/file.h>
37 #include <sys/stat.h>
38 #include <sys/ioctl.h>
39 #include <sys/scsiio.h>
40 #include <sys/buf.h>
41 #include <sys/uio.h>
42 #include <sys/malloc.h>
43 #include <sys/errno.h>
44 #include <sys/device.h>
45 #include <sys/disklabel.h>
46 #include <sys/disk.h>
47 #include <sys/proc.h>
48 #include <sys/conf.h>
49 #include <sys/vnode.h>
50 #include <machine/stdarg.h>
51 
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>
59 
60 /*
61  * Platform Independent Driver Internal Definitions for SES devices.
62  */
63 typedef enum {
64 	SES_NONE,
65 	SES_SES_SCSI2,
66 	SES_SES,
67 	SES_SES_PASSTHROUGH,
68 	SES_SEN,
69 	SES_SAFT
70 } enctyp;
71 
72 struct ses_softc;
73 typedef struct ses_softc ses_softc_t;
74 typedef struct {
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);
81 } encvec;
82 
83 #define	ENCI_SVALID	0x80
84 
85 typedef struct {
86 	uint32_t
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 */
92 } encobj;
93 
94 #define	SEN_ID		"UNISYS           SUN_SEN"
95 #define	SEN_ID_LEN	24
96 
97 static enctyp ses_type(struct scsipi_inquiry_data *);
98 
99 
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);
107 
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);
114 
115 /*
116  * Platform implementation defines/functions for SES internal kernel stuff
117  */
118 
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
124 #else
125 #define	SES_VLOG		if (0) ses_log
126 #endif
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
135 
136 static dev_type_open(sesopen);
137 static dev_type_close(sesclose);
138 static dev_type_ioctl(sesioctl);
139 
140 const struct cdevsw ses_cdevsw = {
141 	sesopen, sesclose, noread, nowrite, sesioctl,
142 	nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
143 };
144 
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)));
148 
149 /*
150  * General NetBSD kernel stuff.
151  */
152 
153 struct ses_softc {
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 */
162 	u_int8_t	ses_flags;
163 };
164 #define	SES_FLAG_INVALID	0x01
165 #define	SES_FLAG_OPEN		0x02
166 #define	SES_FLAG_INITIALIZED	0x04
167 
168 #define SESUNIT(x)       (minor((x)))
169 
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 *);
173 
174 CFATTACH_DECL(ses, sizeof (struct ses_softc),
175     ses_match, ses_attach, NULL, NULL);
176 
177 extern struct cfdriver ses_cd;
178 
179 static const struct scsipi_periphsw ses_switch = {
180 	NULL,
181 	NULL,
182 	NULL,
183 	NULL
184 };
185 
186 static int
187 ses_match(device_t parent, cfdata_t match,
188     void *aux)
189 {
190 	struct scsipibus_attach_args *sa = aux;
191 
192 	switch (ses_device_type(sa)) {
193 	case SES_SES:
194 	case SES_SES_SCSI2:
195 	case SES_SEN:
196 	case SES_SAFT:
197 	case SES_SES_PASSTHROUGH:
198 		/*
199 		 * For these devices, it's a perfect match.
200 		 */
201 		return (24);
202 	default:
203 		return (0);
204 	}
205 }
206 
207 
208 /*
209  * Complete the attachment.
210  *
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.
214  */
215 static void
216 ses_attach(device_t parent, device_t self, void *aux)
217 {
218 	const char *tname;
219 	struct ses_softc *softc = device_private(self);
220 	struct scsipibus_attach_args *sa = aux;
221 	struct scsipi_periph *periph = sa->sa_periph;
222 
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;
228 
229 	softc->ses_type = ses_device_type(sa);
230 	switch (softc->ses_type) {
231 	case SES_SES:
232 	case SES_SES_SCSI2:
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;
240 		break;
241         case SES_SAFT:
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;
248 		break;
249         case SES_SEN:
250 		break;
251 	case SES_NONE:
252 	default:
253 		break;
254 	}
255 
256 	switch (softc->ses_type) {
257 	default:
258 	case SES_NONE:
259 		tname = "No SES device";
260 		break;
261 	case SES_SES_SCSI2:
262 		tname = "SCSI-2 SES Device";
263 		break;
264 	case SES_SES:
265 		tname = "SCSI-3 SES Device";
266 		break;
267         case SES_SES_PASSTHROUGH:
268 		tname = "SES Passthrough Device";
269 		break;
270         case SES_SEN:
271 		tname = "UNISYS SEN Device (NOT HANDLED YET)";
272 		break;
273         case SES_SAFT:
274 		tname = "SAF-TE Compliant Device";
275 		break;
276 	}
277 	printf("\n%s: %s\n", device_xname(&softc->sc_device), tname);
278 }
279 
280 
281 static enctyp
282 ses_device_type(struct scsipibus_attach_args *sa)
283 {
284 	struct scsipi_inquiry_data *inqp = sa->sa_inqptr;
285 
286 	if (inqp == NULL)
287 		return (SES_NONE);
288 
289 	return (ses_type(inqp));
290 }
291 
292 static int
293 sesopen(dev_t dev, int flags, int fmt, struct lwp *l)
294 {
295 	struct ses_softc *softc;
296 	int error, unit;
297 
298 	unit = SESUNIT(dev);
299 	softc = device_lookup_private(&ses_cd, unit);
300 	if (softc == NULL)
301 		return (ENXIO);
302 
303 	if (softc->ses_flags & SES_FLAG_INVALID) {
304 		error = ENXIO;
305 		goto out;
306 	}
307 	if (softc->ses_flags & SES_FLAG_OPEN) {
308 		error = EBUSY;
309 		goto out;
310 	}
311 	if (softc->ses_vec.softc_init == NULL) {
312 		error = ENXIO;
313 		goto out;
314 	}
315 	error = scsipi_adapter_addref(
316 	    softc->sc_periph->periph_channel->chan_adapter);
317 	if (error != 0)
318                 goto out;
319 
320 
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);
324 		if (error)
325 			softc->ses_flags &= ~SES_FLAG_OPEN;
326 		else
327 			softc->ses_flags |= SES_FLAG_INITIALIZED;
328 	}
329 
330 out:
331 	return (error);
332 }
333 
334 static int
335 sesclose(dev_t dev, int flags, int fmt,
336     struct lwp *l)
337 {
338 	struct ses_softc *softc;
339 	int unit;
340 
341 	unit = SESUNIT(dev);
342 	softc = device_lookup_private(&ses_cd, unit);
343 	if (softc == NULL)
344 		return (ENXIO);
345 
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;
349 	return (0);
350 }
351 
352 static int
353 sesioctl(dev_t dev, u_long cmd, void *arg_addr, int flag, struct lwp *l)
354 {
355 	ses_encstat tmp;
356 	ses_objstat objs;
357 	ses_object obj, *uobj;
358 	struct ses_softc *ssc = device_lookup_private(&ses_cd, SESUNIT(dev));
359 	void *addr;
360 	int error, i;
361 
362 
363 	if (arg_addr)
364 		addr = *((void **) arg_addr);
365 	else
366 		addr = NULL;
367 
368 	SC_DEBUG(ssc->sc_periph, SCSIPI_DB2, ("sesioctl 0x%lx ", cmd));
369 
370 	/*
371 	 * Now check to see whether we're initialized or not.
372 	 */
373 	if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
374 		return (ENODEV);
375 	}
376 
377 	error = 0;
378 
379 	/*
380 	 * If this command can change the device's state,
381 	 * we must have the device open for writing.
382 	 */
383 	switch (cmd) {
384 	case SESIOC_GETNOBJ:
385 	case SESIOC_GETOBJMAP:
386 	case SESIOC_GETENCSTAT:
387 	case SESIOC_GETOBJSTAT:
388 		break;
389 	default:
390 		if ((flag & FWRITE) == 0) {
391 			return (EBADF);
392 		}
393 	}
394 
395 	switch (cmd) {
396 	case SESIOC_GETNOBJ:
397 		if (addr == NULL)
398 			return EINVAL;
399 		error = copyout(&ssc->ses_nobjects, addr,
400 		    sizeof (ssc->ses_nobjects));
401 		break;
402 
403 	case SESIOC_GETOBJMAP:
404 		if (addr == NULL)
405 			return EINVAL;
406 		for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++, uobj++) {
407 			obj.obj_id = i;
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));
411 			if (error) {
412 				break;
413 			}
414 		}
415 		break;
416 
417 	case SESIOC_GETENCSTAT:
418 		if (addr == NULL)
419 			return EINVAL;
420 		error = (*ssc->ses_vec.get_encstat)(ssc, 1);
421 		if (error)
422 			break;
423 		tmp = ssc->ses_encstat & ~ENCI_SVALID;
424 		error = copyout(&tmp, addr, sizeof (ses_encstat));
425 		ssc->ses_encstat = tmp;
426 		break;
427 
428 	case SESIOC_SETENCSTAT:
429 		if (addr == NULL)
430 			return EINVAL;
431 		error = copyin(addr, &tmp, sizeof (ses_encstat));
432 		if (error)
433 			break;
434 		error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
435 		break;
436 
437 	case SESIOC_GETOBJSTAT:
438 		if (addr == NULL)
439 			return EINVAL;
440 		error = copyin(addr, &objs, sizeof (ses_objstat));
441 		if (error)
442 			break;
443 		if (objs.obj_id >= ssc->ses_nobjects) {
444 			error = EINVAL;
445 			break;
446 		}
447 		error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
448 		if (error)
449 			break;
450 		error = copyout(&objs, addr, sizeof (ses_objstat));
451 		/*
452 		 * Always (for now) invalidate entry.
453 		 */
454 		ssc->ses_objmap[objs.obj_id].svalid = 0;
455 		break;
456 
457 	case SESIOC_SETOBJSTAT:
458 		if (addr == NULL)
459 			return EINVAL;
460 		error = copyin(addr, &objs, sizeof (ses_objstat));
461 		if (error)
462 			break;
463 
464 		if (objs.obj_id >= ssc->ses_nobjects) {
465 			error = EINVAL;
466 			break;
467 		}
468 		error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
469 
470 		/*
471 		 * Always (for now) invalidate entry.
472 		 */
473 		ssc->ses_objmap[objs.obj_id].svalid = 0;
474 		break;
475 
476 	case SESIOC_INIT:
477 
478 		error = (*ssc->ses_vec.init_enc)(ssc);
479 		break;
480 
481 	default:
482 		error = scsipi_do_ioctl(ssc->sc_periph,
483 			    dev, cmd, arg_addr, flag, l);
484 		break;
485 	}
486 	return (error);
487 }
488 
489 static int
490 ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp)
491 {
492 	struct scsipi_generic sgen;
493 	int dl, flg, error;
494 
495 	if (dptr) {
496 		if ((dl = *dlenp) < 0) {
497 			dl = -dl;
498 			flg = XS_CTL_DATA_OUT;
499 		} else {
500 			flg = XS_CTL_DATA_IN;
501 		}
502 	} else {
503 		dl = 0;
504 		flg = 0;
505 	}
506 
507 	if (cdbl > sizeof (struct scsipi_generic)) {
508 		cdbl = sizeof (struct scsipi_generic);
509 	}
510 	memcpy(&sgen, cdb, cdbl);
511 #ifndef	SCSIDEBUG
512 	flg |= XS_CTL_SILENT;
513 #endif
514 	error = scsipi_command(ssc->sc_periph, &sgen, cdbl,
515 	    (u_char *) dptr, dl, SCSIPIRETRIES, 30000, NULL, flg);
516 
517 	if (error == 0 && dptr)
518 		*dlenp = 0;
519 
520 	return (error);
521 }
522 
523 static void
524 ses_log(struct ses_softc *ssc, const char *fmt, ...)
525 {
526 	va_list ap;
527 
528 	printf("%s: ", device_xname(&ssc->sc_device));
529 	va_start(ap, fmt);
530 	vprintf(fmt, ap);
531 	va_end(ap);
532 }
533 
534 /*
535  * The code after this point runs on many platforms,
536  * so forgive the slightly awkward and nonconforming
537  * appearance.
538  */
539 
540 /*
541  * Is this a device that supports enclosure services?
542  *
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
545  * handle that too.
546  */
547 
548 #define	SAFTE_START	44
549 #define	SAFTE_END	50
550 #define	SAFTE_LEN	SAFTE_END-SAFTE_START
551 
552 static enctyp
553 ses_type(struct scsipi_inquiry_data *inqp)
554 {
555 	size_t	given_len = inqp->additional_length + 4;
556 
557 	if (given_len < 8+SEN_ID_LEN)
558 		return (SES_NONE);
559 
560 	if ((inqp->device & SID_TYPE) == T_ENCLOSURE) {
561 		if (STRNCMP(inqp->vendor, SEN_ID, SEN_ID_LEN) == 0) {
562 			return (SES_SEN);
563 		} else if ((inqp->version & SID_ANSII) > 2) {
564 			return (SES_SES);
565 		} else {
566 			return (SES_SES_SCSI2);
567 		}
568 		return (SES_NONE);
569 	}
570 
571 #ifdef	SES_ENABLE_PASSTHROUGH
572 	if ((inqp->flags2 & SID_EncServ) && (inqp->version & SID_ANSII) >= 2) {
573 		/*
574 		 * PassThrough Device.
575 		 */
576 		return (SES_SES_PASSTHROUGH);
577 	}
578 #endif
579 
580 	/*
581 	 * The comparison is short for a reason-
582 	 * some vendors were chopping it short.
583 	 */
584 
585 	if (given_len < SAFTE_END - 2) {
586 		return (SES_NONE);
587 	}
588 
589 	if (STRNCMP((char *)&inqp->vendor_specific[8], "SAF-TE",
590 			SAFTE_LEN - 2) == 0) {
591 		return (SES_SAFT);
592 	}
593 
594 	return (SES_NONE);
595 }
596 
597 /*
598  * SES Native Type Device Support
599  */
600 
601 /*
602  * SES Diagnostic Page Codes
603  */
604 
605 typedef enum {
606 	SesConfigPage = 0x1,
607 	SesControlPage,
608 #define	SesStatusPage SesControlPage
609 	SesHelpTxt,
610 	SesStringOut,
611 #define	SesStringIn	SesStringOut
612 	SesThresholdOut,
613 #define	SesThresholdIn SesThresholdOut
614 	SesArrayControl,
615 #define	SesArrayStatus	SesArrayControl
616 	SesElementDescriptor,
617 	SesShortStatus
618 } SesDiagPageCodes;
619 
620 /*
621  * minimal amounts
622  */
623 
624 /*
625  * Minimum amount of data, starting from byte 0, to have
626  * the config header.
627  */
628 #define	SES_CFGHDR_MINLEN	12
629 
630 /*
631  * Minimum amount of data, starting from byte 0, to have
632  * the config header and one enclosure header.
633  */
634 #define	SES_ENCHDR_MINLEN	48
635 
636 /*
637  * Take this value, subtract it from VEnclen and you know
638  * the length of the vendor unique bytes.
639  */
640 #define	SES_ENCHDR_VMIN		36
641 
642 /*
643  * SES Data Structures
644  */
645 
646 typedef struct {
647 	uint32_t GenCode;	/* Generation Code */
648 	uint8_t	Nsubenc;	/* Number of Subenclosures */
649 } SesCfgHdr;
650 
651 typedef struct {
652 	uint8_t	Subencid;	/* SubEnclosure Identifier */
653 	uint8_t	Ntypes;		/* # of supported types */
654 	uint8_t	VEnclen;	/* Enclosure Descriptor Length */
655 } SesEncHdr;
656 
657 typedef struct {
658 	uint8_t	encWWN[8];	/* XXX- Not Right Yet */
659 	uint8_t	encVid[8];
660 	uint8_t	encPid[16];
661 	uint8_t	encRev[4];
662 	uint8_t	encVen[1];
663 } SesEncDesc;
664 
665 typedef struct {
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 */
670 } SesThdr;
671 
672 typedef struct {
673 	uint8_t	comstatus;
674 	uint8_t	comstat[3];
675 } SesComStat;
676 
677 struct typidx {
678 	int ses_tidx;
679 	int ses_oidx;
680 };
681 
682 struct sscfg {
683 	uint8_t ses_ntypes;	/* total number of types supported */
684 
685 	/*
686 	 * We need to keep a type index as well as an
687 	 * object index for each object in an enclosure.
688 	 */
689 	struct typidx *ses_typidx;
690 
691 	/*
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.
696 	 */
697 	uint8_t *	ses_eltmap;
698 };
699 
700 
701 /*
702  * (de)canonicalization defines
703  */
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)
707 
708 #define	sset16(outp, idx, sval)	\
709 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
710 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
711 
712 
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)
717 
718 
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)
724 
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])
729 
730 #define	sget16(inp, idx, lval)	\
731 	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
732 		(((uint8_t *)(inp))[idx+1]), idx += 2
733 
734 #define	gget16(inp, idx, lval)	\
735 	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
736 		(((uint8_t *)(inp))[idx+1])
737 
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
742 
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])
747 
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
753 
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])
759 
760 #define	SCSZ	0x2000
761 #define	CFLEN	(256 + SES_ENCHDR_MINLEN)
762 
763 /*
764  * Routines specific && private to SES only
765  */
766 
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 *);
775 
776 static int
777 ses_softc_init(ses_softc_t *ssc, int doinit)
778 {
779 	if (doinit == 0) {
780 		struct sscfg *cc;
781 		if (ssc->ses_nobjects) {
782 			SES_FREE(ssc->ses_objmap,
783 			    ssc->ses_nobjects * sizeof (encobj));
784 			ssc->ses_objmap = NULL;
785 		}
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;
790 				cc->ses_ntypes = 0;
791 			}
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;
796 			}
797 			SES_FREE(cc, sizeof (struct sscfg));
798 			ssc->ses_private = NULL;
799 		}
800 		ssc->ses_nobjects = 0;
801 		return (0);
802 	}
803 	if (ssc->ses_private == NULL) {
804 		ssc->ses_private = SES_MALLOC(sizeof (struct sscfg));
805 	}
806 	if (ssc->ses_private == NULL) {
807 		return (ENOMEM);
808 	}
809 	ssc->ses_nobjects = 0;
810 	ssc->ses_encstat = 0;
811 	return (ses_getconfig(ssc));
812 }
813 
814 static int
815 ses_init_enc(ses_softc_t *ssc)
816 {
817 	return (0);
818 }
819 
820 static int
821 ses_get_encstat(ses_softc_t *ssc, int slpflag)
822 {
823 	SesComStat ComStat;
824 	int status;
825 
826 	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) {
827 		return (status);
828 	}
829 	ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID;
830 	return (0);
831 }
832 
833 static int
834 ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag)
835 {
836 	SesComStat ComStat;
837 	int status;
838 
839 	ComStat.comstatus = encstat & 0xf;
840 	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) {
841 		return (status);
842 	}
843 	ssc->ses_encstat = encstat & 0xf;	/* note no SVALID set */
844 	return (0);
845 }
846 
847 static int
848 ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
849 {
850 	int i = (int)obp->obj_id;
851 
852 	if (ssc->ses_objmap[i].svalid == 0) {
853 		SesComStat ComStat;
854 		int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1);
855 		if (err)
856 			return (err);
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;
862 	}
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];
867 	return (0);
868 }
869 
870 static int
871 ses_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
872 {
873 	SesComStat ComStat;
874 	int err;
875 	/*
876 	 * If this is clear, we don't do diddly.
877 	 */
878 	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
879 		return (0);
880 	}
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;
887 	return (err);
888 }
889 
890 static int
891 ses_getconfig(ses_softc_t *ssc)
892 {
893 	struct sscfg *cc;
894 	SesCfgHdr cf;
895 	SesEncHdr hd;
896 	SesEncDesc *cdp;
897 	SesThdr thdr;
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
902 	};
903 
904 	cc = ssc->ses_private;
905 	if (cc == NULL) {
906 		return (ENXIO);
907 	}
908 
909 	sdata = SES_MALLOC(SCSZ);
910 	if (sdata == NULL)
911 		return (ENOMEM);
912 
913 	amt = SCSZ;
914 	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
915 	if (err) {
916 		SES_FREE(sdata, SCSZ);
917 		return (err);
918 	}
919 	amt = SCSZ - amt;
920 
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);
924 		return (EIO);
925 	}
926 	if (amt < SES_ENCHDR_MINLEN) {
927 		SES_LOG(ssc, "runt enclosure length (%d)\n", amt);
928 		SES_FREE(sdata, SCSZ);
929 		return (EIO);
930 	}
931 
932 	SES_VLOG(ssc, "GenCode %x %d Subenclosures\n", cf.GenCode, cf.Nsubenc);
933 
934 	/*
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.
940 	 */
941 
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);
949 			return (EIO);
950 		}
951 		SES_VLOG(ssc, " SubEnclosure ID %d, %d Types With this ID, En"
952 		    "closure Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen);
953 
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);
957 			return (EIO);
958 		}
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]);
963 		ntype += hd.Ntypes;
964 	}
965 
966 	/*
967 	 * Now waltz through all the types that are available, getting
968 	 * the type header so we can start adding up the number of
969 	 * objects available.
970 	 */
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);
975 			return (EIO);
976 		}
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;
981 	}
982 
983 
984 	/*
985 	 * Now allocate the object array and type map.
986 	 */
987 
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);
991 
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;
997 		}
998 		if (cc->ses_typidx) {
999 			SES_FREE(cc->ses_typidx,
1000 			    (nobj * sizeof (struct typidx)));
1001 			cc->ses_typidx = NULL;
1002 		}
1003 		if (cc->ses_eltmap) {
1004 			SES_FREE(cc->ses_eltmap, ntype);
1005 			cc->ses_eltmap = NULL;
1006 		}
1007 		SES_FREE(sdata, SCSZ);
1008 		return (ENOMEM);
1009 	}
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;
1015 
1016 	/*
1017 	 * Now waltz through the # of types again to fill in the types
1018 	 * (and subenclosure ids) of the allocated objects.
1019 	 */
1020 	nobj = 0;
1021 	for (i = 0; i < ntype; i++) {
1022 		int j;
1023 		if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
1024 			continue;
1025 		}
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;
1032 		}
1033 	}
1034 	SES_FREE(sdata, SCSZ);
1035 	return (0);
1036 }
1037 
1038 static int
1039 ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp,
1040     int in)
1041 {
1042 	struct sscfg *cc;
1043 	int err, amt, bufsiz, tidx, oidx;
1044 	char cdb[6], *sdata;
1045 
1046 	cc = ssc->ses_private;
1047 	if (cc == NULL) {
1048 		return (ENXIO);
1049 	}
1050 
1051 	/*
1052 	 * If we're just getting overall enclosure status,
1053 	 * we only need 2 bytes of data storage.
1054 	 *
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.
1060 	 */
1061 	if (objid == -1) {
1062 		bufsiz = 2;
1063 	} else {
1064 		bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8;
1065 	}
1066 	sdata = SES_MALLOC(bufsiz);
1067 	if (sdata == NULL)
1068 		return (ENOMEM);
1069 
1070 	cdb[0] = RECEIVE_DIAGNOSTIC;
1071 	cdb[1] = 1;
1072 	cdb[2] = SesStatusPage;
1073 	cdb[3] = bufsiz >> 8;
1074 	cdb[4] = bufsiz & 0xff;
1075 	cdb[5] = 0;
1076 	amt = bufsiz;
1077 	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
1078 	if (err) {
1079 		SES_FREE(sdata, bufsiz);
1080 		return (err);
1081 	}
1082 	amt = bufsiz - amt;
1083 
1084 	if (objid == -1) {
1085 		tidx = -1;
1086 		oidx = -1;
1087 	} else {
1088 		tidx = cc->ses_typidx[objid].ses_tidx;
1089 		oidx = cc->ses_typidx[objid].ses_oidx;
1090 	}
1091 	if (in) {
1092 		if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
1093 			err = ENODEV;
1094 		}
1095 	} else {
1096 		if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
1097 			err = ENODEV;
1098 		} else {
1099 			cdb[0] = SEND_DIAGNOSTIC;
1100 			cdb[1] = 0x10;
1101 			cdb[2] = 0;
1102 			cdb[3] = bufsiz >> 8;
1103 			cdb[4] = bufsiz & 0xff;
1104 			cdb[5] = 0;
1105 			amt = -bufsiz;
1106 			err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
1107 		}
1108 	}
1109 	SES_FREE(sdata, bufsiz);
1110 	return (0);
1111 }
1112 
1113 
1114 /*
1115  * Routines to parse returned SES data structures.
1116  * Architecture and compiler independent.
1117  */
1118 
1119 static int
1120 ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp)
1121 {
1122 	if (buflen < SES_CFGHDR_MINLEN) {
1123 		return (-1);
1124 	}
1125 	gget8(buffer, 1, cfp->Nsubenc);
1126 	gget32(buffer, 4, cfp->GenCode);
1127 	return (0);
1128 }
1129 
1130 static int
1131 ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp)
1132 {
1133 	int s, off = 8;
1134 	for (s = 0; s < SubEncId; s++) {
1135 		if (off + 3 > amt)
1136 			return (-1);
1137 		off += buffer[off+3] + 4;
1138 	}
1139 	if (off + 3 > amt) {
1140 		return (-1);
1141 	}
1142 	gget8(buffer, off+1, chp->Subencid);
1143 	gget8(buffer, off+2, chp->Ntypes);
1144 	gget8(buffer, off+3, chp->VEnclen);
1145 	return (0);
1146 }
1147 
1148 static int
1149 ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp)
1150 {
1151 	int s, e, enclen, off = 8;
1152 	for (s = 0; s < SubEncId; s++) {
1153 		if (off + 3 > amt)
1154 			return (-1);
1155 		off += buffer[off+3] + 4;
1156 	}
1157 	if (off + 3 > amt) {
1158 		return (-1);
1159 	}
1160 	gget8(buffer, off+3, enclen);
1161 	off += 4;
1162 	if (off  >= amt)
1163 		return (-1);
1164 
1165 	e = off + enclen;
1166 	if (e > amt) {
1167 		e = amt;
1168 	}
1169 	MEMCPY(cdp, &buffer[off], e - off);
1170 	return (0);
1171 }
1172 
1173 static int
1174 ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp)
1175 {
1176 	int s, off = 8;
1177 
1178 	if (amt < SES_CFGHDR_MINLEN) {
1179 		return (-1);
1180 	}
1181 	for (s = 0; s < buffer[1]; s++) {
1182 		if (off + 3 > amt)
1183 			return (-1);
1184 		off += buffer[off+3] + 4;
1185 	}
1186 	if (off + 3 > amt) {
1187 		return (-1);
1188 	}
1189 	off += buffer[off+3] + 4 + (nth * 4);
1190 	if (amt < (off + 4))
1191 		return (-1);
1192 
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);
1197 	return (0);
1198 }
1199 
1200 /*
1201  * This function needs a little explanation.
1202  *
1203  * The arguments are:
1204  *
1205  *
1206  *	char *b, int amt
1207  *
1208  *		These describes the raw input SES status data and length.
1209  *
1210  *	uint8_t *ep
1211  *
1212  *		This is a map of the number of types for each element type
1213  *		in the enclosure.
1214  *
1215  *	int elt
1216  *
1217  *		This is the element type being sought. If elt is -1,
1218  *		then overall enclosure status is being sought.
1219  *
1220  *	int elm
1221  *
1222  *		This is the ordinal Mth element of type elt being sought.
1223  *
1224  *	SesComStat *sp
1225  *
1226  *		This is the output area to store the status for
1227  *		the Mth element of type Elt.
1228  */
1229 
1230 static int
1231 ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
1232 {
1233 	int idx, i;
1234 
1235 	/*
1236 	 * If it's overall enclosure status being sought, get that.
1237 	 * We need at least 2 bytes of status data to get that.
1238 	 */
1239 	if (elt == -1) {
1240 		if (amt < 2)
1241 			return (-1);
1242 		gget8(b, 1, sp->comstatus);
1243 		sp->comstat[0] = 0;
1244 		sp->comstat[1] = 0;
1245 		sp->comstat[2] = 0;
1246 		return (0);
1247 	}
1248 
1249 	/*
1250 	 * Check to make sure that the Mth element is legal for type Elt.
1251 	 */
1252 
1253 	if (elm >= ep[elt])
1254 		return (-1);
1255 
1256 	/*
1257 	 * Starting at offset 8, start skipping over the storage
1258 	 * for the element types we're not interested in.
1259 	 */
1260 	for (idx = 8, i = 0; i < elt; i++) {
1261 		idx += ((ep[i] + 1) * 4);
1262 	}
1263 
1264 	/*
1265 	 * Skip over Overall status for this element type.
1266 	 */
1267 	idx += 4;
1268 
1269 	/*
1270 	 * And skip to the index for the Mth element that we're going for.
1271 	 */
1272 	idx += (4 * elm);
1273 
1274 	/*
1275 	 * Make sure we haven't overflowed the buffer.
1276 	 */
1277 	if (idx+4 > amt)
1278 		return (-1);
1279 
1280 	/*
1281 	 * Retrieve the status.
1282 	 */
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]);
1287 #if	0
1288 	PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4);
1289 #endif
1290 	return (0);
1291 }
1292 
1293 /*
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.
1298  */
1299 
1300 static int
1301 ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
1302 {
1303 	int idx, i;
1304 
1305 	/*
1306 	 * If it's overall enclosure status being sought, get that.
1307 	 * We need at least 2 bytes of status data to get that.
1308 	 */
1309 	if (elt == -1) {
1310 		if (amt < 2)
1311 			return (-1);
1312 		i = 0;
1313 		sset8(b, i, 0);
1314 		sset8(b, i, sp->comstatus & 0xf);
1315 #if	0
1316 		PRINTF("set EncStat %x\n", sp->comstatus);
1317 #endif
1318 		return (0);
1319 	}
1320 
1321 	/*
1322 	 * Check to make sure that the Mth element is legal for type Elt.
1323 	 */
1324 
1325 	if (elm >= ep[elt])
1326 		return (-1);
1327 
1328 	/*
1329 	 * Starting at offset 8, start skipping over the storage
1330 	 * for the element types we're not interested in.
1331 	 */
1332 	for (idx = 8, i = 0; i < elt; i++) {
1333 		idx += ((ep[i] + 1) * 4);
1334 	}
1335 
1336 	/*
1337 	 * Skip over Overall status for this element type.
1338 	 */
1339 	idx += 4;
1340 
1341 	/*
1342 	 * And skip to the index for the Mth element that we're going for.
1343 	 */
1344 	idx += (4 * elm);
1345 
1346 	/*
1347 	 * Make sure we haven't overflowed the buffer.
1348 	 */
1349 	if (idx+4 > amt)
1350 		return (-1);
1351 
1352 	/*
1353 	 * Set the status.
1354 	 */
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]);
1359 	idx -= 4;
1360 
1361 #if	0
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]);
1365 #endif
1366 
1367 	/*
1368 	 * Now make sure all other 'Select' bits are off.
1369 	 */
1370 	for (i = 8; i < amt; i += 4) {
1371 		if (i != idx)
1372 			b[i] &= ~0x80;
1373 	}
1374 	/*
1375 	 * And make sure the INVOP bit is clear.
1376 	 */
1377 	b[2] &= ~0x10;
1378 
1379 	return (0);
1380 }
1381 
1382 /*
1383  * SAF-TE Type Device Emulation
1384  */
1385 
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);
1392 
1393 #define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
1394 	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
1395 /*
1396  * SAF-TE specific defines- Mandatory ones only...
1397  */
1398 
1399 /*
1400  * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
1401  */
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 */
1405 
1406 /*
1407  * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
1408  */
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 */
1414 
1415 
1416 #define	SAFT_SCRATCH	64
1417 #define	NPSEUDO_THERM	16
1418 #define	NPSEUDO_ALARM	1
1419 struct scfg {
1420 	/*
1421 	 * Cached Configuration
1422 	 */
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) */
1430 	/*
1431 	 * Cached Flag Bytes for Global Status
1432 	 */
1433 	uint8_t	flag1;
1434 	uint8_t	flag2;
1435 	/*
1436 	 * What object index ID is where various slots start.
1437 	 */
1438 	uint8_t	pwroff;
1439 	uint8_t	slotoff;
1440 #define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
1441 };
1442 
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
1451 
1452 #define	SAFT_FLG2_LOCKDOOR	0x4
1453 #define	SAFT_PRIVATE		sizeof (struct scfg)
1454 
1455 static const char safte_2little[] = "Too Little Data Returned (%d) at line %d\n";
1456 #define	SAFT_BAIL(r, x, k, l)	\
1457 	if (r >= x) { \
1458 		SES_LOG(ssc, safte_2little, x, __LINE__);\
1459 		SES_FREE(k, l); \
1460 		return (EIO); \
1461 	}
1462 
1463 
1464 static int
1465 safte_softc_init(ses_softc_t *ssc, int doinit)
1466 {
1467 	int err, i, r;
1468 	struct scfg *cc;
1469 
1470 	if (doinit == 0) {
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;
1476 			}
1477 			ssc->ses_nobjects = 0;
1478 		}
1479 		if (ssc->ses_private) {
1480 			SES_FREE(ssc->ses_private, SAFT_PRIVATE);
1481 			ssc->ses_private = NULL;
1482 		}
1483 		return (0);
1484 	}
1485 
1486 	if (ssc->ses_private == NULL) {
1487 		ssc->ses_private = SES_MALLOC(SAFT_PRIVATE);
1488 		if (ssc->ses_private == NULL) {
1489 			return (ENOMEM);
1490 		}
1491 		MEMZERO(ssc->ses_private, SAFT_PRIVATE);
1492 	}
1493 
1494 	ssc->ses_nobjects = 0;
1495 	ssc->ses_encstat = 0;
1496 
1497 	if ((err = safte_getconfig(ssc)) != 0) {
1498 		return (err);
1499 	}
1500 
1501 	/*
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.
1505 	 */
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) {
1512 		return (ENOMEM);
1513 	}
1514 	MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj));
1515 
1516 	r = 0;
1517 	/*
1518 	 * Note that this is all arranged for the convenience
1519 	 * in later fetches of status.
1520 	 */
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;
1538 	return (0);
1539 }
1540 
1541 static int
1542 safte_init_enc(ses_softc_t *ssc)
1543 {
1544 	int err, amt;
1545 	char *sdata;
1546 	static char cdb0[6] = { SEND_DIAGNOSTIC };
1547 	static char cdb[10] =
1548 	    { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
1549 
1550 	sdata = SES_MALLOC(SAFT_SCRATCH);
1551 	if (sdata == NULL)
1552 		return (ENOMEM);
1553 
1554 	err = ses_runcmd(ssc, cdb0, 6, NULL, 0);
1555 	if (err) {
1556 		SES_FREE(sdata, SAFT_SCRATCH);
1557 		return (err);
1558 	}
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);
1564 	return (err);
1565 }
1566 
1567 static int
1568 safte_get_encstat(ses_softc_t *ssc, int slpflg)
1569 {
1570 	return (safte_rdstat(ssc, slpflg));
1571 }
1572 
1573 static int
1574 safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg)
1575 {
1576 	struct scfg *cc = ssc->ses_private;
1577 	if (cc == NULL)
1578 		return (0);
1579 	/*
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.
1584 	 */
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;
1593 	}
1594 	return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
1595 }
1596 
1597 static int
1598 safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg)
1599 {
1600 	int i = (int)obp->obj_id;
1601 
1602 	if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
1603 	    (ssc->ses_objmap[i].svalid) == 0) {
1604 		int err = safte_rdstat(ssc, slpflg);
1605 		if (err)
1606 			return (err);
1607 	}
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];
1612 	return (0);
1613 }
1614 
1615 
1616 static int
1617 safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp)
1618 {
1619 	int idx, err;
1620 	encobj *ep;
1621 	struct scfg *cc;
1622 
1623 
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],
1626 	    obp->cstat[3]);
1627 
1628 	/*
1629 	 * If this is clear, we don't do diddly.
1630 	 */
1631 	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
1632 		return (0);
1633 	}
1634 
1635 	err = 0;
1636 	/*
1637 	 * Check to see if the common bits are set and do them first.
1638 	 */
1639 	if (obp->cstat[0] & ~SESCTL_CSEL) {
1640 		err = set_objstat_sel(ssc, obp, slp);
1641 		if (err)
1642 			return (err);
1643 	}
1644 
1645 	cc = ssc->ses_private;
1646 	if (cc == NULL)
1647 		return (0);
1648 
1649 	idx = (int)obp->obj_id;
1650 	ep = &ssc->ses_objmap[idx];
1651 
1652 	switch (ep->enctype) {
1653 	case SESTYP_DEVICE:
1654 	{
1655 		uint8_t slotop = 0;
1656 		/*
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.
1661 		 */
1662 		if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
1663 			slotop |= 0x2;
1664 		}
1665 		if (obp->cstat[2] & SESCTL_RQSID) {
1666 			slotop |= 0x4;
1667 		}
1668 		err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff,
1669 		    slotop, slp);
1670 		if (err)
1671 			return (err);
1672 		if (obp->cstat[3] & SESCTL_RQSFLT) {
1673 			ep->priv |= 0x2;
1674 		} else {
1675 			ep->priv &= ~0x2;
1676 		}
1677 		if (ep->priv & 0xc6) {
1678 			ep->priv &= ~0x1;
1679 		} else {
1680 			ep->priv |= 0x1;	/* no errors */
1681 		}
1682 		wrslot_stat(ssc, slp);
1683 		break;
1684 	}
1685 	case SESTYP_POWER:
1686 		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
1687 			cc->flag1 |= SAFT_FLG1_ENCPWRFAIL;
1688 		} else {
1689 			cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
1690 		}
1691 		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1692 		    cc->flag2, 0, slp);
1693 		if (err)
1694 			return (err);
1695 		if (obp->cstat[3] & SESCTL_RQSTON) {
1696 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
1697 				idx - cc->pwroff, 0, 0, slp);
1698 		} else {
1699 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
1700 				idx - cc->pwroff, 0, 1, slp);
1701 		}
1702 		break;
1703 	case SESTYP_FAN:
1704 		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
1705 			cc->flag1 |= SAFT_FLG1_ENCFANFAIL;
1706 		} else {
1707 			cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
1708 		}
1709 		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1710 		    cc->flag2, 0, slp);
1711 		if (err)
1712 			return (err);
1713 		if (obp->cstat[3] & SESCTL_RQSTON) {
1714 			uint8_t fsp;
1715 			if ((obp->cstat[3] & 0x7) == 7) {
1716 				fsp = 4;
1717 			} else if ((obp->cstat[3] & 0x7) == 6) {
1718 				fsp = 3;
1719 			} else if ((obp->cstat[3] & 0x7) == 4) {
1720 				fsp = 2;
1721 			} else {
1722 				fsp = 1;
1723 			}
1724 			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
1725 		} else {
1726 			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
1727 		}
1728 		break;
1729 	case SESTYP_DOORLOCK:
1730 		if (obp->cstat[3] & 0x1) {
1731 			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
1732 		} else {
1733 			cc->flag2 |= SAFT_FLG2_LOCKDOOR;
1734 		}
1735 		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1736 		    cc->flag2, 0, slp);
1737 		break;
1738 	case SESTYP_ALARM:
1739 		/*
1740 		 * On all nonzero but the 'muted' bit, we turn on the alarm,
1741 		 */
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;
1747 		} else {
1748 			cc->flag2 &= ~SAFT_FLG1_ALARM;
1749 		}
1750 		ep->priv = obp->cstat[3];
1751 		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1752 			cc->flag2, 0, slp);
1753 		break;
1754 	default:
1755 		break;
1756 	}
1757 	ep->svalid = 0;
1758 	return (0);
1759 }
1760 
1761 static int
1762 safte_getconfig(ses_softc_t *ssc)
1763 {
1764 	struct scfg *cfg;
1765 	int err, amt;
1766 	char *sdata;
1767 	static char cdb[10] =
1768 	    { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
1769 
1770 	cfg = ssc->ses_private;
1771 	if (cfg == NULL)
1772 		return (ENXIO);
1773 
1774 	sdata = SES_MALLOC(SAFT_SCRATCH);
1775 	if (sdata == NULL)
1776 		return (ENOMEM);
1777 
1778 	amt = SAFT_SCRATCH;
1779 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
1780 	if (err) {
1781 		SES_FREE(sdata, SAFT_SCRATCH);
1782 		return (err);
1783 	}
1784 	amt = SAFT_SCRATCH - amt;
1785 	if (amt < 6) {
1786 		SES_LOG(ssc, "too little data (%d) for configuration\n", amt);
1787 		SES_FREE(sdata, SAFT_SCRATCH);
1788 		return (EIO);
1789 	}
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);
1800 	return (0);
1801 }
1802 
1803 static int
1804 safte_rdstat(ses_softc_t *ssc, int slpflg)
1805 {
1806 	int err, oid, r, i, hiwater, nitems, amt;
1807 	uint16_t tempflags;
1808 	size_t buflen;
1809 	uint8_t status, oencstat;
1810 	char *sdata, cdb[10];
1811 	struct scfg *cc = ssc->ses_private;
1812 
1813 
1814 	/*
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.
1819 	 */
1820 	buflen = 4 * cc->Nslots;
1821 	if (ssc->ses_nobjects > buflen)
1822 		buflen = ssc->ses_nobjects;
1823 	sdata = SES_MALLOC(buflen);
1824 	if (sdata == NULL)
1825 		return (ENOMEM);
1826 
1827 	cdb[0] = READ_BUFFER;
1828 	cdb[1] = 1;
1829 	cdb[2] = SAFTE_RD_RDESTS;
1830 	cdb[3] = 0;
1831 	cdb[4] = 0;
1832 	cdb[5] = 0;
1833 	cdb[6] = 0;
1834 	cdb[7] = (buflen >> 8) & 0xff;
1835 	cdb[8] = buflen & 0xff;
1836 	cdb[9] = 0;
1837 	amt = buflen;
1838 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
1839 	if (err) {
1840 		SES_FREE(sdata, buflen);
1841 		return (err);
1842 	}
1843 	hiwater = buflen - amt;
1844 
1845 
1846 	/*
1847 	 * invalidate all status bits.
1848 	 */
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;
1853 
1854 
1855 	/*
1856 	 * Now parse returned buffer.
1857 	 * If we didn't get enough data back,
1858 	 * that's considered a fatal error.
1859 	 */
1860 	oid = r = 0;
1861 
1862 	for (nitems = i = 0; i < cc->Nfans; i++) {
1863 		SAFT_BAIL(r, hiwater, sdata, buflen);
1864 		/*
1865 		 * 0 = Fan Operational
1866 		 * 1 = Fan is malfunctioning
1867 		 * 2 = Fan is not present
1868 		 * 0x80 = Unknown or Not Reportable Status
1869 		 */
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]) {
1873 		case 0:
1874 			nitems++;
1875 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
1876 			/*
1877 			 * We could get fancier and cache
1878 			 * fan speeds that we have set, but
1879 			 * that isn't done now.
1880 			 */
1881 			ssc->ses_objmap[oid].encstat[3] = 7;
1882 			break;
1883 
1884 		case 1:
1885 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
1886 			/*
1887 			 * FAIL and FAN STOPPED synthesized
1888 			 */
1889 			ssc->ses_objmap[oid].encstat[3] = 0x40;
1890 			/*
1891 			 * Enclosure marked with CRITICAL error
1892 			 * if only one fan or no thermometers,
1893 			 * else the NONCRITICAL error is set.
1894 			 */
1895 			if (cc->Nfans == 1 || cc->Ntherm == 0)
1896 				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
1897 			else
1898 				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
1899 			break;
1900 		case 2:
1901 			ssc->ses_objmap[oid].encstat[0] =
1902 			    SES_OBJSTAT_NOTINSTALLED;
1903 			ssc->ses_objmap[oid].encstat[3] = 0;
1904 			/*
1905 			 * Enclosure marked with CRITICAL error
1906 			 * if only one fan or no thermometers,
1907 			 * else the NONCRITICAL error is set.
1908 			 */
1909 			if (cc->Nfans == 1)
1910 				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
1911 			else
1912 				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
1913 			break;
1914 		case 0x80:
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;
1918 			break;
1919 		default:
1920 			ssc->ses_objmap[oid].encstat[0] =
1921 			    SES_OBJSTAT_UNSUPPORTED;
1922 			SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i,
1923 			    sdata[r] & 0xff);
1924 			break;
1925 		}
1926 		ssc->ses_objmap[oid++].svalid = 1;
1927 		r++;
1928 	}
1929 
1930 	/*
1931 	 * No matter how you cut it, no cooling elements when there
1932 	 * should be some there is critical.
1933 	 */
1934 	if (cc->Nfans && nitems == 0) {
1935 		ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
1936 	}
1937 
1938 
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;
1948 			break;
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;
1953 			break;
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;
1958 			break;
1959 
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;
1964 			break;
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;
1970 			break;
1971 		case 0x21:	/* pws is present */
1972 			/*
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.
1976 			 */
1977 			/* FALLTHROUGH */
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;
1982 			break;
1983 		default:
1984 			SES_LOG(ssc, "unknown power supply %d status (0x%x)\n",
1985 			    i, sdata[r] & 0xff);
1986 			break;
1987 		}
1988 		ssc->ses_objmap[oid++].svalid = 1;
1989 		r++;
1990 	}
1991 
1992 	/*
1993 	 * Skip over Slot SCSI IDs
1994 	 */
1995 	r += cc->Nslots;
1996 
1997 	/*
1998 	 * We always have doorlock status, no matter what,
1999 	 * but we only save the status if we have one.
2000 	 */
2001 	SAFT_BAIL(r, hiwater, sdata, buflen);
2002 	if (cc->DoorLock) {
2003 		/*
2004 		 * 0 = Door Locked
2005 		 * 1 = Door Unlocked, or no Lock Installed
2006 		 * 0x80 = Unknown or Not Reportable Status
2007 		 */
2008 		ssc->ses_objmap[oid].encstat[1] = 0;
2009 		ssc->ses_objmap[oid].encstat[2] = 0;
2010 		switch ((uint8_t)sdata[r]) {
2011 		case 0:
2012 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
2013 			ssc->ses_objmap[oid].encstat[3] = 0;
2014 			break;
2015 		case 1:
2016 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
2017 			ssc->ses_objmap[oid].encstat[3] = 1;
2018 			break;
2019 		case 0x80:
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;
2023 			break;
2024 		default:
2025 			ssc->ses_objmap[oid].encstat[0] =
2026 			    SES_OBJSTAT_UNSUPPORTED;
2027 			SES_LOG(ssc, "unknown lock status 0x%x\n",
2028 			    sdata[r] & 0xff);
2029 			break;
2030 		}
2031 		ssc->ses_objmap[oid++].svalid = 1;
2032 	}
2033 	r++;
2034 
2035 	/*
2036 	 * We always have speaker status, no matter what,
2037 	 * but we only save the status if we have one.
2038 	 */
2039 	SAFT_BAIL(r, hiwater, sdata, buflen);
2040 	if (cc->Nspkrs) {
2041 		ssc->ses_objmap[oid].encstat[1] = 0;
2042 		ssc->ses_objmap[oid].encstat[2] = 0;
2043 		if (sdata[r] == 1) {
2044 			/*
2045 			 * We need to cache tone urgency indicators.
2046 			 * Someday.
2047 			 */
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;
2054 		} else {
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",
2059 			    sdata[r] & 0xff);
2060 		}
2061 		ssc->ses_objmap[oid++].svalid = 1;
2062 	}
2063 	r++;
2064 
2065 	for (i = 0; i < cc->Ntherm; i++) {
2066 		SAFT_BAIL(r, hiwater, sdata, buflen);
2067 		/*
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.
2074 		 *
2075 		 * So what's over and under temperature?
2076 		 * Hmm- we'll state that 'normal' operating
2077 		 * is 10 to 40 deg Celsius.
2078 		 */
2079 
2080 		/*
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.
2084 		 *
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.
2090 		 *
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.
2096 		 */
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;
2102 		r++;
2103 	}
2104 
2105 	/*
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.
2113 	 */
2114 
2115 	SAFT_BAIL(r, hiwater, sdata, buflen);
2116 	tempflags = sdata[r++];
2117 	SAFT_BAIL(r, hiwater, sdata, buflen);
2118 	tempflags |= (tempflags << 8) | sdata[r++];
2119 
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;
2125 			/*
2126 			 * Set 'over temperature' failure.
2127 			 */
2128 			ssc->ses_objmap[oid].encstat[3] = 8;
2129 			ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
2130 		} else {
2131 			/*
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
2135 			 * zero.
2136 			 */
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;
2140 		}
2141 		ssc->ses_objmap[oid++].svalid = 1;
2142 	}
2143 
2144 	/*
2145 	 * Get alarm status.
2146 	 */
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;
2150 
2151 	/*
2152 	 * Now get drive slot status
2153 	 */
2154 	cdb[2] = SAFTE_RD_RDDSTS;
2155 	amt = buflen;
2156 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
2157 	if (err) {
2158 		SES_FREE(sdata, buflen);
2159 		return (err);
2160 	}
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;
2172 		} else {
2173 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
2174 		}
2175 		if (status & 0x2) {
2176 			ssc->ses_objmap[oid].encstat[2] = 0x8;
2177 		}
2178 		if ((status & 0x4) == 0) {
2179 			ssc->ses_objmap[oid].encstat[3] = 0x10;
2180 		}
2181 		ssc->ses_objmap[oid++].svalid = 1;
2182 	}
2183 	/* see comment below about sticky enclosure status */
2184 	ssc->ses_encstat |= ENCI_SVALID | oencstat;
2185 	SES_FREE(sdata, buflen);
2186 	return (0);
2187 }
2188 
2189 static int
2190 set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp)
2191 {
2192 	int idx;
2193 	encobj *ep;
2194 	struct scfg *cc = ssc->ses_private;
2195 
2196 	if (cc == NULL)
2197 		return (0);
2198 
2199 	idx = (int)obp->obj_id;
2200 	ep = &ssc->ses_objmap[idx];
2201 
2202 	switch (ep->enctype) {
2203 	case SESTYP_DEVICE:
2204 		if (obp->cstat[0] & SESCTL_PRDFAIL) {
2205 			ep->priv |= 0x40;
2206 		}
2207 		/* SESCTL_RSTSWAP has no correspondence in SAF-TE */
2208 		if (obp->cstat[0] & SESCTL_DISABLE) {
2209 			ep->priv |= 0x80;
2210 			/*
2211 			 * Hmm. Try to set the 'No Drive' flag.
2212 			 * Maybe that will count as a 'disable'.
2213 			 */
2214 		}
2215 		if (ep->priv & 0xc6) {
2216 			ep->priv &= ~0x1;
2217 		} else {
2218 			ep->priv |= 0x1;	/* no errors */
2219 		}
2220 		wrslot_stat(ssc, slp);
2221 		break;
2222 	case SESTYP_POWER:
2223 		/*
2224 		 * Okay- the only one that makes sense here is to
2225 		 * do the 'disable' for a power supply.
2226 		 */
2227 		if (obp->cstat[0] & SESCTL_DISABLE) {
2228 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
2229 				idx - cc->pwroff, 0, 0, slp);
2230 		}
2231 		break;
2232 	case SESTYP_FAN:
2233 		/*
2234 		 * Okay- the only one that makes sense here is to
2235 		 * set fan speed to zero on disable.
2236 		 */
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);
2240 		}
2241 		break;
2242 	case SESTYP_DOORLOCK:
2243 		/*
2244 		 * Well, we can 'disable' the lock.
2245 		 */
2246 		if (obp->cstat[0] & SESCTL_DISABLE) {
2247 			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
2248 			(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
2249 				cc->flag2, 0, slp);
2250 		}
2251 		break;
2252 	case SESTYP_ALARM:
2253 		/*
2254 		 * Well, we can 'disable' the alarm.
2255 		 */
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,
2260 				cc->flag2, 0, slp);
2261 		}
2262 		break;
2263 	default:
2264 		break;
2265 	}
2266 	ep->svalid = 0;
2267 	return (0);
2268 }
2269 
2270 /*
2271  * This function handles all of the 16 byte WRITE BUFFER commands.
2272  */
2273 static int
2274 wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2,
2275     uint8_t b3, int slp)
2276 {
2277 	int err, amt;
2278 	char *sdata;
2279 	struct scfg *cc = ssc->ses_private;
2280 	static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
2281 
2282 	if (cc == NULL)
2283 		return (0);
2284 
2285 	sdata = SES_MALLOC(16);
2286 	if (sdata == NULL)
2287 		return (ENOMEM);
2288 
2289 	SES_VLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3);
2290 
2291 	sdata[0] = op;
2292 	sdata[1] = b1;
2293 	sdata[2] = b2;
2294 	sdata[3] = b3;
2295 	MEMZERO(&sdata[4], 12);
2296 	amt = -16;
2297 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
2298 	SES_FREE(sdata, 16);
2299 	return (err);
2300 }
2301 
2302 /*
2303  * This function updates the status byte for the device slot described.
2304  *
2305  * Since this is an optional SAF-TE command, there's no point in
2306  * returning an error.
2307  */
2308 static void
2309 wrslot_stat(ses_softc_t *ssc, int slp)
2310 {
2311 	int i, amt;
2312 	encobj *ep;
2313 	char cdb[10], *sdata;
2314 	struct scfg *cc = ssc->ses_private;
2315 
2316 	if (cc == NULL)
2317 		return;
2318 
2319 	SES_VLOG(ssc, "saf_wrslot\n");
2320 	cdb[0] = WRITE_BUFFER;
2321 	cdb[1] = 1;
2322 	cdb[2] = 0;
2323 	cdb[3] = 0;
2324 	cdb[4] = 0;
2325 	cdb[5] = 0;
2326 	cdb[6] = 0;
2327 	cdb[7] = 0;
2328 	cdb[8] = cc->Nslots * 3 + 1;
2329 	cdb[9] = 0;
2330 
2331 	sdata = SES_MALLOC(cc->Nslots * 3 + 1);
2332 	if (sdata == NULL)
2333 		return;
2334 	MEMZERO(sdata, cc->Nslots * 3 + 1);
2335 
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;
2341 	}
2342 	amt = -(cc->Nslots * 3 + 1);
2343 	(void) ses_runcmd(ssc, cdb, 10, sdata, &amt);
2344 	SES_FREE(sdata, cc->Nslots * 3 + 1);
2345 }
2346 
2347 /*
2348  * This function issues the "PERFORM SLOT OPERATION" command.
2349  */
2350 static int
2351 perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp)
2352 {
2353 	int err, amt;
2354 	char *sdata;
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 };
2358 
2359 	if (cc == NULL)
2360 		return (0);
2361 
2362 	sdata = SES_MALLOC(SAFT_SCRATCH);
2363 	if (sdata == NULL)
2364 		return (ENOMEM);
2365 	MEMZERO(sdata, SAFT_SCRATCH);
2366 
2367 	sdata[0] = SAFTE_WT_SLTOP;
2368 	sdata[1] = slot;
2369 	sdata[2] = opflag;
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);
2374 	return (err);
2375 }
2376