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  * Enclosure Services Devices, SAF-TE Enclosure Routines
  24  *
  25  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 #pragma ident   "%Z%%M% %I%     %E% SMI"
  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/sesio.h>
  36 #include <sys/scsi/targets/ses.h>
  37 
  38 
  39 static int set_objstat_sel(ses_softc_t *, ses_objarg *, int);
  40 static int wrbuf16(ses_softc_t *, uchar_t, uchar_t, uchar_t, uchar_t, int);
  41 static void wrslot_stat(ses_softc_t *, int);
  42 static int perf_slotop(ses_softc_t *, uchar_t, uchar_t, int);
  43 
  44 #define ALL_ENC_STAT \
  45         (ENCSTAT_CRITICAL|ENCSTAT_UNRECOV|ENCSTAT_NONCRITICAL|ENCSTAT_INFO)
  46 
  47 #define SCRATCH 64
  48 #define NPSEUDO_THERM   1
  49 #define NPSEUDO_ALARM   1
  50 struct scfg {
  51         /*
  52          * Cached Configuration
  53          */
  54         uchar_t Nfans;          /* Number of Fans */
  55         uchar_t Npwr;           /* Number of Power Supplies */
  56         uchar_t Nslots;         /* Number of Device Slots */
  57         uchar_t DoorLock;       /* Door Lock Installed */
  58         uchar_t Ntherm;         /* Number of Temperature Sensors */
  59         uchar_t Nspkrs;         /* Number of Speakers */
  60         uchar_t  Nalarm;                /* Number of Alarms (at least one) */
  61         /*
  62          * Cached Flag Bytes for Global Status
  63          */
  64         uchar_t flag1;
  65         uchar_t flag2;
  66         /*
  67          * What object index ID is where various slots start.
  68          */
  69         uchar_t pwroff;
  70         uchar_t slotoff;
  71 #define ALARM_OFFSET(cc)        (cc)->slotoff - 1
  72 };
  73 #define FLG1_ALARM      0x1
  74 #define FLG1_GLOBFAIL   0x2
  75 #define FLG1_GLOBWARN   0x4
  76 #define FLG1_ENCPWROFF  0x8
  77 #define FLG1_ENCFANFAIL 0x10
  78 #define FLG1_ENCPWRFAIL 0x20
  79 #define FLG1_ENCDRVFAIL 0x40
  80 #define FLG1_ENCDRVWARN 0x80
  81 
  82 #define FLG2_LOCKDOOR   0x4
  83 #define SAFTE_PRIVATE   sizeof (struct scfg)
  84 
  85 #if     !defined(lint)
  86 _NOTE(MUTEX_PROTECTS_DATA(scsi_device::sd_mutex, scfg))
  87 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nfans))
  88 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Npwr))
  89 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nslots))
  90 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::DoorLock))
  91 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Ntherm))
  92 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nspkrs))
  93 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nalarm))
  94 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::flag1))
  95 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::flag2))
  96 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::pwroff))
  97 _NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::slotoff))
  98 #endif
  99 
 100 static int
 101 safte_getconfig(ses_softc_t *ssc)
 102 {
 103         struct scfg *cfg;
 104         int err;
 105         Uscmd local, *lp = &local;
 106         char rqbuf[SENSE_LENGTH], *sdata;
 107         static char cdb[CDB_GROUP1] =
 108             { SCMD_READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SCRATCH, 0 };
 109 
 110         cfg = ssc->ses_private;
 111         if (cfg == NULL)
 112                 return (ENXIO);
 113 
 114         sdata = kmem_alloc(SCRATCH, KM_SLEEP);
 115         if (sdata == NULL)
 116                 return (ENOMEM);
 117 
 118         lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE;
 119         lp->uscsi_timeout = ses_io_time;
 120         lp->uscsi_cdb = cdb;
 121         lp->uscsi_bufaddr = sdata;
 122         lp->uscsi_buflen = SCRATCH;
 123         lp->uscsi_cdblen = sizeof (cdb);
 124         lp->uscsi_rqbuf = rqbuf;
 125         lp->uscsi_rqlen = sizeof (rqbuf);
 126 
 127         err = ses_runcmd(ssc, lp);
 128         if (err) {
 129                 kmem_free(sdata, SCRATCH);
 130                 return (err);
 131         }
 132 
 133         if ((lp->uscsi_buflen - lp->uscsi_resid) < 6) {
 134                 SES_LOG(ssc, CE_NOTE, "Too little data (%ld) for configuration",
 135                     lp->uscsi_buflen - lp->uscsi_resid);
 136                 kmem_free(sdata, SCRATCH);
 137                 return (EIO);
 138         }
 139         SES_LOG(ssc, SES_CE_DEBUG1, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm "
 140             "%d Nspkrs %d", sdata[0], sdata[1], sdata[2], sdata[3], sdata[4],
 141             sdata[5]);
 142 
 143         mutex_enter(&ssc->ses_devp->sd_mutex);
 144         cfg->Nfans = sdata[0];
 145         cfg->Npwr = sdata[1];
 146         cfg->Nslots = sdata[2];
 147         cfg->DoorLock = sdata[3];
 148         cfg->Ntherm = sdata[4];
 149         cfg->Nspkrs = sdata[5];
 150         cfg->Nalarm = NPSEUDO_ALARM;
 151         mutex_exit(&ssc->ses_devp->sd_mutex);
 152         kmem_free(sdata, SCRATCH);
 153         return (0);
 154 }
 155 
 156 int
 157 safte_softc_init(ses_softc_t *ssc, int doinit)
 158 {
 159         int r, i;
 160         struct scfg *cc;
 161 
 162         if (doinit == 0) {
 163                 mutex_enter(&ssc->ses_devp->sd_mutex);
 164                 if (ssc->ses_nobjects) {
 165                         if (ssc->ses_objmap) {
 166                                 kmem_free(ssc->ses_objmap,
 167                                     ssc->ses_nobjects * sizeof (encobj));
 168                                 ssc->ses_objmap = NULL;
 169                         }
 170                         ssc->ses_nobjects = 0;
 171                 }
 172                 if (ssc->ses_private) {
 173                         kmem_free(ssc->ses_private, SAFTE_PRIVATE);
 174                         ssc->ses_private = NULL;
 175                 }
 176                 mutex_exit(&ssc->ses_devp->sd_mutex);
 177                 return (0);
 178         }
 179 
 180         mutex_enter(&ssc->ses_devp->sd_mutex);
 181         if (ssc->ses_private == NULL) {
 182                 ssc->ses_private = kmem_zalloc(SAFTE_PRIVATE, KM_SLEEP);
 183                 if (ssc->ses_private == NULL) {
 184                         mutex_exit(&ssc->ses_devp->sd_mutex);
 185                         return (ENOMEM);
 186                 }
 187         }
 188 
 189         ssc->ses_nobjects = 0;
 190         ssc->ses_encstat = 0;
 191         mutex_exit(&ssc->ses_devp->sd_mutex);
 192 
 193         if ((r = safte_getconfig(ssc)) != 0) {
 194                 return (r);
 195         }
 196 
 197         /*
 198          * The number of objects here, as well as that reported by the
 199          * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15)
 200          * that get reported during READ_BUFFER/READ_ENC_STATUS.
 201          */
 202         mutex_enter(&ssc->ses_devp->sd_mutex);
 203         cc = ssc->ses_private;
 204         ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock +
 205             cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM;
 206         ssc->ses_objmap = (encobj *)
 207             kmem_zalloc(ssc->ses_nobjects * sizeof (encobj), KM_SLEEP);
 208         mutex_exit(&ssc->ses_devp->sd_mutex);
 209         if (ssc->ses_objmap == NULL)
 210                 return (ENOMEM);
 211         r = 0;
 212         /*
 213          * Note that this is all arranged for the convenience
 214          * in later fetches of status.
 215          */
 216         mutex_enter(&ssc->ses_devp->sd_mutex);
 217         for (i = 0; i < cc->Nfans; i++)
 218                 ssc->ses_objmap[r++].enctype = SESTYP_FAN;
 219         cc->pwroff = (uchar_t)r;
 220         for (i = 0; i < cc->Npwr; i++)
 221                 ssc->ses_objmap[r++].enctype = SESTYP_POWER;
 222         for (i = 0; i < cc->DoorLock; i++)
 223                 ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK;
 224         for (i = 0; i < cc->Nspkrs; i++)
 225                 ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 226         for (i = 0; i < cc->Ntherm; i++)
 227                 ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 228         for (i = 0; i < NPSEUDO_THERM; i++)
 229                 ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 230         ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 231         cc->slotoff = (uchar_t)r;
 232         for (i = 0; i < cc->Nslots; i++)
 233                 ssc->ses_objmap[r++].enctype = SESTYP_DEVICE;
 234         mutex_exit(&ssc->ses_devp->sd_mutex);
 235         return (0);
 236 }
 237 
 238 int
 239 safte_init_enc(ses_softc_t *ssc)
 240 {
 241         int err;
 242         Uscmd local, *lp = &local;
 243         char rqbuf[SENSE_LENGTH], *sdata;
 244         static char cdb0[CDB_GROUP1] = { SCMD_SDIAG };
 245         static char cdb[CDB_GROUP1] =
 246             { SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SCRATCH, 0 };
 247 
 248         sdata = kmem_alloc(SCRATCH, KM_SLEEP);
 249         lp->uscsi_flags = USCSI_RQENABLE;
 250         lp->uscsi_timeout = ses_io_time;
 251         lp->uscsi_cdb = cdb0;
 252         lp->uscsi_bufaddr = NULL;
 253         lp->uscsi_buflen = 0;
 254         lp->uscsi_cdblen = sizeof (cdb0);
 255         lp->uscsi_rqbuf = rqbuf;
 256         lp->uscsi_rqlen = sizeof (rqbuf);
 257         err = ses_runcmd(ssc, lp);
 258         if (err) {
 259                 kmem_free(sdata, SCRATCH);
 260                 return (err);
 261         }
 262 
 263         lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
 264         lp->uscsi_timeout = ses_io_time;
 265         lp->uscsi_cdb = cdb;
 266         lp->uscsi_bufaddr = sdata;
 267         lp->uscsi_buflen = SCRATCH;
 268         lp->uscsi_cdblen = sizeof (cdb);
 269         lp->uscsi_rqbuf = rqbuf;
 270         lp->uscsi_rqlen = sizeof (rqbuf);
 271         bzero(&sdata[1], 15);
 272         sdata[0] = SAFTE_WT_GLOBAL;
 273         err = ses_runcmd(ssc, lp);
 274         kmem_free(sdata, SCRATCH);
 275         return (err);
 276 }
 277 
 278 
 279 static char *toolittle = "Too Little Data Returned (%d) at line %d";
 280 #define BAIL(r, x, k, l, m, n) \
 281         if (r >= x) { \
 282                 SES_LOG(ssc, CE_NOTE, toolittle, x, __LINE__); \
 283                 kmem_free(k, l); \
 284                 kmem_free(m, n); \
 285                 return (EIO); \
 286         }
 287 
 288 static int
 289 safte_rdstat(ses_softc_t *ssc, int slpflg)
 290 {
 291         int err, oid, r, i, hiwater, nitems;
 292         ushort_t tempflags;
 293         size_t buflen;
 294         uchar_t status, oencstat;
 295         Uscmd local, *lp = &local;
 296         struct scfg *cc = ssc->ses_private;
 297         char rqbuf[SENSE_LENGTH], *sdata;
 298         char cdb[CDB_GROUP1];
 299         int *driveids, id_size = cc->Nslots * sizeof (int);
 300 
 301         driveids = kmem_alloc(id_size, slpflg);
 302         if (driveids == NULL) {
 303                 return (ENOMEM);
 304         }
 305 
 306         /*
 307          * The number of bytes of data we need to get is
 308          * Nfans + Npwr + Nslots + Nspkrs + Ntherm + nochoice
 309          * (nochoice = 1 doorlock + 1 spkr + 2 pseudo therms + 10 extra)
 310          * the extra are simply for good luck.
 311          */
 312         buflen = cc->Nfans + cc->Npwr + cc->Nslots + cc->Nspkrs;
 313         buflen += cc->Ntherm + 14;
 314 
 315         /*
 316          * Towards the end of this function this buffer is reused.
 317          * Thus we need to make sure that we have allocated enough
 318          * memory retrieving buffer 1 & 4.
 319          * buffer 1 -> element status & drive id
 320          * buffer 4 -> drive status & drive command history.
 321          * buffer 4 uses 4 bytes per drive bay.
 322          */
 323 
 324         if (buflen < cc->Nslots * 4) {
 325                 buflen = cc->Nslots * 4;
 326         }
 327 
 328         if (ssc->ses_nobjects > buflen)
 329                 buflen = ssc->ses_nobjects;
 330 
 331         if (buflen > 0xffff) {
 332                 cmn_err(CE_WARN, "Illogical SCSI data");
 333                 return (EIO);
 334         }
 335 
 336         sdata = kmem_alloc(buflen, slpflg);
 337         if (sdata == NULL) {
 338                 kmem_free(driveids, id_size);
 339                 return (ENOMEM);
 340         }
 341 
 342         cdb[0] = SCMD_READ_BUFFER;
 343         cdb[1] = 1;
 344         cdb[2] = SAFTE_RD_RDESTS;
 345         cdb[3] = 0;
 346         cdb[4] = 0;
 347         cdb[5] = 0;
 348         cdb[6] = 0;
 349         cdb[7] = (buflen >> 8) & 0xff;
 350         cdb[8] = buflen & 0xff;
 351         cdb[9] = 0;
 352         lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE;
 353         lp->uscsi_timeout = ses_io_time;
 354         lp->uscsi_cdb = cdb;
 355         lp->uscsi_bufaddr = sdata;
 356         lp->uscsi_buflen = buflen;
 357         lp->uscsi_cdblen = sizeof (cdb);
 358         lp->uscsi_rqbuf = rqbuf;
 359         lp->uscsi_rqlen = sizeof (rqbuf);
 360 
 361         err = ses_runcmd(ssc, lp);
 362         if (err) {
 363                 kmem_free(sdata, buflen);
 364                 kmem_free(driveids, id_size);
 365                 return (err);
 366         }
 367 
 368         hiwater = lp->uscsi_buflen - lp->uscsi_resid;
 369 
 370         /*
 371          * invalidate all status bits.
 372          */
 373         mutex_enter(&ssc->ses_devp->sd_mutex);
 374         for (i = 0; i < ssc->ses_nobjects; i++)
 375                 ssc->ses_objmap[i].svalid = 0;
 376         oencstat = ssc->ses_encstat & ALL_ENC_STAT;
 377         ssc->ses_encstat = 0;
 378         mutex_exit(&ssc->ses_devp->sd_mutex);
 379 
 380         /*
 381          * Now parse returned buffer.
 382          * If we didn't get enough data back,
 383          * that's considered a fatal error.
 384          */
 385         oid = r = 0;
 386 
 387         for (nitems = i = 0; i < cc->Nfans; i++) {
 388                 BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 389                 /*
 390                  * 0 = Fan Operational
 391                  * 1 = Fan is malfunctioning
 392                  * 2 = Fan is not present
 393                  * 0x80 = Unknown or Not Reportable Status
 394                  */
 395                 mutex_enter(&ssc->ses_devp->sd_mutex);
 396                 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */
 397                 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */
 398                 switch ((uchar_t)sdata[r]) {
 399                 case 0:
 400                         nitems++;
 401                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 402                         /*
 403                          * We could get fancier and cache
 404                          * fan speeds that we have set, but
 405                          * that isn't done now.
 406                          */
 407                         ssc->ses_objmap[oid].encstat[3] = 7;
 408                         break;
 409 
 410                 case 1:
 411                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 412                         /*
 413                          * FAIL and FAN STOPPED synthesized
 414                          */
 415                         ssc->ses_objmap[oid].encstat[3] = 0x40;
 416                         /*
 417                          * Enclosure marked with CRITICAL error
 418                          * if only one fan or no thermometers,
 419                          * else NONCRIT error set.
 420                          */
 421                         if (cc->Nfans == 1 || cc->Ntherm == 0)
 422                                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 423                         else
 424                                 ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
 425                         break;
 426                 case 2:
 427                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
 428                         ssc->ses_objmap[oid].encstat[3] = 0;
 429                         if (cc->Nfans == 1)
 430                                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 431                         else
 432                                 ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
 433                         break;
 434                 case 0x80:
 435                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
 436                         ssc->ses_objmap[oid].encstat[3] = 0;
 437                         ssc->ses_encstat |= ENCSTAT_INFO;
 438                         break;
 439                 default:
 440                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 441                         SES_LOG(ssc, CE_NOTE, "unknown fan%d status 0x%x",
 442                             i, sdata[r] & 0xff);
 443                         break;
 444                 }
 445                 ssc->ses_objmap[oid++].svalid = 1;
 446                 mutex_exit(&ssc->ses_devp->sd_mutex);
 447                 r++;
 448         }
 449         mutex_enter(&ssc->ses_devp->sd_mutex);
 450         /*
 451          * No matter how you cut it, no cooling elements when there
 452          * should be some there is critical.
 453          */
 454         if (cc->Nfans && nitems == 0) {
 455                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 456         }
 457         mutex_exit(&ssc->ses_devp->sd_mutex);
 458 
 459 
 460         for (i = 0; i < cc->Npwr; i++) {
 461                 BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 462                 mutex_enter(&ssc->ses_devp->sd_mutex);
 463                 ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 464                 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */
 465                 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */
 466                 ssc->ses_objmap[oid].encstat[3] = 0x20;      /* requested on */
 467                 switch ((uchar_t)sdata[r]) {
 468                 case 0x00:      /* pws operational and on */
 469                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 470                         break;
 471                 case 0x01:      /* pws operational and off */
 472                         ssc->ses_objmap[oid].encstat[3] = 0x10;
 473                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTAVAIL;
 474                         ssc->ses_encstat |= ENCSTAT_INFO;
 475                         break;
 476                 case 0x10:      /* pws is malfunctioning and commanded on */
 477                         ssc->ses_objmap[oid].encstat[3] = 0x61;
 478                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 479                         if (cc->Npwr < 2)
 480                                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 481                         else
 482                                 ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
 483                         break;
 484 
 485                 case 0x11:      /* pws is malfunctioning and commanded off */
 486                         ssc->ses_objmap[oid].encstat[3] = 0x51;
 487                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 488                         if (cc->Npwr < 2)
 489                                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 490                         else
 491                                 ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
 492                         break;
 493                 case 0x20:      /* pws is not present */
 494                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
 495                         ssc->ses_objmap[oid].encstat[3] = 0;
 496                         if (cc->Npwr < 2)
 497                                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 498                         else
 499                                 ssc->ses_encstat |= ENCSTAT_INFO;
 500                         break;
 501                 case 0x21:      /* pws is present */
 502                         break;
 503                 case 0x80:      /* Unknown or Not Reportable Status */
 504                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
 505                         ssc->ses_objmap[oid].encstat[3] = 0;
 506                         ssc->ses_encstat |= ENCSTAT_INFO;
 507                         break;
 508                 default:
 509                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 510                         SES_LOG(ssc, CE_NOTE, "unknown pwr%d status 0x%x",
 511                             i, sdata[r] & 0xff);
 512                         break;
 513                 }
 514                 ssc->ses_objmap[oid++].svalid = 1;
 515                 mutex_exit(&ssc->ses_devp->sd_mutex);
 516                 r++;
 517         }
 518 
 519         /*
 520          * Now I am going to save the target id's for the end of
 521          * the function.  (when I build the drive objects)
 522          * that is when I will be getting the drive status from buffer 4
 523          */
 524 
 525         for (i = 0; i < cc->Nslots; i++) {
 526                 driveids[i] = sdata[r++];
 527         }
 528 
 529 
 530 
 531         /*
 532          * We always have doorlock status, no matter what,
 533          * but we only save the status if we have one.
 534          */
 535         BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 536         if (cc->DoorLock) {
 537                 /*
 538                  * 0 = Door Locked
 539                  * 1 = Door Unlocked, or no Lock Installed
 540                  * 0x80 = Unknown or Not Reportable Status
 541                  */
 542                 mutex_enter(&ssc->ses_devp->sd_mutex);
 543                 ssc->ses_objmap[oid].encstat[1] = 0;
 544                 ssc->ses_objmap[oid].encstat[2] = 0;
 545                 switch ((uchar_t)sdata[r]) {
 546                 case 0:
 547                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 548                         ssc->ses_objmap[oid].encstat[3] = 0;
 549                         break;
 550                 case 1:
 551                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 552                         ssc->ses_objmap[oid].encstat[3] = 1;
 553                         break;
 554                 case 0x80:
 555                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
 556                         ssc->ses_objmap[oid].encstat[3] = 0;
 557                         ssc->ses_encstat |= ENCSTAT_INFO;
 558                         break;
 559                 default:
 560                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 561                         SES_LOG(ssc, CE_NOTE, "unknown lock status 0x%x",
 562                             sdata[r] & 0xff);
 563                         break;
 564                 }
 565                 ssc->ses_objmap[oid++].svalid = 1;
 566                 mutex_exit(&ssc->ses_devp->sd_mutex);
 567         }
 568         r++;
 569 
 570         /*
 571          * We always have speaker status, no matter what,
 572          * but we only save the status if we have one.
 573          */
 574         BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 575         if (cc->Nspkrs) {
 576                 mutex_enter(&ssc->ses_devp->sd_mutex);
 577                 ssc->ses_objmap[oid].encstat[1] = 0;
 578                 ssc->ses_objmap[oid].encstat[2] = 0;
 579                 if (sdata[r] == 1) {
 580                         /*
 581                          * We need to cache tone urgency indicators.
 582                          * Someday.
 583                          */
 584                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_NONCRIT;
 585                         ssc->ses_objmap[oid].encstat[3] = 0x8;
 586                         ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
 587                 } else if (sdata[r] == 0) {
 588                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 589                         ssc->ses_objmap[oid].encstat[3] = 0;
 590                 } else {
 591                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 592                         ssc->ses_objmap[oid].encstat[3] = 0;
 593                         SES_LOG(ssc, CE_NOTE, "unknown spkr status 0x%x",
 594                             sdata[r] & 0xff);
 595                 }
 596                 ssc->ses_objmap[oid++].svalid = 1;
 597                 mutex_exit(&ssc->ses_devp->sd_mutex);
 598         }
 599         r++;
 600 
 601         for (i = 0; i < cc->Ntherm; i++) {
 602                 BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 603                 /*
 604                  * Status is a range from -10 to 245 deg Celsius,
 605                  * which we need to normalize to -20 to -235 according
 606                  * to the latest SCSI spec.
 607                  */
 608                 mutex_enter(&ssc->ses_devp->sd_mutex);
 609                 ssc->ses_objmap[oid].encstat[1] = 0;
 610                 ssc->ses_objmap[oid].encstat[2] =
 611                     ((unsigned int) sdata[r]) - 10;
 612                 if (sdata[r] < 20) {
 613                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 614                         /*
 615                          * Set 'under temperature' failure.
 616                          */
 617                         ssc->ses_objmap[oid].encstat[3] = 2;
 618                         ssc->ses_encstat |= ENCSTAT_CRITICAL;
 619                 } else if (sdata[r] > 30) {
 620                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 621                         /*
 622                          * Set 'over temperature' failure.
 623                          */
 624                         ssc->ses_objmap[oid].encstat[3] = 8;
 625                         ssc->ses_encstat |= ENCSTAT_CRITICAL;
 626                 } else {
 627                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 628                 }
 629                 ssc->ses_objmap[oid++].svalid = 1;
 630                 mutex_exit(&ssc->ses_devp->sd_mutex);
 631                 r++;
 632         }
 633 
 634         /*
 635          * Now, for "pseudo" thermometers, we have two bytes
 636          * of information in enclosure status- 16 bits. Actually,
 637          * the MSB is a single TEMP ALERT flag indicating whether
 638          * any other bits are set, but, thanks to fuzzy thinking,
 639          * in the SAF-TE spec, this can also be set even if no
 640          * other bits are set, thus making this really another
 641          * binary temperature sensor.
 642          */
 643 
 644         BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 645         tempflags = sdata[r++];
 646         BAIL(r, hiwater, sdata, buflen, driveids, id_size);
 647         tempflags |= (tempflags << 8) | sdata[r++];
 648         mutex_enter(&ssc->ses_devp->sd_mutex);
 649 
 650 #if     NPSEUDO_THERM == 1
 651         ssc->ses_objmap[oid].encstat[1] = 0;
 652         if (tempflags) {
 653                 /* Set 'over temperature' failure. */
 654                 ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 655                 ssc->ses_objmap[oid].encstat[3] = 8;
 656                 ssc->ses_encstat |= ENCSTAT_CRITICAL;
 657         } else {
 658                 /* Set 'nominal' temperature. */
 659                 ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 660         }
 661         ssc->ses_objmap[oid++].svalid = 1;
 662 
 663 #else   /* NPSEUDO_THERM == 1 */
 664         for (i = 0; i < NPSEUDO_THERM; i++) {
 665                 ssc->ses_objmap[oid].encstat[1] = 0;
 666                 if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) {
 667                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
 668                         /* ssc->ses_objmap[oid].encstat[2] = 0; */
 669 
 670                         /*
 671                          * Set 'over temperature' failure.
 672                          */
 673                         ssc->ses_objmap[oid].encstat[3] = 8;
 674                         ssc->ses_encstat |= ENCSTAT_CRITICAL;
 675                 } else {
 676                         /*
 677                          * Set 'nominal' temperature.
 678                          */
 679                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 680                         /* ssc->ses_objmap[oid].encstat[2] = 0; */
 681                 }
 682                 ssc->ses_objmap[oid++].svalid = 1;
 683         }
 684 #endif  /* NPSEUDO_THERM == 1 */
 685 
 686 
 687         /*
 688          * Get alarm status.
 689          */
 690         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 691         ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv;
 692         ssc->ses_objmap[oid++].svalid = 1;
 693         mutex_exit(&ssc->ses_devp->sd_mutex);
 694 
 695         /*
 696          * Now get drive slot status
 697          */
 698         cdb[2] = SAFTE_RD_RDDSTS;
 699         err = ses_runcmd(ssc, lp);
 700         if (err) {
 701                 kmem_free(sdata, buflen);
 702                 kmem_free(driveids, id_size);
 703                 return (err);
 704         }
 705         hiwater = lp->uscsi_buflen - lp->uscsi_resid;
 706         for (r = i = 0; i < cc->Nslots; i++, r += 4) {
 707                 BAIL(r+3, hiwater, sdata, buflen, driveids, id_size);
 708                 mutex_enter(&ssc->ses_devp->sd_mutex);
 709                 ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
 710                 ssc->ses_objmap[oid].encstat[1] = (uchar_t)driveids[i];
 711                 ssc->ses_objmap[oid].encstat[2] = 0;
 712                 ssc->ses_objmap[oid].encstat[3] = 0;
 713                 status = sdata[r+3];
 714                 if ((status & 0x1) == 0) {  /* no device */
 715                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
 716                 } else {
 717                         ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
 718                 }
 719                 if (status & 0x2) {
 720                         ssc->ses_objmap[oid].encstat[2] = 0x8;
 721                 }
 722                 if ((status & 0x4) == 0) {
 723                         ssc->ses_objmap[oid].encstat[3] = 0x10;
 724                 }
 725                 ssc->ses_objmap[oid++].svalid = 1;
 726                 mutex_exit(&ssc->ses_devp->sd_mutex);
 727         }
 728         mutex_enter(&ssc->ses_devp->sd_mutex);
 729         /* see comment below about sticky enclosure status */
 730         ssc->ses_encstat |= ENCI_SVALID | oencstat;
 731         mutex_exit(&ssc->ses_devp->sd_mutex);
 732         kmem_free(sdata, buflen);
 733         kmem_free(driveids, id_size);
 734         return (0);
 735 }
 736 
 737 int
 738 safte_get_encstat(ses_softc_t *ssc, int slpflg)
 739 {
 740         return (safte_rdstat(ssc, slpflg));
 741 }
 742 
 743 int
 744 safte_set_encstat(ses_softc_t *ssc, uchar_t encstat, int slpflg)
 745 {
 746         struct scfg *cc = ssc->ses_private;
 747         if (cc == NULL)
 748                 return (0);
 749         mutex_enter(&ssc->ses_devp->sd_mutex);
 750         /*
 751          * Since SAF-TE devices aren't necessarily sticky in terms
 752          * of state, make our soft copy of enclosure status 'sticky'-
 753          * that is, things set in enclosure status stay set (as implied
 754          * by conditions set in reading object status) until cleared.
 755          */
 756         ssc->ses_encstat &= ~ALL_ENC_STAT;
 757         ssc->ses_encstat |= (encstat & ALL_ENC_STAT);
 758         ssc->ses_encstat |= ENCI_SVALID;
 759         cc->flag1 &= ~(FLG1_ALARM|FLG1_GLOBFAIL|FLG1_GLOBWARN);
 760         if ((encstat & (ENCSTAT_CRITICAL|ENCSTAT_UNRECOV)) != 0) {
 761                 cc->flag1 |= FLG1_ALARM|FLG1_GLOBFAIL;
 762         } else if ((encstat & ENCSTAT_NONCRITICAL) != 0) {
 763                 cc->flag1 |= FLG1_GLOBWARN;
 764         }
 765         mutex_exit(&ssc->ses_devp->sd_mutex);
 766         return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
 767 }
 768 
 769 int
 770 safte_get_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflg)
 771 {
 772         int i = (int)obp->obj_id;
 773 
 774         if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
 775             (ssc->ses_objmap[i].svalid) == 0) {
 776                 int r = safte_rdstat(ssc, slpflg);
 777                 if (r)
 778                         return (r);
 779         }
 780         obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
 781         obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
 782         obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
 783         obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
 784         return (0);
 785 }
 786 
 787 
 788 int
 789 safte_set_objstat(ses_softc_t *ssc, ses_objarg *obp, int slp)
 790 {
 791         int idx, err;
 792         encobj *ep;
 793         struct scfg *cc;
 794 
 795 
 796         SES_LOG(ssc, SES_CE_DEBUG2, "safte_set_objstat(%d): %x %x %x %x",
 797             (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2],
 798             obp->cstat[3]);
 799 
 800         /*
 801          * If this is clear, we don't do diddly.
 802          */
 803         if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
 804                 return (0);
 805         }
 806 
 807         err = 0;
 808         /*
 809          * Check to see if the common bits are set and do them first.
 810          */
 811         if (obp->cstat[0] & ~SESCTL_CSEL) {
 812                 err = set_objstat_sel(ssc, obp, slp);
 813                 if (err)
 814                         return (err);
 815         }
 816 
 817         cc = ssc->ses_private;
 818         if (cc == NULL)
 819                 return (0);
 820 
 821         idx = (int)obp->obj_id;
 822         ep = &ssc->ses_objmap[idx];
 823 
 824         switch (ep->enctype) {
 825         case SESTYP_DEVICE:
 826         {
 827                 uchar_t slotop = 0;
 828                 /*
 829                  * XXX: I should probably cache the previous state
 830                  * XXX: of SESCTL_DEVOFF so that when it goes from
 831                  * XXX: true to false I can then set PREPARE FOR OPERATION
 832                  * XXX: flag in PERFORM SLOT OPERATION write buffer command.
 833                  */
 834                 if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
 835                         slotop |= 0x2;
 836                 }
 837                 if (obp->cstat[2] & SESCTL_RQSID) {
 838                         slotop |= 0x4;
 839                 }
 840                 err = perf_slotop(ssc, (uchar_t)idx - (uchar_t)cc->slotoff,
 841                     slotop, slp);
 842                 if (err)
 843                         return (err);
 844                 mutex_enter(&ssc->ses_devp->sd_mutex);
 845                 if (obp->cstat[3] & SESCTL_RQSFLT) {
 846                         ep->priv |= 0x2;
 847                 } else {
 848                         ep->priv &= ~0x2;
 849                 }
 850                 if (ep->priv & 0xc6) {
 851                         ep->priv &= ~0x1;
 852                 } else {
 853                         ep->priv |= 0x1;     /* no errors */
 854                 }
 855                 mutex_exit(&ssc->ses_devp->sd_mutex);
 856                 wrslot_stat(ssc, slp);
 857                 break;
 858         }
 859         case SESTYP_POWER:
 860                 mutex_enter(&ssc->ses_devp->sd_mutex);
 861                 if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 862                         cc->flag1 |= FLG1_ENCPWRFAIL;
 863                 } else {
 864                         cc->flag1 &= ~FLG1_ENCPWRFAIL;
 865                 }
 866                 mutex_exit(&ssc->ses_devp->sd_mutex);
 867                 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 868                     cc->flag2, 0, slp);
 869                 if (err)
 870                         return (err);
 871                 if (obp->cstat[3] & SESCTL_RQSTON) {
 872                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 873                                 idx - cc->pwroff, 0, 0, slp);
 874                 } else {
 875                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 876                                 idx - cc->pwroff, 0, 1, slp);
 877                 }
 878                 break;
 879         case SESTYP_FAN:
 880                 mutex_enter(&ssc->ses_devp->sd_mutex);
 881                 if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 882                         cc->flag1 |= FLG1_ENCFANFAIL;
 883                 } else {
 884                         cc->flag1 &= ~FLG1_ENCFANFAIL;
 885                 }
 886                 mutex_exit(&ssc->ses_devp->sd_mutex);
 887                 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 888                     cc->flag2, 0, slp);
 889                 if (err)
 890                         return (err);
 891                 if (obp->cstat[3] & SESCTL_RQSTON) {
 892                         uchar_t fsp;
 893                         if ((obp->cstat[3] & 0x7) == 7) {
 894                                 fsp = 4;
 895                         } else if ((obp->cstat[3] & 0x7) == 6) {
 896                                 fsp = 3;
 897                         } else if ((obp->cstat[3] & 0x7) == 4) {
 898                                 fsp = 2;
 899                         } else {
 900                                 fsp = 1;
 901                         }
 902                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
 903                 } else {
 904                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 905                 }
 906                 break;
 907         case SESTYP_DOORLOCK:
 908                 mutex_enter(&ssc->ses_devp->sd_mutex);
 909                 if (obp->cstat[3] & 0x1) {
 910                         cc->flag2 &= ~FLG2_LOCKDOOR;
 911                 } else {
 912                         cc->flag2 |= FLG2_LOCKDOOR;
 913                 }
 914                 mutex_exit(&ssc->ses_devp->sd_mutex);
 915                 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 916                     cc->flag2, 0, slp);
 917                 break;
 918         case SESTYP_ALARM:
 919                 /*
 920                  * On all nonzero but the 'muted' bit, we turn on the alarm,
 921                  */
 922                 mutex_enter(&ssc->ses_devp->sd_mutex);
 923                 obp->cstat[3] &= ~0xa;
 924                 if (obp->cstat[3] & 0x40) {
 925                         cc->flag2 &= ~FLG1_ALARM;
 926                 } else if (obp->cstat[3] != 0) {
 927                         cc->flag2 |= FLG1_ALARM;
 928                 } else {
 929                         cc->flag2 &= ~FLG1_ALARM;
 930                 }
 931                 ep->priv = obp->cstat[3];
 932                 mutex_exit(&ssc->ses_devp->sd_mutex);
 933                 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 934                         cc->flag2, 0, slp);
 935                 break;
 936         default:
 937                 break;
 938         }
 939         mutex_enter(&ssc->ses_devp->sd_mutex);
 940         ep->svalid = 0;
 941         mutex_exit(&ssc->ses_devp->sd_mutex);
 942         return (0);
 943 }
 944 
 945 static int
 946 set_objstat_sel(ses_softc_t *ssc, ses_objarg *obp, int slp)
 947 {
 948         int idx;
 949         encobj *ep;
 950         struct scfg *cc = ssc->ses_private;
 951 
 952         if (cc == NULL)
 953                 return (0);
 954 
 955         idx = (int)obp->obj_id;
 956         ep = &ssc->ses_objmap[idx];
 957 
 958         switch (ep->enctype) {
 959         case SESTYP_DEVICE:
 960                 mutex_enter(&ssc->ses_devp->sd_mutex);
 961                 if (obp->cstat[0] & SESCTL_PRDFAIL) {
 962                         ep->priv |= 0x40;
 963                 }
 964                 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */
 965                 if (obp->cstat[0] & SESCTL_DISABLE) {
 966                         ep->priv |= 0x80;
 967                         /*
 968                          * Hmm. Try to set the 'No Drive' flag.
 969                          * Maybe that will count as a 'disable'.
 970                          */
 971                 }
 972                 if (ep->priv & 0xc6) {
 973                         ep->priv &= ~0x1;
 974                 } else {
 975                         ep->priv |= 0x1;     /* no errors */
 976                 }
 977                 mutex_exit(&ssc->ses_devp->sd_mutex);
 978                 wrslot_stat(ssc, slp);
 979                 break;
 980         case SESTYP_POWER:
 981                 /*
 982                  * Okay- the only one that makes sense here is to
 983                  * do the 'disable' for a power supply.
 984                  */
 985                 if (obp->cstat[0] & SESCTL_DISABLE) {
 986                         (void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 987                                 idx - cc->pwroff, 0, 0, slp);
 988                 }
 989                 break;
 990         case SESTYP_FAN:
 991                 /*
 992                  * Okay- the only one that makes sense here is to
 993                  * set fan speed to zero on disable.
 994                  */
 995                 if (obp->cstat[0] & SESCTL_DISABLE) {
 996                         /* remember- fans are the first items, so idx works */
 997                         (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 998                 }
 999                 break;
1000         case SESTYP_DOORLOCK:
1001                 /*
1002                  * Well, we can 'disable' the lock.
1003                  */
1004                 if (obp->cstat[0] & SESCTL_DISABLE) {
1005                         mutex_enter(&ssc->ses_devp->sd_mutex);
1006                         cc->flag2 &= ~FLG2_LOCKDOOR;
1007                         mutex_exit(&ssc->ses_devp->sd_mutex);
1008                         (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1009                                 cc->flag2, 0, slp);
1010                 }
1011                 break;
1012         case SESTYP_ALARM:
1013                 /*
1014                  * Well, we can 'disable' the alarm.
1015                  */
1016                 if (obp->cstat[0] & SESCTL_DISABLE) {
1017                         mutex_enter(&ssc->ses_devp->sd_mutex);
1018                         cc->flag2 &= ~FLG1_ALARM;
1019                         ep->priv |= 0x40;    /* Muted */
1020                         mutex_exit(&ssc->ses_devp->sd_mutex);
1021                         (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
1022                                 cc->flag2, 0, slp);
1023                 }
1024                 break;
1025         default:
1026                 break;
1027         }
1028         mutex_enter(&ssc->ses_devp->sd_mutex);
1029         ep->svalid = 0;
1030         mutex_exit(&ssc->ses_devp->sd_mutex);
1031         return (0);
1032 }
1033 
1034 /*
1035  * This function handles all of the 16 byte WRITE BUFFER commands.
1036  */
1037 static int
1038 wrbuf16(ses_softc_t *ssc, uchar_t op, uchar_t b1, uchar_t b2,
1039     uchar_t b3, int slp)
1040 {
1041         int err;
1042         Uscmd local, *lp = &local;
1043         char rqbuf[SENSE_LENGTH], *sdata;
1044         struct scfg *cc = ssc->ses_private;
1045         static char cdb[CDB_GROUP1] =
1046             { SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
1047 
1048         if (cc == NULL)
1049                 return (0);
1050 
1051         sdata = kmem_alloc(16, slp);
1052         if (sdata == NULL)
1053                 return (ENOMEM);
1054 
1055         lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
1056         lp->uscsi_timeout = ses_io_time;
1057         lp->uscsi_cdb = cdb;
1058         lp->uscsi_bufaddr = sdata;
1059         lp->uscsi_buflen = SCRATCH;
1060         lp->uscsi_cdblen = sizeof (cdb);
1061         lp->uscsi_rqbuf = rqbuf;
1062         lp->uscsi_rqlen = sizeof (rqbuf);
1063 
1064         sdata[0] = op;
1065         sdata[1] = b1;
1066         sdata[2] = b2;
1067         sdata[3] = b3;
1068         SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrbuf16 %x %x %x %x", op, b1, b2, b3);
1069         bzero(&sdata[4], 12);
1070         err = ses_runcmd(ssc, lp);
1071         kmem_free(sdata, 16);
1072         return (err);
1073 }
1074 
1075 /*
1076  * This function updates the status byte for the device slot described.
1077  *
1078  * Since this is an optional SAF-TE command, there's no point in
1079  * returning an error.
1080  */
1081 static void
1082 wrslot_stat(ses_softc_t *ssc, int slp)
1083 {
1084         int i;
1085         encobj *ep;
1086         Uscmd local, *lp = &local;
1087         char rqbuf[SENSE_LENGTH], cdb[CDB_GROUP1], *sdata;
1088         struct scfg *cc = ssc->ses_private;
1089 
1090         if (cc == NULL)
1091                 return;
1092 
1093         SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrslot");
1094         cdb[0] = SCMD_WRITE_BUFFER;
1095         cdb[1] = 1;
1096         cdb[2] = 0;
1097         cdb[3] = 0;
1098         cdb[4] = 0;
1099         cdb[5] = 0;
1100         cdb[6] = 0;
1101         cdb[7] = 0;
1102         cdb[8] = cc->Nslots * 3 + 1;
1103         cdb[9] = 0;
1104 
1105         sdata = kmem_zalloc(cc->Nslots * 3 + 1, slp);
1106         if (sdata == NULL)
1107                 return;
1108 
1109         lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
1110         lp->uscsi_timeout = ses_io_time;
1111         lp->uscsi_cdb = cdb;
1112         lp->uscsi_bufaddr = sdata;
1113         lp->uscsi_buflen = cc->Nslots * 3 + 1;
1114         lp->uscsi_cdblen = sizeof (cdb);
1115         lp->uscsi_rqbuf = rqbuf;
1116         lp->uscsi_rqlen = sizeof (rqbuf);
1117 
1118         sdata[0] = SAFTE_WT_DSTAT;
1119         for (i = 0; i < cc->Nslots; i++) {
1120                 ep = &ssc->ses_objmap[cc->slotoff + i];
1121                 SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrslot %d <- %x", i,
1122                     ep->priv & 0xff);
1123                 sdata[1 + (3 * i)] = ep->priv & 0xff;
1124         }
1125         (void) ses_runcmd(ssc, lp);
1126         kmem_free(sdata, cc->Nslots * 3 + 1);
1127 }
1128 
1129 /*
1130  * This function issues the "PERFORM SLOT OPERATION" command.
1131  */
1132 static int
1133 perf_slotop(ses_softc_t *ssc, uchar_t slot, uchar_t opflag, int slp)
1134 {
1135         int err;
1136         Uscmd local, *lp = &local;
1137         char rqbuf[SENSE_LENGTH], *sdata;
1138         struct scfg *cc = ssc->ses_private;
1139         static char cdb[CDB_GROUP1] =
1140             { SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SCRATCH, 0 };
1141 
1142         if (cc == NULL)
1143                 return (0);
1144 
1145         sdata = kmem_zalloc(SCRATCH, slp);
1146         if (sdata == NULL)
1147                 return (ENOMEM);
1148 
1149         lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
1150         lp->uscsi_timeout = ses_io_time;
1151         lp->uscsi_cdb = cdb;
1152         lp->uscsi_bufaddr = sdata;
1153         lp->uscsi_buflen = SCRATCH;
1154         lp->uscsi_cdblen = sizeof (cdb);
1155         lp->uscsi_rqbuf = rqbuf;
1156         lp->uscsi_rqlen = sizeof (rqbuf);
1157 
1158         sdata[0] = SAFTE_WT_SLTOP;
1159         sdata[1] = slot;
1160         sdata[2] = opflag;
1161         SES_LOG(ssc, SES_CE_DEBUG2, "saf_slotop slot %d op %x", slot, opflag);
1162         err = ses_runcmd(ssc, lp);
1163         kmem_free(sdata, SCRATCH);
1164         return (err);
1165 }
1166 
1167 /*
1168  * mode: c
1169  * Local variables:
1170  * c-indent-level: 8
1171  * c-brace-imaginary-offset: 0
1172  * c-brace-offset: -8
1173  * c-argdecl-indent: 8
1174  * c-label-offset: -8
1175  * c-continued-statement-offset: 8
1176  * c-continued-brace-offset: 0
1177  * End:
1178  */