scsi_enc_safte.c revision 299373
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: head/sys/cam/scsi/scsi_enc_safte.c 299373 2016-05-10 16:20: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; 228235911SmavSYSCTL_DECL(_kern_cam_enc); 229267992ShselaskySYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN, 230235911Smav &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE"); 231235911Smav 232235911Smavstatic int 233235911Smavsafte_fill_read_buf_io(enc_softc_t *enc, struct enc_fsm_state *state, 234235911Smav union ccb *ccb, uint8_t *buf) 235235911Smav{ 236235911Smav 237235911Smav if (state->page_code != SAFTE_RD_RDCFG && 238235911Smav enc->enc_cache.nelms == 0) { 239235911Smav enc_update_request(enc, SAFTE_UPDATE_READCONFIG); 240235911Smav return (-1); 241235911Smav } 242235911Smav 243235911Smav if (enc->enc_type == ENC_SEMB_SAFT) { 244235911Smav semb_read_buffer(&ccb->ataio, /*retries*/5, 245256843Smav NULL, MSG_SIMPLE_Q_TAG, 246235911Smav state->page_code, buf, state->buf_size, 247235911Smav state->timeout); 248235911Smav } else { 249235911Smav scsi_read_buffer(&ccb->csio, /*retries*/5, 250256843Smav NULL, MSG_SIMPLE_Q_TAG, 1, 251235911Smav state->page_code, 0, buf, state->buf_size, 252235911Smav SSD_FULL_SIZE, state->timeout); 253235911Smav } 254235911Smav return (0); 255235911Smav} 256235911Smav 257235911Smavstatic int 258235911Smavsafte_process_config(enc_softc_t *enc, struct enc_fsm_state *state, 259235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 260235911Smav{ 261235911Smav struct scfg *cfg; 262235911Smav uint8_t *buf = *bufp; 263235911Smav int i, r; 264235911Smav 265235911Smav cfg = enc->enc_private; 266235911Smav if (cfg == NULL) 267235911Smav return (ENXIO); 268235911Smav if (error != 0) 269235911Smav return (error); 270235911Smav if (xfer_len < 6) { 271239213Smjacob ENC_VLOG(enc, "too little data (%d) for configuration\n", 272235911Smav xfer_len); 273235911Smav return (EIO); 274235911Smav } 275235911Smav cfg->Nfans = buf[0]; 276235911Smav cfg->Npwr = buf[1]; 277235911Smav cfg->Nslots = buf[2]; 278235911Smav cfg->DoorLock = buf[3]; 279235911Smav cfg->Ntherm = buf[4]; 280235911Smav cfg->Nspkrs = buf[5]; 281235911Smav if (xfer_len >= 7) 282235911Smav cfg->Ntstats = buf[6] & 0x0f; 283235911Smav else 284235911Smav cfg->Ntstats = 0; 285235911Smav ENC_VLOG(enc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d " 286235911Smav "Ntstats %d\n", 287235911Smav cfg->Nfans, cfg->Npwr, cfg->Nslots, cfg->DoorLock, cfg->Ntherm, 288235911Smav cfg->Nspkrs, cfg->Ntstats); 289235911Smav 290235911Smav enc->enc_cache.nelms = cfg->Nfans + cfg->Npwr + cfg->Nslots + 291235911Smav cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1; 292235911Smav ENC_FREE_AND_NULL(enc->enc_cache.elm_map); 293235911Smav enc->enc_cache.elm_map = 294299373Smav malloc(enc->enc_cache.nelms * sizeof(enc_element_t), 295299373Smav M_SCSIENC, M_WAITOK|M_ZERO); 296235911Smav 297235911Smav r = 0; 298235911Smav /* 299235911Smav * Note that this is all arranged for the convenience 300235911Smav * in later fetches of status. 301235911Smav */ 302235911Smav for (i = 0; i < cfg->Nfans; i++) 303235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN; 304235911Smav cfg->pwroff = (uint8_t) r; 305235911Smav for (i = 0; i < cfg->Npwr; i++) 306235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER; 307235911Smav for (i = 0; i < cfg->DoorLock; i++) 308235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK; 309235911Smav if (cfg->Nspkrs > 0) 310235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM; 311235911Smav for (i = 0; i < cfg->Ntherm; i++) 312235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; 313235911Smav for (i = 0; i <= cfg->Ntstats; i++) 314235911Smav enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM; 315235911Smav cfg->slotoff = (uint8_t) r; 316235911Smav for (i = 0; i < cfg->Nslots; i++) 317235911Smav enc->enc_cache.elm_map[r++].enctype = 318235911Smav emulate_array_devices ? ELMTYP_ARRAY_DEV : 319235911Smav ELMTYP_DEVICE; 320235911Smav 321235911Smav enc_update_request(enc, SAFTE_UPDATE_READGFLAGS); 322235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 323235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 324235911Smav 325235911Smav return (0); 326235911Smav} 327235911Smav 328235911Smavstatic int 329235911Smavsafte_process_gflags(enc_softc_t *enc, struct enc_fsm_state *state, 330235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 331235911Smav{ 332235911Smav struct scfg *cfg; 333235911Smav uint8_t *buf = *bufp; 334235911Smav 335235911Smav cfg = enc->enc_private; 336235911Smav if (cfg == NULL) 337235911Smav return (ENXIO); 338235911Smav if (error != 0) 339235911Smav return (error); 340235911Smav SAFT_BAIL(3, xfer_len); 341235911Smav cfg->flag1 = buf[1]; 342235911Smav cfg->flag2 = buf[2]; 343235911Smav 344235911Smav cfg->adm_status = 0; 345235911Smav if (cfg->flag1 & SAFT_FLG1_GLOBFAIL) 346235911Smav cfg->adm_status |= SES_ENCSTAT_CRITICAL; 347235911Smav else if (cfg->flag1 & SAFT_FLG1_GLOBWARN) 348235911Smav cfg->adm_status |= SES_ENCSTAT_NONCRITICAL; 349235911Smav 350235911Smav return (0); 351235911Smav} 352235911Smav 353235911Smavstatic int 354235911Smavsafte_process_status(enc_softc_t *enc, struct enc_fsm_state *state, 355235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 356235911Smav{ 357235911Smav struct scfg *cfg; 358235911Smav uint8_t *buf = *bufp; 359235911Smav int oid, r, i, nitems; 360235911Smav uint16_t tempflags; 361235911Smav enc_cache_t *cache = &enc->enc_cache; 362235911Smav 363235911Smav cfg = enc->enc_private; 364235911Smav if (cfg == NULL) 365235911Smav return (ENXIO); 366235911Smav if (error != 0) 367235911Smav return (error); 368235911Smav 369235911Smav oid = r = 0; 370235911Smav cfg->enc_status = 0; 371235911Smav 372235911Smav for (nitems = i = 0; i < cfg->Nfans; i++) { 373235911Smav SAFT_BAIL(r, xfer_len); 374235911Smav /* 375235911Smav * 0 = Fan Operational 376235911Smav * 1 = Fan is malfunctioning 377235911Smav * 2 = Fan is not present 378235911Smav * 0x80 = Unknown or Not Reportable Status 379235911Smav */ 380235911Smav cache->elm_map[oid].encstat[1] = 0; /* resvd */ 381235911Smav cache->elm_map[oid].encstat[2] = 0; /* resvd */ 382235911Smav if (cfg->flag1 & SAFT_FLG1_ENCFANFAIL) 383235911Smav cache->elm_map[oid].encstat[3] |= 0x40; 384235911Smav else 385235911Smav cache->elm_map[oid].encstat[3] &= ~0x40; 386235911Smav switch ((int)buf[r]) { 387235911Smav case 0: 388235911Smav nitems++; 389235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 390235911Smav if ((cache->elm_map[oid].encstat[3] & 0x37) == 0) 391235911Smav cache->elm_map[oid].encstat[3] |= 0x27; 392235911Smav break; 393235911Smav 394235911Smav case 1: 395235911Smav cache->elm_map[oid].encstat[0] = 396235911Smav SES_OBJSTAT_CRIT; 397235911Smav /* 398235911Smav * FAIL and FAN STOPPED synthesized 399235911Smav */ 400235911Smav cache->elm_map[oid].encstat[3] |= 0x10; 401235911Smav cache->elm_map[oid].encstat[3] &= ~0x07; 402235911Smav /* 403235911Smav * Enclosure marked with CRITICAL error 404235911Smav * if only one fan or no thermometers, 405235911Smav * else the NONCRITICAL error is set. 406235911Smav */ 407235911Smav if (cfg->Nfans == 1 || (cfg->Ntherm + cfg->Ntstats) == 0) 408235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 409235911Smav else 410235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 411235911Smav break; 412235911Smav case 2: 413235911Smav cache->elm_map[oid].encstat[0] = 414235911Smav SES_OBJSTAT_NOTINSTALLED; 415235911Smav cache->elm_map[oid].encstat[3] |= 0x10; 416235911Smav cache->elm_map[oid].encstat[3] &= ~0x07; 417235911Smav /* 418235911Smav * Enclosure marked with CRITICAL error 419235911Smav * if only one fan or no thermometers, 420235911Smav * else the NONCRITICAL error is set. 421235911Smav */ 422235911Smav if (cfg->Nfans == 1) 423235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 424235911Smav else 425235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 426235911Smav break; 427235911Smav case 0x80: 428235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 429235911Smav cache->elm_map[oid].encstat[3] = 0; 430235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 431235911Smav break; 432235911Smav default: 433235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED; 434239213Smjacob ENC_VLOG(enc, "Unknown fan%d status 0x%x\n", i, 435235911Smav buf[r] & 0xff); 436235911Smav break; 437235911Smav } 438235911Smav cache->elm_map[oid++].svalid = 1; 439235911Smav r++; 440235911Smav } 441235911Smav 442235911Smav /* 443235911Smav * No matter how you cut it, no cooling elements when there 444235911Smav * should be some there is critical. 445235911Smav */ 446235911Smav if (cfg->Nfans && nitems == 0) 447235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 448235911Smav 449235911Smav for (i = 0; i < cfg->Npwr; i++) { 450235911Smav SAFT_BAIL(r, xfer_len); 451235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 452235911Smav cache->elm_map[oid].encstat[1] = 0; /* resvd */ 453235911Smav cache->elm_map[oid].encstat[2] = 0; /* resvd */ 454235911Smav cache->elm_map[oid].encstat[3] = 0x20; /* requested on */ 455235911Smav switch (buf[r]) { 456235911Smav case 0x00: /* pws operational and on */ 457235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 458235911Smav break; 459235911Smav case 0x01: /* pws operational and off */ 460235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 461235911Smav cache->elm_map[oid].encstat[3] = 0x10; 462235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 463235911Smav break; 464235911Smav case 0x10: /* pws is malfunctioning and commanded on */ 465235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 466235911Smav cache->elm_map[oid].encstat[3] = 0x61; 467235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 468235911Smav break; 469235911Smav 470235911Smav case 0x11: /* pws is malfunctioning and commanded off */ 471235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 472235911Smav cache->elm_map[oid].encstat[3] = 0x51; 473235911Smav cfg->enc_status |= SES_ENCSTAT_NONCRITICAL; 474235911Smav break; 475235911Smav case 0x20: /* pws is not present */ 476235911Smav cache->elm_map[oid].encstat[0] = 477235911Smav SES_OBJSTAT_NOTINSTALLED; 478235911Smav cache->elm_map[oid].encstat[3] = 0; 479235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 480235911Smav break; 481235911Smav case 0x21: /* pws is present */ 482235911Smav /* 483235911Smav * This is for enclosures that cannot tell whether the 484235911Smav * device is on or malfunctioning, but know that it is 485235911Smav * present. Just fall through. 486235911Smav */ 487235911Smav /* FALLTHROUGH */ 488235911Smav case 0x80: /* Unknown or Not Reportable Status */ 489235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 490235911Smav cache->elm_map[oid].encstat[3] = 0; 491235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 492235911Smav break; 493235911Smav default: 494239213Smjacob ENC_VLOG(enc, "unknown power supply %d status (0x%x)\n", 495235911Smav i, buf[r] & 0xff); 496235911Smav break; 497235911Smav } 498235911Smav enc->enc_cache.elm_map[oid++].svalid = 1; 499235911Smav r++; 500235911Smav } 501235911Smav 502235911Smav /* 503235911Smav * Copy Slot SCSI IDs 504235911Smav */ 505235911Smav for (i = 0; i < cfg->Nslots; i++) { 506235911Smav SAFT_BAIL(r, xfer_len); 507235911Smav if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE) 508235911Smav cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r]; 509235911Smav r++; 510235911Smav } 511235911Smav 512235911Smav /* 513235911Smav * We always have doorlock status, no matter what, 514235911Smav * but we only save the status if we have one. 515235911Smav */ 516235911Smav SAFT_BAIL(r, xfer_len); 517235911Smav if (cfg->DoorLock) { 518235911Smav /* 519235911Smav * 0 = Door Locked 520235911Smav * 1 = Door Unlocked, or no Lock Installed 521235911Smav * 0x80 = Unknown or Not Reportable Status 522235911Smav */ 523235911Smav cache->elm_map[oid].encstat[1] = 0; 524235911Smav cache->elm_map[oid].encstat[2] = 0; 525235911Smav switch (buf[r]) { 526235911Smav case 0: 527235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 528235911Smav cache->elm_map[oid].encstat[3] = 0; 529235911Smav break; 530235911Smav case 1: 531235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 532235911Smav cache->elm_map[oid].encstat[3] = 1; 533235911Smav break; 534235911Smav case 0x80: 535235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 536235911Smav cache->elm_map[oid].encstat[3] = 0; 537235911Smav cfg->enc_status |= SES_ENCSTAT_INFO; 538235911Smav break; 539235911Smav default: 540235911Smav cache->elm_map[oid].encstat[0] = 541235911Smav SES_OBJSTAT_UNSUPPORTED; 542239213Smjacob ENC_VLOG(enc, "unknown lock status 0x%x\n", 543235911Smav buf[r] & 0xff); 544235911Smav break; 545235911Smav } 546235911Smav cache->elm_map[oid++].svalid = 1; 547235911Smav } 548235911Smav r++; 549235911Smav 550235911Smav /* 551235911Smav * We always have speaker status, no matter what, 552235911Smav * but we only save the status if we have one. 553235911Smav */ 554235911Smav SAFT_BAIL(r, xfer_len); 555235911Smav if (cfg->Nspkrs) { 556235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 557235911Smav cache->elm_map[oid].encstat[1] = 0; 558235911Smav cache->elm_map[oid].encstat[2] = 0; 559235911Smav if (buf[r] == 0) { 560235911Smav cache->elm_map[oid].encstat[0] |= SESCTL_DISABLE; 561235911Smav cache->elm_map[oid].encstat[3] |= 0x40; 562235911Smav } 563235911Smav cache->elm_map[oid++].svalid = 1; 564235911Smav } 565235911Smav r++; 566235911Smav 567235911Smav /* 568235911Smav * Now, for "pseudo" thermometers, we have two bytes 569235911Smav * of information in enclosure status- 16 bits. Actually, 570235911Smav * the MSB is a single TEMP ALERT flag indicating whether 571235911Smav * any other bits are set, but, thanks to fuzzy thinking, 572235911Smav * in the SAF-TE spec, this can also be set even if no 573235911Smav * other bits are set, thus making this really another 574235911Smav * binary temperature sensor. 575235911Smav */ 576235911Smav 577235911Smav SAFT_BAIL(r + cfg->Ntherm, xfer_len); 578235911Smav tempflags = buf[r + cfg->Ntherm]; 579235911Smav SAFT_BAIL(r + cfg->Ntherm + 1, xfer_len); 580235911Smav tempflags |= (tempflags << 8) | buf[r + cfg->Ntherm + 1]; 581235911Smav 582235911Smav for (i = 0; i < cfg->Ntherm; i++) { 583235911Smav SAFT_BAIL(r, xfer_len); 584235911Smav /* 585235911Smav * Status is a range from -10 to 245 deg Celsius, 586235911Smav * which we need to normalize to -20 to -245 according 587235911Smav * to the latest SCSI spec, which makes little 588235911Smav * sense since this would overflow an 8bit value. 589235911Smav * Well, still, the base normalization is -20, 590235911Smav * not -10, so we have to adjust. 591235911Smav * 592235911Smav * So what's over and under temperature? 593235911Smav * Hmm- we'll state that 'normal' operating 594235911Smav * is 10 to 40 deg Celsius. 595235911Smav */ 596235911Smav 597235911Smav /* 598235911Smav * Actually.... All of the units that people out in the world 599235911Smav * seem to have do not come even close to setting a value that 600235911Smav * complies with this spec. 601235911Smav * 602235911Smav * The closest explanation I could find was in an 603235911Smav * LSI-Logic manual, which seemed to indicate that 604235911Smav * this value would be set by whatever the I2C code 605235911Smav * would interpolate from the output of an LM75 606235911Smav * temperature sensor. 607235911Smav * 608235911Smav * This means that it is impossible to use the actual 609235911Smav * numeric value to predict anything. But we don't want 610235911Smav * to lose the value. So, we'll propagate the *uncorrected* 611235911Smav * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the 612235911Smav * temperature flags for warnings. 613235911Smav */ 614235911Smav if (tempflags & (1 << i)) { 615235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 616235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 617235911Smav } else 618235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 619235911Smav cache->elm_map[oid].encstat[1] = 0; 620235911Smav cache->elm_map[oid].encstat[2] = buf[r]; 621235911Smav cache->elm_map[oid].encstat[3] = 0; 622235911Smav cache->elm_map[oid++].svalid = 1; 623235911Smav r++; 624235911Smav } 625235911Smav 626235911Smav for (i = 0; i <= cfg->Ntstats; i++) { 627235911Smav cache->elm_map[oid].encstat[1] = 0; 628235911Smav if (tempflags & (1 << 629235911Smav ((i == cfg->Ntstats) ? 15 : (cfg->Ntherm + i)))) { 630235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 631235911Smav cache->elm_map[4].encstat[2] = 0xff; 632235911Smav /* 633235911Smav * Set 'over temperature' failure. 634235911Smav */ 635235911Smav cache->elm_map[oid].encstat[3] = 8; 636235911Smav cfg->enc_status |= SES_ENCSTAT_CRITICAL; 637235911Smav } else { 638235911Smav /* 639235911Smav * We used to say 'not available' and synthesize a 640235911Smav * nominal 30 deg (C)- that was wrong. Actually, 641235911Smav * Just say 'OK', and use the reserved value of 642235911Smav * zero. 643235911Smav */ 644235911Smav if ((cfg->Ntherm + cfg->Ntstats) == 0) 645235911Smav cache->elm_map[oid].encstat[0] = 646235911Smav SES_OBJSTAT_NOTAVAIL; 647235911Smav else 648235911Smav cache->elm_map[oid].encstat[0] = 649235911Smav SES_OBJSTAT_OK; 650235911Smav cache->elm_map[oid].encstat[2] = 0; 651235911Smav cache->elm_map[oid].encstat[3] = 0; 652235911Smav } 653235911Smav cache->elm_map[oid++].svalid = 1; 654235911Smav } 655235911Smav r += 2; 656235911Smav 657235911Smav cache->enc_status = 658235911Smav cfg->enc_status | cfg->slot_status | cfg->adm_status; 659235911Smav return (0); 660235911Smav} 661235911Smav 662235911Smavstatic int 663235911Smavsafte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state, 664235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 665235911Smav{ 666235911Smav struct scfg *cfg; 667235911Smav uint8_t *buf = *bufp; 668235911Smav enc_cache_t *cache = &enc->enc_cache; 669235911Smav int oid, r, i; 670235911Smav 671235911Smav cfg = enc->enc_private; 672235911Smav if (cfg == NULL) 673235911Smav return (ENXIO); 674235911Smav if (error != 0) 675235911Smav return (error); 676235911Smav cfg->slot_status = 0; 677235911Smav oid = cfg->slotoff; 678235911Smav for (r = i = 0; i < cfg->Nslots; i++, r += 4) { 679235911Smav SAFT_BAIL(r+3, xfer_len); 680235911Smav if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) 681235911Smav cache->elm_map[oid].encstat[1] = 0; 682235911Smav cache->elm_map[oid].encstat[2] &= SESCTL_RQSID; 683235911Smav cache->elm_map[oid].encstat[3] = 0; 684235911Smav if ((buf[r+3] & 0x01) == 0) { /* no device */ 685235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NOTINSTALLED; 686235911Smav } else if (buf[r+0] & 0x02) { 687235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT; 688235911Smav cfg->slot_status |= SES_ENCSTAT_CRITICAL; 689235911Smav } else if (buf[r+0] & 0x40) { 690235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 691235911Smav cfg->slot_status |= SES_ENCSTAT_NONCRITICAL; 692235911Smav } else { 693235911Smav cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK; 694235911Smav } 695235911Smav if (buf[r+3] & 0x2) { 696235911Smav if (buf[r+3] & 0x01) 697235911Smav cache->elm_map[oid].encstat[2] |= SESCTL_RQSRMV; 698235911Smav else 699235911Smav cache->elm_map[oid].encstat[2] |= SESCTL_RQSINS; 700235911Smav } 701235911Smav if ((buf[r+3] & 0x04) == 0) 702235911Smav cache->elm_map[oid].encstat[3] |= SESCTL_DEVOFF; 703235911Smav if (buf[r+0] & 0x02) 704235911Smav cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT; 705235911Smav if (buf[r+0] & 0x40) 706235911Smav cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL; 707235911Smav if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) { 708235911Smav if (buf[r+0] & 0x01) 709235911Smav cache->elm_map[oid].encstat[1] |= 0x80; 710235911Smav if (buf[r+0] & 0x04) 711235911Smav cache->elm_map[oid].encstat[1] |= 0x02; 712235911Smav if (buf[r+0] & 0x08) 713235911Smav cache->elm_map[oid].encstat[1] |= 0x04; 714235911Smav if (buf[r+0] & 0x10) 715235911Smav cache->elm_map[oid].encstat[1] |= 0x08; 716235911Smav if (buf[r+0] & 0x20) 717235911Smav cache->elm_map[oid].encstat[1] |= 0x10; 718235911Smav if (buf[r+1] & 0x01) 719235911Smav cache->elm_map[oid].encstat[1] |= 0x20; 720235911Smav if (buf[r+1] & 0x02) 721235911Smav cache->elm_map[oid].encstat[1] |= 0x01; 722235911Smav } 723235911Smav cache->elm_map[oid++].svalid = 1; 724235911Smav } 725235911Smav 726235911Smav cache->enc_status = 727235911Smav cfg->enc_status | cfg->slot_status | cfg->adm_status; 728235911Smav return (0); 729235911Smav} 730235911Smav 731235911Smavstatic int 732235911Smavsafte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 733235911Smav union ccb *ccb, uint8_t *buf) 734235911Smav{ 735235911Smav struct scfg *cfg; 736235911Smav enc_element_t *ep, *ep1; 737235911Smav safte_control_request_t *req; 738235911Smav int i, idx, xfer_len; 739235911Smav 740235911Smav cfg = enc->enc_private; 741235911Smav if (cfg == NULL) 742235911Smav return (ENXIO); 743235911Smav 744235911Smav if (enc->enc_cache.nelms == 0) { 745235911Smav enc_update_request(enc, SAFTE_UPDATE_READCONFIG); 746235911Smav return (-1); 747235911Smav } 748235911Smav 749235911Smav if (cfg->current_request == NULL) { 750235911Smav cfg->current_request = TAILQ_FIRST(&cfg->requests); 751235911Smav TAILQ_REMOVE(&cfg->requests, cfg->current_request, links); 752235911Smav cfg->current_request_stage = 0; 753235911Smav cfg->current_request_stages = 1; 754235911Smav } 755235911Smav req = cfg->current_request; 756235911Smav 757235911Smav idx = (int)req->elm_idx; 758235911Smav if (req->elm_idx == SES_SETSTATUS_ENC_IDX) { 759235911Smav cfg->adm_status = req->elm_stat[0] & ALL_ENC_STAT; 760235911Smav cfg->flag1 &= ~(SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN); 761235911Smav if (req->elm_stat[0] & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) 762235911Smav cfg->flag1 |= SAFT_FLG1_GLOBFAIL; 763235911Smav else if (req->elm_stat[0] & SES_ENCSTAT_NONCRITICAL) 764235911Smav cfg->flag1 |= SAFT_FLG1_GLOBWARN; 765235911Smav buf[0] = SAFTE_WT_GLOBAL; 766235911Smav buf[1] = cfg->flag1; 767235911Smav buf[2] = cfg->flag2; 768235911Smav buf[3] = 0; 769235911Smav xfer_len = 16; 770235911Smav } else { 771235911Smav ep = &enc->enc_cache.elm_map[idx]; 772235911Smav 773235911Smav switch (ep->enctype) { 774235911Smav case ELMTYP_DEVICE: 775235911Smav case ELMTYP_ARRAY_DEV: 776235911Smav switch (cfg->current_request_stage) { 777235911Smav case 0: 778235911Smav ep->priv = 0; 779235911Smav if (req->elm_stat[0] & SESCTL_PRDFAIL) 780235911Smav ep->priv |= 0x40; 781235911Smav if (req->elm_stat[3] & SESCTL_RQSFLT) 782235911Smav ep->priv |= 0x02; 783235911Smav if (ep->enctype == ELMTYP_ARRAY_DEV) { 784235911Smav if (req->elm_stat[1] & 0x01) 785235911Smav ep->priv |= 0x200; 786235911Smav if (req->elm_stat[1] & 0x02) 787235911Smav ep->priv |= 0x04; 788235911Smav if (req->elm_stat[1] & 0x04) 789235911Smav ep->priv |= 0x08; 790235911Smav if (req->elm_stat[1] & 0x08) 791235911Smav ep->priv |= 0x10; 792235911Smav if (req->elm_stat[1] & 0x10) 793235911Smav ep->priv |= 0x20; 794235911Smav if (req->elm_stat[1] & 0x20) 795235911Smav ep->priv |= 0x100; 796235911Smav if (req->elm_stat[1] & 0x80) 797235911Smav ep->priv |= 0x01; 798235911Smav } 799235911Smav if (ep->priv == 0) 800235911Smav ep->priv |= 0x01; /* no errors */ 801235911Smav 802235911Smav buf[0] = SAFTE_WT_DSTAT; 803235911Smav for (i = 0; i < cfg->Nslots; i++) { 804235911Smav ep1 = &enc->enc_cache.elm_map[cfg->slotoff + i]; 805235911Smav buf[1 + (3 * i)] = ep1->priv; 806235911Smav buf[2 + (3 * i)] = ep1->priv >> 8; 807235911Smav } 808235911Smav xfer_len = cfg->Nslots * 3 + 1; 809235911Smav#define DEVON(x) (!(((x)[2] & SESCTL_RQSINS) | \ 810235911Smav ((x)[2] & SESCTL_RQSRMV) | \ 811235911Smav ((x)[3] & SESCTL_DEVOFF))) 812235911Smav if (DEVON(req->elm_stat) != DEVON(ep->encstat)) 813235911Smav cfg->current_request_stages++; 814235911Smav#define IDON(x) (!!((x)[2] & SESCTL_RQSID)) 815235911Smav if (IDON(req->elm_stat) != IDON(ep->encstat)) 816235911Smav cfg->current_request_stages++; 817235911Smav break; 818235911Smav case 1: 819235911Smav case 2: 820235911Smav buf[0] = SAFTE_WT_SLTOP; 821235911Smav buf[1] = idx - cfg->slotoff; 822235911Smav if (cfg->current_request_stage == 1 && 823235911Smav DEVON(req->elm_stat) != DEVON(ep->encstat)) { 824235911Smav if (DEVON(req->elm_stat)) 825235911Smav buf[2] = 0x01; 826235911Smav else 827235911Smav buf[2] = 0x02; 828235911Smav } else { 829235911Smav if (IDON(req->elm_stat)) 830235911Smav buf[2] = 0x04; 831235911Smav else 832235911Smav buf[2] = 0x00; 833235911Smav ep->encstat[2] &= ~SESCTL_RQSID; 834235911Smav ep->encstat[2] |= req->elm_stat[2] & 835235911Smav SESCTL_RQSID; 836235911Smav } 837235911Smav xfer_len = 64; 838235911Smav break; 839235911Smav default: 840235911Smav return (EINVAL); 841235911Smav } 842235911Smav break; 843235911Smav case ELMTYP_POWER: 844235911Smav cfg->current_request_stages = 2; 845235911Smav switch (cfg->current_request_stage) { 846235911Smav case 0: 847235911Smav if (req->elm_stat[3] & SESCTL_RQSTFAIL) { 848235911Smav cfg->flag1 |= SAFT_FLG1_ENCPWRFAIL; 849235911Smav } else { 850235911Smav cfg->flag1 &= ~SAFT_FLG1_ENCPWRFAIL; 851235911Smav } 852235911Smav buf[0] = SAFTE_WT_GLOBAL; 853235911Smav buf[1] = cfg->flag1; 854235911Smav buf[2] = cfg->flag2; 855235911Smav buf[3] = 0; 856235911Smav xfer_len = 16; 857235911Smav break; 858235911Smav case 1: 859235911Smav buf[0] = SAFTE_WT_ACTPWS; 860235911Smav buf[1] = idx - cfg->pwroff; 861235911Smav if (req->elm_stat[3] & SESCTL_RQSTON) 862235911Smav buf[2] = 0x01; 863235911Smav else 864235911Smav buf[2] = 0x00; 865235911Smav buf[3] = 0; 866235911Smav xfer_len = 16; 867235911Smav default: 868235911Smav return (EINVAL); 869235911Smav } 870235911Smav break; 871235911Smav case ELMTYP_FAN: 872235911Smav if ((req->elm_stat[3] & 0x7) != 0) 873235911Smav cfg->current_request_stages = 2; 874235911Smav switch (cfg->current_request_stage) { 875235911Smav case 0: 876235911Smav if (req->elm_stat[3] & SESCTL_RQSTFAIL) 877235911Smav cfg->flag1 |= SAFT_FLG1_ENCFANFAIL; 878235911Smav else 879235911Smav cfg->flag1 &= ~SAFT_FLG1_ENCFANFAIL; 880235911Smav buf[0] = SAFTE_WT_GLOBAL; 881235911Smav buf[1] = cfg->flag1; 882235911Smav buf[2] = cfg->flag2; 883235911Smav buf[3] = 0; 884235911Smav xfer_len = 16; 885235911Smav break; 886235911Smav case 1: 887235911Smav buf[0] = SAFTE_WT_FANSPD; 888235911Smav buf[1] = idx; 889235911Smav if (req->elm_stat[3] & SESCTL_RQSTON) { 890235911Smav if ((req->elm_stat[3] & 0x7) == 7) 891235911Smav buf[2] = 4; 892235911Smav else if ((req->elm_stat[3] & 0x7) >= 5) 893235911Smav buf[2] = 3; 894235911Smav else if ((req->elm_stat[3] & 0x7) >= 3) 895235911Smav buf[2] = 2; 896235911Smav else 897235911Smav buf[2] = 1; 898235911Smav } else 899235911Smav buf[2] = 0; 900235911Smav buf[3] = 0; 901235911Smav xfer_len = 16; 902235911Smav ep->encstat[3] = req->elm_stat[3] & 0x67; 903235911Smav default: 904235911Smav return (EINVAL); 905235911Smav } 906235911Smav break; 907235911Smav case ELMTYP_DOORLOCK: 908235911Smav if (req->elm_stat[3] & 0x1) 909235911Smav cfg->flag2 &= ~SAFT_FLG2_LOCKDOOR; 910235911Smav else 911235911Smav cfg->flag2 |= SAFT_FLG2_LOCKDOOR; 912235911Smav buf[0] = SAFTE_WT_GLOBAL; 913235911Smav buf[1] = cfg->flag1; 914235911Smav buf[2] = cfg->flag2; 915235911Smav buf[3] = 0; 916235911Smav xfer_len = 16; 917235911Smav break; 918235911Smav case ELMTYP_ALARM: 919235911Smav if ((req->elm_stat[0] & SESCTL_DISABLE) || 920235911Smav (req->elm_stat[3] & 0x40)) { 921235911Smav cfg->flag2 &= ~SAFT_FLG1_ALARM; 922235911Smav } else if ((req->elm_stat[3] & 0x0f) != 0) { 923235911Smav cfg->flag2 |= SAFT_FLG1_ALARM; 924235911Smav } else { 925235911Smav cfg->flag2 &= ~SAFT_FLG1_ALARM; 926235911Smav } 927235911Smav buf[0] = SAFTE_WT_GLOBAL; 928235911Smav buf[1] = cfg->flag1; 929235911Smav buf[2] = cfg->flag2; 930235911Smav buf[3] = 0; 931235911Smav xfer_len = 16; 932235911Smav ep->encstat[3] = req->elm_stat[3]; 933235911Smav break; 934235911Smav default: 935235911Smav return (EINVAL); 936235911Smav } 937235911Smav } 938235911Smav 939235911Smav if (enc->enc_type == ENC_SEMB_SAFT) { 940235911Smav semb_write_buffer(&ccb->ataio, /*retries*/5, 941256843Smav NULL, MSG_SIMPLE_Q_TAG, 942235911Smav buf, xfer_len, state->timeout); 943235911Smav } else { 944235911Smav scsi_write_buffer(&ccb->csio, /*retries*/5, 945256843Smav NULL, MSG_SIMPLE_Q_TAG, 1, 946235911Smav 0, 0, buf, xfer_len, 947235911Smav SSD_FULL_SIZE, state->timeout); 948235911Smav } 949235911Smav return (0); 950235911Smav} 951235911Smav 952235911Smavstatic int 953235911Smavsafte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 954235911Smav union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 955235911Smav{ 956235911Smav struct scfg *cfg; 957235911Smav safte_control_request_t *req; 958235911Smav int idx, type; 959235911Smav 960235911Smav cfg = enc->enc_private; 961235911Smav if (cfg == NULL) 962235911Smav return (ENXIO); 963235911Smav 964235911Smav req = cfg->current_request; 965235911Smav if (req->result == 0) 966235911Smav req->result = error; 967235911Smav if (++cfg->current_request_stage >= cfg->current_request_stages) { 968235911Smav idx = req->elm_idx; 969235911Smav if (idx == SES_SETSTATUS_ENC_IDX) 970235911Smav type = -1; 971235911Smav else 972235911Smav type = enc->enc_cache.elm_map[idx].enctype; 973235911Smav if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV) 974235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 975235911Smav else 976235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 977235911Smav cfg->current_request = NULL; 978235911Smav wakeup(req); 979235911Smav } else { 980235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 981235911Smav } 982235911Smav return (0); 983235911Smav} 984235911Smav 985235911Smavstatic void 986235911Smavsafte_softc_invalidate(enc_softc_t *enc) 987235911Smav{ 988235911Smav struct scfg *cfg; 989235911Smav 990235911Smav cfg = enc->enc_private; 991235911Smav safte_terminate_control_requests(&cfg->requests, ENXIO); 992235911Smav} 993235911Smav 994235911Smavstatic void 995235911Smavsafte_softc_cleanup(enc_softc_t *enc) 996235911Smav{ 997235911Smav 998235911Smav ENC_FREE_AND_NULL(enc->enc_cache.elm_map); 999235911Smav ENC_FREE_AND_NULL(enc->enc_private); 1000235911Smav enc->enc_cache.nelms = 0; 1001235911Smav} 1002235911Smav 1003235911Smavstatic int 1004235911Smavsafte_init_enc(enc_softc_t *enc) 1005235911Smav{ 1006235911Smav struct scfg *cfg; 1007235911Smav int err; 1008235911Smav static char cdb0[6] = { SEND_DIAGNOSTIC }; 1009235911Smav 1010235911Smav cfg = enc->enc_private; 1011235911Smav if (cfg == NULL) 1012235911Smav return (ENXIO); 1013235911Smav 1014235911Smav err = enc_runcmd(enc, cdb0, 6, NULL, 0); 1015235911Smav if (err) { 1016235911Smav return (err); 1017235911Smav } 1018235911Smav DELAY(5000); 1019235911Smav cfg->flag1 = 0; 1020235911Smav cfg->flag2 = 0; 1021235911Smav err = safte_set_enc_status(enc, 0, 1); 1022235911Smav return (err); 1023235911Smav} 1024235911Smav 1025235911Smavstatic int 1026235911Smavsafte_get_enc_status(enc_softc_t *enc, int slpflg) 1027235911Smav{ 1028235911Smav 1029235911Smav return (0); 1030235911Smav} 1031235911Smav 1032235911Smavstatic int 1033235911Smavsafte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag) 1034235911Smav{ 1035235911Smav struct scfg *cfg; 1036235911Smav safte_control_request_t req; 1037235911Smav 1038235911Smav cfg = enc->enc_private; 1039235911Smav if (cfg == NULL) 1040235911Smav return (ENXIO); 1041235911Smav 1042235911Smav req.elm_idx = SES_SETSTATUS_ENC_IDX; 1043235911Smav req.elm_stat[0] = encstat & 0xf; 1044235911Smav req.result = 0; 1045235911Smav 1046235911Smav TAILQ_INSERT_TAIL(&cfg->requests, &req, links); 1047235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 1048235911Smav cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 1049235911Smav 1050235911Smav return (req.result); 1051235911Smav} 1052235911Smav 1053235911Smavstatic int 1054235911Smavsafte_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflg) 1055235911Smav{ 1056235911Smav int i = (int)elms->elm_idx; 1057235911Smav 1058235911Smav elms->cstat[0] = enc->enc_cache.elm_map[i].encstat[0]; 1059235911Smav elms->cstat[1] = enc->enc_cache.elm_map[i].encstat[1]; 1060235911Smav elms->cstat[2] = enc->enc_cache.elm_map[i].encstat[2]; 1061235911Smav elms->cstat[3] = enc->enc_cache.elm_map[i].encstat[3]; 1062235911Smav return (0); 1063235911Smav} 1064235911Smav 1065235911Smavstatic int 1066235911Smavsafte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag) 1067235911Smav{ 1068235911Smav struct scfg *cfg; 1069235911Smav safte_control_request_t req; 1070235911Smav 1071235911Smav cfg = enc->enc_private; 1072235911Smav if (cfg == NULL) 1073235911Smav return (ENXIO); 1074235911Smav 1075235911Smav /* If this is clear, we don't do diddly. */ 1076235911Smav if ((elms->cstat[0] & SESCTL_CSEL) == 0) 1077235911Smav return (0); 1078235911Smav 1079235911Smav req.elm_idx = elms->elm_idx; 1080235911Smav memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat)); 1081235911Smav req.result = 0; 1082235911Smav 1083235911Smav TAILQ_INSERT_TAIL(&cfg->requests, &req, links); 1084235911Smav enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS); 1085235911Smav cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 1086235911Smav 1087235911Smav return (req.result); 1088235911Smav} 1089235911Smav 1090235911Smavstatic void 1091235911Smavsafte_poll_status(enc_softc_t *enc) 1092235911Smav{ 1093235911Smav 1094235911Smav enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS); 1095235911Smav enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS); 1096235911Smav} 1097235911Smav 1098235911Smavstatic struct enc_vec safte_enc_vec = 1099235911Smav{ 1100235911Smav .softc_invalidate = safte_softc_invalidate, 1101235911Smav .softc_cleanup = safte_softc_cleanup, 1102235911Smav .init_enc = safte_init_enc, 1103235911Smav .get_enc_status = safte_get_enc_status, 1104235911Smav .set_enc_status = safte_set_enc_status, 1105235911Smav .get_elm_status = safte_get_elm_status, 1106235911Smav .set_elm_status = safte_set_elm_status, 1107235911Smav .poll_status = safte_poll_status 1108235911Smav}; 1109235911Smav 1110235911Smavint 1111235911Smavsafte_softc_init(enc_softc_t *enc) 1112235911Smav{ 1113235911Smav struct scfg *cfg; 1114235911Smav 1115235911Smav enc->enc_vec = safte_enc_vec; 1116235911Smav enc->enc_fsm_states = enc_fsm_states; 1117235911Smav 1118235911Smav if (enc->enc_private == NULL) { 1119235911Smav enc->enc_private = ENC_MALLOCZ(SAFT_PRIVATE); 1120235911Smav if (enc->enc_private == NULL) 1121235911Smav return (ENOMEM); 1122235911Smav } 1123235911Smav cfg = enc->enc_private; 1124235911Smav 1125235911Smav enc->enc_cache.nelms = 0; 1126235911Smav enc->enc_cache.enc_status = 0; 1127235911Smav 1128235911Smav TAILQ_INIT(&cfg->requests); 1129235911Smav return (0); 1130235911Smav} 1131235911Smav 1132