1235911Smav/*- 2235911Smav * Copyright (c) 2000 Matthew Jacob 3235911Smav * All rights reserved. 4235911Smav * 5235911Smav * Redistribution and use in source and binary forms, with or without 6235911Smav * modification, are permitted provided that the following conditions 7235911Smav * are met: 8235911Smav * 1. Redistributions of source code must retain the above copyright 9235911Smav * notice, this list of conditions, and the following disclaimer, 10235911Smav * without modification, immediately at the beginning of the file. 11235911Smav * 2. The name of the author may not be used to endorse or promote products 12235911Smav * derived from this software without specific prior written permission. 13235911Smav * 14235911Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235911Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235911Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235911Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18235911Smav * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235911Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235911Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235911Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235911Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235911Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235911Smav * SUCH DAMAGE. 25235911Smav */ 26235911Smav 27235911Smav#include <sys/cdefs.h> 28235911Smav__FBSDID("$FreeBSD: stable/11/sys/cam/scsi/scsi_enc_safte.c 350793 2019-08-08 21:46:36Z mav $"); 29235911Smav 30235911Smav#include <sys/param.h> 31235911Smav 32235911Smav#include <sys/conf.h> 33235911Smav#include <sys/errno.h> 34235911Smav#include <sys/kernel.h> 35235911Smav#include <sys/malloc.h> 36235911Smav#include <sys/mutex.h> 37235911Smav#include <sys/queue.h> 38235911Smav#include <sys/sx.h> 39235911Smav#include <sys/systm.h> 40235911Smav#include <sys/sysctl.h> 41235911Smav#include <sys/types.h> 42235911Smav 43235911Smav#include <cam/cam.h> 44235911Smav#include <cam/cam_ccb.h> 45235911Smav#include <cam/cam_periph.h> 46235911Smav 47235911Smav#include <cam/scsi/scsi_enc.h> 48235911Smav#include <cam/scsi/scsi_enc_internal.h> 49235911Smav#include <cam/scsi/scsi_message.h> 50235911Smav 51235911Smav/* 52235911Smav * SAF-TE Type Device Emulation 53235911Smav */ 54235911Smav 55235911Smavstatic int safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag); 56235911Smav 57235911Smav#define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \ 58235911Smav SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) 59235911Smav/* 60235911Smav * SAF-TE specific defines- Mandatory ones only... 61235911Smav */ 62235911Smav 63235911Smav/* 64235911Smav * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb 65235911Smav */ 66235911Smav#define SAFTE_RD_RDCFG 0x00 /* read enclosure configuration */ 67235911Smav#define SAFTE_RD_RDESTS 0x01 /* read enclosure status */ 68235911Smav#define SAFTE_RD_RDDSTS 0x04 /* read drive slot status */ 69235911Smav#define SAFTE_RD_RDGFLG 0x05 /* read global flags */ 70235911Smav 71235911Smav/* 72235911Smav * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf 73235911Smav */ 74235911Smav#define SAFTE_WT_DSTAT 0x10 /* write device slot status */ 75235911Smav#define SAFTE_WT_SLTOP 0x12 /* perform slot operation */ 76235911Smav#define SAFTE_WT_FANSPD 0x13 /* set fan speed */ 77235911Smav#define SAFTE_WT_ACTPWS 0x14 /* turn on/off power supply */ 78235911Smav#define SAFTE_WT_GLOBAL 0x15 /* send global command */ 79235911Smav 80235911Smav#define SAFT_SCRATCH 64 81235911Smav#define SCSZ 0x8000 82235911Smav 83235911Smavtypedef enum { 84235911Smav SAFTE_UPDATE_NONE, 85235911Smav SAFTE_UPDATE_READCONFIG, 86235911Smav SAFTE_UPDATE_READGFLAGS, 87235911Smav SAFTE_UPDATE_READENCSTATUS, 88235911Smav SAFTE_UPDATE_READSLOTSTATUS, 89235911Smav SAFTE_PROCESS_CONTROL_REQS, 90235911Smav SAFTE_NUM_UPDATE_STATES 91235911Smav} safte_update_action; 92235911Smav 93235911Smavstatic fsm_fill_handler_t safte_fill_read_buf_io; 94235911Smavstatic fsm_fill_handler_t safte_fill_control_request; 95235911Smavstatic fsm_done_handler_t safte_process_config; 96235911Smavstatic fsm_done_handler_t safte_process_gflags; 97235911Smavstatic fsm_done_handler_t safte_process_status; 98235911Smavstatic fsm_done_handler_t safte_process_slotstatus; 99235911Smavstatic fsm_done_handler_t safte_process_control_request; 100235911Smav 101235911Smavstatic struct enc_fsm_state enc_fsm_states[SAFTE_NUM_UPDATE_STATES] = 102235911Smav{ 103235911Smav { "SAFTE_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL }, 104235911Smav { 105235911Smav "SAFTE_UPDATE_READCONFIG", 106235911Smav SAFTE_RD_RDCFG, 107235911Smav SAFT_SCRATCH, 108235911Smav 60 * 1000, 109235911Smav safte_fill_read_buf_io, 110235911Smav safte_process_config, 111235911Smav enc_error 112235911Smav }, 113235911Smav { 114235911Smav "SAFTE_UPDATE_READGFLAGS", 115235911Smav SAFTE_RD_RDGFLG, 116235911Smav 16, 117235911Smav 60 * 1000, 118235911Smav safte_fill_read_buf_io, 119235911Smav safte_process_gflags, 120235911Smav enc_error 121235911Smav }, 122235911Smav { 123235911Smav "SAFTE_UPDATE_READENCSTATUS", 124235911Smav SAFTE_RD_RDESTS, 125235911Smav SCSZ, 126235911Smav 60 * 1000, 127235911Smav safte_fill_read_buf_io, 128235911Smav safte_process_status, 129235911Smav enc_error 130235911Smav }, 131235911Smav { 132235911Smav "SAFTE_UPDATE_READSLOTSTATUS", 133235911Smav SAFTE_RD_RDDSTS, 134235911Smav SCSZ, 135235911Smav 60 * 1000, 136235911Smav safte_fill_read_buf_io, 137235911Smav safte_process_slotstatus, 138235911Smav enc_error 139235911Smav }, 140235911Smav { 141235911Smav "SAFTE_PROCESS_CONTROL_REQS", 142235911Smav 0, 143235911Smav SCSZ, 144235911Smav 60 * 1000, 145235911Smav safte_fill_control_request, 146235911Smav safte_process_control_request, 147235911Smav enc_error 148235911Smav } 149235911Smav}; 150235911Smav 151235911Smavtypedef struct safte_control_request { 152235911Smav int elm_idx; 153235911Smav uint8_t elm_stat[4]; 154235911Smav int result; 155235911Smav TAILQ_ENTRY(safte_control_request) links; 156235911Smav} safte_control_request_t; 157235911SmavTAILQ_HEAD(safte_control_reqlist, safte_control_request); 158235911Smavtypedef struct safte_control_reqlist safte_control_reqlist_t; 159235911Smavenum { 160235911Smav SES_SETSTATUS_ENC_IDX = -1 161235911Smav}; 162235911Smav 163235911Smavstatic void 164235911Smavsafte_terminate_control_requests(safte_control_reqlist_t *reqlist, int result) 165235911Smav{ 166235911Smav safte_control_request_t *req; 167235911Smav 168235911Smav while ((req = TAILQ_FIRST(reqlist)) != NULL) { 169235911Smav TAILQ_REMOVE(reqlist, req, links); 170235911Smav req->result = result; 171235911Smav wakeup(req); 172235911Smav } 173235911Smav} 174235911Smav 175235911Smavstruct scfg { 176235911Smav /* 177235911Smav * Cached Configuration 178235911Smav */ 179235911Smav uint8_t Nfans; /* Number of Fans */ 180235911Smav uint8_t Npwr; /* Number of Power Supplies */ 181235911Smav uint8_t Nslots; /* Number of Device Slots */ 182235911Smav uint8_t DoorLock; /* Door Lock Installed */ 183235911Smav uint8_t Ntherm; /* Number of Temperature Sensors */ 184235911Smav uint8_t Nspkrs; /* Number of Speakers */ 185235911Smav uint8_t Ntstats; /* Number of Thermostats */ 186235911Smav /* 187235911Smav * Cached Flag Bytes for Global Status 188235911Smav */ 189235911Smav uint8_t flag1; 190235911Smav uint8_t flag2; 191235911Smav /* 192235911Smav * What object index ID is where various slots start. 193235911Smav */ 194235911Smav uint8_t pwroff; 195235911Smav uint8_t slotoff; 196235911Smav#define SAFT_ALARM_OFFSET(cc) (cc)->slotoff - 1 197235911Smav 198235911Smav encioc_enc_status_t adm_status; 199235911Smav encioc_enc_status_t enc_status; 200235911Smav encioc_enc_status_t slot_status; 201235911Smav 202235911Smav safte_control_reqlist_t requests; 203235911Smav safte_control_request_t *current_request; 204235911Smav int current_request_stage; 205235911Smav int current_request_stages; 206235911Smav}; 207235911Smav 208235911Smav#define SAFT_FLG1_ALARM 0x1 209235911Smav#define SAFT_FLG1_GLOBFAIL 0x2 210235911Smav#define SAFT_FLG1_GLOBWARN 0x4 211235911Smav#define SAFT_FLG1_ENCPWROFF 0x8 212235911Smav#define SAFT_FLG1_ENCFANFAIL 0x10 213235911Smav#define SAFT_FLG1_ENCPWRFAIL 0x20 214235911Smav#define SAFT_FLG1_ENCDRVFAIL 0x40 215235911Smav#define SAFT_FLG1_ENCDRVWARN 0x80 216235911Smav 217235911Smav#define SAFT_FLG2_LOCKDOOR 0x4 218235911Smav#define SAFT_PRIVATE sizeof (struct scfg) 219235911Smav 220235911Smavstatic char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; 221235911Smav#define SAFT_BAIL(r, x) \ 222235911Smav if ((r) >= (x)) { \ 223239213Smjacob ENC_VLOG(enc, safte_2little, x, __LINE__);\ 224235911Smav return (EIO); \ 225235911Smav } 226235911Smav 227235911Smavint emulate_array_devices = 1; 228267992ShselaskySYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN, 229235911Smav &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE"); 230235911Smav 231235911Smavstatic int 232235911Smavsafte_fill_read_buf_io(enc_softc_t *enc, struct enc_fsm_state *state, 233235911Smav union ccb *ccb, uint8_t *buf) 234235911Smav{ 235235911Smav 236235911Smav if (state->page_code != SAFTE_RD_RDCFG && 237235911Smav enc->enc_cache.nelms == 0) { 238235911Smav enc_update_request(enc, SAFTE_UPDATE_READCONFIG); 239235911Smav return (-1); 240235911Smav } 241235911Smav 242235911Smav if (enc->enc_type == ENC_SEMB_SAFT) { 243235911Smav semb_read_buffer(&ccb->ataio, /*retries*/5, 244256843Smav NULL, MSG_SIMPLE_Q_TAG, 245235911Smav state->page_code, buf, state->buf_size, 246235911Smav state->timeout); 247235911Smav } else { 248235911Smav scsi_read_buffer(&ccb->csio, /*retries*/5, 249256843Smav NULL, MSG_SIMPLE_Q_TAG, 1, 250235911Smav state->page_code, 0, buf, state->buf_size, 251235911Smav SSD_FULL_SIZE, state->timeout); 252235911Smav } 253235911Smav return (0); 254235911Smav} 255235911Smav 256235911Smavstatic int 257235911Smavsafte_process_config(enc_softc_t *enc, struct enc_fsm_state *state, 258235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 259235911Smav{ 260235911Smav struct scfg *cfg; 261235911Smav uint8_t *buf = *bufp; 262235911Smav int i, r; 263235911Smav 264235911Smav cfg = enc->enc_private; 265235911Smav if (cfg == NULL) 266235911Smav return (ENXIO); 267235911Smav if (error != 0) 268235911Smav return (error); 269235911Smav if (xfer_len < 6) { 270239213Smjacob ENC_VLOG(enc, "too little data (%d) for configuration\n", 271235911Smav xfer_len); 272235911Smav return (EIO); 273235911Smav } 274235911Smav cfg->Nfans = buf[0]; 275235911Smav cfg->Npwr = buf[1]; 276235911Smav cfg->Nslots = buf[2]; 277235911Smav cfg->DoorLock = buf[3]; 278235911Smav cfg->Ntherm = buf[4]; 279235911Smav cfg->Nspkrs = buf[5]; 280235911Smav if (xfer_len >= 7) 281235911Smav cfg->Ntstats = buf[6] & 0x0f; 282235911Smav else 283235911Smav cfg->Ntstats = 0; 284235911Smav ENC_VLOG(enc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d " 285235911Smav "Ntstats %d\n", 286235911Smav cfg->Nfans, cfg->Npwr, cfg->Nslots, cfg->DoorLock, cfg->Ntherm, 287235911Smav cfg->Nspkrs, cfg->Ntstats); 288235911Smav 289235911Smav enc->enc_cache.nelms = cfg->Nfans + cfg->Npwr + cfg->Nslots + 290235911Smav cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1; 291235911Smav ENC_FREE_AND_NULL(enc->enc_cache.elm_map); 292235911Smav enc->enc_cache.elm_map = 293299373Smav malloc(enc->enc_cache.nelms * sizeof(enc_element_t), 294299373Smav M_SCSIENC, M_WAITOK|M_ZERO); 295235911Smav 296235911Smav r = 0; 297235911Smav /* 298235911Smav * Note that this is all arranged for the convenience 299235911Smav * in later fetches of status. 300235911Smav */ 301235911Smav for (i = 0; i < cfg->Nfans; i++) 302350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN; 303235911Smav cfg->pwroff = (uint8_t) r; 304235911Smav for (i = 0; i < cfg->Npwr; i++) 305350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER; 306235911Smav for (i = 0; i < cfg->DoorLock; i++) 307350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK; 308235911Smav if (cfg->Nspkrs > 0) 309350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM; 310235911Smav for (i = 0; i < cfg->Ntherm; i++) 311350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; 312235911Smav for (i = 0; i <= cfg->Ntstats; i++) 313350793Smav enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM; 314235911Smav cfg->slotoff = (uint8_t) r; 315235911Smav for (i = 0; i < cfg->Nslots; i++) 316350793Smav enc->enc_cache.elm_map[r++].elm_type = 317235911Smav emulate_array_devices ? ELMTYP_ARRAY_DEV : 318235911Smav ELMTYP_DEVICE; 319235911Smav 320235911Smav enc_update_request(enc, SAFTE_UPDATE_READGFLAGS); 321235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 322235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 323235911Smav 324235911Smav return (0); 325235911Smav} 326235911Smav 327235911Smavstatic int 328235911Smavsafte_process_gflags(enc_softc_t *enc, struct enc_fsm_state *state, 329235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 330235911Smav{ 331235911Smav struct scfg *cfg; 332235911Smav uint8_t *buf = *bufp; 333235911Smav 334235911Smav cfg = enc->enc_private; 335235911Smav if (cfg == NULL) 336235911Smav return (ENXIO); 337235911Smav if (error != 0) 338235911Smav return (error); 339235911Smav SAFT_BAIL(3, xfer_len); 340235911Smav cfg->flag1 = buf[1]; 341235911Smav cfg->flag2 = buf[2]; 342235911Smav 343235911Smav cfg->adm_status = 0; 344235911Smav if (cfg->flag1 & SAFT_FLG1_GLOBFAIL) 345235911Smav cfg->adm_status |= SES_ENCSTAT_CRITICAL; 346235911Smav else if (cfg->flag1 & SAFT_FLG1_GLOBWARN) 347235911Smav cfg->adm_status |= SES_ENCSTAT_NONCRITICAL; 348235911Smav 349235911Smav return (0); 350235911Smav} 351235911Smav 352235911Smavstatic int 353235911Smavsafte_process_status(enc_softc_t *enc, struct enc_fsm_state *state, 354235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 355235911Smav{ 356235911Smav struct scfg *cfg; 357235911Smav uint8_t *buf = *bufp; 358235911Smav int oid, r, i, nitems; 359235911Smav uint16_t tempflags; 360235911Smav enc_cache_t *cache = &enc->enc_cache; 361235911Smav 362235911Smav cfg = enc->enc_private; 363235911Smav if (cfg == NULL) 364235911Smav return (ENXIO); 365235911Smav if (error != 0) 366235911Smav return (error); 367235911Smav 368235911Smav oid = r = 0; 369235911Smav cfg->enc_status = 0; 370235911Smav 371235911Smav for (nitems = i = 0; i < cfg->Nfans; i++) { 372235911Smav SAFT_BAIL(r, xfer_len); 373235911Smav /* 374235911Smav * 0 = Fan Operational 375235911Smav * 1 = Fan is malfunctioning 376235911Smav * 2 = Fan is not present 377235911Smav * 0x80 = Unknown or Not Reportable Status 378235911Smav */ 379235911Smav cache->elm_map[oid].encstat[1] = 0; /* resvd */ 380235911Smav cache->elm_map[oid].encstat[2] = 0; /* resvd */ 381235911Smav if (cfg->flag1 & SAFT_FLG1_ENCFANFAIL) 382235911Smav cache->elm_map[oid].encstat[3] |= 0x40; 383235911Smav else 384235911Smav cache->elm_map[oid].encstat[3] &= ~0x40; 385235911Smav switch ((int)buf[r]) { 386235911Smav case 0: 387235911Smav nitems++; 388235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 389235911Smav if ((cache->elm_map[oid].encstat[3] & 0x37) == 0) 390235911Smav cache->elm_map[oid].encstat[3] |= 0x27; 391235911Smav break; 392235911Smav 393235911Smav case 1: 394235911Smav cache->elm_map[oid].encstat[0] = 395235911Smav SES_OBJSTAT_CRIT; 396235911Smav /* 397235911Smav * FAIL and FAN STOPPED synthesized 398235911Smav */ 399235911Smav cache->elm_map[oid].encstat[3] |= 0x10; 400235911Smav cache->elm_map[oid].encstat[3] &= ~0x07; 401235911Smav /* 402235911Smav * Enclosure marked with CRITICAL error 403235911Smav * if only one fan or no thermometers, 404235911Smav * else the NONCRITICAL error is set. 405235911Smav */ 406235911Smav if (cfg->Nfans == 1 || (cfg->Ntherm + cfg->Ntstats) == 0) 407235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 408235911Smav else 409235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 410235911Smav break; 411235911Smav case 2: 412235911Smav cache->elm_map[oid].encstat[0] = 413235911Smav SES_OBJSTAT_NOTINSTALLED; 414235911Smav cache->elm_map[oid].encstat[3] |= 0x10; 415235911Smav cache->elm_map[oid].encstat[3] &= ~0x07; 416235911Smav /* 417235911Smav * Enclosure marked with CRITICAL error 418235911Smav * if only one fan or no thermometers, 419235911Smav * else the NONCRITICAL error is set. 420235911Smav */ 421235911Smav if (cfg->Nfans == 1) 422235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 423235911Smav else 424235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 425235911Smav break; 426235911Smav case 0x80: 427235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 428235911Smav cache->elm_map[oid].encstat[3] = 0; 429235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 430235911Smav break; 431235911Smav default: 432235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED; 433239213Smjacob ENC_VLOG(enc, "Unknown fan%d status 0x%x\n", i, 434235911Smav buf[r] & 0xff); 435235911Smav break; 436235911Smav } 437235911Smav cache->elm_map[oid++].svalid = 1; 438235911Smav r++; 439235911Smav } 440235911Smav 441235911Smav /* 442235911Smav * No matter how you cut it, no cooling elements when there 443235911Smav * should be some there is critical. 444235911Smav */ 445235911Smav if (cfg->Nfans && nitems == 0) 446235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 447235911Smav 448235911Smav for (i = 0; i < cfg->Npwr; i++) { 449235911Smav SAFT_BAIL(r, xfer_len); 450235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 451235911Smav cache->elm_map[oid].encstat[1] = 0; /* resvd */ 452235911Smav cache->elm_map[oid].encstat[2] = 0; /* resvd */ 453235911Smav cache->elm_map[oid].encstat[3] = 0x20; /* requested on */ 454235911Smav switch (buf[r]) { 455235911Smav case 0x00: /* pws operational and on */ 456235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 457235911Smav break; 458235911Smav case 0x01: /* pws operational and off */ 459235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 460235911Smav cache->elm_map[oid].encstat[3] = 0x10; 461235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 462235911Smav break; 463235911Smav case 0x10: /* pws is malfunctioning and commanded on */ 464235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 465235911Smav cache->elm_map[oid].encstat[3] = 0x61; 466235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 467235911Smav break; 468235911Smav 469235911Smav case 0x11: /* pws is malfunctioning and commanded off */ 470235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 471235911Smav cache->elm_map[oid].encstat[3] = 0x51; 472235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 473235911Smav break; 474235911Smav case 0x20: /* pws is not present */ 475235911Smav cache->elm_map[oid].encstat[0] = 476235911Smav SES_OBJSTAT_NOTINSTALLED; 477235911Smav cache->elm_map[oid].encstat[3] = 0; 478235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 479235911Smav break; 480235911Smav case 0x21: /* pws is present */ 481235911Smav /* 482235911Smav * This is for enclosures that cannot tell whether the 483235911Smav * device is on or malfunctioning, but know that it is 484235911Smav * present. Just fall through. 485235911Smav */ 486235911Smav /* FALLTHROUGH */ 487235911Smav case 0x80: /* Unknown or Not Reportable Status */ 488235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 489235911Smav cache->elm_map[oid].encstat[3] = 0; 490235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 491235911Smav break; 492235911Smav default: 493239213Smjacob ENC_VLOG(enc, "unknown power supply %d status (0x%x)\n", 494235911Smav i, buf[r] & 0xff); 495235911Smav break; 496235911Smav } 497235911Smav enc->enc_cache.elm_map[oid++].svalid = 1; 498235911Smav r++; 499235911Smav } 500235911Smav 501235911Smav /* 502235911Smav * Copy Slot SCSI IDs 503235911Smav */ 504235911Smav for (i = 0; i < cfg->Nslots; i++) { 505235911Smav SAFT_BAIL(r, xfer_len); 506350793Smav if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE) 507235911Smav cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r]; 508235911Smav r++; 509235911Smav } 510235911Smav 511235911Smav /* 512235911Smav * We always have doorlock status, no matter what, 513235911Smav * but we only save the status if we have one. 514235911Smav */ 515235911Smav SAFT_BAIL(r, xfer_len); 516235911Smav if (cfg->DoorLock) { 517235911Smav /* 518235911Smav * 0 = Door Locked 519235911Smav * 1 = Door Unlocked, or no Lock Installed 520235911Smav * 0x80 = Unknown or Not Reportable Status 521235911Smav */ 522235911Smav cache->elm_map[oid].encstat[1] = 0; 523235911Smav cache->elm_map[oid].encstat[2] = 0; 524235911Smav switch (buf[r]) { 525235911Smav case 0: 526235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 527235911Smav cache->elm_map[oid].encstat[3] = 0; 528235911Smav break; 529235911Smav case 1: 530235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 531235911Smav cache->elm_map[oid].encstat[3] = 1; 532235911Smav break; 533235911Smav case 0x80: 534235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 535235911Smav cache->elm_map[oid].encstat[3] = 0; 536235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 537235911Smav break; 538235911Smav default: 539235911Smav cache->elm_map[oid].encstat[0] = 540235911Smav SES_OBJSTAT_UNSUPPORTED; 541239213Smjacob ENC_VLOG(enc, "unknown lock status 0x%x\n", 542235911Smav buf[r] & 0xff); 543235911Smav break; 544235911Smav } 545235911Smav cache->elm_map[oid++].svalid = 1; 546235911Smav } 547235911Smav r++; 548235911Smav 549235911Smav /* 550235911Smav * We always have speaker status, no matter what, 551235911Smav * but we only save the status if we have one. 552235911Smav */ 553235911Smav SAFT_BAIL(r, xfer_len); 554235911Smav if (cfg->Nspkrs) { 555235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 556235911Smav cache->elm_map[oid].encstat[1] = 0; 557235911Smav cache->elm_map[oid].encstat[2] = 0; 558235911Smav if (buf[r] == 0) { 559235911Smav cache->elm_map[oid].encstat[0] |= SESCTL_DISABLE; 560235911Smav cache->elm_map[oid].encstat[3] |= 0x40; 561235911Smav } 562235911Smav cache->elm_map[oid++].svalid = 1; 563235911Smav } 564235911Smav r++; 565235911Smav 566235911Smav /* 567235911Smav * Now, for "pseudo" thermometers, we have two bytes 568235911Smav * of information in enclosure status- 16 bits. Actually, 569235911Smav * the MSB is a single TEMP ALERT flag indicating whether 570235911Smav * any other bits are set, but, thanks to fuzzy thinking, 571235911Smav * in the SAF-TE spec, this can also be set even if no 572235911Smav * other bits are set, thus making this really another 573235911Smav * binary temperature sensor. 574235911Smav */ 575235911Smav 576235911Smav SAFT_BAIL(r + cfg->Ntherm, xfer_len); 577235911Smav tempflags = buf[r + cfg->Ntherm]; 578235911Smav SAFT_BAIL(r + cfg->Ntherm + 1, xfer_len); 579235911Smav tempflags |= (tempflags << 8) | buf[r + cfg->Ntherm + 1]; 580235911Smav 581235911Smav for (i = 0; i < cfg->Ntherm; i++) { 582235911Smav SAFT_BAIL(r, xfer_len); 583235911Smav /* 584235911Smav * Status is a range from -10 to 245 deg Celsius, 585235911Smav * which we need to normalize to -20 to -245 according 586235911Smav * to the latest SCSI spec, which makes little 587235911Smav * sense since this would overflow an 8bit value. 588235911Smav * Well, still, the base normalization is -20, 589235911Smav * not -10, so we have to adjust. 590235911Smav * 591235911Smav * So what's over and under temperature? 592235911Smav * Hmm- we'll state that 'normal' operating 593235911Smav * is 10 to 40 deg Celsius. 594235911Smav */ 595235911Smav 596235911Smav /* 597235911Smav * Actually.... All of the units that people out in the world 598235911Smav * seem to have do not come even close to setting a value that 599235911Smav * complies with this spec. 600235911Smav * 601235911Smav * The closest explanation I could find was in an 602235911Smav * LSI-Logic manual, which seemed to indicate that 603235911Smav * this value would be set by whatever the I2C code 604235911Smav * would interpolate from the output of an LM75 605235911Smav * temperature sensor. 606235911Smav * 607235911Smav * This means that it is impossible to use the actual 608235911Smav * numeric value to predict anything. But we don't want 609235911Smav * to lose the value. So, we'll propagate the *uncorrected* 610235911Smav * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the 611235911Smav * temperature flags for warnings. 612235911Smav */ 613235911Smav if (tempflags & (1 << i)) { 614235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 615235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 616235911Smav } else 617235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 618235911Smav cache->elm_map[oid].encstat[1] = 0; 619235911Smav cache->elm_map[oid].encstat[2] = buf[r]; 620235911Smav cache->elm_map[oid].encstat[3] = 0; 621235911Smav cache->elm_map[oid++].svalid = 1; 622235911Smav r++; 623235911Smav } 624235911Smav 625235911Smav for (i = 0; i <= cfg->Ntstats; i++) { 626235911Smav cache->elm_map[oid].encstat[1] = 0; 627235911Smav if (tempflags & (1 << 628235911Smav ((i == cfg->Ntstats) ? 15 : (cfg->Ntherm + i)))) { 629235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 630235911Smav cache->elm_map[4].encstat[2] = 0xff; 631235911Smav /* 632235911Smav * Set 'over temperature' failure. 633235911Smav */ 634235911Smav cache->elm_map[oid].encstat[3] = 8; 635235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 636235911Smav } else { 637235911Smav /* 638235911Smav * We used to say 'not available' and synthesize a 639235911Smav * nominal 30 deg (C)- that was wrong. Actually, 640235911Smav * Just say 'OK', and use the reserved value of 641235911Smav * zero. 642235911Smav */ 643235911Smav if ((cfg->Ntherm + cfg->Ntstats) == 0) 644235911Smav cache->elm_map[oid].encstat[0] = 645235911Smav SES_OBJSTAT_NOTAVAIL; 646235911Smav else 647235911Smav cache->elm_map[oid].encstat[0] = 648235911Smav SES_OBJSTAT_OK; 649235911Smav cache->elm_map[oid].encstat[2] = 0; 650235911Smav cache->elm_map[oid].encstat[3] = 0; 651235911Smav } 652235911Smav cache->elm_map[oid++].svalid = 1; 653235911Smav } 654235911Smav r += 2; 655235911Smav 656235911Smav cache->enc_status = 657235911Smav cfg->enc_status | cfg->slot_status | cfg->adm_status; 658235911Smav return (0); 659235911Smav} 660235911Smav 661235911Smavstatic int 662235911Smavsafte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, 663235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 664235911Smav{ 665235911Smav struct scfg *cfg; 666235911Smav uint8_t *buf = *bufp; 667235911Smav enc_cache_t *cache = &enc->enc_cache; 668235911Smav int oid, r, i; 669235911Smav 670235911Smav cfg = enc->enc_private; 671235911Smav if (cfg == NULL) 672235911Smav return (ENXIO); 673235911Smav if (error != 0) 674235911Smav return (error); 675235911Smav cfg->slot_status = 0; 676235911Smav oid = cfg->slotoff; 677235911Smav for (r = i = 0; i < cfg->Nslots; i++, r += 4) { 678235911Smav SAFT_BAIL(r+3, xfer_len); 679350793Smav if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) 680235911Smav cache->elm_map[oid].encstat[1] = 0; 681235911Smav cache->elm_map[oid].encstat[2] &= SESCTL_RQSID; 682235911Smav cache->elm_map[oid].encstat[3] = 0; 683235911Smav if ((buf[r+3] & 0x01) == 0) { /* no device */ 684235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NOTINSTALLED; 685235911Smav } else if (buf[r+0] & 0x02) { 686235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 687235911Smav cfg->slot_status |= SES_ENCSTAT_CRITICAL; 688235911Smav } else if (buf[r+0] & 0x40) { 689235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 690235911Smav cfg->slot_status |= SES_ENCSTAT_NONCRITICAL; 691235911Smav } else { 692235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 693235911Smav } 694235911Smav if (buf[r+3] & 0x2) { 695235911Smav if (buf[r+3] & 0x01) 696235911Smav cache->elm_map[oid].encstat[2] |= SESCTL_RQSRMV; 697235911Smav else 698235911Smav cache->elm_map[oid].encstat[2] |= SESCTL_RQSINS; 699235911Smav } 700235911Smav if ((buf[r+3] & 0x04) == 0) 701235911Smav cache->elm_map[oid].encstat[3] |= SESCTL_DEVOFF; 702235911Smav if (buf[r+0] & 0x02) 703235911Smav cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT; 704235911Smav if (buf[r+0] & 0x40) 705235911Smav cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL; 706350793Smav if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) { 707235911Smav if (buf[r+0] & 0x01) 708235911Smav cache->elm_map[oid].encstat[1] |= 0x80; 709235911Smav if (buf[r+0] & 0x04) 710235911Smav cache->elm_map[oid].encstat[1] |= 0x02; 711235911Smav if (buf[r+0] & 0x08) 712235911Smav cache->elm_map[oid].encstat[1] |= 0x04; 713235911Smav if (buf[r+0] & 0x10) 714235911Smav cache->elm_map[oid].encstat[1] |= 0x08; 715235911Smav if (buf[r+0] & 0x20) 716235911Smav cache->elm_map[oid].encstat[1] |= 0x10; 717235911Smav if (buf[r+1] & 0x01) 718235911Smav cache->elm_map[oid].encstat[1] |= 0x20; 719235911Smav if (buf[r+1] & 0x02) 720235911Smav cache->elm_map[oid].encstat[1] |= 0x01; 721235911Smav } 722235911Smav cache->elm_map[oid++].svalid = 1; 723235911Smav } 724235911Smav 725235911Smav cache->enc_status = 726235911Smav cfg->enc_status | cfg->slot_status | cfg->adm_status; 727235911Smav return (0); 728235911Smav} 729235911Smav 730235911Smavstatic int 731235911Smavsafte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 732235911Smav union ccb *ccb, uint8_t *buf) 733235911Smav{ 734235911Smav struct scfg *cfg; 735235911Smav enc_element_t *ep, *ep1; 736235911Smav safte_control_request_t *req; 737235911Smav int i, idx, xfer_len; 738235911Smav 739235911Smav cfg = enc->enc_private; 740235911Smav if (cfg == NULL) 741235911Smav return (ENXIO); 742235911Smav 743235911Smav if (enc->enc_cache.nelms == 0) { 744235911Smav enc_update_request(enc, SAFTE_UPDATE_READCONFIG); 745235911Smav return (-1); 746235911Smav } 747235911Smav 748235911Smav if (cfg->current_request == NULL) { 749235911Smav cfg->current_request = TAILQ_FIRST(&cfg->requests); 750235911Smav TAILQ_REMOVE(&cfg->requests, cfg->current_request, links); 751235911Smav cfg->current_request_stage = 0; 752235911Smav cfg->current_request_stages = 1; 753235911Smav } 754235911Smav req = cfg->current_request; 755235911Smav 756235911Smav idx = (int)req->elm_idx; 757235911Smav if (req->elm_idx == SES_SETSTATUS_ENC_IDX) { 758235911Smav cfg->adm_status = req->elm_stat[0] & ALL_ENC_STAT; 759235911Smav cfg->flag1 &= ~(SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN); 760235911Smav if (req->elm_stat[0] & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) 761235911Smav cfg->flag1 |= SAFT_FLG1_GLOBFAIL; 762235911Smav else if (req->elm_stat[0] & SES_ENCSTAT_NONCRITICAL) 763235911Smav cfg->flag1 |= SAFT_FLG1_GLOBWARN; 764235911Smav buf[0] = SAFTE_WT_GLOBAL; 765235911Smav buf[1] = cfg->flag1; 766235911Smav buf[2] = cfg->flag2; 767235911Smav buf[3] = 0; 768235911Smav xfer_len = 16; 769235911Smav } else { 770235911Smav ep = &enc->enc_cache.elm_map[idx]; 771235911Smav 772350793Smav switch (ep->elm_type) { 773235911Smav case ELMTYP_DEVICE: 774235911Smav case ELMTYP_ARRAY_DEV: 775235911Smav switch (cfg->current_request_stage) { 776235911Smav case 0: 777235911Smav ep->priv = 0; 778235911Smav if (req->elm_stat[0] & SESCTL_PRDFAIL) 779235911Smav ep->priv |= 0x40; 780235911Smav if (req->elm_stat[3] & SESCTL_RQSFLT) 781235911Smav ep->priv |= 0x02; 782350793Smav if (ep->elm_type == ELMTYP_ARRAY_DEV) { 783235911Smav if (req->elm_stat[1] & 0x01) 784235911Smav ep->priv |= 0x200; 785235911Smav if (req->elm_stat[1] & 0x02) 786235911Smav ep->priv |= 0x04; 787235911Smav if (req->elm_stat[1] & 0x04) 788235911Smav ep->priv |= 0x08; 789235911Smav if (req->elm_stat[1] & 0x08) 790235911Smav ep->priv |= 0x10; 791235911Smav if (req->elm_stat[1] & 0x10) 792235911Smav ep->priv |= 0x20; 793235911Smav if (req->elm_stat[1] & 0x20) 794235911Smav ep->priv |= 0x100; 795235911Smav if (req->elm_stat[1] & 0x80) 796235911Smav ep->priv |= 0x01; 797235911Smav } 798235911Smav if (ep->priv == 0) 799235911Smav ep->priv |= 0x01; /* no errors */ 800235911Smav 801235911Smav buf[0] = SAFTE_WT_DSTAT; 802235911Smav for (i = 0; i < cfg->Nslots; i++) { 803235911Smav ep1 = &enc->enc_cache.elm_map[cfg->slotoff + i]; 804235911Smav buf[1 + (3 * i)] = ep1->priv; 805235911Smav buf[2 + (3 * i)] = ep1->priv >> 8; 806235911Smav } 807235911Smav xfer_len = cfg->Nslots * 3 + 1; 808235911Smav#define DEVON(x) (!(((x)[2] & SESCTL_RQSINS) | \ 809235911Smav ((x)[2] & SESCTL_RQSRMV) | \ 810235911Smav ((x)[3] & SESCTL_DEVOFF))) 811235911Smav if (DEVON(req->elm_stat) != DEVON(ep->encstat)) 812235911Smav cfg->current_request_stages++; 813235911Smav#define IDON(x) (!!((x)[2] & SESCTL_RQSID)) 814235911Smav if (IDON(req->elm_stat) != IDON(ep->encstat)) 815235911Smav cfg->current_request_stages++; 816235911Smav break; 817235911Smav case 1: 818235911Smav case 2: 819235911Smav buf[0] = SAFTE_WT_SLTOP; 820235911Smav buf[1] = idx - cfg->slotoff; 821235911Smav if (cfg->current_request_stage == 1 && 822235911Smav DEVON(req->elm_stat) != DEVON(ep->encstat)) { 823235911Smav if (DEVON(req->elm_stat)) 824235911Smav buf[2] = 0x01; 825235911Smav else 826235911Smav buf[2] = 0x02; 827235911Smav } else { 828235911Smav if (IDON(req->elm_stat)) 829235911Smav buf[2] = 0x04; 830235911Smav else 831235911Smav buf[2] = 0x00; 832235911Smav ep->encstat[2] &= ~SESCTL_RQSID; 833235911Smav ep->encstat[2] |= req->elm_stat[2] & 834235911Smav SESCTL_RQSID; 835235911Smav } 836235911Smav xfer_len = 64; 837235911Smav break; 838235911Smav default: 839235911Smav return (EINVAL); 840235911Smav } 841235911Smav break; 842235911Smav case ELMTYP_POWER: 843235911Smav cfg->current_request_stages = 2; 844235911Smav switch (cfg->current_request_stage) { 845235911Smav case 0: 846235911Smav if (req->elm_stat[3] & SESCTL_RQSTFAIL) { 847235911Smav cfg->flag1 |= SAFT_FLG1_ENCPWRFAIL; 848235911Smav } else { 849235911Smav cfg->flag1 &= ~SAFT_FLG1_ENCPWRFAIL; 850235911Smav } 851235911Smav buf[0] = SAFTE_WT_GLOBAL; 852235911Smav buf[1] = cfg->flag1; 853235911Smav buf[2] = cfg->flag2; 854235911Smav buf[3] = 0; 855235911Smav xfer_len = 16; 856235911Smav break; 857235911Smav case 1: 858235911Smav buf[0] = SAFTE_WT_ACTPWS; 859235911Smav buf[1] = idx - cfg->pwroff; 860235911Smav if (req->elm_stat[3] & SESCTL_RQSTON) 861235911Smav buf[2] = 0x01; 862235911Smav else 863235911Smav buf[2] = 0x00; 864235911Smav buf[3] = 0; 865235911Smav xfer_len = 16; 866235911Smav default: 867235911Smav return (EINVAL); 868235911Smav } 869235911Smav break; 870235911Smav case ELMTYP_FAN: 871235911Smav if ((req->elm_stat[3] & 0x7) != 0) 872235911Smav cfg->current_request_stages = 2; 873235911Smav switch (cfg->current_request_stage) { 874235911Smav case 0: 875235911Smav if (req->elm_stat[3] & SESCTL_RQSTFAIL) 876235911Smav cfg->flag1 |= SAFT_FLG1_ENCFANFAIL; 877235911Smav else 878235911Smav cfg->flag1 &= ~SAFT_FLG1_ENCFANFAIL; 879235911Smav buf[0] = SAFTE_WT_GLOBAL; 880235911Smav buf[1] = cfg->flag1; 881235911Smav buf[2] = cfg->flag2; 882235911Smav buf[3] = 0; 883235911Smav xfer_len = 16; 884235911Smav break; 885235911Smav case 1: 886235911Smav buf[0] = SAFTE_WT_FANSPD; 887235911Smav buf[1] = idx; 888235911Smav if (req->elm_stat[3] & SESCTL_RQSTON) { 889235911Smav if ((req->elm_stat[3] & 0x7) == 7) 890235911Smav buf[2] = 4; 891235911Smav else if ((req->elm_stat[3] & 0x7) >= 5) 892235911Smav buf[2] = 3; 893235911Smav else if ((req->elm_stat[3] & 0x7) >= 3) 894235911Smav buf[2] = 2; 895235911Smav else 896235911Smav buf[2] = 1; 897235911Smav } else 898235911Smav buf[2] = 0; 899235911Smav buf[3] = 0; 900235911Smav xfer_len = 16; 901235911Smav ep->encstat[3] = req->elm_stat[3] & 0x67; 902235911Smav default: 903235911Smav return (EINVAL); 904235911Smav } 905235911Smav break; 906235911Smav case ELMTYP_DOORLOCK: 907235911Smav if (req->elm_stat[3] & 0x1) 908235911Smav cfg->flag2 &= ~SAFT_FLG2_LOCKDOOR; 909235911Smav else 910235911Smav cfg->flag2 |= SAFT_FLG2_LOCKDOOR; 911235911Smav buf[0] = SAFTE_WT_GLOBAL; 912235911Smav buf[1] = cfg->flag1; 913235911Smav buf[2] = cfg->flag2; 914235911Smav buf[3] = 0; 915235911Smav xfer_len = 16; 916235911Smav break; 917235911Smav case ELMTYP_ALARM: 918235911Smav if ((req->elm_stat[0] & SESCTL_DISABLE) || 919235911Smav (req->elm_stat[3] & 0x40)) { 920235911Smav cfg->flag2 &= ~SAFT_FLG1_ALARM; 921235911Smav } else if ((req->elm_stat[3] & 0x0f) != 0) { 922235911Smav cfg->flag2 |= SAFT_FLG1_ALARM; 923235911Smav } else { 924235911Smav cfg->flag2 &= ~SAFT_FLG1_ALARM; 925235911Smav } 926235911Smav buf[0] = SAFTE_WT_GLOBAL; 927235911Smav buf[1] = cfg->flag1; 928235911Smav buf[2] = cfg->flag2; 929235911Smav buf[3] = 0; 930235911Smav xfer_len = 16; 931235911Smav ep->encstat[3] = req->elm_stat[3]; 932235911Smav break; 933235911Smav default: 934235911Smav return (EINVAL); 935235911Smav } 936235911Smav } 937235911Smav 938235911Smav if (enc->enc_type == ENC_SEMB_SAFT) { 939235911Smav semb_write_buffer(&ccb->ataio, /*retries*/5, 940256843Smav NULL, MSG_SIMPLE_Q_TAG, 941235911Smav buf, xfer_len, state->timeout); 942235911Smav } else { 943235911Smav scsi_write_buffer(&ccb->csio, /*retries*/5, 944256843Smav NULL, MSG_SIMPLE_Q_TAG, 1, 945235911Smav 0, 0, buf, xfer_len, 946235911Smav SSD_FULL_SIZE, state->timeout); 947235911Smav } 948235911Smav return (0); 949235911Smav} 950235911Smav 951235911Smavstatic int 952235911Smavsafte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 953235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 954235911Smav{ 955235911Smav struct scfg *cfg; 956235911Smav safte_control_request_t *req; 957235911Smav int idx, type; 958235911Smav 959235911Smav cfg = enc->enc_private; 960235911Smav if (cfg == NULL) 961235911Smav return (ENXIO); 962235911Smav 963235911Smav req = cfg->current_request; 964235911Smav if (req->result == 0) 965235911Smav req->result = error; 966235911Smav if (++cfg->current_request_stage >= cfg->current_request_stages) { 967235911Smav idx = req->elm_idx; 968235911Smav if (idx == SES_SETSTATUS_ENC_IDX) 969235911Smav type = -1; 970235911Smav else 971350793Smav type = enc->enc_cache.elm_map[idx].elm_type; 972235911Smav if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV) 973235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 974235911Smav else 975235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 976235911Smav cfg->current_request = NULL; 977235911Smav wakeup(req); 978235911Smav } else { 979235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 980235911Smav } 981235911Smav return (0); 982235911Smav} 983235911Smav 984235911Smavstatic void 985235911Smavsafte_softc_invalidate(enc_softc_t *enc) 986235911Smav{ 987235911Smav struct scfg *cfg; 988235911Smav 989235911Smav cfg = enc->enc_private; 990235911Smav safte_terminate_control_requests(&cfg->requests, ENXIO); 991235911Smav} 992235911Smav 993235911Smavstatic void 994235911Smavsafte_softc_cleanup(enc_softc_t *enc) 995235911Smav{ 996235911Smav 997235911Smav ENC_FREE_AND_NULL(enc->enc_cache.elm_map); 998235911Smav ENC_FREE_AND_NULL(enc->enc_private); 999235911Smav enc->enc_cache.nelms = 0; 1000235911Smav} 1001235911Smav 1002235911Smavstatic int 1003235911Smavsafte_init_enc(enc_softc_t *enc) 1004235911Smav{ 1005235911Smav struct scfg *cfg; 1006235911Smav int err; 1007235911Smav static char cdb0[6] = { SEND_DIAGNOSTIC }; 1008235911Smav 1009235911Smav cfg = enc->enc_private; 1010235911Smav if (cfg == NULL) 1011235911Smav return (ENXIO); 1012235911Smav 1013235911Smav err = enc_runcmd(enc, cdb0, 6, NULL, 0); 1014235911Smav if (err) { 1015235911Smav return (err); 1016235911Smav } 1017235911Smav DELAY(5000); 1018235911Smav cfg->flag1 = 0; 1019235911Smav cfg->flag2 = 0; 1020235911Smav err = safte_set_enc_status(enc, 0, 1); 1021235911Smav return (err); 1022235911Smav} 1023235911Smav 1024235911Smavstatic int 1025235911Smavsafte_get_enc_status(enc_softc_t *enc, int slpflg) 1026235911Smav{ 1027235911Smav 1028235911Smav return (0); 1029235911Smav} 1030235911Smav 1031235911Smavstatic int 1032235911Smavsafte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag) 1033235911Smav{ 1034235911Smav struct scfg *cfg; 1035235911Smav safte_control_request_t req; 1036235911Smav 1037235911Smav cfg = enc->enc_private; 1038235911Smav if (cfg == NULL) 1039235911Smav return (ENXIO); 1040235911Smav 1041235911Smav req.elm_idx = SES_SETSTATUS_ENC_IDX; 1042235911Smav req.elm_stat[0] = encstat & 0xf; 1043235911Smav req.result = 0; 1044235911Smav 1045235911Smav TAILQ_INSERT_TAIL(&cfg->requests, &req, links); 1046235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 1047235911Smav cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 1048235911Smav 1049235911Smav return (req.result); 1050235911Smav} 1051235911Smav 1052235911Smavstatic int 1053235911Smavsafte_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflg) 1054235911Smav{ 1055235911Smav int i = (int)elms->elm_idx; 1056235911Smav 1057235911Smav elms->cstat[0] = enc->enc_cache.elm_map[i].encstat[0]; 1058235911Smav elms->cstat[1] = enc->enc_cache.elm_map[i].encstat[1]; 1059235911Smav elms->cstat[2] = enc->enc_cache.elm_map[i].encstat[2]; 1060235911Smav elms->cstat[3] = enc->enc_cache.elm_map[i].encstat[3]; 1061235911Smav return (0); 1062235911Smav} 1063235911Smav 1064235911Smavstatic int 1065235911Smavsafte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag) 1066235911Smav{ 1067235911Smav struct scfg *cfg; 1068235911Smav safte_control_request_t req; 1069235911Smav 1070235911Smav cfg = enc->enc_private; 1071235911Smav if (cfg == NULL) 1072235911Smav return (ENXIO); 1073235911Smav 1074235911Smav /* If this is clear, we don't do diddly. */ 1075235911Smav if ((elms->cstat[0] & SESCTL_CSEL) == 0) 1076235911Smav return (0); 1077235911Smav 1078235911Smav req.elm_idx = elms->elm_idx; 1079235911Smav memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat)); 1080235911Smav req.result = 0; 1081235911Smav 1082235911Smav TAILQ_INSERT_TAIL(&cfg->requests, &req, links); 1083235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 1084235911Smav cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 1085235911Smav 1086235911Smav return (req.result); 1087235911Smav} 1088235911Smav 1089235911Smavstatic void 1090235911Smavsafte_poll_status(enc_softc_t *enc) 1091235911Smav{ 1092235911Smav 1093235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 1094235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 1095235911Smav} 1096235911Smav 1097235911Smavstatic struct enc_vec safte_enc_vec = 1098235911Smav{ 1099235911Smav .softc_invalidate = safte_softc_invalidate, 1100235911Smav .softc_cleanup = safte_softc_cleanup, 1101235911Smav .init_enc = safte_init_enc, 1102235911Smav .get_enc_status = safte_get_enc_status, 1103235911Smav .set_enc_status = safte_set_enc_status, 1104235911Smav .get_elm_status = safte_get_elm_status, 1105235911Smav .set_elm_status = safte_set_elm_status, 1106235911Smav .poll_status = safte_poll_status 1107235911Smav}; 1108235911Smav 1109235911Smavint 1110235911Smavsafte_softc_init(enc_softc_t *enc) 1111235911Smav{ 1112235911Smav struct scfg *cfg; 1113235911Smav 1114235911Smav enc->enc_vec = safte_enc_vec; 1115235911Smav enc->enc_fsm_states = enc_fsm_states; 1116235911Smav 1117235911Smav if (enc->enc_private == NULL) { 1118235911Smav enc->enc_private = ENC_MALLOCZ(SAFT_PRIVATE); 1119235911Smav if (enc->enc_private == NULL) 1120235911Smav return (ENOMEM); 1121235911Smav } 1122235911Smav cfg = enc->enc_private; 1123235911Smav 1124235911Smav enc->enc_cache.nelms = 0; 1125235911Smav enc->enc_cache.enc_status = 0; 1126235911Smav 1127235911Smav TAILQ_INIT(&cfg->requests); 1128235911Smav return (0); 1129235911Smav} 1130235911Smav 1131