[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_ses.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/cam/scsi/scsi_ses.c,v 1.39 2008/09/27 08:51:18 ed Exp $");
 29 
 30 #include <sys/param.h>
 31 #include <sys/queue.h>
 32 #include <sys/systm.h>
 33 #include <sys/kernel.h>
 34 #include <sys/types.h>
 35 #include <sys/malloc.h>
 36 #include <sys/fcntl.h>
 37 #include <sys/conf.h>
 38 #include <sys/errno.h>
 39 #include <machine/stdarg.h>
 40 
 41 #include <cam/cam.h>
 42 #include <cam/cam_ccb.h>
 43 #include <cam/cam_periph.h>
 44 #include <cam/cam_xpt_periph.h>
 45 #include <cam/cam_debug.h>
 46 #include <cam/cam_sim.h>
 47 
 48 #include <cam/scsi/scsi_all.h>
 49 #include <cam/scsi/scsi_message.h>
 50 #include <sys/ioccom.h>
 51 #include <cam/scsi/scsi_ses.h>
 52 
 53 #include <opt_ses.h>
 54 
 55 MALLOC_DEFINE(M_SCSISES, "SCSI SES", "SCSI SES buffers");
 56 
 57 /*
 58  * Platform Independent Driver Internal Definitions for SES devices.
 59  */
 60 typedef enum {
 61         SES_NONE,
 62         SES_SES_SCSI2,
 63         SES_SES,
 64         SES_SES_PASSTHROUGH,
 65         SES_SEN,
 66         SES_SAFT
 67 } enctyp;
 68 
 69 struct ses_softc;
 70 typedef struct ses_softc ses_softc_t;
 71 typedef struct {
 72         int (*softc_init)(ses_softc_t *, int);
 73         int (*init_enc)(ses_softc_t *);
 74         int (*get_encstat)(ses_softc_t *, int);
 75         int (*set_encstat)(ses_softc_t *, ses_encstat, int);
 76         int (*get_objstat)(ses_softc_t *, ses_objstat *, int);
 77         int (*set_objstat)(ses_softc_t *, ses_objstat *, int);
 78 } encvec;
 79 
 80 #define ENCI_SVALID     0x80
 81 
 82 typedef struct {
 83         uint32_t
 84                 enctype : 8,            /* enclosure type */
 85                 subenclosure : 8,       /* subenclosure id */
 86                 svalid  : 1,            /* enclosure information valid */
 87                 priv    : 15;           /* private data, per object */
 88         uint8_t encstat[4];     /* state && stats */
 89 } encobj;
 90 
 91 #define SEN_ID          "UNISYS           SUN_SEN"
 92 #define SEN_ID_LEN      24
 93 
 94 
 95 static enctyp ses_type(void *, int);
 96 
 97 
 98 /* Forward reference to Enclosure Functions */
 99 static int ses_softc_init(ses_softc_t *, int);
100 static int ses_init_enc(ses_softc_t *);
101 static int ses_get_encstat(ses_softc_t *, int);
102 static int ses_set_encstat(ses_softc_t *, uint8_t, int);
103 static int ses_get_objstat(ses_softc_t *, ses_objstat *, int);
104 static int ses_set_objstat(ses_softc_t *, ses_objstat *, int);
105 
106 static int safte_softc_init(ses_softc_t *, int);
107 static int safte_init_enc(ses_softc_t *);
108 static int safte_get_encstat(ses_softc_t *, int);
109 static int safte_set_encstat(ses_softc_t *, uint8_t, int);
110 static int safte_get_objstat(ses_softc_t *, ses_objstat *, int);
111 static int safte_set_objstat(ses_softc_t *, ses_objstat *, int);
112 
113 /*
114  * Platform implementation defines/functions for SES internal kernel stuff
115  */
116 
117 #define STRNCMP                 strncmp
118 #define PRINTF                  printf
119 #define SES_LOG                 ses_log
120 #ifdef  DEBUG
121 #define SES_DLOG                ses_log
122 #else
123 #define SES_DLOG                if (0) ses_log
124 #endif
125 #define SES_VLOG                if (bootverbose) ses_log
126 #define SES_MALLOC(amt)         malloc(amt, M_SCSISES, M_NOWAIT)
127 #define SES_FREE(ptr, amt)      free(ptr, M_SCSISES)
128 #define MEMZERO                 bzero
129 #define MEMCPY(dest, src, amt)  bcopy(src, dest, amt)
130 
131 static int ses_runcmd(struct ses_softc *, char *, int, char *, int *);
132 static void ses_log(struct ses_softc *, const char *, ...);
133 
134 /*
135  * Gerenal FreeBSD kernel stuff.
136  */
137 
138 
139 #define ccb_state       ppriv_field0
140 #define ccb_bp          ppriv_ptr1
141 
142 struct ses_softc {
143         enctyp          ses_type;       /* type of enclosure */
144         encvec          ses_vec;        /* vector to handlers */
145         void *          ses_private;    /* per-type private data */
146         encobj *        ses_objmap;     /* objects */
147         uint32_t        ses_nobjects;   /* number of objects */
148         ses_encstat     ses_encstat;    /* overall status */
149         uint8_t ses_flags;
150         union ccb       ses_saved_ccb;
151         struct cdev *ses_dev;
152         struct cam_periph *periph;
153 };
154 #define SES_FLAG_INVALID        0x01
155 #define SES_FLAG_OPEN           0x02
156 #define SES_FLAG_INITIALIZED    0x04
157 
158 #define SESUNIT(x)       (dev2unit((x)))
159 
160 static  d_open_t        sesopen;
161 static  d_close_t       sesclose;
162 static  d_ioctl_t       sesioctl;
163 static  periph_init_t   sesinit;
164 static  periph_ctor_t   sesregister;
165 static  periph_oninv_t  sesoninvalidate;
166 static  periph_dtor_t   sescleanup;
167 static  periph_start_t  sesstart;
168 
169 static void sesasync(void *, uint32_t, struct cam_path *, void *);
170 static void sesdone(struct cam_periph *, union ccb *);
171 static int seserror(union ccb *, uint32_t, uint32_t);
172 
173 static struct periph_driver sesdriver = {
174         sesinit, "ses",
175         TAILQ_HEAD_INITIALIZER(sesdriver.units), /* generation */ 0
176 };
177 
178 PERIPHDRIVER_DECLARE(ses, sesdriver);
179 
180 static struct cdevsw ses_cdevsw = {
181         .d_version =    D_VERSION,
182         .d_open =       sesopen,
183         .d_close =      sesclose,
184         .d_ioctl =      sesioctl,
185         .d_name =       "ses",
186         .d_flags =      0,
187 };
188 
189 static void
190 sesinit(void)
191 {
192         cam_status status;
193 
194         /*
195          * Install a global async callback.  This callback will
196          * receive async callbacks like "new device found".
197          */
198         status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL);
199 
200         if (status != CAM_REQ_CMP) {
201                 printf("ses: Failed to attach master async callback "
202                        "due to status 0x%x!\n", status);
203         }
204 }
205 
206 static void
207 sesoninvalidate(struct cam_periph *periph)
208 {
209         struct ses_softc *softc;
210 
211         softc = (struct ses_softc *)periph->softc;
212 
213         /*
214          * Unregister any async callbacks.
215          */
216         xpt_register_async(0, sesasync, periph, periph->path);
217 
218         softc->ses_flags |= SES_FLAG_INVALID;
219 
220         xpt_print(periph->path, "lost device\n");
221 }
222 
223 static void
224 sescleanup(struct cam_periph *periph)
225 {
226         struct ses_softc *softc;
227 
228         softc = (struct ses_softc *)periph->softc;
229 
230         destroy_dev(softc->ses_dev);
231 
232         xpt_print(periph->path, "removing device entry\n");
233         free(softc, M_SCSISES);
234 }
235 
236 static void
237 sesasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
238 {
239         struct cam_periph *periph;
240 
241         periph = (struct cam_periph *)callback_arg;
242 
243         switch(code) {
244         case AC_FOUND_DEVICE:
245         {
246                 cam_status status;
247                 struct ccb_getdev *cgd;
248                 int inq_len;
249 
250                 cgd = (struct ccb_getdev *)arg;
251                 if (arg == NULL) {
252                         break;
253                 }
254 
255                 inq_len = cgd->inq_data.additional_length + 4;
256 
257                 /*
258                  * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS
259                  * PROBLEM: IS A SAF-TE DEVICE.
260                  */
261                 switch (ses_type(&cgd->inq_data, inq_len)) {
262                 case SES_SES:
263                 case SES_SES_SCSI2:
264                 case SES_SES_PASSTHROUGH:
265                 case SES_SEN:
266                 case SES_SAFT:
267                         break;
268                 default:
269                         return;
270                 }
271 
272                 status = cam_periph_alloc(sesregister, sesoninvalidate,
273                     sescleanup, sesstart, "ses", CAM_PERIPH_BIO,
274                     cgd->ccb_h.path, sesasync, AC_FOUND_DEVICE, cgd);
275 
276                 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
277                         printf("sesasync: Unable to probe new device due to "
278                             "status 0x%x\n", status);
279                 }
280                 break;
281         }
282         default:
283                 cam_periph_async(periph, code, path, arg);
284                 break;
285         }
286 }
287 
288 static cam_status
289 sesregister(struct cam_periph *periph, void *arg)
290 {
291         struct ses_softc *softc;
292         struct ccb_getdev *cgd;
293         char *tname;
294 
295         cgd = (struct ccb_getdev *)arg;
296         if (periph == NULL) {
297                 printf("sesregister: periph was NULL!!\n");
298                 return (CAM_REQ_CMP_ERR);
299         }
300 
301         if (cgd == NULL) {
302                 printf("sesregister: no getdev CCB, can't register device\n");
303                 return (CAM_REQ_CMP_ERR);
304         }
305 
306         softc = SES_MALLOC(sizeof (struct ses_softc));
307         if (softc == NULL) {
308                 printf("sesregister: Unable to probe new device. "
309                        "Unable to allocate softc\n");                           
310                 return (CAM_REQ_CMP_ERR);
311         }
312         bzero(softc, sizeof (struct ses_softc));
313         periph->softc = softc;
314         softc->periph = periph;
315 
316         softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data));
317 
318         switch (softc->ses_type) {
319         case SES_SES:
320         case SES_SES_SCSI2:
321         case SES_SES_PASSTHROUGH:
322                 softc->ses_vec.softc_init = ses_softc_init;
323                 softc->ses_vec.init_enc = ses_init_enc;
324                 softc->ses_vec.get_encstat = ses_get_encstat;
325                 softc->ses_vec.set_encstat = ses_set_encstat;
326                 softc->ses_vec.get_objstat = ses_get_objstat;
327                 softc->ses_vec.set_objstat = ses_set_objstat;
328                 break;
329         case SES_SAFT:
330                 softc->ses_vec.softc_init = safte_softc_init;
331                 softc->ses_vec.init_enc = safte_init_enc;
332                 softc->ses_vec.get_encstat = safte_get_encstat;
333                 softc->ses_vec.set_encstat = safte_set_encstat;
334                 softc->ses_vec.get_objstat = safte_get_objstat;
335                 softc->ses_vec.set_objstat = safte_set_objstat;
336                 break;
337         case SES_SEN:
338                 break;
339         case SES_NONE:
340         default:
341                 free(softc, M_SCSISES);
342                 return (CAM_REQ_CMP_ERR);
343         }
344 
345         cam_periph_unlock(periph);
346         softc->ses_dev = make_dev(&ses_cdevsw, periph->unit_number,
347             UID_ROOT, GID_OPERATOR, 0600, "%s%d",
348             periph->periph_name, periph->unit_number);
349         cam_periph_lock(periph);
350         softc->ses_dev->si_drv1 = periph;
351 
352         /*
353          * Add an async callback so that we get
354          * notified if this device goes away.
355          */
356         xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path);
357 
358         switch (softc->ses_type) {
359         default:
360         case SES_NONE:
361                 tname = "No SES device";
362                 break;
363         case SES_SES_SCSI2:
364                 tname = "SCSI-2 SES Device";
365                 break;
366         case SES_SES:
367                 tname = "SCSI-3 SES Device";
368                 break;
369         case SES_SES_PASSTHROUGH:
370                 tname = "SES Passthrough Device";
371                 break;
372         case SES_SEN:
373                 tname = "UNISYS SEN Device (NOT HANDLED YET)";
374                 break;
375         case SES_SAFT:
376                 tname = "SAF-TE Compliant Device";
377                 break;
378         }
379         xpt_announce_periph(periph, tname);
380         return (CAM_REQ_CMP);
381 }
382 
383 static int
384 sesopen(struct cdev *dev, int flags, int fmt, struct thread *td)
385 {
386         struct cam_periph *periph;
387         struct ses_softc *softc;
388         int error = 0;
389 
390         periph = (struct cam_periph *)dev->si_drv1;
391         if (periph == NULL) {
392                 return (ENXIO);
393         }
394 
395         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
396                 cam_periph_unlock(periph);
397                 return (ENXIO);
398         }
399 
400         cam_periph_lock(periph);
401 
402         softc = (struct ses_softc *)periph->softc;
403 
404         if (softc->ses_flags & SES_FLAG_INVALID) {
405                 error = ENXIO;
406                 goto out;
407         }
408         if (softc->ses_flags & SES_FLAG_OPEN) {
409                 error = EBUSY;
410                 goto out;
411         }
412         if (softc->ses_vec.softc_init == NULL) {
413                 error = ENXIO;
414                 goto out;
415         }
416 
417         softc->ses_flags |= SES_FLAG_OPEN;
418         if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
419                 error = (*softc->ses_vec.softc_init)(softc, 1);
420                 if (error)
421                         softc->ses_flags &= ~SES_FLAG_OPEN;
422                 else
423                         softc->ses_flags |= SES_FLAG_INITIALIZED;
424         }
425 
426 out:
427         cam_periph_unlock(periph);
428         if (error) {
429                 cam_periph_release(periph);
430         }
431         return (error);
432 }
433 
434 static int
435 sesclose(struct cdev *dev, int flag, int fmt, struct thread *td)
436 {
437         struct cam_periph *periph;
438         struct ses_softc *softc;
439         int error;
440 
441         error = 0;
442 
443         periph = (struct cam_periph *)dev->si_drv1;
444         if (periph == NULL)
445                 return (ENXIO);
446 
447         cam_periph_lock(periph);
448 
449         softc = (struct ses_softc *)periph->softc;
450         softc->ses_flags &= ~SES_FLAG_OPEN;
451 
452         cam_periph_unlock(periph);
453         cam_periph_release(periph);
454 
455         return (0);
456 }
457 
458 static void
459 sesstart(struct cam_periph *p, union ccb *sccb)
460 {
461         if (p->immediate_priority <= p->pinfo.priority) {
462                 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
463                 p->immediate_priority = CAM_PRIORITY_NONE;
464                 wakeup(&p->ccb_list);
465         }
466 }
467 
468 static void
469 sesdone(struct cam_periph *periph, union ccb *dccb)
470 {
471         wakeup(&dccb->ccb_h.cbfcnp);
472 }
473 
474 static int
475 seserror(union ccb *ccb, uint32_t cflags, uint32_t sflags)
476 {
477         struct ses_softc *softc;
478         struct cam_periph *periph;
479 
480         periph = xpt_path_periph(ccb->ccb_h.path);
481         softc = (struct ses_softc *)periph->softc;
482 
483         return (cam_periph_error(ccb, cflags, sflags, &softc->ses_saved_ccb));
484 }
485 
486 static int
487 sesioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, struct thread *td)
488 {
489         struct cam_periph *periph;
490         ses_encstat tmp;
491         ses_objstat objs;
492         ses_object *uobj;
493         struct ses_softc *ssc;
494         void *addr;
495         int error, i;
496 
497 
498         if (arg_addr)
499                 addr = *((caddr_t *) arg_addr);
500         else
501                 addr = NULL;
502 
503         periph = (struct cam_periph *)dev->si_drv1;
504         if (periph == NULL)
505                 return (ENXIO);
506 
507         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n"));
508 
509         cam_periph_lock(periph);
510         ssc = (struct ses_softc *)periph->softc;
511 
512         /*
513          * Now check to see whether we're initialized or not.
514          * This actually should never fail as we're not supposed
515          * to get past ses_open w/o successfully initializing
516          * things.
517          */
518         if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
519                 cam_periph_unlock(periph);
520                 return (ENXIO);
521         }
522         cam_periph_unlock(periph);
523 
524         error = 0;
525 
526         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
527             ("trying to do ioctl %#lx\n", cmd));
528 
529         /*
530          * If this command can change the device's state,
531          * we must have the device open for writing.
532          *
533          * For commands that get information about the
534          * device- we don't need to lock the peripheral
535          * if we aren't running a command. The number
536          * of objects and the contents will stay stable
537          * after the first open that does initialization.
538          * The periph also can't go away while a user
539          * process has it open.
540          */
541         switch (cmd) {
542         case SESIOC_GETNOBJ:
543         case SESIOC_GETOBJMAP:
544         case SESIOC_GETENCSTAT:
545         case SESIOC_GETOBJSTAT:
546                 break;
547         default:
548                 if ((flag & FWRITE) == 0) {
549                         return (EBADF);
550                 }
551         }
552 
553         switch (cmd) {
554         case SESIOC_GETNOBJ:
555                 error = copyout(&ssc->ses_nobjects, addr,
556                     sizeof (ssc->ses_nobjects));
557                 break;
558                 
559         case SESIOC_GETOBJMAP:
560                 for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++) {
561                         ses_object kobj;
562                         kobj.obj_id = i;
563                         kobj.subencid = ssc->ses_objmap[i].subenclosure;
564                         kobj.object_type = ssc->ses_objmap[i].enctype;
565                         error = copyout(&kobj, &uobj[i], sizeof (ses_object));
566                         if (error) {
567                                 break;
568                         }
569                 }
570                 break;
571 
572         case SESIOC_GETENCSTAT:
573                 cam_periph_lock(periph);
574                 error = (*ssc->ses_vec.get_encstat)(ssc, 1);
575                 if (error) {
576                         cam_periph_unlock(periph);
577                         break;
578                 }
579                 tmp = ssc->ses_encstat & ~ENCI_SVALID;
580                 cam_periph_unlock(periph);
581                 error = copyout(&tmp, addr, sizeof (ses_encstat));
582                 ssc->ses_encstat = tmp;
583                 break;
584 
585         case SESIOC_SETENCSTAT:
586                 error = copyin(addr, &tmp, sizeof (ses_encstat));
587                 if (error)
588                         break;
589                 cam_periph_lock(periph);
590                 error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
591                 cam_periph_unlock(periph);
592                 break;
593 
594         case SESIOC_GETOBJSTAT:
595                 error = copyin(addr, &objs, sizeof (ses_objstat));
596                 if (error)
597                         break;
598                 if (objs.obj_id >= ssc->ses_nobjects) {
599                         error = EINVAL;
600                         break;
601                 }
602                 cam_periph_lock(periph);
603                 error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
604                 cam_periph_unlock(periph);
605                 if (error)
606                         break;
607                 error = copyout(&objs, addr, sizeof (ses_objstat));
608                 /*
609                  * Always (for now) invalidate entry.
610                  */
611                 ssc->ses_objmap[objs.obj_id].svalid = 0;
612                 break;
613 
614         case SESIOC_SETOBJSTAT:
615                 error = copyin(addr, &objs, sizeof (ses_objstat));
616                 if (error)
617                         break;
618 
619                 if (objs.obj_id >= ssc->ses_nobjects) {
620                         error = EINVAL;
621                         break;
622                 }
623                 cam_periph_lock(periph);
624                 error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
625                 cam_periph_unlock(periph);
626 
627                 /*
628                  * Always (for now) invalidate entry.
629                  */
630                 ssc->ses_objmap[objs.obj_id].svalid = 0;
631                 break;
632 
633         case SESIOC_INIT:
634 
635                 cam_periph_lock(periph);
636                 error = (*ssc->ses_vec.init_enc)(ssc);
637                 cam_periph_unlock(periph);
638                 break;
639 
640         default:
641                 cam_periph_lock(periph);
642                 error = cam_periph_ioctl(periph, cmd, arg_addr, seserror);
643                 cam_periph_unlock(periph);
644                 break;
645         }
646         return (error);
647 }
648 
649 #define SES_CFLAGS      CAM_RETRY_SELTO
650 #define SES_FLAGS       SF_NO_PRINT | SF_RETRY_UA
651 static int
652 ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp)
653 {
654         int error, dlen;
655         ccb_flags ddf;
656         union ccb *ccb;
657 
658         if (dptr) {
659                 if ((dlen = *dlenp) < 0) {
660                         dlen = -dlen;
661                         ddf = CAM_DIR_OUT;
662                 } else {
663                         ddf = CAM_DIR_IN;
664                 }
665         } else {
666                 dlen = 0;
667                 ddf = CAM_DIR_NONE;
668         }
669 
670         if (cdbl > IOCDBLEN) {
671                 cdbl = IOCDBLEN;
672         }
673 
674         ccb = cam_periph_getccb(ssc->periph, 1);
675         cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, dptr,
676             dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000);
677         bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
678 
679         error = cam_periph_runccb(ccb, seserror, SES_CFLAGS, SES_FLAGS, NULL);
680         if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
681                 cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
682         if (error) {
683                 if (dptr) {
684                         *dlenp = dlen;
685                 }
686         } else {
687                 if (dptr) {
688                         *dlenp = ccb->csio.resid;
689                 }
690         }
691         xpt_release_ccb(ccb);
692         return (error);
693 }
694 
695 static void
696 ses_log(struct ses_softc *ssc, const char *fmt, ...)
697 {
698         va_list ap;
699 
700         printf("%s%d: ", ssc->periph->periph_name, ssc->periph->unit_number);
701         va_start(ap, fmt);
702         vprintf(fmt, ap);
703         va_end(ap);
704 }
705 
706 /*
707  * The code after this point runs on many platforms,
708  * so forgive the slightly awkward and nonconforming
709  * appearance.
710  */
711 
712 /*
713  * Is this a device that supports enclosure services?
714  *
715  * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's
716  * an SES device. If it happens to be an old UNISYS SEN device, we can
717  * handle that too.
718  */
719 
720 #define SAFTE_START     44
721 #define SAFTE_END       50
722 #define SAFTE_LEN       SAFTE_END-SAFTE_START
723 
724 static enctyp
725 ses_type(void *buf, int buflen)
726 {
727         unsigned char *iqd = buf;
728 
729         if (buflen < 8+SEN_ID_LEN)
730                 return (SES_NONE);
731 
732         if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
733                 if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) {
734                         return (SES_SEN);
735                 } else if ((iqd[2] & 0x7) > 2) {
736                         return (SES_SES);
737                 } else {
738                         return (SES_SES_SCSI2);
739                 }
740                 return (SES_NONE);
741         }
742 
743 #ifdef  SES_ENABLE_PASSTHROUGH
744         if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
745                 /*
746                  * PassThrough Device.
747                  */
748                 return (SES_SES_PASSTHROUGH);
749         }
750 #endif
751 
752         /*
753          * The comparison is short for a reason-
754          * some vendors were chopping it short.
755          */
756 
757         if (buflen < SAFTE_END - 2) {
758                 return (SES_NONE);
759         }
760 
761         if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
762                 return (SES_SAFT);
763         }
764         return (SES_NONE);
765 }
766 
767 /*
768  * SES Native Type Device Support
769  */
770 
771 /*
772  * SES Diagnostic Page Codes
773  */
774 
775 typedef enum {
776         SesConfigPage = 0x1,
777         SesControlPage,
778 #define SesStatusPage SesControlPage
779         SesHelpTxt,
780         SesStringOut,
781 #define SesStringIn     SesStringOut
782         SesThresholdOut,
783 #define SesThresholdIn SesThresholdOut
784         SesArrayControl,
785 #define SesArrayStatus  SesArrayControl
786         SesElementDescriptor,
787         SesShortStatus
788 } SesDiagPageCodes;
789 
790 /*
791  * minimal amounts
792  */
793 
794 /*
795  * Minimum amount of data, starting from byte 0, to have
796  * the config header.
797  */
798 #define SES_CFGHDR_MINLEN       12
799 
800 /*
801  * Minimum amount of data, starting from byte 0, to have
802  * the config header and one enclosure header.
803  */
804 #define SES_ENCHDR_MINLEN       48
805 
806 /*
807  * Take this value, subtract it from VEnclen and you know
808  * the length of the vendor unique bytes.
809  */
810 #define SES_ENCHDR_VMIN         36
811 
812 /*
813  * SES Data Structures
814  */
815 
816 typedef struct {
817         uint32_t GenCode;       /* Generation Code */
818         uint8_t Nsubenc;        /* Number of Subenclosures */
819 } SesCfgHdr;
820 
821 typedef struct {
822         uint8_t Subencid;       /* SubEnclosure Identifier */
823         uint8_t Ntypes;         /* # of supported types */
824         uint8_t VEnclen;        /* Enclosure Descriptor Length */
825 } SesEncHdr;
826 
827 typedef struct {
828         uint8_t encWWN[8];      /* XXX- Not Right Yet */
829         uint8_t encVid[8];
830         uint8_t encPid[16];
831         uint8_t encRev[4];
832         uint8_t encVen[1];
833 } SesEncDesc;
834 
835 typedef struct {
836         uint8_t enc_type;               /* type of element */
837         uint8_t enc_maxelt;             /* maximum supported */
838         uint8_t enc_subenc;             /* in SubEnc # N */
839         uint8_t enc_tlen;               /* Type Descriptor Text Length */
840 } SesThdr;
841 
842 typedef struct {
843         uint8_t comstatus;
844         uint8_t comstat[3];
845 } SesComStat;
846 
847 struct typidx {
848         int ses_tidx;
849         int ses_oidx;
850 };
851 
852 struct sscfg {
853         uint8_t ses_ntypes;     /* total number of types supported */
854 
855         /*
856          * We need to keep a type index as well as an
857          * object index for each object in an enclosure.
858          */
859         struct typidx *ses_typidx;
860 
861         /*
862          * We also need to keep track of the number of elements
863          * per type of element. This is needed later so that we
864          * can find precisely in the returned status data the
865          * status for the Nth element of the Kth type.
866          */
867         uint8_t *       ses_eltmap;
868 };
869 
870 
871 /*
872  * (de)canonicalization defines
873  */
874 #define sbyte(x, byte)          ((((uint32_t)(x)) >> (byte * 8)) & 0xff)
875 #define sbit(x, bit)            (((uint32_t)(x)) << bit)
876 #define sset8(outp, idx, sval)  (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
877 
878 #define sset16(outp, idx, sval) \
879         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
880         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
881 
882 
883 #define sset24(outp, idx, sval) \
884         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
885         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
886         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
887 
888 
889 #define sset32(outp, idx, sval) \
890         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \
891         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
892         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
893         (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
894 
895 #define gbyte(x, byte)  ((((uint32_t)(x)) & 0xff) << (byte * 8))
896 #define gbit(lv, in, idx, shft, mask)   lv = ((in[idx] >> shft) & mask)
897 #define sget8(inp, idx, lval)   lval = (((uint8_t *)(inp))[idx++])
898 #define gget8(inp, idx, lval)   lval = (((uint8_t *)(inp))[idx])
899 
900 #define sget16(inp, idx, lval)  \
901         lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
902                 (((uint8_t *)(inp))[idx+1]), idx += 2
903 
904 #define gget16(inp, idx, lval)  \
905         lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
906                 (((uint8_t *)(inp))[idx+1])
907 
908 #define sget24(inp, idx, lval)  \
909         lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
910                 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
911                         (((uint8_t *)(inp))[idx+2]), idx += 3
912 
913 #define gget24(inp, idx, lval)  \
914         lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
915                 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
916                         (((uint8_t *)(inp))[idx+2])
917 
918 #define sget32(inp, idx, lval)  \
919         lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
920                 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
921                 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
922                         (((uint8_t *)(inp))[idx+3]), idx += 4
923 
924 #define gget32(inp, idx, lval)  \
925         lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
926                 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
927                 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
928                         (((uint8_t *)(inp))[idx+3])
929 
930 #define SCSZ    0x2000
931 #define CFLEN   (256 + SES_ENCHDR_MINLEN)
932 
933 /*
934  * Routines specific && private to SES only
935  */
936 
937 static int ses_getconfig(ses_softc_t *);
938 static int ses_getputstat(ses_softc_t *, int, SesComStat *, int, int);
939 static int ses_cfghdr(uint8_t *, int, SesCfgHdr *);
940 static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr *);
941 static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc *);
942 static int ses_getthdr(uint8_t *, int,  int, SesThdr *);
943 static int ses_decode(char *, int, uint8_t *, int, int, SesComStat *);
944 static int ses_encode(char *, int, uint8_t *, int, int, SesComStat *);
945 
946 static int
947 ses_softc_init(ses_softc_t *ssc, int doinit)
948 {
949         if (doinit == 0) {
950                 struct sscfg *cc;
951                 if (ssc->ses_nobjects) {
952                         SES_FREE(ssc->ses_objmap,
953                             ssc->ses_nobjects * sizeof (encobj));
954                         ssc->ses_objmap = NULL;
955                 }
956                 if ((cc = ssc->ses_private) != NULL) {
957                         if (cc->ses_eltmap && cc->ses_ntypes) {
958                                 SES_FREE(cc->ses_eltmap, cc->ses_ntypes);
959                                 cc->ses_eltmap = NULL;
960                                 cc->ses_ntypes = 0;
961                         }
962                         if (cc->ses_typidx && ssc->ses_nobjects) {
963                                 SES_FREE(cc->ses_typidx,
964                                     ssc->ses_nobjects * sizeof (struct typidx));
965                                 cc->ses_typidx = NULL;
966                         }
967                         SES_FREE(cc, sizeof (struct sscfg));
968                         ssc->ses_private = NULL;
969                 }
970                 ssc->ses_nobjects = 0;
971                 return (0);
972         }
973         if (ssc->ses_private == NULL) {
974                 ssc->ses_private = SES_MALLOC(sizeof (struct sscfg));
975         }
976         if (ssc->ses_private == NULL) {
977                 return (ENOMEM);
978         }
979         ssc->ses_nobjects = 0;
980         ssc->ses_encstat = 0;
981         return (ses_getconfig(ssc));
982 }
983 
984 static int
985 ses_init_enc(ses_softc_t *ssc)
986 {
987         return (0);
988 }
989 
990 static int
991 ses_get_encstat(ses_softc_t *ssc, int slpflag)
992 {
993         SesComStat ComStat;
994         int status;
995 
996         if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) {
997                 return (status);
998         }
999         ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID;
1000         return (0);
1001 }
1002 
1003 static int
1004 ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag)
1005 {
1006         SesComStat ComStat;
1007         int status;
1008 
1009         ComStat.comstatus = encstat & 0xf;
1010         if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) {
1011                 return (status);
1012         }
1013         ssc->ses_encstat = encstat & 0xf;       /* note no SVALID set */
1014         return (0);
1015 }
1016 
1017 static int
1018 ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
1019 {
1020         int i = (int)obp->obj_id;
1021 
1022         if (ssc->ses_objmap[i].svalid == 0) {
1023                 SesComStat ComStat;
1024                 int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1);