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