#include <sys/modctl.h>
#include <sys/file.h>
#include <sys/scsi/scsi.h>
#include <sys/stat.h>
#include <sys/scsi/targets/sesio.h>
#include <sys/scsi/targets/ses.h>
static int set_objstat_sel(ses_softc_t *, ses_objarg *, int);
static int wrbuf16(ses_softc_t *, uchar_t, uchar_t, uchar_t, uchar_t, int);
static void wrslot_stat(ses_softc_t *, int);
static int perf_slotop(ses_softc_t *, uchar_t, uchar_t, int);
#define ALL_ENC_STAT \
(ENCSTAT_CRITICAL|ENCSTAT_UNRECOV|ENCSTAT_NONCRITICAL|ENCSTAT_INFO)
#define SCRATCH 64
#define NPSEUDO_THERM 1
#define NPSEUDO_ALARM 1
struct scfg {
uchar_t Nfans;
uchar_t Npwr;
uchar_t Nslots;
uchar_t DoorLock;
uchar_t Ntherm;
uchar_t Nspkrs;
uchar_t Nalarm;
uchar_t flag1;
uchar_t flag2;
uchar_t pwroff;
uchar_t slotoff;
#define ALARM_OFFSET(cc) (cc)->slotoff - 1
};
#define FLG1_ALARM 0x1
#define FLG1_GLOBFAIL 0x2
#define FLG1_GLOBWARN 0x4
#define FLG1_ENCPWROFF 0x8
#define FLG1_ENCFANFAIL 0x10
#define FLG1_ENCPWRFAIL 0x20
#define FLG1_ENCDRVFAIL 0x40
#define FLG1_ENCDRVWARN 0x80
#define FLG2_LOCKDOOR 0x4
#define SAFTE_PRIVATE sizeof (struct scfg)
#if !defined(lint)
_NOTE(MUTEX_PROTECTS_DATA(scsi_device::sd_mutex, scfg))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nfans))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Npwr))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nslots))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::DoorLock))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Ntherm))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nspkrs))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::Nalarm))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::flag1))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::flag2))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::pwroff))
_NOTE(DATA_READABLE_WITHOUT_LOCK(scfg::slotoff))
#endif
static int
safte_getconfig(ses_softc_t *ssc)
{
struct scfg *cfg;
int err;
Uscmd local, *lp = &local;
char rqbuf[SENSE_LENGTH], *sdata;
static char cdb[CDB_GROUP1] =
{ SCMD_READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SCRATCH, 0 };
cfg = ssc->ses_private;
if (cfg == NULL)
return (ENXIO);
sdata = kmem_alloc(SCRATCH, 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 = SCRATCH;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
err = ses_runcmd(ssc, lp);
if (err) {
kmem_free(sdata, SCRATCH);
return (err);
}
if ((lp->uscsi_buflen - lp->uscsi_resid) < 6) {
SES_LOG(ssc, CE_NOTE, "Too little data (%ld) for configuration",
lp->uscsi_buflen - lp->uscsi_resid);
kmem_free(sdata, SCRATCH);
return (EIO);
}
SES_LOG(ssc, SES_CE_DEBUG1, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm "
"%d Nspkrs %d", sdata[0], sdata[1], sdata[2], sdata[3], sdata[4],
sdata[5]);
mutex_enter(&ssc->ses_devp->sd_mutex);
cfg->Nfans = sdata[0];
cfg->Npwr = sdata[1];
cfg->Nslots = sdata[2];
cfg->DoorLock = sdata[3];
cfg->Ntherm = sdata[4];
cfg->Nspkrs = sdata[5];
cfg->Nalarm = NPSEUDO_ALARM;
mutex_exit(&ssc->ses_devp->sd_mutex);
kmem_free(sdata, SCRATCH);
return (0);
}
int
safte_softc_init(ses_softc_t *ssc, int doinit)
{
int r, i;
struct scfg *cc;
if (doinit == 0) {
mutex_enter(&ssc->ses_devp->sd_mutex);
if (ssc->ses_nobjects) {
if (ssc->ses_objmap) {
kmem_free(ssc->ses_objmap,
ssc->ses_nobjects * sizeof (encobj));
ssc->ses_objmap = NULL;
}
ssc->ses_nobjects = 0;
}
if (ssc->ses_private) {
kmem_free(ssc->ses_private, SAFTE_PRIVATE);
ssc->ses_private = NULL;
}
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(SAFTE_PRIVATE, 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);
if ((r = safte_getconfig(ssc)) != 0) {
return (r);
}
mutex_enter(&ssc->ses_devp->sd_mutex);
cc = ssc->ses_private;
ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock +
cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM;
ssc->ses_objmap = (encobj *)
kmem_zalloc(ssc->ses_nobjects * sizeof (encobj), KM_SLEEP);
mutex_exit(&ssc->ses_devp->sd_mutex);
if (ssc->ses_objmap == NULL)
return (ENOMEM);
r = 0;
mutex_enter(&ssc->ses_devp->sd_mutex);
for (i = 0; i < cc->Nfans; i++)
ssc->ses_objmap[r++].enctype = SESTYP_FAN;
cc->pwroff = (uchar_t)r;
for (i = 0; i < cc->Npwr; i++)
ssc->ses_objmap[r++].enctype = SESTYP_POWER;
for (i = 0; i < cc->DoorLock; i++)
ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK;
for (i = 0; i < cc->Nspkrs; i++)
ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
for (i = 0; i < cc->Ntherm; i++)
ssc->ses_objmap[r++].enctype = SESTYP_THERM;
for (i = 0; i < NPSEUDO_THERM; i++)
ssc->ses_objmap[r++].enctype = SESTYP_THERM;
ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
cc->slotoff = (uchar_t)r;
for (i = 0; i < cc->Nslots; i++)
ssc->ses_objmap[r++].enctype = SESTYP_DEVICE;
mutex_exit(&ssc->ses_devp->sd_mutex);
return (0);
}
int
safte_init_enc(ses_softc_t *ssc)
{
int err;
Uscmd local, *lp = &local;
char rqbuf[SENSE_LENGTH], *sdata;
static char cdb0[CDB_GROUP1] = { SCMD_SDIAG };
static char cdb[CDB_GROUP1] =
{ SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SCRATCH, 0 };
sdata = kmem_alloc(SCRATCH, KM_SLEEP);
lp->uscsi_flags = USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb0;
lp->uscsi_bufaddr = NULL;
lp->uscsi_buflen = 0;
lp->uscsi_cdblen = sizeof (cdb0);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
err = ses_runcmd(ssc, lp);
if (err) {
kmem_free(sdata, SCRATCH);
return (err);
}
lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb;
lp->uscsi_bufaddr = sdata;
lp->uscsi_buflen = SCRATCH;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
bzero(&sdata[1], 15);
sdata[0] = SAFTE_WT_GLOBAL;
err = ses_runcmd(ssc, lp);
kmem_free(sdata, SCRATCH);
return (err);
}
static char *toolittle = "Too Little Data Returned (%d) at line %d";
#define BAIL(r, x, k, l, m, n) \
if (r >= x) { \
SES_LOG(ssc, CE_NOTE, toolittle, x, __LINE__); \
kmem_free(k, l); \
kmem_free(m, n); \
return (EIO); \
}
static int
safte_rdstat(ses_softc_t *ssc, int slpflg)
{
int err, oid, r, i, hiwater, nitems;
ushort_t tempflags;
size_t buflen;
uchar_t status, oencstat;
Uscmd local, *lp = &local;
struct scfg *cc = ssc->ses_private;
char rqbuf[SENSE_LENGTH], *sdata;
char cdb[CDB_GROUP1];
int *driveids, id_size = cc->Nslots * sizeof (int);
driveids = kmem_alloc(id_size, slpflg);
if (driveids == NULL) {
return (ENOMEM);
}
buflen = cc->Nfans + cc->Npwr + cc->Nslots + cc->Nspkrs;
buflen += cc->Ntherm + 14;
if (buflen < cc->Nslots * 4) {
buflen = cc->Nslots * 4;
}
if (ssc->ses_nobjects > buflen)
buflen = ssc->ses_nobjects;
if (buflen > 0xffff) {
cmn_err(CE_WARN, "Illogical SCSI data");
kmem_free(driveids, id_size);
return (EIO);
}
sdata = kmem_alloc(buflen, slpflg);
if (sdata == NULL) {
kmem_free(driveids, id_size);
return (ENOMEM);
}
cdb[0] = SCMD_READ_BUFFER;
cdb[1] = 1;
cdb[2] = SAFTE_RD_RDESTS;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
cdb[6] = 0;
cdb[7] = (buflen >> 8) & 0xff;
cdb[8] = buflen & 0xff;
cdb[9] = 0;
lp->uscsi_flags = USCSI_READ|USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb;
lp->uscsi_bufaddr = sdata;
lp->uscsi_buflen = buflen;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
err = ses_runcmd(ssc, lp);
if (err) {
kmem_free(sdata, buflen);
kmem_free(driveids, id_size);
return (err);
}
hiwater = lp->uscsi_buflen - lp->uscsi_resid;
mutex_enter(&ssc->ses_devp->sd_mutex);
for (i = 0; i < ssc->ses_nobjects; i++)
ssc->ses_objmap[i].svalid = 0;
oencstat = ssc->ses_encstat & ALL_ENC_STAT;
ssc->ses_encstat = 0;
mutex_exit(&ssc->ses_devp->sd_mutex);
oid = r = 0;
for (nitems = i = 0; i < cc->Nfans; i++) {
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[1] = 0;
ssc->ses_objmap[oid].encstat[2] = 0;
switch ((uchar_t)sdata[r]) {
case 0:
nitems++;
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
ssc->ses_objmap[oid].encstat[3] = 7;
break;
case 1:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
ssc->ses_objmap[oid].encstat[3] = 0x40;
if (cc->Nfans == 1 || cc->Ntherm == 0)
ssc->ses_encstat |= ENCSTAT_CRITICAL;
else
ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
break;
case 2:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
ssc->ses_objmap[oid].encstat[3] = 0;
if (cc->Nfans == 1)
ssc->ses_encstat |= ENCSTAT_CRITICAL;
else
ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
break;
case 0x80:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
ssc->ses_objmap[oid].encstat[3] = 0;
ssc->ses_encstat |= ENCSTAT_INFO;
break;
default:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
SES_LOG(ssc, CE_NOTE, "unknown fan%d status 0x%x",
i, sdata[r] & 0xff);
break;
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
r++;
}
mutex_enter(&ssc->ses_devp->sd_mutex);
if (cc->Nfans && nitems == 0) {
ssc->ses_encstat |= ENCSTAT_CRITICAL;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
for (i = 0; i < cc->Npwr; i++) {
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
ssc->ses_objmap[oid].encstat[1] = 0;
ssc->ses_objmap[oid].encstat[2] = 0;
ssc->ses_objmap[oid].encstat[3] = 0x20;
switch ((uchar_t)sdata[r]) {
case 0x00:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
break;
case 0x01:
ssc->ses_objmap[oid].encstat[3] = 0x10;
ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTAVAIL;
ssc->ses_encstat |= ENCSTAT_INFO;
break;
case 0x10:
ssc->ses_objmap[oid].encstat[3] = 0x61;
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
if (cc->Npwr < 2)
ssc->ses_encstat |= ENCSTAT_CRITICAL;
else
ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
break;
case 0x11:
ssc->ses_objmap[oid].encstat[3] = 0x51;
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
if (cc->Npwr < 2)
ssc->ses_encstat |= ENCSTAT_CRITICAL;
else
ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
break;
case 0x20:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
ssc->ses_objmap[oid].encstat[3] = 0;
if (cc->Npwr < 2)
ssc->ses_encstat |= ENCSTAT_CRITICAL;
else
ssc->ses_encstat |= ENCSTAT_INFO;
break;
case 0x21:
break;
case 0x80:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
ssc->ses_objmap[oid].encstat[3] = 0;
ssc->ses_encstat |= ENCSTAT_INFO;
break;
default:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
SES_LOG(ssc, CE_NOTE, "unknown pwr%d status 0x%x",
i, sdata[r] & 0xff);
break;
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
r++;
}
for (i = 0; i < cc->Nslots; i++) {
driveids[i] = sdata[r++];
}
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
if (cc->DoorLock) {
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[1] = 0;
ssc->ses_objmap[oid].encstat[2] = 0;
switch ((uchar_t)sdata[r]) {
case 0:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
ssc->ses_objmap[oid].encstat[3] = 0;
break;
case 1:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
ssc->ses_objmap[oid].encstat[3] = 1;
break;
case 0x80:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNKNOWN;
ssc->ses_objmap[oid].encstat[3] = 0;
ssc->ses_encstat |= ENCSTAT_INFO;
break;
default:
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
SES_LOG(ssc, CE_NOTE, "unknown lock status 0x%x",
sdata[r] & 0xff);
break;
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
}
r++;
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
if (cc->Nspkrs) {
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[1] = 0;
ssc->ses_objmap[oid].encstat[2] = 0;
if (sdata[r] == 1) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_NONCRIT;
ssc->ses_objmap[oid].encstat[3] = 0x8;
ssc->ses_encstat |= ENCSTAT_NONCRITICAL;
} else if (sdata[r] == 0) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
ssc->ses_objmap[oid].encstat[3] = 0;
} else {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
ssc->ses_objmap[oid].encstat[3] = 0;
SES_LOG(ssc, CE_NOTE, "unknown spkr status 0x%x",
sdata[r] & 0xff);
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
}
r++;
for (i = 0; i < cc->Ntherm; i++) {
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[1] = 0;
ssc->ses_objmap[oid].encstat[2] =
((unsigned int) sdata[r]) - 10;
if (sdata[r] < 20) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
ssc->ses_objmap[oid].encstat[3] = 2;
ssc->ses_encstat |= ENCSTAT_CRITICAL;
} else if (sdata[r] > 30) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
ssc->ses_objmap[oid].encstat[3] = 8;
ssc->ses_encstat |= ENCSTAT_CRITICAL;
} else {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
r++;
}
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
tempflags = sdata[r++];
BAIL(r, hiwater, sdata, buflen, driveids, id_size);
tempflags |= (tempflags << 8) | sdata[r++];
mutex_enter(&ssc->ses_devp->sd_mutex);
#if NPSEUDO_THERM == 1
ssc->ses_objmap[oid].encstat[1] = 0;
if (tempflags) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
ssc->ses_objmap[oid].encstat[3] = 8;
ssc->ses_encstat |= ENCSTAT_CRITICAL;
} else {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
}
ssc->ses_objmap[oid++].svalid = 1;
#else
for (i = 0; i < NPSEUDO_THERM; i++) {
ssc->ses_objmap[oid].encstat[1] = 0;
if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_CRIT;
ssc->ses_objmap[oid].encstat[3] = 8;
ssc->ses_encstat |= ENCSTAT_CRITICAL;
} else {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
}
ssc->ses_objmap[oid++].svalid = 1;
}
#endif
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv;
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
cdb[2] = SAFTE_RD_RDDSTS;
err = ses_runcmd(ssc, lp);
if (err) {
kmem_free(sdata, buflen);
kmem_free(driveids, id_size);
return (err);
}
hiwater = lp->uscsi_buflen - lp->uscsi_resid;
for (r = i = 0; i < cc->Nslots; i++, r += 4) {
BAIL(r+3, hiwater, sdata, buflen, driveids, id_size);
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_objmap[oid].encstat[0] = SESSTAT_UNSUPPORTED;
ssc->ses_objmap[oid].encstat[1] = (uchar_t)driveids[i];
ssc->ses_objmap[oid].encstat[2] = 0;
ssc->ses_objmap[oid].encstat[3] = 0;
status = sdata[r+3];
if ((status & 0x1) == 0) {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_NOTINSTALLED;
} else {
ssc->ses_objmap[oid].encstat[0] = SESSTAT_OK;
}
if (status & 0x2) {
ssc->ses_objmap[oid].encstat[2] = 0x8;
}
if ((status & 0x4) == 0) {
ssc->ses_objmap[oid].encstat[3] = 0x10;
}
ssc->ses_objmap[oid++].svalid = 1;
mutex_exit(&ssc->ses_devp->sd_mutex);
}
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_encstat |= ENCI_SVALID | oencstat;
mutex_exit(&ssc->ses_devp->sd_mutex);
kmem_free(sdata, buflen);
kmem_free(driveids, id_size);
return (0);
}
int
safte_get_encstat(ses_softc_t *ssc, int slpflg)
{
return (safte_rdstat(ssc, slpflg));
}
int
safte_set_encstat(ses_softc_t *ssc, uchar_t encstat, int slpflg)
{
struct scfg *cc = ssc->ses_private;
if (cc == NULL)
return (0);
mutex_enter(&ssc->ses_devp->sd_mutex);
ssc->ses_encstat &= ~ALL_ENC_STAT;
ssc->ses_encstat |= (encstat & ALL_ENC_STAT);
ssc->ses_encstat |= ENCI_SVALID;
cc->flag1 &= ~(FLG1_ALARM|FLG1_GLOBFAIL|FLG1_GLOBWARN);
if ((encstat & (ENCSTAT_CRITICAL|ENCSTAT_UNRECOV)) != 0) {
cc->flag1 |= FLG1_ALARM|FLG1_GLOBFAIL;
} else if ((encstat & ENCSTAT_NONCRITICAL) != 0) {
cc->flag1 |= FLG1_GLOBWARN;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
}
int
safte_get_objstat(ses_softc_t *ssc, ses_objarg *obp, int slpflg)
{
int i = (int)obp->obj_id;
if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
(ssc->ses_objmap[i].svalid) == 0) {
int r = safte_rdstat(ssc, slpflg);
if (r)
return (r);
}
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
safte_set_objstat(ses_softc_t *ssc, ses_objarg *obp, int slp)
{
int idx, err;
encobj *ep;
struct scfg *cc;
SES_LOG(ssc, SES_CE_DEBUG2, "safte_set_objstat(%d): %x %x %x %x",
(int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2],
obp->cstat[3]);
if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
return (0);
}
err = 0;
if (obp->cstat[0] & ~SESCTL_CSEL) {
err = set_objstat_sel(ssc, obp, slp);
if (err)
return (err);
}
cc = ssc->ses_private;
if (cc == NULL)
return (0);
idx = (int)obp->obj_id;
ep = &ssc->ses_objmap[idx];
switch (ep->enctype) {
case SESTYP_DEVICE:
{
uchar_t slotop = 0;
if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
slotop |= 0x2;
}
if (obp->cstat[2] & SESCTL_RQSID) {
slotop |= 0x4;
}
err = perf_slotop(ssc, (uchar_t)idx - (uchar_t)cc->slotoff,
slotop, slp);
if (err)
return (err);
mutex_enter(&ssc->ses_devp->sd_mutex);
if (obp->cstat[3] & SESCTL_RQSFLT) {
ep->priv |= 0x2;
} else {
ep->priv &= ~0x2;
}
if (ep->priv & 0xc6) {
ep->priv &= ~0x1;
} else {
ep->priv |= 0x1;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
wrslot_stat(ssc, slp);
break;
}
case SESTYP_POWER:
mutex_enter(&ssc->ses_devp->sd_mutex);
if (obp->cstat[3] & SESCTL_RQSTFAIL) {
cc->flag1 |= FLG1_ENCPWRFAIL;
} else {
cc->flag1 &= ~FLG1_ENCPWRFAIL;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
if (err)
return (err);
if (obp->cstat[3] & SESCTL_RQSTON) {
(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
idx - cc->pwroff, 0, 0, slp);
} else {
(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
idx - cc->pwroff, 0, 1, slp);
}
break;
case SESTYP_FAN:
mutex_enter(&ssc->ses_devp->sd_mutex);
if (obp->cstat[3] & SESCTL_RQSTFAIL) {
cc->flag1 |= FLG1_ENCFANFAIL;
} else {
cc->flag1 &= ~FLG1_ENCFANFAIL;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
if (err)
return (err);
if (obp->cstat[3] & SESCTL_RQSTON) {
uchar_t fsp;
if ((obp->cstat[3] & 0x7) == 7) {
fsp = 4;
} else if ((obp->cstat[3] & 0x7) == 6) {
fsp = 3;
} else if ((obp->cstat[3] & 0x7) == 4) {
fsp = 2;
} else {
fsp = 1;
}
(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
} else {
(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
}
break;
case SESTYP_DOORLOCK:
mutex_enter(&ssc->ses_devp->sd_mutex);
if (obp->cstat[3] & 0x1) {
cc->flag2 &= ~FLG2_LOCKDOOR;
} else {
cc->flag2 |= FLG2_LOCKDOOR;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
break;
case SESTYP_ALARM:
mutex_enter(&ssc->ses_devp->sd_mutex);
obp->cstat[3] &= ~0xa;
if (obp->cstat[3] & 0x40) {
cc->flag2 &= ~FLG1_ALARM;
} else if (obp->cstat[3] != 0) {
cc->flag2 |= FLG1_ALARM;
} else {
cc->flag2 &= ~FLG1_ALARM;
}
ep->priv = obp->cstat[3];
mutex_exit(&ssc->ses_devp->sd_mutex);
(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
break;
default:
break;
}
mutex_enter(&ssc->ses_devp->sd_mutex);
ep->svalid = 0;
mutex_exit(&ssc->ses_devp->sd_mutex);
return (0);
}
static int
set_objstat_sel(ses_softc_t *ssc, ses_objarg *obp, int slp)
{
int idx;
encobj *ep;
struct scfg *cc = ssc->ses_private;
if (cc == NULL)
return (0);
idx = (int)obp->obj_id;
ep = &ssc->ses_objmap[idx];
switch (ep->enctype) {
case SESTYP_DEVICE:
mutex_enter(&ssc->ses_devp->sd_mutex);
if (obp->cstat[0] & SESCTL_PRDFAIL) {
ep->priv |= 0x40;
}
if (obp->cstat[0] & SESCTL_DISABLE) {
ep->priv |= 0x80;
}
if (ep->priv & 0xc6) {
ep->priv &= ~0x1;
} else {
ep->priv |= 0x1;
}
mutex_exit(&ssc->ses_devp->sd_mutex);
wrslot_stat(ssc, slp);
break;
case SESTYP_POWER:
if (obp->cstat[0] & SESCTL_DISABLE) {
(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
idx - cc->pwroff, 0, 0, slp);
}
break;
case SESTYP_FAN:
if (obp->cstat[0] & SESCTL_DISABLE) {
(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
}
break;
case SESTYP_DOORLOCK:
if (obp->cstat[0] & SESCTL_DISABLE) {
mutex_enter(&ssc->ses_devp->sd_mutex);
cc->flag2 &= ~FLG2_LOCKDOOR;
mutex_exit(&ssc->ses_devp->sd_mutex);
(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
}
break;
case SESTYP_ALARM:
if (obp->cstat[0] & SESCTL_DISABLE) {
mutex_enter(&ssc->ses_devp->sd_mutex);
cc->flag2 &= ~FLG1_ALARM;
ep->priv |= 0x40;
mutex_exit(&ssc->ses_devp->sd_mutex);
(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
cc->flag2, 0, slp);
}
break;
default:
break;
}
mutex_enter(&ssc->ses_devp->sd_mutex);
ep->svalid = 0;
mutex_exit(&ssc->ses_devp->sd_mutex);
return (0);
}
static int
wrbuf16(ses_softc_t *ssc, uchar_t op, uchar_t b1, uchar_t b2,
uchar_t b3, int slp)
{
int err;
Uscmd local, *lp = &local;
char rqbuf[SENSE_LENGTH], *sdata;
struct scfg *cc = ssc->ses_private;
static char cdb[CDB_GROUP1] =
{ SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
if (cc == NULL)
return (0);
sdata = kmem_alloc(16, slp);
if (sdata == NULL)
return (ENOMEM);
lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb;
lp->uscsi_bufaddr = sdata;
lp->uscsi_buflen = SCRATCH;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
sdata[0] = op;
sdata[1] = b1;
sdata[2] = b2;
sdata[3] = b3;
SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrbuf16 %x %x %x %x", op, b1, b2, b3);
bzero(&sdata[4], 12);
err = ses_runcmd(ssc, lp);
kmem_free(sdata, 16);
return (err);
}
static void
wrslot_stat(ses_softc_t *ssc, int slp)
{
int i;
encobj *ep;
Uscmd local, *lp = &local;
char rqbuf[SENSE_LENGTH], cdb[CDB_GROUP1], *sdata;
struct scfg *cc = ssc->ses_private;
if (cc == NULL)
return;
SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrslot");
cdb[0] = SCMD_WRITE_BUFFER;
cdb[1] = 1;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
cdb[6] = 0;
cdb[7] = 0;
cdb[8] = cc->Nslots * 3 + 1;
cdb[9] = 0;
sdata = kmem_zalloc(cc->Nslots * 3 + 1, slp);
if (sdata == NULL)
return;
lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb;
lp->uscsi_bufaddr = sdata;
lp->uscsi_buflen = cc->Nslots * 3 + 1;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
sdata[0] = SAFTE_WT_DSTAT;
for (i = 0; i < cc->Nslots; i++) {
ep = &ssc->ses_objmap[cc->slotoff + i];
SES_LOG(ssc, SES_CE_DEBUG2, "saf_wrslot %d <- %x", i,
ep->priv & 0xff);
sdata[1 + (3 * i)] = ep->priv & 0xff;
}
(void) ses_runcmd(ssc, lp);
kmem_free(sdata, cc->Nslots * 3 + 1);
}
static int
perf_slotop(ses_softc_t *ssc, uchar_t slot, uchar_t opflag, int slp)
{
int err;
Uscmd local, *lp = &local;
char rqbuf[SENSE_LENGTH], *sdata;
struct scfg *cc = ssc->ses_private;
static char cdb[CDB_GROUP1] =
{ SCMD_WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SCRATCH, 0 };
if (cc == NULL)
return (0);
sdata = kmem_zalloc(SCRATCH, slp);
if (sdata == NULL)
return (ENOMEM);
lp->uscsi_flags = USCSI_WRITE|USCSI_RQENABLE;
lp->uscsi_timeout = ses_io_time;
lp->uscsi_cdb = cdb;
lp->uscsi_bufaddr = sdata;
lp->uscsi_buflen = SCRATCH;
lp->uscsi_cdblen = sizeof (cdb);
lp->uscsi_rqbuf = rqbuf;
lp->uscsi_rqlen = sizeof (rqbuf);
sdata[0] = SAFTE_WT_SLTOP;
sdata[1] = slot;
sdata[2] = opflag;
SES_LOG(ssc, SES_CE_DEBUG2, "saf_slotop slot %d op %x", slot, opflag);
err = ses_runcmd(ssc, lp);
kmem_free(sdata, SCRATCH);
return (err);
}