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