xref: /freebsd/sys/cam/scsi/scsi_enc_safte.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2000 Matthew Jacob
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 
34 #include <sys/conf.h>
35 #include <sys/errno.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mutex.h>
39 #include <sys/queue.h>
40 #include <sys/sx.h>
41 #include <sys/systm.h>
42 #include <sys/sysctl.h>
43 #include <sys/types.h>
44 
45 #include <cam/cam.h>
46 #include <cam/cam_ccb.h>
47 #include <cam/cam_periph.h>
48 
49 #include <cam/scsi/scsi_enc.h>
50 #include <cam/scsi/scsi_enc_internal.h>
51 #include <cam/scsi/scsi_message.h>
52 
53 /*
54  * SAF-TE Type Device Emulation
55  */
56 
57 static int safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag);
58 
59 #define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
60 	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
61 /*
62  * SAF-TE specific defines- Mandatory ones only...
63  */
64 
65 /*
66  * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
67  */
68 #define	SAFTE_RD_RDCFG	0x00	/* read enclosure configuration */
69 #define	SAFTE_RD_RDESTS	0x01	/* read enclosure status */
70 #define	SAFTE_RD_RDDSTS	0x04	/* read drive slot status */
71 #define	SAFTE_RD_RDGFLG	0x05	/* read global flags */
72 
73 /*
74  * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
75  */
76 #define	SAFTE_WT_DSTAT	0x10	/* write device slot status */
77 #define	SAFTE_WT_SLTOP	0x12	/* perform slot operation */
78 #define	SAFTE_WT_FANSPD	0x13	/* set fan speed */
79 #define	SAFTE_WT_ACTPWS	0x14	/* turn on/off power supply */
80 #define	SAFTE_WT_GLOBAL	0x15	/* send global command */
81 
82 #define	SAFT_SCRATCH	64
83 #define	SCSZ		0x8000
84 
85 typedef enum {
86 	SAFTE_UPDATE_NONE,
87 	SAFTE_UPDATE_READCONFIG,
88 	SAFTE_UPDATE_READGFLAGS,
89 	SAFTE_UPDATE_READENCSTATUS,
90 	SAFTE_UPDATE_READSLOTSTATUS,
91 	SAFTE_PROCESS_CONTROL_REQS,
92 	SAFTE_NUM_UPDATE_STATES
93 } safte_update_action;
94 
95 static fsm_fill_handler_t safte_fill_read_buf_io;
96 static fsm_fill_handler_t safte_fill_control_request;
97 static fsm_done_handler_t safte_process_config;
98 static fsm_done_handler_t safte_process_gflags;
99 static fsm_done_handler_t safte_process_status;
100 static fsm_done_handler_t safte_process_slotstatus;
101 static fsm_done_handler_t safte_process_control_request;
102 
103 static struct enc_fsm_state enc_fsm_states[SAFTE_NUM_UPDATE_STATES] =
104 {
105 	{ "SAFTE_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL },
106 	{
107 		"SAFTE_UPDATE_READCONFIG",
108 		SAFTE_RD_RDCFG,
109 		SAFT_SCRATCH,
110 		60 * 1000,
111 		safte_fill_read_buf_io,
112 		safte_process_config,
113 		enc_error
114 	},
115 	{
116 		"SAFTE_UPDATE_READGFLAGS",
117 		SAFTE_RD_RDGFLG,
118 		16,
119 		60 * 1000,
120 		safte_fill_read_buf_io,
121 		safte_process_gflags,
122 		enc_error
123 	},
124 	{
125 		"SAFTE_UPDATE_READENCSTATUS",
126 		SAFTE_RD_RDESTS,
127 		SCSZ,
128 		60 * 1000,
129 		safte_fill_read_buf_io,
130 		safte_process_status,
131 		enc_error
132 	},
133 	{
134 		"SAFTE_UPDATE_READSLOTSTATUS",
135 		SAFTE_RD_RDDSTS,
136 		SCSZ,
137 		60 * 1000,
138 		safte_fill_read_buf_io,
139 		safte_process_slotstatus,
140 		enc_error
141 	},
142 	{
143 		"SAFTE_PROCESS_CONTROL_REQS",
144 		0,
145 		SCSZ,
146 		60 * 1000,
147 		safte_fill_control_request,
148 		safte_process_control_request,
149 		enc_error
150 	}
151 };
152 
153 typedef struct safte_control_request {
154 	int	elm_idx;
155 	uint8_t	elm_stat[4];
156 	int	result;
157 	TAILQ_ENTRY(safte_control_request) links;
158 } safte_control_request_t;
159 TAILQ_HEAD(safte_control_reqlist, safte_control_request);
160 typedef struct safte_control_reqlist safte_control_reqlist_t;
161 enum {
162 	SES_SETSTATUS_ENC_IDX = -1
163 };
164 
165 static void
166 safte_terminate_control_requests(safte_control_reqlist_t *reqlist, int result)
167 {
168 	safte_control_request_t *req;
169 
170 	while ((req = TAILQ_FIRST(reqlist)) != NULL) {
171 		TAILQ_REMOVE(reqlist, req, links);
172 		req->result = result;
173 		wakeup(req);
174 	}
175 }
176 
177 struct scfg {
178 	/*
179 	 * Cached Configuration
180 	 */
181 	uint8_t	Nfans;		/* Number of Fans */
182 	uint8_t	Npwr;		/* Number of Power Supplies */
183 	uint8_t	Nslots;		/* Number of Device Slots */
184 	uint8_t	DoorLock;	/* Door Lock Installed */
185 	uint8_t	Ntherm;		/* Number of Temperature Sensors */
186 	uint8_t	Nspkrs;		/* Number of Speakers */
187 	uint8_t	Ntstats;	/* Number of Thermostats */
188 	/*
189 	 * Cached Flag Bytes for Global Status
190 	 */
191 	uint8_t	flag1;
192 	uint8_t	flag2;
193 	/*
194 	 * What object index ID is where various slots start.
195 	 */
196 	uint8_t	pwroff;
197 	uint8_t	slotoff;
198 #define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
199 
200 	encioc_enc_status_t	adm_status;
201 	encioc_enc_status_t	enc_status;
202 	encioc_enc_status_t	slot_status;
203 
204 	safte_control_reqlist_t	requests;
205 	safte_control_request_t	*current_request;
206 	int			current_request_stage;
207 	int			current_request_stages;
208 };
209 
210 #define	SAFT_FLG1_ALARM		0x1
211 #define	SAFT_FLG1_GLOBFAIL	0x2
212 #define	SAFT_FLG1_GLOBWARN	0x4
213 #define	SAFT_FLG1_ENCPWROFF	0x8
214 #define	SAFT_FLG1_ENCFANFAIL	0x10
215 #define	SAFT_FLG1_ENCPWRFAIL	0x20
216 #define	SAFT_FLG1_ENCDRVFAIL	0x40
217 #define	SAFT_FLG1_ENCDRVWARN	0x80
218 
219 #define	SAFT_FLG2_LOCKDOOR	0x4
220 #define	SAFT_PRIVATE		sizeof (struct scfg)
221 
222 static char *safte_2little = "Too Little Data Returned (%d) at line %d\n";
223 #define	SAFT_BAIL(r, x)	\
224 	if ((r) >= (x)) { \
225 		ENC_VLOG(enc, safte_2little, x, __LINE__);\
226 		return (EIO); \
227 	}
228 
229 int emulate_array_devices = 1;
230 SYSCTL_INT(_kern_cam_enc, OID_AUTO, emulate_array_devices, CTLFLAG_RWTUN,
231            &emulate_array_devices, 0, "Emulate Array Devices for SAF-TE");
232 
233 static int
234 safte_fill_read_buf_io(enc_softc_t *enc, struct enc_fsm_state *state,
235 		       union ccb *ccb, uint8_t *buf)
236 {
237 
238 	if (state->page_code != SAFTE_RD_RDCFG &&
239 	    enc->enc_cache.nelms == 0) {
240 		enc_update_request(enc, SAFTE_UPDATE_READCONFIG);
241 		return (-1);
242 	}
243 
244 	if (enc->enc_type == ENC_SEMB_SAFT) {
245 		semb_read_buffer(&ccb->ataio, /*retries*/5,
246 				NULL, MSG_SIMPLE_Q_TAG,
247 				state->page_code, buf, state->buf_size,
248 				state->timeout);
249 	} else {
250 		scsi_read_buffer(&ccb->csio, /*retries*/5,
251 				NULL, MSG_SIMPLE_Q_TAG, 1,
252 				state->page_code, 0, buf, state->buf_size,
253 				SSD_FULL_SIZE, state->timeout);
254 	}
255 	return (0);
256 }
257 
258 static int
259 safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state,
260     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
261 {
262 	struct scfg *cfg;
263 	uint8_t *buf = *bufp;
264 	int i, r;
265 
266 	cfg = enc->enc_private;
267 	if (cfg == NULL)
268 		return (ENXIO);
269 	if (error != 0)
270 		return (error);
271 	if (xfer_len < 6) {
272 		ENC_VLOG(enc, "too little data (%d) for configuration\n",
273 		    xfer_len);
274 		return (EIO);
275 	}
276 	cfg->Nfans = buf[0];
277 	cfg->Npwr = buf[1];
278 	cfg->Nslots = buf[2];
279 	cfg->DoorLock = buf[3];
280 	cfg->Ntherm = buf[4];
281 	cfg->Nspkrs = buf[5];
282 	if (xfer_len >= 7)
283 		cfg->Ntstats = buf[6] & 0x0f;
284 	else
285 		cfg->Ntstats = 0;
286 	ENC_VLOG(enc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d "
287 	    "Ntstats %d\n",
288 	    cfg->Nfans, cfg->Npwr, cfg->Nslots, cfg->DoorLock, cfg->Ntherm,
289 	    cfg->Nspkrs, cfg->Ntstats);
290 
291 	enc->enc_cache.nelms = cfg->Nfans + cfg->Npwr + cfg->Nslots +
292 	    cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1;
293 	ENC_FREE_AND_NULL(enc->enc_cache.elm_map);
294 	enc->enc_cache.elm_map =
295 	    malloc(enc->enc_cache.nelms * sizeof(enc_element_t),
296 	    M_SCSIENC, M_WAITOK|M_ZERO);
297 
298 	r = 0;
299 	/*
300 	 * Note that this is all arranged for the convenience
301 	 * in later fetches of status.
302 	 */
303 	for (i = 0; i < cfg->Nfans; i++)
304 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN;
305 	cfg->pwroff = (uint8_t) r;
306 	for (i = 0; i < cfg->Npwr; i++)
307 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER;
308 	for (i = 0; i < cfg->DoorLock; i++)
309 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK;
310 	if (cfg->Nspkrs > 0)
311 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM;
312 	for (i = 0; i < cfg->Ntherm; i++)
313 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM;
314 	for (i = 0; i <= cfg->Ntstats; i++)
315 		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM;
316 	cfg->slotoff = (uint8_t) r;
317 	for (i = 0; i < cfg->Nslots; i++)
318 		enc->enc_cache.elm_map[r++].elm_type =
319 		    emulate_array_devices ? ELMTYP_ARRAY_DEV :
320 		     ELMTYP_DEVICE;
321 
322 	enc_update_request(enc, SAFTE_UPDATE_READGFLAGS);
323 	enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
324 	enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
325 
326 	return (0);
327 }
328 
329 static int
330 safte_process_gflags(enc_softc_t *enc, struct enc_fsm_state *state,
331     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
332 {
333 	struct scfg *cfg;
334 	uint8_t *buf = *bufp;
335 
336 	cfg = enc->enc_private;
337 	if (cfg == NULL)
338 		return (ENXIO);
339 	if (error != 0)
340 		return (error);
341 	SAFT_BAIL(3, xfer_len);
342 	cfg->flag1 = buf[1];
343 	cfg->flag2 = buf[2];
344 
345 	cfg->adm_status = 0;
346 	if (cfg->flag1 & SAFT_FLG1_GLOBFAIL)
347 		cfg->adm_status |= SES_ENCSTAT_CRITICAL;
348 	else if (cfg->flag1 & SAFT_FLG1_GLOBWARN)
349 		cfg->adm_status |= SES_ENCSTAT_NONCRITICAL;
350 
351 	return (0);
352 }
353 
354 static int
355 safte_process_status(enc_softc_t *enc, struct enc_fsm_state *state,
356     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
357 {
358 	struct scfg *cfg;
359 	uint8_t *buf = *bufp;
360 	int oid, r, i, nitems;
361 	uint16_t tempflags;
362 	enc_cache_t *cache = &enc->enc_cache;
363 
364 	cfg = enc->enc_private;
365 	if (cfg == NULL)
366 		return (ENXIO);
367 	if (error != 0)
368 		return (error);
369 
370 	oid = r = 0;
371 	cfg->enc_status = 0;
372 
373 	for (nitems = i = 0; i < cfg->Nfans; i++) {
374 		SAFT_BAIL(r, xfer_len);
375 		/*
376 		 * 0 = Fan Operational
377 		 * 1 = Fan is malfunctioning
378 		 * 2 = Fan is not present
379 		 * 0x80 = Unknown or Not Reportable Status
380 		 */
381 		cache->elm_map[oid].encstat[1] = 0;	/* resvd */
382 		cache->elm_map[oid].encstat[2] = 0;	/* resvd */
383 		if (cfg->flag1 & SAFT_FLG1_ENCFANFAIL)
384 			cache->elm_map[oid].encstat[3] |= 0x40;
385 		else
386 			cache->elm_map[oid].encstat[3] &= ~0x40;
387 		switch ((int)buf[r]) {
388 		case 0:
389 			nitems++;
390 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
391 			if ((cache->elm_map[oid].encstat[3] & 0x37) == 0)
392 				cache->elm_map[oid].encstat[3] |= 0x27;
393 			break;
394 
395 		case 1:
396 			cache->elm_map[oid].encstat[0] =
397 			    SES_OBJSTAT_CRIT;
398 			/*
399 			 * FAIL and FAN STOPPED synthesized
400 			 */
401 			cache->elm_map[oid].encstat[3] |= 0x10;
402 			cache->elm_map[oid].encstat[3] &= ~0x07;
403 			/*
404 			 * Enclosure marked with CRITICAL error
405 			 * if only one fan or no thermometers,
406 			 * else the NONCRITICAL error is set.
407 			 */
408 			if (cfg->Nfans == 1 || (cfg->Ntherm + cfg->Ntstats) == 0)
409 				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
410 			else
411 				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
412 			break;
413 		case 2:
414 			cache->elm_map[oid].encstat[0] =
415 			    SES_OBJSTAT_NOTINSTALLED;
416 			cache->elm_map[oid].encstat[3] |= 0x10;
417 			cache->elm_map[oid].encstat[3] &= ~0x07;
418 			/*
419 			 * Enclosure marked with CRITICAL error
420 			 * if only one fan or no thermometers,
421 			 * else the NONCRITICAL error is set.
422 			 */
423 			if (cfg->Nfans == 1)
424 				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
425 			else
426 				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
427 			break;
428 		case 0x80:
429 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
430 			cache->elm_map[oid].encstat[3] = 0;
431 			cfg->enc_status |= SES_ENCSTAT_INFO;
432 			break;
433 		default:
434 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
435 			ENC_VLOG(enc, "Unknown fan%d status 0x%x\n", i,
436 			    buf[r] & 0xff);
437 			break;
438 		}
439 		cache->elm_map[oid++].svalid = 1;
440 		r++;
441 	}
442 
443 	/*
444 	 * No matter how you cut it, no cooling elements when there
445 	 * should be some there is critical.
446 	 */
447 	if (cfg->Nfans && nitems == 0)
448 		cfg->enc_status |= SES_ENCSTAT_CRITICAL;
449 
450 	for (i = 0; i < cfg->Npwr; i++) {
451 		SAFT_BAIL(r, xfer_len);
452 		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
453 		cache->elm_map[oid].encstat[1] = 0;	/* resvd */
454 		cache->elm_map[oid].encstat[2] = 0;	/* resvd */
455 		cache->elm_map[oid].encstat[3] = 0x20;	/* requested on */
456 		switch (buf[r]) {
457 		case 0x00:	/* pws operational and on */
458 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
459 			break;
460 		case 0x01:	/* pws operational and off */
461 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
462 			cache->elm_map[oid].encstat[3] = 0x10;
463 			cfg->enc_status |= SES_ENCSTAT_INFO;
464 			break;
465 		case 0x10:	/* pws is malfunctioning and commanded on */
466 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
467 			cache->elm_map[oid].encstat[3] = 0x61;
468 			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
469 			break;
470 
471 		case 0x11:	/* pws is malfunctioning and commanded off */
472 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
473 			cache->elm_map[oid].encstat[3] = 0x51;
474 			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
475 			break;
476 		case 0x20:	/* pws is not present */
477 			cache->elm_map[oid].encstat[0] =
478 			    SES_OBJSTAT_NOTINSTALLED;
479 			cache->elm_map[oid].encstat[3] = 0;
480 			cfg->enc_status |= SES_ENCSTAT_INFO;
481 			break;
482 		case 0x21:	/* pws is present */
483 			/*
484 			 * This is for enclosures that cannot tell whether the
485 			 * device is on or malfunctioning, but know that it is
486 			 * present. Just fall through.
487 			 */
488 			/* FALLTHROUGH */
489 		case 0x80:	/* Unknown or Not Reportable Status */
490 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
491 			cache->elm_map[oid].encstat[3] = 0;
492 			cfg->enc_status |= SES_ENCSTAT_INFO;
493 			break;
494 		default:
495 			ENC_VLOG(enc, "unknown power supply %d status (0x%x)\n",
496 			    i, buf[r] & 0xff);
497 			break;
498 		}
499 		enc->enc_cache.elm_map[oid++].svalid = 1;
500 		r++;
501 	}
502 
503 	/*
504 	 * Copy Slot SCSI IDs
505 	 */
506 	for (i = 0; i < cfg->Nslots; i++) {
507 		SAFT_BAIL(r, xfer_len);
508 		if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE)
509 			cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r];
510 		r++;
511 	}
512 
513 	/*
514 	 * We always have doorlock status, no matter what,
515 	 * but we only save the status if we have one.
516 	 */
517 	SAFT_BAIL(r, xfer_len);
518 	if (cfg->DoorLock) {
519 		/*
520 		 * 0 = Door Locked
521 		 * 1 = Door Unlocked, or no Lock Installed
522 		 * 0x80 = Unknown or Not Reportable Status
523 		 */
524 		cache->elm_map[oid].encstat[1] = 0;
525 		cache->elm_map[oid].encstat[2] = 0;
526 		switch (buf[r]) {
527 		case 0:
528 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
529 			cache->elm_map[oid].encstat[3] = 0;
530 			break;
531 		case 1:
532 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
533 			cache->elm_map[oid].encstat[3] = 1;
534 			break;
535 		case 0x80:
536 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
537 			cache->elm_map[oid].encstat[3] = 0;
538 			cfg->enc_status |= SES_ENCSTAT_INFO;
539 			break;
540 		default:
541 			cache->elm_map[oid].encstat[0] =
542 			    SES_OBJSTAT_UNSUPPORTED;
543 			ENC_VLOG(enc, "unknown lock status 0x%x\n",
544 			    buf[r] & 0xff);
545 			break;
546 		}
547 		cache->elm_map[oid++].svalid = 1;
548 	}
549 	r++;
550 
551 	/*
552 	 * We always have speaker status, no matter what,
553 	 * but we only save the status if we have one.
554 	 */
555 	SAFT_BAIL(r, xfer_len);
556 	if (cfg->Nspkrs) {
557 		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
558 		cache->elm_map[oid].encstat[1] = 0;
559 		cache->elm_map[oid].encstat[2] = 0;
560 		if (buf[r] == 0) {
561 			cache->elm_map[oid].encstat[0] |= SESCTL_DISABLE;
562 			cache->elm_map[oid].encstat[3] |= 0x40;
563 		}
564 		cache->elm_map[oid++].svalid = 1;
565 	}
566 	r++;
567 
568 	/*
569 	 * Now, for "pseudo" thermometers, we have two bytes
570 	 * of information in enclosure status- 16 bits. Actually,
571 	 * the MSB is a single TEMP ALERT flag indicating whether
572 	 * any other bits are set, but, thanks to fuzzy thinking,
573 	 * in the SAF-TE spec, this can also be set even if no
574 	 * other bits are set, thus making this really another
575 	 * binary temperature sensor.
576 	 */
577 
578 	SAFT_BAIL(r + cfg->Ntherm, xfer_len);
579 	tempflags = buf[r + cfg->Ntherm];
580 	SAFT_BAIL(r + cfg->Ntherm + 1, xfer_len);
581 	tempflags |= (tempflags << 8) | buf[r + cfg->Ntherm + 1];
582 
583 	for (i = 0; i < cfg->Ntherm; i++) {
584 		SAFT_BAIL(r, xfer_len);
585 		/*
586 		 * Status is a range from -10 to 245 deg Celsius,
587 		 * which we need to normalize to -20 to -245 according
588 		 * to the latest SCSI spec, which makes little
589 		 * sense since this would overflow an 8bit value.
590 		 * Well, still, the base normalization is -20,
591 		 * not -10, so we have to adjust.
592 		 *
593 		 * So what's over and under temperature?
594 		 * Hmm- we'll state that 'normal' operating
595 		 * is 10 to 40 deg Celsius.
596 		 */
597 
598 		/*
599 		 * Actually.... All of the units that people out in the world
600 		 * seem to have do not come even close to setting a value that
601 		 * complies with this spec.
602 		 *
603 		 * The closest explanation I could find was in an
604 		 * LSI-Logic manual, which seemed to indicate that
605 		 * this value would be set by whatever the I2C code
606 		 * would interpolate from the output of an LM75
607 		 * temperature sensor.
608 		 *
609 		 * This means that it is impossible to use the actual
610 		 * numeric value to predict anything. But we don't want
611 		 * to lose the value. So, we'll propagate the *uncorrected*
612 		 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
613 		 * temperature flags for warnings.
614 		 */
615 		if (tempflags & (1 << i)) {
616 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
617 			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
618 		} else
619 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
620 		cache->elm_map[oid].encstat[1] = 0;
621 		cache->elm_map[oid].encstat[2] = buf[r];
622 		cache->elm_map[oid].encstat[3] = 0;
623 		cache->elm_map[oid++].svalid = 1;
624 		r++;
625 	}
626 
627 	for (i = 0; i <= cfg->Ntstats; i++) {
628 		cache->elm_map[oid].encstat[1] = 0;
629 		if (tempflags & (1 <<
630 		    ((i == cfg->Ntstats) ? 15 : (cfg->Ntherm + i)))) {
631 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
632 			cache->elm_map[4].encstat[2] = 0xff;
633 			/*
634 			 * Set 'over temperature' failure.
635 			 */
636 			cache->elm_map[oid].encstat[3] = 8;
637 			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
638 		} else {
639 			/*
640 			 * We used to say 'not available' and synthesize a
641 			 * nominal 30 deg (C)- that was wrong. Actually,
642 			 * Just say 'OK', and use the reserved value of
643 			 * zero.
644 			 */
645 			if ((cfg->Ntherm + cfg->Ntstats) == 0)
646 				cache->elm_map[oid].encstat[0] =
647 				    SES_OBJSTAT_NOTAVAIL;
648 			else
649 				cache->elm_map[oid].encstat[0] =
650 				    SES_OBJSTAT_OK;
651 			cache->elm_map[oid].encstat[2] = 0;
652 			cache->elm_map[oid].encstat[3] = 0;
653 		}
654 		cache->elm_map[oid++].svalid = 1;
655 	}
656 	r += 2;
657 
658 	cache->enc_status =
659 	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
660 	return (0);
661 }
662 
663 static int
664 safte_process_slotstatus(enc_softc_t *enc, struct enc_fsm_state *state,
665     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
666 {
667 	struct scfg *cfg;
668 	uint8_t *buf = *bufp;
669 	enc_cache_t *cache = &enc->enc_cache;
670 	int oid, r, i;
671 
672 	cfg = enc->enc_private;
673 	if (cfg == NULL)
674 		return (ENXIO);
675 	if (error != 0)
676 		return (error);
677 	cfg->slot_status = 0;
678 	oid = cfg->slotoff;
679 	for (r = i = 0; i < cfg->Nslots; i++, r += 4) {
680 		SAFT_BAIL(r+3, xfer_len);
681 		if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV)
682 			cache->elm_map[oid].encstat[1] = 0;
683 		cache->elm_map[oid].encstat[2] &= SESCTL_RQSID;
684 		cache->elm_map[oid].encstat[3] = 0;
685 		if ((buf[r+3] & 0x01) == 0) {	/* no device */
686 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NOTINSTALLED;
687 		} else if (buf[r+0] & 0x02) {
688 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
689 			cfg->slot_status |= SES_ENCSTAT_CRITICAL;
690 		} else if (buf[r+0] & 0x40) {
691 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
692 			cfg->slot_status |= SES_ENCSTAT_NONCRITICAL;
693 		} else {
694 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
695 		}
696 		if (buf[r+3] & 0x2) {
697 			if (buf[r+3] & 0x01)
698 				cache->elm_map[oid].encstat[2] |= SESCTL_RQSRMV;
699 			else
700 				cache->elm_map[oid].encstat[2] |= SESCTL_RQSINS;
701 		}
702 		if ((buf[r+3] & 0x04) == 0)
703 			cache->elm_map[oid].encstat[3] |= SESCTL_DEVOFF;
704 		if (buf[r+0] & 0x02)
705 			cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT;
706 		if (buf[r+0] & 0x40)
707 			cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL;
708 		if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) {
709 			if (buf[r+0] & 0x01)
710 				cache->elm_map[oid].encstat[1] |= 0x80;
711 			if (buf[r+0] & 0x04)
712 				cache->elm_map[oid].encstat[1] |= 0x02;
713 			if (buf[r+0] & 0x08)
714 				cache->elm_map[oid].encstat[1] |= 0x04;
715 			if (buf[r+0] & 0x10)
716 				cache->elm_map[oid].encstat[1] |= 0x08;
717 			if (buf[r+0] & 0x20)
718 				cache->elm_map[oid].encstat[1] |= 0x10;
719 			if (buf[r+1] & 0x01)
720 				cache->elm_map[oid].encstat[1] |= 0x20;
721 			if (buf[r+1] & 0x02)
722 				cache->elm_map[oid].encstat[1] |= 0x01;
723 		}
724 		cache->elm_map[oid++].svalid = 1;
725 	}
726 
727 	cache->enc_status =
728 	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
729 	return (0);
730 }
731 
732 static int
733 safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
734 		       union ccb *ccb, uint8_t *buf)
735 {
736 	struct scfg *cfg;
737 	enc_element_t *ep, *ep1;
738 	safte_control_request_t *req;
739 	int i, idx, xfer_len;
740 
741 	cfg = enc->enc_private;
742 	if (cfg == NULL)
743 		return (ENXIO);
744 
745 	if (enc->enc_cache.nelms == 0) {
746 		enc_update_request(enc, SAFTE_UPDATE_READCONFIG);
747 		return (-1);
748 	}
749 
750 	if (cfg->current_request == NULL) {
751 		cfg->current_request = TAILQ_FIRST(&cfg->requests);
752 		TAILQ_REMOVE(&cfg->requests, cfg->current_request, links);
753 		cfg->current_request_stage = 0;
754 		cfg->current_request_stages = 1;
755 	}
756 	req = cfg->current_request;
757 
758 	idx = (int)req->elm_idx;
759 	if (req->elm_idx == SES_SETSTATUS_ENC_IDX) {
760 		cfg->adm_status = req->elm_stat[0] & ALL_ENC_STAT;
761 		cfg->flag1 &= ~(SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
762 		if (req->elm_stat[0] & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV))
763 			cfg->flag1 |= SAFT_FLG1_GLOBFAIL;
764 		else if (req->elm_stat[0] & SES_ENCSTAT_NONCRITICAL)
765 			cfg->flag1 |= SAFT_FLG1_GLOBWARN;
766 		buf[0] = SAFTE_WT_GLOBAL;
767 		buf[1] = cfg->flag1;
768 		buf[2] = cfg->flag2;
769 		buf[3] = 0;
770 		xfer_len = 16;
771 	} else {
772 		ep = &enc->enc_cache.elm_map[idx];
773 
774 		switch (ep->elm_type) {
775 		case ELMTYP_DEVICE:
776 		case ELMTYP_ARRAY_DEV:
777 			switch (cfg->current_request_stage) {
778 			case 0:
779 				ep->priv = 0;
780 				if (req->elm_stat[0] & SESCTL_PRDFAIL)
781 					ep->priv |= 0x40;
782 				if (req->elm_stat[3] & SESCTL_RQSFLT)
783 					ep->priv |= 0x02;
784 				if (ep->elm_type == ELMTYP_ARRAY_DEV) {
785 					if (req->elm_stat[1] & 0x01)
786 						ep->priv |= 0x200;
787 					if (req->elm_stat[1] & 0x02)
788 						ep->priv |= 0x04;
789 					if (req->elm_stat[1] & 0x04)
790 						ep->priv |= 0x08;
791 					if (req->elm_stat[1] & 0x08)
792 						ep->priv |= 0x10;
793 					if (req->elm_stat[1] & 0x10)
794 						ep->priv |= 0x20;
795 					if (req->elm_stat[1] & 0x20)
796 						ep->priv |= 0x100;
797 					if (req->elm_stat[1] & 0x80)
798 						ep->priv |= 0x01;
799 				}
800 				if (ep->priv == 0)
801 					ep->priv |= 0x01;	/* no errors */
802 
803 				buf[0] = SAFTE_WT_DSTAT;
804 				for (i = 0; i < cfg->Nslots; i++) {
805 					ep1 = &enc->enc_cache.elm_map[cfg->slotoff + i];
806 					buf[1 + (3 * i)] = ep1->priv;
807 					buf[2 + (3 * i)] = ep1->priv >> 8;
808 				}
809 				xfer_len = cfg->Nslots * 3 + 1;
810 #define DEVON(x)	(!(((x)[2] & SESCTL_RQSINS) |	\
811 			   ((x)[2] & SESCTL_RQSRMV) |	\
812 			   ((x)[3] & SESCTL_DEVOFF)))
813 				if (DEVON(req->elm_stat) != DEVON(ep->encstat))
814 					cfg->current_request_stages++;
815 #define IDON(x)		(!!((x)[2] & SESCTL_RQSID))
816 				if (IDON(req->elm_stat) != IDON(ep->encstat))
817 					cfg->current_request_stages++;
818 				break;
819 			case 1:
820 			case 2:
821 				buf[0] = SAFTE_WT_SLTOP;
822 				buf[1] = idx - cfg->slotoff;
823 				if (cfg->current_request_stage == 1 &&
824 				    DEVON(req->elm_stat) != DEVON(ep->encstat)) {
825 					if (DEVON(req->elm_stat))
826 						buf[2] = 0x01;
827 					else
828 						buf[2] = 0x02;
829 				} else {
830 					if (IDON(req->elm_stat))
831 						buf[2] = 0x04;
832 					else
833 						buf[2] = 0x00;
834 					ep->encstat[2] &= ~SESCTL_RQSID;
835 					ep->encstat[2] |= req->elm_stat[2] &
836 					    SESCTL_RQSID;
837 				}
838 				xfer_len = 64;
839 				break;
840 			default:
841 				return (EINVAL);
842 			}
843 			break;
844 		case ELMTYP_POWER:
845 			cfg->current_request_stages = 2;
846 			switch (cfg->current_request_stage) {
847 			case 0:
848 				if (req->elm_stat[3] & SESCTL_RQSTFAIL) {
849 					cfg->flag1 |= SAFT_FLG1_ENCPWRFAIL;
850 				} else {
851 					cfg->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
852 				}
853 				buf[0] = SAFTE_WT_GLOBAL;
854 				buf[1] = cfg->flag1;
855 				buf[2] = cfg->flag2;
856 				buf[3] = 0;
857 				xfer_len = 16;
858 				break;
859 			case 1:
860 				buf[0] = SAFTE_WT_ACTPWS;
861 				buf[1] = idx - cfg->pwroff;
862 				if (req->elm_stat[3] & SESCTL_RQSTON)
863 					buf[2] = 0x01;
864 				else
865 					buf[2] = 0x00;
866 				buf[3] = 0;
867 				xfer_len = 16;
868 			default:
869 				return (EINVAL);
870 			}
871 			break;
872 		case ELMTYP_FAN:
873 			if ((req->elm_stat[3] & 0x7) != 0)
874 				cfg->current_request_stages = 2;
875 			switch (cfg->current_request_stage) {
876 			case 0:
877 				if (req->elm_stat[3] & SESCTL_RQSTFAIL)
878 					cfg->flag1 |= SAFT_FLG1_ENCFANFAIL;
879 				else
880 					cfg->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
881 				buf[0] = SAFTE_WT_GLOBAL;
882 				buf[1] = cfg->flag1;
883 				buf[2] = cfg->flag2;
884 				buf[3] = 0;
885 				xfer_len = 16;
886 				break;
887 			case 1:
888 				buf[0] = SAFTE_WT_FANSPD;
889 				buf[1] = idx;
890 				if (req->elm_stat[3] & SESCTL_RQSTON) {
891 					if ((req->elm_stat[3] & 0x7) == 7)
892 						buf[2] = 4;
893 					else if ((req->elm_stat[3] & 0x7) >= 5)
894 						buf[2] = 3;
895 					else if ((req->elm_stat[3] & 0x7) >= 3)
896 						buf[2] = 2;
897 					else
898 						buf[2] = 1;
899 				} else
900 					buf[2] = 0;
901 				buf[3] = 0;
902 				xfer_len = 16;
903 				ep->encstat[3] = req->elm_stat[3] & 0x67;
904 			default:
905 				return (EINVAL);
906 			}
907 			break;
908 		case ELMTYP_DOORLOCK:
909 			if (req->elm_stat[3] & 0x1)
910 				cfg->flag2 &= ~SAFT_FLG2_LOCKDOOR;
911 			else
912 				cfg->flag2 |= SAFT_FLG2_LOCKDOOR;
913 			buf[0] = SAFTE_WT_GLOBAL;
914 			buf[1] = cfg->flag1;
915 			buf[2] = cfg->flag2;
916 			buf[3] = 0;
917 			xfer_len = 16;
918 			break;
919 		case ELMTYP_ALARM:
920 			if ((req->elm_stat[0] & SESCTL_DISABLE) ||
921 			    (req->elm_stat[3] & 0x40)) {
922 				cfg->flag2 &= ~SAFT_FLG1_ALARM;
923 			} else if ((req->elm_stat[3] & 0x0f) != 0) {
924 				cfg->flag2 |= SAFT_FLG1_ALARM;
925 			} else {
926 				cfg->flag2 &= ~SAFT_FLG1_ALARM;
927 			}
928 			buf[0] = SAFTE_WT_GLOBAL;
929 			buf[1] = cfg->flag1;
930 			buf[2] = cfg->flag2;
931 			buf[3] = 0;
932 			xfer_len = 16;
933 			ep->encstat[3] = req->elm_stat[3];
934 			break;
935 		default:
936 			return (EINVAL);
937 		}
938 	}
939 
940 	if (enc->enc_type == ENC_SEMB_SAFT) {
941 		semb_write_buffer(&ccb->ataio, /*retries*/5,
942 				NULL, MSG_SIMPLE_Q_TAG,
943 				buf, xfer_len, state->timeout);
944 	} else {
945 		scsi_write_buffer(&ccb->csio, /*retries*/5,
946 				NULL, MSG_SIMPLE_Q_TAG, 1,
947 				0, 0, buf, xfer_len,
948 				SSD_FULL_SIZE, state->timeout);
949 	}
950 	return (0);
951 }
952 
953 static int
954 safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
955     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
956 {
957 	struct scfg *cfg;
958 	safte_control_request_t *req;
959 	int idx, type;
960 
961 	cfg = enc->enc_private;
962 	if (cfg == NULL)
963 		return (ENXIO);
964 
965 	req = cfg->current_request;
966 	if (req->result == 0)
967 		req->result = error;
968 	if (++cfg->current_request_stage >= cfg->current_request_stages) {
969 		idx = req->elm_idx;
970 		if (idx == SES_SETSTATUS_ENC_IDX)
971 			type = -1;
972 		else
973 			type = enc->enc_cache.elm_map[idx].elm_type;
974 		if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV)
975 			enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
976 		else
977 			enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
978 		cfg->current_request = NULL;
979 		wakeup(req);
980 	} else {
981 		enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
982 	}
983 	return (0);
984 }
985 
986 static void
987 safte_softc_invalidate(enc_softc_t *enc)
988 {
989 	struct scfg *cfg;
990 
991 	cfg = enc->enc_private;
992 	safte_terminate_control_requests(&cfg->requests, ENXIO);
993 }
994 
995 static void
996 safte_softc_cleanup(enc_softc_t *enc)
997 {
998 
999 	ENC_FREE_AND_NULL(enc->enc_cache.elm_map);
1000 	ENC_FREE_AND_NULL(enc->enc_private);
1001 	enc->enc_cache.nelms = 0;
1002 }
1003 
1004 static int
1005 safte_init_enc(enc_softc_t *enc)
1006 {
1007 	struct scfg *cfg;
1008 	int err;
1009 	static char cdb0[6] = { SEND_DIAGNOSTIC };
1010 
1011 	cfg = enc->enc_private;
1012 	if (cfg == NULL)
1013 		return (ENXIO);
1014 
1015 	err = enc_runcmd(enc, cdb0, 6, NULL, 0);
1016 	if (err) {
1017 		return (err);
1018 	}
1019 	DELAY(5000);
1020 	cfg->flag1 = 0;
1021 	cfg->flag2 = 0;
1022 	err = safte_set_enc_status(enc, 0, 1);
1023 	return (err);
1024 }
1025 
1026 static int
1027 safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag)
1028 {
1029 	struct scfg *cfg;
1030 	safte_control_request_t req;
1031 
1032 	cfg = enc->enc_private;
1033 	if (cfg == NULL)
1034 		return (ENXIO);
1035 
1036 	req.elm_idx = SES_SETSTATUS_ENC_IDX;
1037 	req.elm_stat[0] = encstat & 0xf;
1038 	req.result = 0;
1039 
1040 	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
1041 	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
1042 	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
1043 
1044 	return (req.result);
1045 }
1046 
1047 static int
1048 safte_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflg)
1049 {
1050 	int i = (int)elms->elm_idx;
1051 
1052 	elms->cstat[0] = enc->enc_cache.elm_map[i].encstat[0];
1053 	elms->cstat[1] = enc->enc_cache.elm_map[i].encstat[1];
1054 	elms->cstat[2] = enc->enc_cache.elm_map[i].encstat[2];
1055 	elms->cstat[3] = enc->enc_cache.elm_map[i].encstat[3];
1056 	return (0);
1057 }
1058 
1059 static int
1060 safte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
1061 {
1062 	struct scfg *cfg;
1063 	safte_control_request_t req;
1064 
1065 	cfg = enc->enc_private;
1066 	if (cfg == NULL)
1067 		return (ENXIO);
1068 
1069 	/* If this is clear, we don't do diddly.  */
1070 	if ((elms->cstat[0] & SESCTL_CSEL) == 0)
1071 		return (0);
1072 
1073 	req.elm_idx = elms->elm_idx;
1074 	memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat));
1075 	req.result = 0;
1076 
1077 	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
1078 	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
1079 	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
1080 
1081 	return (req.result);
1082 }
1083 
1084 static void
1085 safte_poll_status(enc_softc_t *enc)
1086 {
1087 
1088 	enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
1089 	enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
1090 }
1091 
1092 static struct enc_vec safte_enc_vec =
1093 {
1094 	.softc_invalidate	= safte_softc_invalidate,
1095 	.softc_cleanup	= safte_softc_cleanup,
1096 	.init_enc	= safte_init_enc,
1097 	.set_enc_status	= safte_set_enc_status,
1098 	.get_elm_status	= safte_get_elm_status,
1099 	.set_elm_status	= safte_set_elm_status,
1100 	.poll_status	= safte_poll_status
1101 };
1102 
1103 int
1104 safte_softc_init(enc_softc_t *enc)
1105 {
1106 	struct scfg *cfg;
1107 
1108 	enc->enc_vec = safte_enc_vec;
1109 	enc->enc_fsm_states = enc_fsm_states;
1110 
1111 	if (enc->enc_private == NULL) {
1112 		enc->enc_private = ENC_MALLOCZ(SAFT_PRIVATE);
1113 		if (enc->enc_private == NULL)
1114 			return (ENOMEM);
1115 	}
1116 	cfg = enc->enc_private;
1117 
1118 	enc->enc_cache.nelms = 0;
1119 	enc->enc_cache.enc_status = 0;
1120 
1121 	TAILQ_INIT(&cfg->requests);
1122 	return (0);
1123 }
1124