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); |