1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 /*
29  * Enclosure Services Devices, SES Enclosure Routines
30  */
31 
32 #include <sys/modctl.h>
33 #include <sys/file.h>
34 #include <sys/scsi/scsi.h>
35 #include <sys/stat.h>
36 #include <sys/scsi/targets/ses.h>
37 
38 /*
39  * SES Diagnostic Page Codes
40  */
41 
42 typedef enum {
43 	SesConfigPage = 0x1,
44 	SesControlPage,
45 #define	SesStatusPage SesControlPage
46 	SesHelpTxt,
47 	SesStringOut,
48 #define	SesStringIn	SesStringOut
49 	SesThresholdOut,
50 #define	SesThresholdIn SesThresholdOut
51 	SesArrayControl,
52 #define	SesArrayStatus	SesArrayControl
53 	SesElementDescriptor,
54 	SesShortStatus
55 } SesDiagPageCodes;
56 
57 /*
58  * minimal amounts
59  */
60 
61 /*
62  * Minimum amount of data, starting from byte 0, to have
63  * the config header.
64  */
65 #define	SES_CFGHDR_MINLEN	12
66 
67 /*
68  * Minimum amount of data, starting from byte 0, to have
69  * the config header and one enclosure header.
70  */
71 #define	SES_ENCHDR_MINLEN	48
72 
73 /*
74  * Take this value, subtract it from VEnclen and you know
75  * the length of the vendor unique bytes.
76  */
77 #define	SES_ENCHDR_VMIN		36
78 
79 /*
80  * SES Data Structures
81  */
82 
83 typedef struct {
84 	ulong_t	GenCode;	/* Generation Code */
85 	uchar_t	Nsubenc;	/* Number of Subenclosures */
86 } SesCfgHdr;
87 
88 typedef struct {
89 	uchar_t	Subencid;	/* SubEnclosure Identifier */
90 	uchar_t	Ntypes;		/* # of supported types */
91 	uchar_t	VEnclen;	/* Enclosure Descriptor Length */
92 } SesEncHdr;
93 
94 typedef struct {
95 	uchar_t	encWWN[8];	/* XXX- Not Right Yet */
96 	uchar_t	encVid[8];
97 	uchar_t	encPid[16];
98 	uchar_t	encRev[4];
99 	uchar_t	encVen[1];
100 } SesEncDesc;
101 
102 typedef struct {
103 	uchar_t	enc_type;		/* type of element */
104 	uchar_t	enc_maxelt;		/* maximum supported */
105 	uchar_t	enc_subenc;		/* in SubEnc # N */
106 	uchar_t	enc_tlen;		/* Type Descriptor Text Length */
107 } SesThdr;
108 
109 typedef struct {
110 	uchar_t	comstatus;
111 	uchar_t	comstat[3];
112 } SesComStat;
113 #if	!defined(lint)
114 _NOTE(SCHEME_PROTECTS_DATA("because I said so", SesComStat))
115 #endif
116 
117 struct typidx {
118 	int ses_tidx;
119 	int ses_oidx;
120 };
121 #if	!defined(lint)
122 _NOTE(SCHEME_PROTECTS_DATA("because I said so", typidx))
123 #endif
124 
125 struct sscfg {
126 	uchar_t ses_ntypes;	/* total number of types supported */
127 
128 	/*
129 	 * We need to keep a type index as well as an object index
130 	 * for each object in an enclosure.
131 	 */
132 	struct typidx *ses_typidx;
133 	/*
134 	 * We also need to keep track of the number of elements
135 	 * per type of element. This is needed later so that we
136 	 * can find precisely in the returned status data the
137 	 * status for the Nth element of the Kth type.
138 	 */
139 	uchar_t *ses_eltmap;
140 };
141 #if	!defined(lint)
142 _NOTE(MUTEX_PROTECTS_DATA(scsi_device::sd_mutex, sscfg))
143 _NOTE(DATA_READABLE_WITHOUT_LOCK(sscfg))
144 #endif
145 
146 
147 /*
148  * (de)canonicalization defines
149  */
150 #define	sbyte(x, byte)	((((ulong_t)(x)) >> (byte * 8)) & 0xff)
151 #define	sbit(x, bit)	(((ulong_t)(x)) << bit)
152 #define	sset8(outp, idx, sval)	\
153 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 0)
154 
155 #define	sset16(outp, idx, sval)	\
156 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \
157 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 0)
158 
159 
160 #define	sset24(outp, idx, sval)	\
161 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 2), \
162 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \
163 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 0)
164 
165 
166 #define	sset32(outp, idx, sval)	\
167 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 3), \
168 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 2), \
169 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \
170 	(((uchar_t *)(outp))[idx++]) = sbyte(sval, 0)
171 
172 #define	gbyte(x, byte)	((((ulong_t)(x)) & 0xff) << (byte * 8))
173 #define	gbit(lv, in, idx, shft, mask)	lv = ((in[idx] >> shft) & mask)
174 #define	sget8(inp, idx, lval)	lval = (((uchar_t *)(inp))[idx++])
175 #define	gget8(inp, idx, lval)	lval = (((uchar_t *)(inp))[idx])
176 
177 #define	sget16(inp, idx, lval)	\
178 	lval = gbyte((((uchar_t *)(inp))[idx]), 1) | \
179 		(((uchar_t *)(inp))[idx+1]), idx += 2
180 
181 #define	gget16(inp, idx, lval)	\
182 	lval = gbyte((((uchar_t *)(inp))[idx]), 1) | \
183 		(((uchar_t *)(inp))[idx+1])
184 
185 #define	sget24(inp, idx, lval)	\
186 	lval = gbyte((((uchar_t *)(inp))[idx]), 2) | \
187 		gbyte((((uchar_t *)(inp))[idx+1]), 1) | \
188 			(((uchar_t *)(inp))[idx+2]), idx += 3
189 
190 #define	gget24(inp, idx, lval)	\
191 	lval = gbyte((((uchar_t *)(inp))[idx]), 2) | \
192 		gbyte((((uchar_t *)(inp))[idx+1]), 1) | \
193 			(((uchar_t *)(inp))[idx+2])
194 
195 #define	sget32(inp, idx, lval)	\
196 	lval = gbyte((((uchar_t *)(inp))[idx]), 3) | \
197 		gbyte((((uchar_t *)(inp))[idx+1]), 2) | \
198 		gbyte((((uchar_t *)(inp))[idx+2]), 1) | \
199 			(((uchar_t *)(inp))[idx+3]), idx += 4
200 
201 #define	gget32(inp, idx, lval)	\
202 	lval = gbyte((((uchar_t *)(inp))[idx]), 3) | \
203 		gbyte((((uchar_t *)(inp))[idx+1]), 2) | \
204 		gbyte((((uchar_t *)(inp))[idx+2]), 1) | \
205 			(((uchar_t *)(inp))[idx+3])
206 #define	skip8(idx)	idx += 1
207 #define	skip16(idx)	idx += 2
208 #define	skip24(idx)	idx += 3
209 #define	skip32(idx)	idx += 4
210 static int ses_cfghdr(uchar_t *, int, SesCfgHdr *);
211 static int ses_enchdr(uchar_t *, int, uchar_t, SesEncHdr *);
212 static int ses_encdesc(uchar_t *, int, uchar_t, SesEncDesc *);
213 static int ses_getthdr(uchar_t *, int,  int, SesThdr *);
214 static int ses_decode(char *, int, uchar_t *, int, int, SesComStat *);
215 static int ses_encode(char *, int, uchar_t *, int, int, SesComStat *);
216 
217 #define	SCSZ	0x4cc
218 
219 static int
220 ses_getconfig(ses_softc_t *ssc)
221 {
222 	struct sscfg *cc;
223 	SesCfgHdr cf;
224 	SesEncHdr hd;
225 	SesEncDesc *cdp;
226 	SesThdr thdr;
227 	int err, amt, i, nobj, ntype, maxima;
228 	Uscmd local, *lp = &local;
229 	char storage[SCSZ], *sdata;
230 	static char cdb[CDB_GROUP0] =
231 	    { SCMD_GDIAG, 0x1, SesConfigPage, (char)(SCSZ >> 8),
232 	    (char)(SCSZ & 0xff), 0 };
233 
234 	cc = ssc->ses_private;
235 	if (cc == NULL) {
236 		return (ENXIO);
237 	}
238 
239 	sdata = kmem_alloc(SCSZ, KM_SLEEP);
240 	if (sdata == NULL)
241 		return (ENOMEM);
242 
243 	lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE;
244 	lp->uscsi_timeout = ses_io_time;
245 	lp->uscsi_cdb = cdb;
246 	lp->uscsi_bufaddr = sdata;
247 	lp->uscsi_buflen = SCSZ;
248 	lp->uscsi_cdblen = sizeof (cdb);
249 	lp->uscsi_rqbuf = storage;
250 	lp->uscsi_rqlen = SENSE_LENGTH;
251 
252 	err = ses_runcmd(ssc, lp);
253 	if (err) {
254 		kmem_free(sdata, SCSZ);
255 		return (err);
256 	}
257 	amt = lp->uscsi_buflen - lp->uscsi_resid;
258 
259 	if (ses_cfghdr((uchar_t *)sdata, amt, &cf)) {
260 		SES_LOG(ssc, CE_NOTE, "Unable to parse SES Config Header");
261 		kmem_free(sdata, SCSZ);
262 		return (EIO);
263 	}
264 	if (amt < SES_ENCHDR_MINLEN) {
265 		SES_LOG(ssc, CE_NOTE, "runt enclosure length (%d)", amt);
266 		kmem_free(sdata, SCSZ);
267 		return (EIO);
268 	}
269 
270 	SES_LOG(ssc, SES_CE_DEBUG3, "GenCode %lx %d Subenclosures",
271 	    cf.GenCode, cf.Nsubenc);
272 
273 	/*
274 	 * Now waltz through all the subenclosures toting up the
275 	 * number of types available in each. For this, we only
276 	 * really need the enclosure header. However, we get the
277 	 * enclosure descriptor for debug purposes, as well
278 	 * as self-consistency checking purposes.
279 	 */
280 
281 	maxima = cf.Nsubenc + 1;
282 	cdp = (SesEncDesc *) storage;
283 	for (ntype = i = 0; i < maxima; i++) {
284 		bzero((caddr_t)cdp, sizeof (*cdp));
285 		if (ses_enchdr((uchar_t *)sdata, amt, i, &hd)) {
286 			SES_LOG(ssc, CE_NOTE,
287 			    "Cannot Extract Enclosure Header %d", i);
288 			kmem_free(sdata, SCSZ);
289 			return (EIO);
290 		}
291 		SES_LOG(ssc, SES_CE_DEBUG3,
292 		    "\tSubEnclosure ID %d, %d Types With this ID, Enclosure "
293 		    "Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen);
294 
295 		if (ses_encdesc((uchar_t *)sdata, amt, i, cdp)) {
296 			SES_LOG(ssc, CE_NOTE,
297 			    "Cannot Extract Enclosure Descriptor %d", i);
298 			kmem_free(sdata, SCSZ);
299 			return (EIO);
300 		}
301 
302 		SES_LOG(ssc, SES_CE_DEBUG3,
303 		    "\tWWN: %02x%02x%02x%02x%02x%02x%02x%02x", cdp->encWWN[0],
304 		    cdp->encWWN[1], cdp->encWWN[2], cdp->encWWN[3],
305 		    cdp->encWWN[4], cdp->encWWN[5], cdp->encWWN[6],
306 		    cdp->encWWN[7]);
307 		ntype += hd.Ntypes;
308 	}
309 
310 	/*
311 	 * Now waltz through all the types that are available, getting
312 	 * the type header so we can start adding up the number of
313 	 * objects available.
314 	 */
315 	for (nobj = i = 0; i < ntype; i++) {
316 		if (ses_getthdr((uchar_t *)sdata, amt, i, &thdr)) {
317 			SES_LOG(ssc, CE_NOTE,
318 			    "Cannot Extract Enclosure Type Header %d", i);
319 			kmem_free(sdata, SCSZ);
320 			return (EIO);
321 		}
322 		SES_LOG(ssc, SES_CE_DEBUG3,
323 		    "\tType Desc[%d]: Type 0x%x, MaxElt %d, In Subenc %d, "
324 		    "Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt,
325 		    thdr.enc_subenc, thdr.enc_tlen);
326 		nobj += thdr.enc_maxelt;
327 	}
328 
329 
330 	/*
331 	 * Now allocate the object array and type map.
332 	 */
333 	mutex_enter(&ssc->ses_devp->sd_mutex);
334 
335 
336 	ssc->ses_objmap = (encobj *)
337 	    kmem_zalloc(nobj * sizeof (encobj), KM_SLEEP);
338 
339 	cc->ses_typidx = (struct typidx *)
340 	    kmem_zalloc(nobj * sizeof (struct typidx), KM_SLEEP);
341 
342 	cc->ses_eltmap = kmem_zalloc(ntype, KM_SLEEP);
343 
344 	if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL ||
345 	    cc->ses_eltmap == NULL) {
346 		if (ssc->ses_objmap) {
347 			kmem_free(ssc->ses_objmap, (nobj * sizeof (encobj)));
348 			ssc->ses_objmap = NULL;
349 		}
350 		if (cc->ses_typidx) {
351 			kmem_free(cc->ses_typidx,
352 			    (nobj * sizeof (struct typidx)));
353 			cc->ses_typidx = NULL;
354 		}
355 		if (cc->ses_eltmap) {
356 			kmem_free(cc->ses_eltmap, ntype);
357 			cc->ses_eltmap = NULL;
358 		}
359 		mutex_exit(&ssc->ses_devp->sd_mutex);
360 		kmem_free(sdata, SCSZ);
361 		return (ENOMEM);
362 	}
363 	cc->ses_ntypes = (uchar_t)ntype;
364 	ssc->ses_nobjects = nobj;
365 
366 	/*
367 	 * Now waltz through the # of types again to fill in the types
368 	 * (and subenclosure ids) of the allocated objects.
369 	 */
370 	nobj = 0;
371 	for (i = 0; i < ntype; i++) {
372 		int j;
373 		if (ses_getthdr((uchar_t *)sdata, amt, i, &thdr)) {
374 			continue;
375 		}
376 		cc->ses_eltmap[i] = thdr.enc_maxelt;
377 		for (j = 0; j < thdr.enc_maxelt; j++) {
378 			cc->ses_typidx[nobj].ses_tidx = i;
379 			cc->ses_typidx[nobj].ses_oidx = j;
380 			ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc;
381 			ssc->ses_objmap[nobj++].enctype = thdr.enc_type;
382 		}
383 	}
384 	mutex_exit(&ssc->ses_devp->sd_mutex);
385 	kmem_free(sdata, SCSZ);
386 	return (0);
387 }
388 
389 /*
390  */
391 int
392 ses_softc_init(ses_softc_t *ssc, int doinit)
393 {
394 	if (doinit == 0) {
395 		struct sscfg *cc;
396 		mutex_enter(&ssc->ses_devp->sd_mutex);
397 		if (ssc->ses_nobjects) {
398 			kmem_free(ssc->ses_objmap,
399 			    ssc->ses_nobjects * sizeof (encobj));
400 			ssc->ses_objmap = NULL;
401 		}
402 		if ((cc = ssc->ses_private) != NULL) {
403 			if (cc->ses_eltmap && cc->ses_ntypes) {
404 				kmem_free(cc->ses_eltmap, cc->ses_ntypes);
405 				cc->ses_eltmap = NULL;
406 				cc->ses_ntypes = 0;
407 			}
408 			if (cc->ses_typidx && ssc->ses_nobjects) {
409 				kmem_free(cc->ses_typidx, ssc->ses_nobjects *
410 				    sizeof (struct typidx));
411 				cc->ses_typidx = NULL;
412 			}
413 			kmem_free(cc, sizeof (struct sscfg));
414 			ssc->ses_private = NULL;
415 		}
416 		ssc->ses_nobjects = 0;
417 		mutex_exit(&ssc->ses_devp->sd_mutex);
418 		return (0);
419 	}
420 	mutex_enter(&ssc->ses_devp->sd_mutex);
421 	if (ssc->ses_private == NULL) {
422 		ssc->ses_private = kmem_zalloc(sizeof (struct sscfg), KM_SLEEP);
423 	}
424 	if (ssc->ses_private == NULL) {
425 		mutex_exit(&ssc->ses_devp->sd_mutex);
426 		return (ENOMEM);
427 	}
428 	ssc->ses_nobjects = 0;
429 	ssc->ses_encstat = 0;
430 	mutex_exit(&ssc->ses_devp->sd_mutex);
431 	return (ses_getconfig(ssc));
432 }
433 
434 int
435 ses_init_enc(ses_softc_t *ssc)
436 {
437 	UNUSED_PARAMETER(ssc);
438 	return (0);
439 }
440 
441 static int
442 ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, int in)
443 {
444 	struct sscfg *cc;
445 	int err, amt, bufsiz, tidx, oidx;
446 	Uscmd local, *lp = &local;
447 	char rqbuf[SENSE_LENGTH], *sdata;
448 	char cdb[CDB_GROUP0];
449 
450 	cc = ssc->ses_private;
451 	if (cc == NULL) {
452 		return (ENXIO);
453 	}
454 
455 	/*
456 	 * If we're just getting overall enclosure status,
457 	 * we only need 2 bytes of data storage.
458 	 *
459 	 * If we're getting anything else, we know how much
460 	 * storage we need by noting that starting at offset
461 	 * 8 in returned data, all object status bytes are 4
462 	 * bytes long, and are stored in chunks of types(M)
463 	 * and nth+1 instances of type M.
464 	 */
465 	if (objid == -1) {
466 		bufsiz = 2;
467 	} else {
468 		bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8;
469 	}
470 	cdb[0] = SCMD_GDIAG;
471 	cdb[1] = 1;
472 	cdb[2] = SesStatusPage;
473 	cdb[3] = bufsiz >> 8;
474 	cdb[4] = bufsiz & 0xff;
475 	cdb[5] = 0;
476 	sdata = kmem_alloc(bufsiz, slp);
477 	if (sdata == NULL)
478 		return (ENOMEM);
479 
480 	lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE;
481 	lp->uscsi_timeout = ses_io_time;
482 	lp->uscsi_cdb = cdb;
483 	lp->uscsi_bufaddr = sdata;
484 	lp->uscsi_buflen = bufsiz;
485 	lp->uscsi_cdblen = sizeof (cdb);
486 	lp->uscsi_rqbuf = rqbuf;
487 	lp->uscsi_rqlen = sizeof (rqbuf);
488 
489 	err = ses_runcmd(ssc, lp);
490 	if (err) {
491 		kmem_free(sdata, bufsiz);
492 		return (err);
493 	}
494 	amt = lp->uscsi_buflen - lp->uscsi_resid;
495 
496 	if (objid == -1) {
497 		tidx = -1;
498 		oidx = -1;
499 	} else {
500 		tidx = cc->ses_typidx[objid].ses_tidx;
501 		oidx = cc->ses_typidx[objid].ses_oidx;
502 	}
503 	if (in) {
504 		if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
505 			err = ENODEV;
506 		}
507 	} else {
508 		if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
509 			err = ENODEV;
510 		} else {
511 			cdb[0] = SCMD_SDIAG;
512 			cdb[1] = 0x10;
513 			cdb[2] = 0;
514 			cdb[3] = bufsiz >> 8;
515 			cdb[4] = bufsiz & 0xff;
516 			cdb[5] = 0;
517 			lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
518 			lp->uscsi_timeout = ses_io_time;
519 			lp->uscsi_cdb = cdb;
520 			lp->uscsi_bufaddr = sdata;
521 			lp->uscsi_buflen = bufsiz;
522 			lp->uscsi_cdblen = sizeof (cdb);
523 			lp->uscsi_rqbuf = rqbuf;
524 			lp->uscsi_rqlen = sizeof (rqbuf);
525 			err = ses_runcmd(ssc, lp);
526 		}
527 	}
528 	kmem_free(sdata, bufsiz);
529 	return (0);
530 }
531 
532 int
533 ses_get_encstat(ses_softc_t *ssc, int slpflag)
534 {
535 	SesComStat s;
536 	int r;
537 
538 	if ((r = ses_getputstat(ssc, -1, &s, slpflag, 1)) != 0) {
539 		return (r);
540 	}
541 	mutex_enter(&ssc->ses_devp->sd_mutex);
542 	ssc->ses_encstat = s.comstatus | ENCI_SVALID;
543 	mutex_exit(&ssc->ses_devp->sd_mutex);
544 	return (0);
545 }
546 
547 int
548 ses_set_encstat(ses_softc_t *ssc, uchar_t encstat, int slpflag)
549 {
550 	SesComStat s;
551 	int r;
552 
553 	s.comstatus = encstat & 0xf;
554 	if ((r = ses_getputstat(ssc, -1, &s, slpflag, 0)) != 0) {
555 		return (r);
556 	}
557 	mutex_enter(&ssc->ses_devp->sd_mutex);
558 	ssc->ses_encstat = encstat & 0xf;	/* note no SVALID set */
559 	mutex_exit(&ssc->ses_devp->sd_mutex);
560 	return (0);
561 }
562 
563 int
564 ses_get_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag)
565 {
566 	int i = (int)obp->obj_id;
567 
568 	if (ssc->ses_objmap[i].svalid == 0) {
569 		SesComStat s;
570 		int r = ses_getputstat(ssc, i, &s, slpflag, 1);
571 		if (r)
572 			return (r);
573 		mutex_enter(&ssc->ses_devp->sd_mutex);
574 		ssc->ses_objmap[i].encstat[0] = s.comstatus;
575 		ssc->ses_objmap[i].encstat[1] = s.comstat[0];
576 		ssc->ses_objmap[i].encstat[2] = s.comstat[1];
577 		ssc->ses_objmap[i].encstat[3] = s.comstat[2];
578 		ssc->ses_objmap[i].svalid = 1;
579 		mutex_exit(&ssc->ses_devp->sd_mutex);
580 	}
581 	obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
582 	obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
583 	obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
584 	obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
585 	return (0);
586 }
587 
588 int
589 ses_set_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag)
590 {
591 	SesComStat s;
592 	int r, i;
593 	/*
594 	 * If this is clear, we don't do diddly.
595 	 */
596 	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
597 		return (0);
598 	}
599 	s.comstatus = obp->cstat[0];
600 	s.comstat[0] = obp->cstat[1];
601 	s.comstat[1] = obp->cstat[2];
602 	s.comstat[2] = obp->cstat[3];
603 	i = (int)obp->obj_id;
604 	r = ses_getputstat(ssc, i, &s, slpflag, 0);
605 	mutex_enter(&ssc->ses_devp->sd_mutex);
606 	ssc->ses_objmap[i].svalid = 0;
607 	mutex_exit(&ssc->ses_devp->sd_mutex);
608 	return (r);
609 }
610 
611 /*
612  * Routines to parse returned SES data structures.
613  * Architecture and compiler independent.
614  */
615 
616 static int
617 ses_cfghdr(uchar_t *buffer, int buflen, SesCfgHdr *cfp)
618 {
619 	if (buflen < SES_CFGHDR_MINLEN)
620 		return (-1);
621 	gget8(buffer, 1, cfp->Nsubenc);
622 	gget32(buffer, 4, cfp->GenCode);
623 	return (0);
624 }
625 
626 static int
627 ses_enchdr(uchar_t *buffer, int amt, uchar_t SubEncId, SesEncHdr *chp)
628 {
629 	int s, off = 8;
630 	for (s = 0; s < SubEncId; s++) {
631 		if (off + 3 > amt)
632 			return (-1);
633 		off += buffer[off+3] + 4;
634 	}
635 	if (off + 3 > amt) {
636 		return (-1);
637 	}
638 	gget8(buffer, off+1, chp->Subencid);
639 	gget8(buffer, off+2, chp->Ntypes);
640 	gget8(buffer, off+3, chp->VEnclen);
641 	return (0);
642 }
643 
644 static int
645 ses_encdesc(uchar_t *buffer, int amt, uchar_t SubEncId, SesEncDesc *cdp)
646 {
647 	int s, e, enclen, off = 8;
648 	for (s = 0; s < SubEncId; s++) {
649 		if (off + 3 > amt)
650 			return (-1);
651 		off += buffer[off+3] + 4;
652 	}
653 	if (off + 3 > amt) {
654 		return (-1);
655 	}
656 	gget8(buffer, off+3, enclen);
657 	off += 4;
658 	if (off  >= amt)
659 		return (-1);
660 
661 	e = off + enclen;
662 	if (e > amt) {
663 		e = amt;
664 	}
665 	bcopy((caddr_t)&buffer[off], (caddr_t)cdp, e - off);
666 	return (0);
667 }
668 
669 static int
670 ses_getthdr(uchar_t *buffer, int amt, int nth, SesThdr *thp)
671 {
672 	int s, off = 8;
673 
674 	if (amt < SES_CFGHDR_MINLEN) {
675 		return (-1);
676 	}
677 	for (s = 0; s < buffer[1]; s++) {
678 		if (off + 3 > amt)
679 			return (-1);
680 		off += buffer[off+3] + 4;
681 	}
682 	if (off + 3 > amt) {
683 		return (-1);
684 	}
685 	off += buffer[off+3] + 4 + (nth * 4);
686 	if (amt < (off + 4))
687 		return (-1);
688 
689 	gget8(buffer, off++, thp->enc_type);
690 	gget8(buffer, off++, thp->enc_maxelt);
691 	gget8(buffer, off++, thp->enc_subenc);
692 	gget8(buffer, off, thp->enc_tlen);
693 	return (0);
694 }
695 
696 /*
697  * This function needs a little explanation.
698  *
699  * The arguments are:
700  *
701  *
702  *	char *b, int amt
703  *
704  *		These describes the raw input SES status data and length.
705  *
706  *	uchar_t *ep
707  *
708  *		This is a map of the number of types for each element type
709  *		in the enclosure.
710  *
711  *	int elt
712  *
713  *		This is the element type being sought. If elt is -1,
714  *		then overal enclosure status is being sought.
715  *
716  *	int elm
717  *
718  *		This is the ordinal Mth element of type elt being sought.
719  *
720  *	SesComStat *sp
721  *
722  *		This is the output area to store the status for
723  *		the Mth element of type Elt.
724  */
725 
726 static int
727 ses_decode(char *b, int amt, uchar_t *ep, int elt, int elm, SesComStat *sp)
728 {
729 	int idx, i;
730 
731 	/*
732 	 * If it's overall enclosure status being sought, get that.
733 	 * We need at least 2 bytes of status data to get that.
734 	 */
735 	if (elt == -1) {
736 		if (amt < 2)
737 			return (-1);
738 		gget8(b, 1, sp->comstatus);
739 		sp->comstat[0] = 0;
740 		sp->comstat[1] = 0;
741 		sp->comstat[2] = 0;
742 		return (0);
743 	}
744 
745 	/*
746 	 * Check to make sure that the Mth element is legal for type Elt.
747 	 */
748 
749 	if (elm >= ep[elt])
750 		return (-1);
751 
752 	/*
753 	 * Starting at offset 8, start skipping over the storage
754 	 * for the element types we're not interested in.
755 	 */
756 	for (idx = 8, i = 0; i < elt; i++) {
757 		idx += ((ep[i] + 1) * 4);
758 	}
759 
760 	/*
761 	 * Skip over Overall status for this element type.
762 	 */
763 	idx += 4;
764 
765 	/*
766 	 * And skip to the index for the Mth element that we're going for.
767 	 */
768 	idx += (4 * elm);
769 
770 	/*
771 	 * Make sure we haven't overflowed the buffer.
772 	 */
773 	if (idx+4 > amt)
774 		return (-1);
775 	/*
776 	 * Retrieve the status.
777 	 */
778 	gget8(b, idx++, sp->comstatus);
779 	gget8(b, idx++, sp->comstat[0]);
780 	gget8(b, idx++, sp->comstat[1]);
781 	gget8(b, idx++, sp->comstat[2]);
782 	SES_LOG(NULL, SES_CE_DEBUG5, "Get Elt 0x%x Elm 0x%x (idx %d)",
783 	    elt, elm, idx-4);
784 	return (0);
785 }
786 
787 /*
788  * This is the mirror function to ses_decode, but we set the 'select'
789  * bit for the object which we're interested in. All other objects,
790  * after a status fetch, should have that bit off. Hmm. It'd be easy
791  * enough to ensure this, so we will.
792  */
793 
794 static int
795 ses_encode(char *b, int amt, uchar_t *ep, int elt, int elm, SesComStat *sp)
796 {
797 	int idx, i;
798 
799 	/*
800 	 * If it's overall enclosure status being sought, get that.
801 	 * We need at least 2 bytes of status data to get that.
802 	 */
803 	if (elt == -1) {
804 		if (amt < 2)
805 			return (-1);
806 		i = 0;
807 		sset8(b, i, 0);
808 		sset8(b, i, sp->comstatus & 0xf);
809 		SES_LOG(NULL, SES_CE_DEBUG5, "set EncStat %x", sp->comstatus);
810 		return (0);
811 	}
812 
813 	/*
814 	 * Check to make sure that the Mth element is legal for type Elt.
815 	 */
816 
817 	if (elm >= ep[elt])
818 		return (-1);
819 
820 	/*
821 	 * Starting at offset 8, start skipping over the storage
822 	 * for the element types we're not interested in.
823 	 */
824 	for (idx = 8, i = 0; i < elt; i++) {
825 		idx += ((ep[i] + 1) * 4);
826 	}
827 
828 	/*
829 	 * Skip over Overall status for this element type.
830 	 */
831 	idx += 4;
832 
833 	/*
834 	 * And skip to the index for the Mth element that we're going for.
835 	 */
836 	idx += (4 * elm);
837 
838 	/*
839 	 * Make sure we haven't overflowed the buffer.
840 	 */
841 	if (idx+4 > amt)
842 		return (-1);
843 
844 	/*
845 	 * Set the status.
846 	 */
847 	sset8(b, idx, sp->comstatus);
848 	sset8(b, idx, sp->comstat[0]);
849 	sset8(b, idx, sp->comstat[1]);
850 	sset8(b, idx, sp->comstat[2]);
851 	idx -= 4;
852 
853 	SES_LOG(NULL, SES_CE_DEBUG2, "Set Elt 0x%x Elm 0x%x (idx %d) with "
854 	    "%x %x %x %x", elt, elm, idx, sp->comstatus, sp->comstat[0],
855 	    sp->comstat[1], sp->comstat[2]);
856 
857 	/*
858 	 * Now make sure all other 'Select' bits are off.
859 	 */
860 	for (i = 8; i < amt; i += 4) {
861 		if (i != idx)
862 			b[i] &= ~0x80;
863 	}
864 	/*
865 	 * And make sure the INVOP bit is clear.
866 	 */
867 	b[1] &= ~INVOP;
868 
869 	return (0);
870 }
871 
872 /*
873  * mode: c
874  * Local variables:
875  * c-indent-level: 8
876  * c-brace-imaginary-offset: 0
877  * c-brace-offset: -8
878  * c-argdecl-indent: 8
879  * c-label-offset: -8
880  * c-continued-statement-offset: 8
881  * c-continued-brace-offset: 0
882  * End:
883  */
884