/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Enclosure Services Devices, SES Enclosure Routines */ #include #include #include #include #include /* * SES Diagnostic Page Codes */ typedef enum { SesConfigPage = 0x1, SesControlPage, #define SesStatusPage SesControlPage SesHelpTxt, SesStringOut, #define SesStringIn SesStringOut SesThresholdOut, #define SesThresholdIn SesThresholdOut SesArrayControl, #define SesArrayStatus SesArrayControl SesElementDescriptor, SesShortStatus } SesDiagPageCodes; /* * minimal amounts */ /* * Minimum amount of data, starting from byte 0, to have * the config header. */ #define SES_CFGHDR_MINLEN 12 /* * Minimum amount of data, starting from byte 0, to have * the config header and one enclosure header. */ #define SES_ENCHDR_MINLEN 48 /* * Take this value, subtract it from VEnclen and you know * the length of the vendor unique bytes. */ #define SES_ENCHDR_VMIN 36 /* * SES Data Structures */ typedef struct { ulong_t GenCode; /* Generation Code */ uchar_t Nsubenc; /* Number of Subenclosures */ } SesCfgHdr; typedef struct { uchar_t Subencid; /* SubEnclosure Identifier */ uchar_t Ntypes; /* # of supported types */ uchar_t VEnclen; /* Enclosure Descriptor Length */ } SesEncHdr; typedef struct { uchar_t encWWN[8]; /* XXX- Not Right Yet */ uchar_t encVid[8]; uchar_t encPid[16]; uchar_t encRev[4]; uchar_t encVen[1]; } SesEncDesc; typedef struct { uchar_t enc_type; /* type of element */ uchar_t enc_maxelt; /* maximum supported */ uchar_t enc_subenc; /* in SubEnc # N */ uchar_t enc_tlen; /* Type Descriptor Text Length */ } SesThdr; typedef struct { uchar_t comstatus; uchar_t comstat[3]; } SesComStat; #if !defined(lint) _NOTE(SCHEME_PROTECTS_DATA("because I said so", SesComStat)) #endif struct typidx { int ses_tidx; int ses_oidx; }; #if !defined(lint) _NOTE(SCHEME_PROTECTS_DATA("because I said so", typidx)) #endif struct sscfg { uchar_t ses_ntypes; /* total number of types supported */ /* * We need to keep a type index as well as an object index * for each object in an enclosure. */ struct typidx *ses_typidx; /* * We also need to keep track of the number of elements * per type of element. This is needed later so that we * can find precisely in the returned status data the * status for the Nth element of the Kth type. */ uchar_t *ses_eltmap; }; #if !defined(lint) _NOTE(MUTEX_PROTECTS_DATA(scsi_device::sd_mutex, sscfg)) _NOTE(DATA_READABLE_WITHOUT_LOCK(sscfg)) #endif /* * (de)canonicalization defines */ #define sbyte(x, byte) ((((ulong_t)(x)) >> (byte * 8)) & 0xff) #define sbit(x, bit) (((ulong_t)(x)) << bit) #define sset8(outp, idx, sval) \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 0) #define sset16(outp, idx, sval) \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 0) #define sset24(outp, idx, sval) \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 2), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 0) #define sset32(outp, idx, sval) \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 3), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 2), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 1), \ (((uchar_t *)(outp))[idx++]) = sbyte(sval, 0) #define gbyte(x, byte) ((((ulong_t)(x)) & 0xff) << (byte * 8)) #define gbit(lv, in, idx, shft, mask) lv = ((in[idx] >> shft) & mask) #define sget8(inp, idx, lval) lval = (((uchar_t *)(inp))[idx++]) #define gget8(inp, idx, lval) lval = (((uchar_t *)(inp))[idx]) #define sget16(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 1) | \ (((uchar_t *)(inp))[idx+1]), idx += 2 #define gget16(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 1) | \ (((uchar_t *)(inp))[idx+1]) #define sget24(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 2) | \ gbyte((((uchar_t *)(inp))[idx+1]), 1) | \ (((uchar_t *)(inp))[idx+2]), idx += 3 #define gget24(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 2) | \ gbyte((((uchar_t *)(inp))[idx+1]), 1) | \ (((uchar_t *)(inp))[idx+2]) #define sget32(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 3) | \ gbyte((((uchar_t *)(inp))[idx+1]), 2) | \ gbyte((((uchar_t *)(inp))[idx+2]), 1) | \ (((uchar_t *)(inp))[idx+3]), idx += 4 #define gget32(inp, idx, lval) \ lval = gbyte((((uchar_t *)(inp))[idx]), 3) | \ gbyte((((uchar_t *)(inp))[idx+1]), 2) | \ gbyte((((uchar_t *)(inp))[idx+2]), 1) | \ (((uchar_t *)(inp))[idx+3]) #define skip8(idx) idx += 1 #define skip16(idx) idx += 2 #define skip24(idx) idx += 3 #define skip32(idx) idx += 4 static int ses_cfghdr(uchar_t *, int, SesCfgHdr *); static int ses_enchdr(uchar_t *, int, uchar_t, SesEncHdr *); static int ses_encdesc(uchar_t *, int, uchar_t, SesEncDesc *); static int ses_getthdr(uchar_t *, int, int, SesThdr *); static int ses_decode(char *, int, uchar_t *, int, int, SesComStat *); static int ses_encode(char *, int, uchar_t *, int, int, SesComStat *); #define SCSZ 0x4cc static int ses_getconfig(ses_softc_t *ssc) { struct sscfg *cc; SesCfgHdr cf; SesEncHdr hd; SesEncDesc *cdp; SesThdr thdr; int err, amt, i, nobj, ntype, maxima; Uscmd local, *lp = &local; char storage[SCSZ], *sdata; static char cdb[CDB_GROUP0] = { SCMD_GDIAG, 0x1, SesConfigPage, (char)(SCSZ >> 8), (char)(SCSZ & 0xff), 0 }; cc = ssc->ses_private; if (cc == NULL) { return (ENXIO); } sdata = kmem_alloc(SCSZ, KM_SLEEP); if (sdata == NULL) return (ENOMEM); lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE; lp->uscsi_timeout = ses_io_time; lp->uscsi_cdb = cdb; lp->uscsi_bufaddr = sdata; lp->uscsi_buflen = SCSZ; lp->uscsi_cdblen = sizeof (cdb); lp->uscsi_rqbuf = storage; lp->uscsi_rqlen = SENSE_LENGTH; err = ses_runcmd(ssc, lp); if (err) { kmem_free(sdata, SCSZ); return (err); } amt = lp->uscsi_buflen - lp->uscsi_resid; if (ses_cfghdr((uchar_t *)sdata, amt, &cf)) { SES_LOG(ssc, CE_NOTE, "Unable to parse SES Config Header"); kmem_free(sdata, SCSZ); return (EIO); } if (amt < SES_ENCHDR_MINLEN) { SES_LOG(ssc, CE_NOTE, "runt enclosure length (%d)", amt); kmem_free(sdata, SCSZ); return (EIO); } SES_LOG(ssc, SES_CE_DEBUG3, "GenCode %lx %d Subenclosures", cf.GenCode, cf.Nsubenc); /* * Now waltz through all the subenclosures toting up the * number of types available in each. For this, we only * really need the enclosure header. However, we get the * enclosure descriptor for debug purposes, as well * as self-consistency checking purposes. */ maxima = cf.Nsubenc + 1; cdp = (SesEncDesc *) storage; for (ntype = i = 0; i < maxima; i++) { bzero((caddr_t)cdp, sizeof (*cdp)); if (ses_enchdr((uchar_t *)sdata, amt, i, &hd)) { SES_LOG(ssc, CE_NOTE, "Cannot Extract Enclosure Header %d", i); kmem_free(sdata, SCSZ); return (EIO); } SES_LOG(ssc, SES_CE_DEBUG3, "\tSubEnclosure ID %d, %d Types With this ID, Enclosure " "Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen); if (ses_encdesc((uchar_t *)sdata, amt, i, cdp)) { SES_LOG(ssc, CE_NOTE, "Cannot Extract Enclosure Descriptor %d", i); kmem_free(sdata, SCSZ); return (EIO); } SES_LOG(ssc, SES_CE_DEBUG3, "\tWWN: %02x%02x%02x%02x%02x%02x%02x%02x", cdp->encWWN[0], cdp->encWWN[1], cdp->encWWN[2], cdp->encWWN[3], cdp->encWWN[4], cdp->encWWN[5], cdp->encWWN[6], cdp->encWWN[7]); ntype += hd.Ntypes; } /* * Now waltz through all the types that are available, getting * the type header so we can start adding up the number of * objects available. */ for (nobj = i = 0; i < ntype; i++) { if (ses_getthdr((uchar_t *)sdata, amt, i, &thdr)) { SES_LOG(ssc, CE_NOTE, "Cannot Extract Enclosure Type Header %d", i); kmem_free(sdata, SCSZ); return (EIO); } SES_LOG(ssc, SES_CE_DEBUG3, "\tType Desc[%d]: Type 0x%x, MaxElt %d, In Subenc %d, " "Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt, thdr.enc_subenc, thdr.enc_tlen); nobj += thdr.enc_maxelt; } /* * Now allocate the object array and type map. */ mutex_enter(&ssc->ses_devp->sd_mutex); ssc->ses_objmap = (encobj *) kmem_zalloc(nobj * sizeof (encobj), KM_SLEEP); cc->ses_typidx = (struct typidx *) kmem_zalloc(nobj * sizeof (struct typidx), KM_SLEEP); cc->ses_eltmap = kmem_zalloc(ntype, KM_SLEEP); if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL || cc->ses_eltmap == NULL) { if (ssc->ses_objmap) { kmem_free(ssc->ses_objmap, (nobj * sizeof (encobj))); ssc->ses_objmap = NULL; } if (cc->ses_typidx) { kmem_free(cc->ses_typidx, (nobj * sizeof (struct typidx))); cc->ses_typidx = NULL; } if (cc->ses_eltmap) { kmem_free(cc->ses_eltmap, ntype); cc->ses_eltmap = NULL; } mutex_exit(&ssc->ses_devp->sd_mutex); kmem_free(sdata, SCSZ); return (ENOMEM); } cc->ses_ntypes = (uchar_t)ntype; ssc->ses_nobjects = nobj; /* * Now waltz through the # of types again to fill in the types * (and subenclosure ids) of the allocated objects. */ nobj = 0; for (i = 0; i < ntype; i++) { int j; if (ses_getthdr((uchar_t *)sdata, amt, i, &thdr)) { continue; } cc->ses_eltmap[i] = thdr.enc_maxelt; for (j = 0; j < thdr.enc_maxelt; j++) { cc->ses_typidx[nobj].ses_tidx = i; cc->ses_typidx[nobj].ses_oidx = j; ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc; ssc->ses_objmap[nobj++].enctype = thdr.enc_type; } } mutex_exit(&ssc->ses_devp->sd_mutex); kmem_free(sdata, SCSZ); return (0); } /* */ int ses_softc_init(ses_softc_t *ssc, int doinit) { if (doinit == 0) { struct sscfg *cc; mutex_enter(&ssc->ses_devp->sd_mutex); if (ssc->ses_nobjects) { kmem_free(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj)); ssc->ses_objmap = NULL; } if ((cc = ssc->ses_private) != NULL) { if (cc->ses_eltmap && cc->ses_ntypes) { kmem_free(cc->ses_eltmap, cc->ses_ntypes); cc->ses_eltmap = NULL; cc->ses_ntypes = 0; } if (cc->ses_typidx && ssc->ses_nobjects) { kmem_free(cc->ses_typidx, ssc->ses_nobjects * sizeof (struct typidx)); cc->ses_typidx = NULL; } kmem_free(cc, sizeof (struct sscfg)); ssc->ses_private = NULL; } ssc->ses_nobjects = 0; mutex_exit(&ssc->ses_devp->sd_mutex); return (0); } mutex_enter(&ssc->ses_devp->sd_mutex); if (ssc->ses_private == NULL) { ssc->ses_private = kmem_zalloc(sizeof (struct sscfg), KM_SLEEP); } if (ssc->ses_private == NULL) { mutex_exit(&ssc->ses_devp->sd_mutex); return (ENOMEM); } ssc->ses_nobjects = 0; ssc->ses_encstat = 0; mutex_exit(&ssc->ses_devp->sd_mutex); return (ses_getconfig(ssc)); } int ses_init_enc(ses_softc_t *ssc) { UNUSED_PARAMETER(ssc); return (0); } static int ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, int in) { struct sscfg *cc; int err, amt, bufsiz, tidx, oidx; Uscmd local, *lp = &local; char rqbuf[SENSE_LENGTH], *sdata; char cdb[CDB_GROUP0]; cc = ssc->ses_private; if (cc == NULL) { return (ENXIO); } /* * If we're just getting overall enclosure status, * we only need 2 bytes of data storage. * * If we're getting anything else, we know how much * storage we need by noting that starting at offset * 8 in returned data, all object status bytes are 4 * bytes long, and are stored in chunks of types(M) * and nth+1 instances of type M. */ if (objid == -1) { bufsiz = 2; } else { bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8; } cdb[0] = SCMD_GDIAG; cdb[1] = 1; cdb[2] = SesStatusPage; cdb[3] = bufsiz >> 8; cdb[4] = bufsiz & 0xff; cdb[5] = 0; sdata = kmem_alloc(bufsiz, slp); if (sdata == NULL) return (ENOMEM); lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE; lp->uscsi_timeout = ses_io_time; lp->uscsi_cdb = cdb; lp->uscsi_bufaddr = sdata; lp->uscsi_buflen = bufsiz; lp->uscsi_cdblen = sizeof (cdb); lp->uscsi_rqbuf = rqbuf; lp->uscsi_rqlen = sizeof (rqbuf); err = ses_runcmd(ssc, lp); if (err) { kmem_free(sdata, bufsiz); return (err); } amt = lp->uscsi_buflen - lp->uscsi_resid; if (objid == -1) { tidx = -1; oidx = -1; } else { tidx = cc->ses_typidx[objid].ses_tidx; oidx = cc->ses_typidx[objid].ses_oidx; } if (in) { if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { err = ENODEV; } } else { if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { err = ENODEV; } else { cdb[0] = SCMD_SDIAG; cdb[1] = 0x10; cdb[2] = 0; cdb[3] = bufsiz >> 8; cdb[4] = bufsiz & 0xff; cdb[5] = 0; lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE; lp->uscsi_timeout = ses_io_time; lp->uscsi_cdb = cdb; lp->uscsi_bufaddr = sdata; lp->uscsi_buflen = bufsiz; lp->uscsi_cdblen = sizeof (cdb); lp->uscsi_rqbuf = rqbuf; lp->uscsi_rqlen = sizeof (rqbuf); err = ses_runcmd(ssc, lp); } } kmem_free(sdata, bufsiz); return (0); } int ses_get_encstat(ses_softc_t *ssc, int slpflag) { SesComStat s; int r; if ((r = ses_getputstat(ssc, -1, &s, slpflag, 1)) != 0) { return (r); } mutex_enter(&ssc->ses_devp->sd_mutex); ssc->ses_encstat = s.comstatus | ENCI_SVALID; mutex_exit(&ssc->ses_devp->sd_mutex); return (0); } int ses_set_encstat(ses_softc_t *ssc, uchar_t encstat, int slpflag) { SesComStat s; int r; s.comstatus = encstat & 0xf; if ((r = ses_getputstat(ssc, -1, &s, slpflag, 0)) != 0) { return (r); } mutex_enter(&ssc->ses_devp->sd_mutex); ssc->ses_encstat = encstat & 0xf; /* note no SVALID set */ mutex_exit(&ssc->ses_devp->sd_mutex); return (0); } int ses_get_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag) { int i = (int)obp->obj_id; if (ssc->ses_objmap[i].svalid == 0) { SesComStat s; int r = ses_getputstat(ssc, i, &s, slpflag, 1); if (r) return (r); mutex_enter(&ssc->ses_devp->sd_mutex); ssc->ses_objmap[i].encstat[0] = s.comstatus; ssc->ses_objmap[i].encstat[1] = s.comstat[0]; ssc->ses_objmap[i].encstat[2] = s.comstat[1]; ssc->ses_objmap[i].encstat[3] = s.comstat[2]; ssc->ses_objmap[i].svalid = 1; mutex_exit(&ssc->ses_devp->sd_mutex); } obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; return (0); } int ses_set_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflag) { SesComStat s; int r, i; /* * If this is clear, we don't do diddly. */ if ((obp->cstat[0] & SESCTL_CSEL) == 0) { return (0); } s.comstatus = obp->cstat[0]; s.comstat[0] = obp->cstat[1]; s.comstat[1] = obp->cstat[2]; s.comstat[2] = obp->cstat[3]; i = (int)obp->obj_id; r = ses_getputstat(ssc, i, &s, slpflag, 0); mutex_enter(&ssc->ses_devp->sd_mutex); ssc->ses_objmap[i].svalid = 0; mutex_exit(&ssc->ses_devp->sd_mutex); return (r); } /* * Routines to parse returned SES data structures. * Architecture and compiler independent. */ static int ses_cfghdr(uchar_t *buffer, int buflen, SesCfgHdr *cfp) { if (buflen < SES_CFGHDR_MINLEN) return (-1); gget8(buffer, 1, cfp->Nsubenc); gget32(buffer, 4, cfp->GenCode); return (0); } static int ses_enchdr(uchar_t *buffer, int amt, uchar_t SubEncId, SesEncHdr *chp) { int s, off = 8; for (s = 0; s < SubEncId; s++) { if (off + 3 > amt) return (-1); off += buffer[off+3] + 4; } if (off + 3 > amt) { return (-1); } gget8(buffer, off+1, chp->Subencid); gget8(buffer, off+2, chp->Ntypes); gget8(buffer, off+3, chp->VEnclen); return (0); } static int ses_encdesc(uchar_t *buffer, int amt, uchar_t SubEncId, SesEncDesc *cdp) { int s, e, enclen, off = 8; for (s = 0; s < SubEncId; s++) { if (off + 3 > amt) return (-1); off += buffer[off+3] + 4; } if (off + 3 > amt) { return (-1); } gget8(buffer, off+3, enclen); off += 4; if (off >= amt) return (-1); e = off + enclen; if (e > amt) { e = amt; } bcopy((caddr_t)&buffer[off], (caddr_t)cdp, e - off); return (0); } static int ses_getthdr(uchar_t *buffer, int amt, int nth, SesThdr *thp) { int s, off = 8; if (amt < SES_CFGHDR_MINLEN) { return (-1); } for (s = 0; s < buffer[1]; s++) { if (off + 3 > amt) return (-1); off += buffer[off+3] + 4; } if (off + 3 > amt) { return (-1); } off += buffer[off+3] + 4 + (nth * 4); if (amt < (off + 4)) return (-1); gget8(buffer, off++, thp->enc_type); gget8(buffer, off++, thp->enc_maxelt); gget8(buffer, off++, thp->enc_subenc); gget8(buffer, off, thp->enc_tlen); return (0); } /* * This function needs a little explanation. * * The arguments are: * * * char *b, int amt * * These describes the raw input SES status data and length. * * uchar_t *ep * * This is a map of the number of types for each element type * in the enclosure. * * int elt * * This is the element type being sought. If elt is -1, * then overal enclosure status is being sought. * * int elm * * This is the ordinal Mth element of type elt being sought. * * SesComStat *sp * * This is the output area to store the status for * the Mth element of type Elt. */ static int ses_decode(char *b, int amt, uchar_t *ep, int elt, int elm, SesComStat *sp) { int idx, i; /* * If it's overall enclosure status being sought, get that. * We need at least 2 bytes of status data to get that. */ if (elt == -1) { if (amt < 2) return (-1); gget8(b, 1, sp->comstatus); sp->comstat[0] = 0; sp->comstat[1] = 0; sp->comstat[2] = 0; return (0); } /* * Check to make sure that the Mth element is legal for type Elt. */ if (elm >= ep[elt]) return (-1); /* * Starting at offset 8, start skipping over the storage * for the element types we're not interested in. */ for (idx = 8, i = 0; i < elt; i++) { idx += ((ep[i] + 1) * 4); } /* * Skip over Overall status for this element type. */ idx += 4; /* * And skip to the index for the Mth element that we're going for. */ idx += (4 * elm); /* * Make sure we haven't overflowed the buffer. */ if (idx+4 > amt) return (-1); /* * Retrieve the status. */ gget8(b, idx++, sp->comstatus); gget8(b, idx++, sp->comstat[0]); gget8(b, idx++, sp->comstat[1]); gget8(b, idx++, sp->comstat[2]); SES_LOG(NULL, SES_CE_DEBUG5, "Get Elt 0x%x Elm 0x%x (idx %d)", elt, elm, idx-4); return (0); } /* * This is the mirror function to ses_decode, but we set the 'select' * bit for the object which we're interested in. All other objects, * after a status fetch, should have that bit off. Hmm. It'd be easy * enough to ensure this, so we will. */ static int ses_encode(char *b, int amt, uchar_t *ep, int elt, int elm, SesComStat *sp) { int idx, i; /* * If it's overall enclosure status being sought, get that. * We need at least 2 bytes of status data to get that. */ if (elt == -1) { if (amt < 2) return (-1); i = 0; sset8(b, i, 0); sset8(b, i, sp->comstatus & 0xf); SES_LOG(NULL, SES_CE_DEBUG5, "set EncStat %x", sp->comstatus); return (0); } /* * Check to make sure that the Mth element is legal for type Elt. */ if (elm >= ep[elt]) return (-1); /* * Starting at offset 8, start skipping over the storage * for the element types we're not interested in. */ for (idx = 8, i = 0; i < elt; i++) { idx += ((ep[i] + 1) * 4); } /* * Skip over Overall status for this element type. */ idx += 4; /* * And skip to the index for the Mth element that we're going for. */ idx += (4 * elm); /* * Make sure we haven't overflowed the buffer. */ if (idx+4 > amt) return (-1); /* * Set the status. */ sset8(b, idx, sp->comstatus); sset8(b, idx, sp->comstat[0]); sset8(b, idx, sp->comstat[1]); sset8(b, idx, sp->comstat[2]); idx -= 4; SES_LOG(NULL, SES_CE_DEBUG2, "Set Elt 0x%x Elm 0x%x (idx %d) with " "%x %x %x %x", elt, elm, idx, sp->comstatus, sp->comstat[0], sp->comstat[1], sp->comstat[2]); /* * Now make sure all other 'Select' bits are off. */ for (i = 8; i < amt; i += 4) { if (i != idx) b[i] &= ~0x80; } /* * And make sure the INVOP bit is clear. */ b[1] &= ~INVOP; return (0); } /* * mode: c * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 * c-brace-offset: -8 * c-argdecl-indent: 8 * c-label-offset: -8 * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * End: */