]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/cam/scsi/scsi_enc.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / cam / scsi / scsi_enc.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/fcntl.h>
35 #include <sys/kernel.h>
36 #include <sys/kthread.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/mutex.h>
40 #include <sys/queue.h>
41 #include <sys/sx.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
44 #include <sys/types.h>
45
46 #include <machine/stdarg.h>
47
48 #include <cam/cam.h>
49 #include <cam/cam_ccb.h>
50 #include <cam/cam_debug.h>
51 #include <cam/cam_periph.h>
52 #include <cam/cam_xpt_periph.h>
53
54 #include <cam/scsi/scsi_all.h>
55 #include <cam/scsi/scsi_message.h>
56 #include <cam/scsi/scsi_enc.h>
57 #include <cam/scsi/scsi_enc_internal.h>
58
59 #include <opt_ses.h>
60
61 MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers");
62
63 /* Enclosure type independent driver */
64
65 static  d_open_t        enc_open;
66 static  d_close_t       enc_close;
67 static  d_ioctl_t       enc_ioctl;
68 static  periph_init_t   enc_init;
69 static  periph_ctor_t   enc_ctor;
70 static  periph_oninv_t  enc_oninvalidate;
71 static  periph_dtor_t   enc_dtor;
72 static  periph_start_t  enc_start;
73
74 static void enc_async(void *, uint32_t, struct cam_path *, void *);
75 static enctyp enc_type(struct ccb_getdev *);
76
77 SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0,
78             "CAM Enclosure Services driver");
79
80 static struct periph_driver encdriver = {
81         enc_init, "ses",
82         TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0
83 };
84
85 PERIPHDRIVER_DECLARE(enc, encdriver);
86
87 static struct cdevsw enc_cdevsw = {
88         .d_version =    D_VERSION,
89         .d_open =       enc_open,
90         .d_close =      enc_close,
91         .d_ioctl =      enc_ioctl,
92         .d_name =       "ses",
93         .d_flags =      D_TRACKCLOSE,
94 };
95
96 static void
97 enc_init(void)
98 {
99         cam_status status;
100
101         /*
102          * Install a global async callback.  This callback will
103          * receive async callbacks like "new device found".
104          */
105         status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL);
106
107         if (status != CAM_REQ_CMP) {
108                 printf("enc: Failed to attach master async callback "
109                        "due to status 0x%x!\n", status);
110         }
111 }
112
113 static void
114 enc_devgonecb(void *arg)
115 {
116         struct cam_sim    *sim;
117         struct cam_periph *periph;
118         struct enc_softc  *enc;
119         int i;
120
121         periph = (struct cam_periph *)arg;
122         sim = periph->sim;
123         enc = (struct enc_softc *)periph->softc;
124
125         mtx_lock(sim->mtx);
126
127         /*
128          * When we get this callback, we will get no more close calls from
129          * devfs.  So if we have any dangling opens, we need to release the
130          * reference held for that particular context.
131          */
132         for (i = 0; i < enc->open_count; i++)
133                 cam_periph_release_locked(periph);
134
135         enc->open_count = 0;
136
137         /*
138          * Release the reference held for the device node, it is gone now.
139          */
140         cam_periph_release_locked(periph);
141
142         /*
143          * We reference the SIM lock directly here, instead of using
144          * cam_periph_unlock().  The reason is that the final call to
145          * cam_periph_release_locked() above could result in the periph
146          * getting freed.  If that is the case, dereferencing the periph
147          * with a cam_periph_unlock() call would cause a page fault.
148          */
149         mtx_unlock(sim->mtx);
150 }
151
152 static void
153 enc_oninvalidate(struct cam_periph *periph)
154 {
155         struct enc_softc *enc;
156
157         enc = periph->softc;
158
159         enc->enc_flags |= ENC_FLAG_INVALID;
160
161         /* If the sub-driver has an invalidate routine, call it */
162         if (enc->enc_vec.softc_invalidate != NULL)
163                 enc->enc_vec.softc_invalidate(enc);
164
165         /*
166          * Unregister any async callbacks.
167          */
168         xpt_register_async(0, enc_async, periph, periph->path);
169
170         /*
171          * Shutdown our daemon.
172          */
173         enc->enc_flags |= ENC_FLAG_SHUTDOWN;
174         if (enc->enc_daemon != NULL) {
175                 /* Signal the ses daemon to terminate. */
176                 wakeup(enc->enc_daemon);
177         }
178         callout_drain(&enc->status_updater);
179
180         destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph);
181 }
182
183 static void
184 enc_dtor(struct cam_periph *periph)
185 {
186         struct enc_softc *enc;
187
188         enc = periph->softc;
189
190         /* If the sub-driver has a cleanup routine, call it */
191         if (enc->enc_vec.softc_cleanup != NULL)
192                 enc->enc_vec.softc_cleanup(enc);
193
194         if (enc->enc_boot_hold_ch.ich_func != NULL) {
195                 config_intrhook_disestablish(&enc->enc_boot_hold_ch);
196                 enc->enc_boot_hold_ch.ich_func = NULL;
197         }
198
199         ENC_FREE(enc);
200 }
201
202 static void
203 enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
204 {
205         struct cam_periph *periph;
206
207         periph = (struct cam_periph *)callback_arg;
208
209         switch(code) {
210         case AC_FOUND_DEVICE:
211         {
212                 struct ccb_getdev *cgd;
213                 cam_status status;
214                 path_id_t path_id;
215
216                 cgd = (struct ccb_getdev *)arg;
217                 if (arg == NULL) {
218                         break;
219                 }
220
221                 if (enc_type(cgd) == ENC_NONE) {
222                         /*
223                          * Schedule announcement of the ENC bindings for
224                          * this device if it is managed by a SEP.
225                          */
226                         path_id = xpt_path_path_id(path);
227                         xpt_lock_buses();
228                         TAILQ_FOREACH(periph, &encdriver.units, unit_links) {
229                                 struct enc_softc *softc;
230
231                                 softc = (struct enc_softc *)periph->softc;
232                                 if (xpt_path_path_id(periph->path) != path_id
233                                  || softc == NULL
234                                  || (softc->enc_flags & ENC_FLAG_INITIALIZED)
235                                   == 0
236                                  || softc->enc_vec.device_found == NULL)
237                                         continue;
238
239                                 softc->enc_vec.device_found(softc);
240                         }
241                         xpt_unlock_buses();
242                         return;
243                 }
244
245                 status = cam_periph_alloc(enc_ctor, enc_oninvalidate,
246                     enc_dtor, enc_start, "ses", CAM_PERIPH_BIO,
247                     cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd);
248
249                 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
250                         printf("enc_async: Unable to probe new device due to "
251                             "status 0x%x\n", status);
252                 }
253                 break;
254         }
255         default:
256                 cam_periph_async(periph, code, path, arg);
257                 break;
258         }
259 }
260
261 static int
262 enc_open(struct cdev *dev, int flags, int fmt, struct thread *td)
263 {
264         struct cam_periph *periph;
265         struct enc_softc *softc;
266         int error = 0;
267
268         periph = (struct cam_periph *)dev->si_drv1;
269         if (periph == NULL) {
270                 return (ENXIO);
271         }
272
273         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
274                 return (ENXIO);
275
276         cam_periph_lock(periph);
277
278         softc = (struct enc_softc *)periph->softc;
279
280         if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
281                 error = ENXIO;
282                 goto out;
283         }
284         if (softc->enc_flags & ENC_FLAG_INVALID) {
285                 error = ENXIO;
286                 goto out;
287         }
288 out:
289         if (error != 0)
290                 cam_periph_release_locked(periph);
291         else
292                 softc->open_count++;
293
294         cam_periph_unlock(periph);
295
296         return (error);
297 }
298
299 static int
300 enc_close(struct cdev *dev, int flag, int fmt, struct thread *td)
301 {
302         struct cam_sim    *sim;
303         struct cam_periph *periph;
304         struct enc_softc  *enc;
305
306         periph = (struct cam_periph *)dev->si_drv1;
307         if (periph == NULL)
308                 return (ENXIO);
309
310         sim = periph->sim;
311         enc = periph->softc;
312
313         mtx_lock(sim->mtx);
314
315         enc->open_count--;
316
317         cam_periph_release_locked(periph);
318
319         /*
320          * We reference the SIM lock directly here, instead of using
321          * cam_periph_unlock().  The reason is that the call to
322          * cam_periph_release_locked() above could result in the periph
323          * getting freed.  If that is the case, dereferencing the periph
324          * with a cam_periph_unlock() call would cause a page fault.
325          *
326          * cam_periph_release() avoids this problem using the same method,
327          * but we're manually acquiring and dropping the lock here to
328          * protect the open count and avoid another lock acquisition and
329          * release.
330          */
331         mtx_unlock(sim->mtx);
332
333         return (0);
334 }
335
336 static void
337 enc_start(struct cam_periph *p, union ccb *sccb)
338 {
339         struct enc_softc *enc;
340
341         enc = p->softc;
342         ENC_DLOG(enc, "%s enter imm=%d prio=%d\n",
343             __func__, p->immediate_priority, p->pinfo.priority);
344         if (p->immediate_priority <= p->pinfo.priority) {
345                 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
346                 p->immediate_priority = CAM_PRIORITY_NONE;
347                 wakeup(&p->ccb_list);
348         } else
349                 xpt_release_ccb(sccb);
350         ENC_DLOG(enc, "%s exit\n", __func__);
351 }
352
353 void
354 enc_done(struct cam_periph *periph, union ccb *dccb)
355 {
356         wakeup(&dccb->ccb_h.cbfcnp);
357 }
358
359 int
360 enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags)
361 {
362         struct enc_softc *softc;
363         struct cam_periph *periph;
364
365         periph = xpt_path_periph(ccb->ccb_h.path);
366         softc = (struct enc_softc *)periph->softc;
367
368         return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb));
369 }
370
371 static int
372 enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag,
373          struct thread *td)
374 {
375         struct cam_periph *periph;
376         encioc_enc_status_t tmp;
377         encioc_string_t sstr;
378         encioc_elm_status_t elms;
379         encioc_elm_desc_t elmd;
380         encioc_elm_devnames_t elmdn;
381         encioc_element_t *uelm;
382         enc_softc_t *enc;
383         enc_cache_t *cache;
384         void *addr;
385         int error, i;
386
387
388         if (arg_addr)
389                 addr = *((caddr_t *) arg_addr);
390         else
391                 addr = NULL;
392
393         periph = (struct cam_periph *)dev->si_drv1;
394         if (periph == NULL)
395                 return (ENXIO);
396
397         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n"));
398
399         cam_periph_lock(periph);
400         enc = (struct enc_softc *)periph->softc;
401         cache = &enc->enc_cache;
402
403         /*
404          * Now check to see whether we're initialized or not.
405          * This actually should never fail as we're not supposed
406          * to get past enc_open w/o successfully initializing
407          * things.
408          */
409         if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
410                 cam_periph_unlock(periph);
411                 return (ENXIO);
412         }
413         cam_periph_unlock(periph);
414
415         error = 0;
416
417         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
418             ("trying to do ioctl %#lx\n", cmd));
419
420         /*
421          * If this command can change the device's state,
422          * we must have the device open for writing.
423          *
424          * For commands that get information about the
425          * device- we don't need to lock the peripheral
426          * if we aren't running a command.  The periph
427          * also can't go away while a user process has
428          * it open.
429          */
430         switch (cmd) {
431         case ENCIOC_GETNELM:
432         case ENCIOC_GETELMMAP:
433         case ENCIOC_GETENCSTAT:
434         case ENCIOC_GETELMSTAT:
435         case ENCIOC_GETELMDESC:
436         case ENCIOC_GETELMDEVNAMES:
437                 break;
438         default:
439                 if ((flag & FWRITE) == 0) {
440                         return (EBADF);
441                 }
442         }
443  
444         /*
445          * XXX The values read here are only valid for the current
446          *     configuration generation.  We need these ioctls
447          *     to also pass in/out a generation number.
448          */
449         sx_slock(&enc->enc_cache_lock);
450         switch (cmd) {
451         case ENCIOC_GETNELM:
452                 error = copyout(&cache->nelms, addr, sizeof (cache->nelms));
453                 break;
454                 
455         case ENCIOC_GETELMMAP:
456                 for (uelm = addr, i = 0; i != cache->nelms; i++) {
457                         encioc_element_t kelm;
458                         kelm.elm_idx = i;
459                         kelm.elm_subenc_id = cache->elm_map[i].subenclosure;
460                         kelm.elm_type = cache->elm_map[i].enctype;
461                         error = copyout(&kelm, &uelm[i], sizeof(kelm));
462                         if (error)
463                                 break;
464                 }
465                 break;
466
467         case ENCIOC_GETENCSTAT:
468                 cam_periph_lock(periph);
469                 error = enc->enc_vec.get_enc_status(enc, 1);
470                 if (error) {
471                         cam_periph_unlock(periph);
472                         break;
473                 }
474                 tmp = cache->enc_status;
475                 cam_periph_unlock(periph);
476                 error = copyout(&tmp, addr, sizeof(tmp));
477                 cache->enc_status = tmp;
478                 break;
479
480         case ENCIOC_SETENCSTAT:
481                 error = copyin(addr, &tmp, sizeof(tmp));
482                 if (error)
483                         break;
484                 cam_periph_lock(periph);
485                 error = enc->enc_vec.set_enc_status(enc, tmp, 1);
486                 cam_periph_unlock(periph);
487                 break;
488
489         case ENCIOC_GETSTRING:
490         case ENCIOC_SETSTRING:
491                 if (enc->enc_vec.handle_string == NULL) {
492                         error = EINVAL;
493                         break;
494                 }
495                 error = copyin(addr, &sstr, sizeof(sstr));
496                 if (error)
497                         break;
498                 cam_periph_lock(periph);
499                 error = enc->enc_vec.handle_string(enc, &sstr, cmd);
500                 cam_periph_unlock(periph);
501                 break;
502
503         case ENCIOC_GETELMSTAT:
504                 error = copyin(addr, &elms, sizeof(elms));
505                 if (error)
506                         break;
507                 if (elms.elm_idx >= cache->nelms) {
508                         error = EINVAL;
509                         break;
510                 }
511                 cam_periph_lock(periph);
512                 error = enc->enc_vec.get_elm_status(enc, &elms, 1);
513                 cam_periph_unlock(periph);
514                 if (error)
515                         break;
516                 error = copyout(&elms, addr, sizeof(elms));
517                 break;
518
519         case ENCIOC_GETELMDESC:
520                 error = copyin(addr, &elmd, sizeof(elmd));
521                 if (error)
522                         break;
523                 if (elmd.elm_idx >= cache->nelms) {
524                         error = EINVAL;
525                         break;
526                 }
527                 if (enc->enc_vec.get_elm_desc != NULL) {
528                         error = enc->enc_vec.get_elm_desc(enc, &elmd);
529                         if (error)
530                                 break;
531                 } else
532                         elmd.elm_desc_len = 0;
533                 error = copyout(&elmd, addr, sizeof(elmd));
534                 break;
535
536         case ENCIOC_GETELMDEVNAMES:
537                 if (enc->enc_vec.get_elm_devnames == NULL) {
538                         error = EINVAL;
539                         break;
540                 }
541                 error = copyin(addr, &elmdn, sizeof(elmdn));
542                 if (error)
543                         break;
544                 if (elmdn.elm_idx >= cache->nelms) {
545                         error = EINVAL;
546                         break;
547                 }
548                 cam_periph_lock(periph);
549                 error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn);
550                 cam_periph_unlock(periph);
551                 if (error)
552                         break;
553                 error = copyout(&elmdn, addr, sizeof(elmdn));
554                 break;
555
556         case ENCIOC_SETELMSTAT:
557                 error = copyin(addr, &elms, sizeof(elms));
558                 if (error)
559                         break;
560
561                 if (elms.elm_idx >= cache->nelms) {
562                         error = EINVAL;
563                         break;
564                 }
565                 cam_periph_lock(periph);
566                 error = enc->enc_vec.set_elm_status(enc, &elms, 1);
567                 cam_periph_unlock(periph);
568
569                 break;
570
571         case ENCIOC_INIT:
572
573                 cam_periph_lock(periph);
574                 error = enc->enc_vec.init_enc(enc);
575                 cam_periph_unlock(periph);
576                 break;
577
578         default:
579                 cam_periph_lock(periph);
580                 error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error);
581                 cam_periph_unlock(periph);
582                 break;
583         }
584         sx_sunlock(&enc->enc_cache_lock);
585         return (error);
586 }
587
588 int
589 enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp)
590 {
591         int error, dlen, tdlen;
592         ccb_flags ddf;
593         union ccb *ccb;
594
595         CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE,
596             ("entering enc_runcmd\n"));
597         if (dptr) {
598                 if ((dlen = *dlenp) < 0) {
599                         dlen = -dlen;
600                         ddf = CAM_DIR_OUT;
601                 } else {
602                         ddf = CAM_DIR_IN;
603                 }
604         } else {
605                 dlen = 0;
606                 ddf = CAM_DIR_NONE;
607         }
608
609         if (cdbl > IOCDBLEN) {
610                 cdbl = IOCDBLEN;
611         }
612
613         ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
614         if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) {
615                 tdlen = min(dlen, 1020);
616                 tdlen = (tdlen + 3) & ~3;
617                 cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen,
618                     30 * 1000);
619                 if (cdb[0] == RECEIVE_DIAGNOSTIC)
620                         ata_28bit_cmd(&ccb->ataio,
621                             ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4);
622                 else if (cdb[0] == SEND_DIAGNOSTIC)
623                         ata_28bit_cmd(&ccb->ataio,
624                             ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
625                             0x82, tdlen / 4);
626                 else if (cdb[0] == READ_BUFFER)
627                         ata_28bit_cmd(&ccb->ataio,
628                             ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4);
629                 else
630                         ata_28bit_cmd(&ccb->ataio,
631                             ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
632                             0x80, tdlen / 4);
633         } else {
634                 tdlen = dlen;
635                 cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG,
636                     dptr, dlen, sizeof (struct scsi_sense_data), cdbl,
637                     60 * 1000);
638                 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
639         }
640
641         error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
642         if (error) {
643                 if (dptr) {
644                         *dlenp = dlen;
645                 }
646         } else {
647                 if (dptr) {
648                         if (ccb->ccb_h.func_code == XPT_ATA_IO)
649                                 *dlenp = ccb->ataio.resid;
650                         else
651                                 *dlenp = ccb->csio.resid;
652                         *dlenp += tdlen - dlen;
653                 }
654         }
655         xpt_release_ccb(ccb);
656         CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
657             ("exiting enc_runcmd: *dlenp = %d\n", *dlenp));
658         return (error);
659 }
660
661 void
662 enc_log(struct enc_softc *enc, const char *fmt, ...)
663 {
664         va_list ap;
665
666         printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number);
667         va_start(ap, fmt);
668         vprintf(fmt, ap);
669         va_end(ap);
670 }
671
672 /*
673  * The code after this point runs on many platforms,
674  * so forgive the slightly awkward and nonconforming
675  * appearance.
676  */
677
678 /*
679  * Is this a device that supports enclosure services?
680  *
681  * It's a pretty simple ruleset- if it is device type
682  * 0x0D (13), it's an ENCLOSURE device.
683  */
684
685 #define SAFTE_START     44
686 #define SAFTE_END       50
687 #define SAFTE_LEN       SAFTE_END-SAFTE_START
688
689 static enctyp
690 enc_type(struct ccb_getdev *cgd)
691 {
692         int buflen;
693         unsigned char *iqd;
694
695         if (cgd->protocol == PROTO_SEMB) {
696                 iqd = (unsigned char *)&cgd->ident_data;
697                 if (STRNCMP(iqd + 43, "S-E-S", 5) == 0)
698                         return (ENC_SEMB_SES);
699                 else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0)
700                         return (ENC_SEMB_SAFT);
701                 return (ENC_NONE);
702
703         } else if (cgd->protocol != PROTO_SCSI)
704                 return (ENC_NONE);
705
706         iqd = (unsigned char *)&cgd->inq_data;
707         buflen = min(sizeof(cgd->inq_data),
708             SID_ADDITIONAL_LENGTH(&cgd->inq_data));
709
710         if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
711                 if ((iqd[2] & 0x7) > 2) {
712                         return (ENC_SES);
713                 } else {
714                         return (ENC_SES_SCSI2);
715                 }
716                 return (ENC_NONE);
717         }
718
719 #ifdef  SES_ENABLE_PASSTHROUGH
720         if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
721                 /*
722                  * PassThrough Device.
723                  */
724                 return (ENC_SES_PASSTHROUGH);
725         }
726 #endif
727
728         /*
729          * The comparison is short for a reason-
730          * some vendors were chopping it short.
731          */
732
733         if (buflen < SAFTE_END - 2) {
734                 return (ENC_NONE);
735         }
736
737         if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
738                 return (ENC_SAFT);
739         }
740         return (ENC_NONE);
741 }
742
743 /*================== Enclosure Monitoring/Processing Daemon ==================*/
744 /**
745  * \brief Queue an update request for a given action, if needed.
746  *
747  * \param enc           SES softc to queue the request for.
748  * \param action        Action requested.
749  */
750 void
751 enc_update_request(enc_softc_t *enc, uint32_t action)
752 {
753         if ((enc->pending_actions & (0x1 << action)) == 0) {
754                 enc->pending_actions |= (0x1 << action);
755                 ENC_DLOG(enc, "%s: queing requested action %d\n",
756                     __func__, action);
757                 if (enc->current_action == ENC_UPDATE_NONE)
758                         wakeup(enc->enc_daemon);
759         } else {
760                 ENC_DLOG(enc, "%s: ignoring requested action %d - "
761                     "Already queued\n", __func__, action);
762         }
763 }
764
765 /**
766  * \brief Invoke the handler of the highest priority pending
767  *        state in the SES state machine.
768  *
769  * \param enc  The SES instance invoking the state machine.
770  */
771 static void
772 enc_fsm_step(enc_softc_t *enc)
773 {
774         union ccb            *ccb;
775         uint8_t              *buf;
776         struct enc_fsm_state *cur_state;
777         int                   error;
778         uint32_t              xfer_len;
779         
780         ENC_DLOG(enc, "%s enter %p\n", __func__, enc);
781
782         enc->current_action   = ffs(enc->pending_actions) - 1;
783         enc->pending_actions &= ~(0x1 << enc->current_action);
784
785         cur_state = &enc->enc_fsm_states[enc->current_action];
786
787         buf = NULL;
788         if (cur_state->buf_size != 0) {
789                 cam_periph_unlock(enc->periph);
790                 buf = malloc(cur_state->buf_size, M_SCSIENC, M_WAITOK|M_ZERO);
791                 cam_periph_lock(enc->periph);
792         }
793
794         error = 0;
795         ccb   = NULL;
796         if (cur_state->fill != NULL) {
797                 ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
798
799                 error = cur_state->fill(enc, cur_state, ccb, buf);
800                 if (error != 0)
801                         goto done;
802
803                 error = cam_periph_runccb(ccb, cur_state->error,
804                                           ENC_CFLAGS,
805                                           ENC_FLAGS|SF_QUIET_IR, NULL);
806         }
807
808         if (ccb != NULL) {
809                 if (ccb->ccb_h.func_code == XPT_ATA_IO)
810                         xfer_len = ccb->ataio.dxfer_len - ccb->ataio.resid;
811                 else
812                         xfer_len = ccb->csio.dxfer_len - ccb->csio.resid;
813         } else
814                 xfer_len = 0;
815
816         cam_periph_unlock(enc->periph);
817         cur_state->done(enc, cur_state, ccb, &buf, error, xfer_len);
818         cam_periph_lock(enc->periph);
819
820 done:
821         ENC_DLOG(enc, "%s exit - result %d\n", __func__, error);
822         ENC_FREE_AND_NULL(buf);
823         if (ccb != NULL)
824                 xpt_release_ccb(ccb);
825 }
826
827 /**
828  * \invariant Called with cam_periph mutex held.
829  */
830 static void
831 enc_status_updater(void *arg)
832 {
833         enc_softc_t *enc;
834
835         enc = arg;
836         if (enc->enc_vec.poll_status != NULL)
837                 enc->enc_vec.poll_status(enc);
838 }
839
840 static void
841 enc_daemon(void *arg)
842 {
843         enc_softc_t *enc;
844
845         enc = arg;
846
847         cam_periph_lock(enc->periph);
848         while ((enc->enc_flags & ENC_FLAG_SHUTDOWN) == 0) {
849                 if (enc->pending_actions == 0) {
850                         struct intr_config_hook *hook;
851
852                         /*
853                          * Reset callout and msleep, or
854                          * issue timed task completion
855                          * status command.
856                          */
857                         enc->current_action = ENC_UPDATE_NONE;
858
859                         /*
860                          * We've been through our state machine at least
861                          * once.  Allow the transition to userland.
862                          */
863                         hook = &enc->enc_boot_hold_ch;
864                         if (hook->ich_func != NULL) {
865                                 config_intrhook_disestablish(hook);
866                                 hook->ich_func = NULL;
867                         }
868
869                         callout_reset(&enc->status_updater, 60*hz,
870                                       enc_status_updater, enc);
871
872                         cam_periph_sleep(enc->periph, enc->enc_daemon,
873                                          PUSER, "idle", 0);
874                 } else {
875                         enc_fsm_step(enc);
876                 }
877         }
878         enc->enc_daemon = NULL;
879         cam_periph_unlock(enc->periph);
880         cam_periph_release(enc->periph);
881         kproc_exit(0);
882 }
883
884 static int
885 enc_kproc_init(enc_softc_t *enc)
886 {
887         int result;
888
889         callout_init_mtx(&enc->status_updater, enc->periph->sim->mtx, 0);
890
891         if (cam_periph_acquire(enc->periph) != CAM_REQ_CMP)
892                 return (ENXIO);
893
894         result = kproc_create(enc_daemon, enc, &enc->enc_daemon, /*flags*/0,
895                               /*stackpgs*/0, "enc_daemon%d",
896                               enc->periph->unit_number);
897         if (result == 0) {
898                 /* Do an initial load of all page data. */
899                 cam_periph_lock(enc->periph);
900                 enc->enc_vec.poll_status(enc);
901                 cam_periph_unlock(enc->periph);
902         } else
903                 cam_periph_release(enc->periph);
904         return (result);
905 }
906  
907 /**
908  * \brief Interrupt configuration hook callback associated with
909  *        enc_boot_hold_ch.
910  *
911  * Since interrupts are always functional at the time of enclosure
912  * configuration, there is nothing to be done when the callback occurs.
913  * This hook is only registered to hold up boot processing while initial
914  * eclosure processing occurs.
915  * 
916  * \param arg  The enclosure softc, but currently unused in this callback.
917  */
918 static void
919 enc_nop_confighook_cb(void *arg __unused)
920 {
921 }
922
923 static cam_status
924 enc_ctor(struct cam_periph *periph, void *arg)
925 {
926         cam_status status = CAM_REQ_CMP_ERR;
927         int err;
928         enc_softc_t *enc;
929         struct ccb_getdev *cgd;
930         char *tname;
931
932         cgd = (struct ccb_getdev *)arg;
933         if (cgd == NULL) {
934                 printf("enc_ctor: no getdev CCB, can't register device\n");
935                 goto out;
936         }
937
938         enc = ENC_MALLOCZ(sizeof(*enc));
939         if (enc == NULL) {
940                 printf("enc_ctor: Unable to probe new device. "
941                        "Unable to allocate enc\n");                             
942                 goto out;
943         }
944         enc->periph = periph;
945         enc->current_action = ENC_UPDATE_INVALID;
946
947         enc->enc_type = enc_type(cgd);
948         sx_init(&enc->enc_cache_lock, "enccache");
949
950         switch (enc->enc_type) {
951         case ENC_SES:
952         case ENC_SES_SCSI2:
953         case ENC_SES_PASSTHROUGH:
954         case ENC_SEMB_SES:
955                 err = ses_softc_init(enc);
956                 break;
957         case ENC_SAFT:
958         case ENC_SEMB_SAFT:
959                 err = safte_softc_init(enc);
960                 break;
961         case ENC_NONE:
962         default:
963                 ENC_FREE(enc);
964                 return (CAM_REQ_CMP_ERR);
965         }
966
967         if (err) {
968                 xpt_print(periph->path, "error %d initializing\n", err);
969                 goto out;
970         }
971
972         /*
973          * Hold off userland until we have made at least one pass
974          * through our state machine so that physical path data is
975          * present.
976          */
977         if (enc->enc_vec.poll_status != NULL) {
978                 enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb;
979                 enc->enc_boot_hold_ch.ich_arg = enc;
980                 config_intrhook_establish(&enc->enc_boot_hold_ch);
981         }
982
983         /*
984          * The softc field is set only once the enc is fully initialized
985          * so that we can rely on this field to detect partially
986          * initialized periph objects in the AC_FOUND_DEVICE handler.
987          */
988         periph->softc = enc;
989
990         cam_periph_unlock(periph);
991         if (enc->enc_vec.poll_status != NULL) {
992                 err = enc_kproc_init(enc);
993                 if (err) {
994                         xpt_print(periph->path,
995                                   "error %d starting enc_daemon\n", err);
996                         goto out;
997                 }
998         }
999
1000         /*
1001          * Acquire a reference to the periph before we create the devfs
1002          * instance for it.  We'll release this reference once the devfs
1003          * instance has been freed.
1004          */
1005         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
1006                 xpt_print(periph->path, "%s: lost periph during "
1007                           "registration!\n", __func__);
1008                 cam_periph_lock(periph);
1009
1010                 return (CAM_REQ_CMP_ERR);
1011         }
1012
1013         enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number,
1014             UID_ROOT, GID_OPERATOR, 0600, "%s%d",
1015             periph->periph_name, periph->unit_number);
1016
1017         cam_periph_lock(periph);
1018         enc->enc_dev->si_drv1 = periph;
1019
1020         enc->enc_flags |= ENC_FLAG_INITIALIZED;
1021
1022         /*
1023          * Add an async callback so that we get notified if this
1024          * device goes away.
1025          */
1026         xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path);
1027
1028         switch (enc->enc_type) {
1029         default:
1030         case ENC_NONE:
1031                 tname = "No ENC device";
1032                 break;
1033         case ENC_SES_SCSI2:
1034                 tname = "SCSI-2 ENC Device";
1035                 break;
1036         case ENC_SES:
1037                 tname = "SCSI-3 ENC Device";
1038                 break;
1039         case ENC_SES_PASSTHROUGH:
1040                 tname = "ENC Passthrough Device";
1041                 break;
1042         case ENC_SAFT:
1043                 tname = "SAF-TE Compliant Device";
1044                 break;
1045         case ENC_SEMB_SES:
1046                 tname = "SEMB SES Device";
1047                 break;
1048         case ENC_SEMB_SAFT:
1049                 tname = "SEMB SAF-TE Device";
1050                 break;
1051         }
1052         xpt_announce_periph(periph, tname);
1053         status = CAM_REQ_CMP;
1054
1055 out:
1056         if (status != CAM_REQ_CMP)
1057                 enc_dtor(periph);
1058         return (status);
1059 }
1060