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