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