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