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