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
ses_getconfig(ses_softc_t * ssc)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
ses_softc_init(ses_softc_t * ssc,int doinit)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
ses_init_enc(ses_softc_t * ssc)435 ses_init_enc(ses_softc_t *ssc)
436 {
437 UNUSED_PARAMETER(ssc);
438 return (0);
439 }
440
441 static int
ses_getputstat(ses_softc_t * ssc,int objid,SesComStat * sp,int slp,int in)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
ses_get_encstat(ses_softc_t * ssc,int slpflag)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
ses_set_encstat(ses_softc_t * ssc,uchar_t encstat,int slpflag)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
ses_get_objstat(ses_softc_t * ssc,ses_objarg * obp,int slpflag)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
ses_set_objstat(ses_softc_t * ssc,ses_objarg * obp,int slpflag)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
ses_cfghdr(uchar_t * buffer,int buflen,SesCfgHdr * cfp)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
ses_enchdr(uchar_t * buffer,int amt,uchar_t SubEncId,SesEncHdr * chp)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
ses_encdesc(uchar_t * buffer,int amt,uchar_t SubEncId,SesEncDesc * cdp)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
ses_getthdr(uchar_t * buffer,int amt,int nth,SesThdr * thp)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
ses_decode(char * b,int amt,uchar_t * ep,int elt,int elm,SesComStat * sp)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
ses_encode(char * b,int amt,uchar_t * ep,int elt,int elm,SesComStat * sp)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