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