File:  [DragonFly] / src / sys / bus / cam / scsi / scsi_ses.c
Revision 1.11: download - view: text, annotated - select for diffs
Wed May 19 22:52:38 2004 UTC (10 years, 2 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

    1: /* $FreeBSD: src/sys/cam/scsi/scsi_ses.c,v 1.8.2.2 2000/08/08 23:19:21 mjacob Exp $ */
    2: /* $DragonFly: src/sys/bus/cam/scsi/scsi_ses.c,v 1.11 2004/05/19 22:52:38 dillon Exp $ */
    3: /*
    4:  * Copyright (c) 2000 Matthew Jacob
    5:  * All rights reserved.
    6:  *
    7:  * Redistribution and use in source and binary forms, with or without
    8:  * modification, are permitted provided that the following conditions
    9:  * are met:
   10:  * 1. Redistributions of source code must retain the above copyright
   11:  *    notice, this list of conditions, and the following disclaimer,
   12:  *    without modification, immediately at the beginning of the file.
   13:  * 2. The name of the author may not be used to endorse or promote products
   14:  *    derived from this software without specific prior written permission.
   15:  *
   16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26:  * SUCH DAMAGE.
   27:  *
   28:  */
   29: #include <sys/param.h>
   30: #include <sys/queue.h>
   31: #include <sys/systm.h>
   32: #include <sys/kernel.h>
   33: #include <sys/types.h>
   34: #include <sys/malloc.h>
   35: #include <sys/fcntl.h>
   36: #include <sys/stat.h>
   37: #include <sys/conf.h>
   38: #include <sys/buf.h>
   39: #include <sys/errno.h>
   40: #include <sys/devicestat.h>
   41: #include <machine/stdarg.h>
   42: 
   43: #include "../cam.h"
   44: #include "../cam_ccb.h"
   45: #include "../cam_extend.h"
   46: #include "../cam_periph.h"
   47: #include "../cam_xpt_periph.h"
   48: #include "../cam_queue.h"
   49: #include "../cam_debug.h"
   50: 
   51: #include "scsi_all.h"
   52: #include "scsi_message.h"
   53: #include <sys/ioccom.h>
   54: #include "scsi_ses.h"
   55: 
   56: #include <opt_ses.h>
   57: 
   58: /*
   59:  * Platform Independent Driver Internal Definitions for SES devices.
   60:  */
   61: typedef enum {
   62: 	SES_NONE,
   63: 	SES_SES_SCSI2,
   64: 	SES_SES,
   65: 	SES_SES_PASSTHROUGH,
   66: 	SES_SEN,
   67: 	SES_SAFT
   68: } enctyp;
   69: 
   70: struct ses_softc;
   71: typedef struct ses_softc ses_softc_t;
   72: typedef struct {
   73: 	int (*softc_init)(ses_softc_t *, int);
   74: 	int (*init_enc)(ses_softc_t *);
   75: 	int (*get_encstat)(ses_softc_t *, int);
   76: 	int (*set_encstat)(ses_softc_t *, ses_encstat, int);
   77: 	int (*get_objstat)(ses_softc_t *, ses_objstat *, int);
   78: 	int (*set_objstat)(ses_softc_t *, ses_objstat *, int);
   79: } encvec;
   80: 
   81: #define	ENCI_SVALID	0x80
   82: 
   83: typedef struct {
   84: 	uint32_t
   85: 		enctype	: 8,		/* enclosure type */
   86: 		subenclosure : 8,	/* subenclosure id */
   87: 		svalid	: 1,		/* enclosure information valid */
   88: 		priv	: 15;		/* private data, per object */
   89: 	uint8_t	encstat[4];	/* state && stats */
   90: } encobj;
   91: 
   92: #define	SEN_ID		"UNISYS           SUN_SEN"
   93: #define	SEN_ID_LEN	24
   94: 
   95: 
   96: static enctyp ses_type(void *, int);
   97: 
   98: 
   99: /* Forward reference to Enclosure Functions */
  100: static int ses_softc_init(ses_softc_t *, int);
  101: static int ses_init_enc(ses_softc_t *);
  102: static int ses_get_encstat(ses_softc_t *, int);
  103: static int ses_set_encstat(ses_softc_t *, uint8_t, int);
  104: static int ses_get_objstat(ses_softc_t *, ses_objstat *, int);
  105: static int ses_set_objstat(ses_softc_t *, ses_objstat *, int);
  106: 
  107: static int safte_softc_init(ses_softc_t *, int);
  108: static int safte_init_enc(ses_softc_t *);
  109: static int safte_get_encstat(ses_softc_t *, int);
  110: static int safte_set_encstat(ses_softc_t *, uint8_t, int);
  111: static int safte_get_objstat(ses_softc_t *, ses_objstat *, int);
  112: static int safte_set_objstat(ses_softc_t *, ses_objstat *, int);
  113: 
  114: /*
  115:  * Platform implementation defines/functions for SES internal kernel stuff
  116:  */
  117: 
  118: #define	STRNCMP			strncmp
  119: #define	PRINTF			printf
  120: #define	SES_LOG			ses_log
  121: #ifdef	DEBUG
  122: #define	SES_DLOG		ses_log
  123: #else
  124: #define	SES_DLOG		if (0) ses_log
  125: #endif
  126: #define	SES_VLOG		if (bootverbose) ses_log
  127: #define	SES_MALLOC(amt)		malloc(amt, M_DEVBUF, M_INTWAIT)
  128: #define	SES_FREE(ptr, amt)	free(ptr, M_DEVBUF)
  129: #define	MEMZERO			bzero
  130: #define	MEMCPY(dest, src, amt)	bcopy(src, dest, amt)
  131: 
  132: static int ses_runcmd(struct ses_softc *, char *, int, char *, int *);
  133: static void ses_log(struct ses_softc *, const char *, ...);
  134: 
  135: /*
  136:  * Gerenal FreeBSD kernel stuff.
  137:  */
  138: 
  139: 
  140: #define ccb_state	ppriv_field0
  141: #define ccb_bp		ppriv_ptr1
  142: 
  143: struct ses_softc {
  144: 	enctyp		ses_type;	/* type of enclosure */
  145: 	encvec		ses_vec;	/* vector to handlers */
  146: 	void *		ses_private;	/* per-type private data */
  147: 	encobj *	ses_objmap;	/* objects */
  148: 	u_int32_t	ses_nobjects;	/* number of objects */
  149: 	ses_encstat	ses_encstat;	/* overall status */
  150: 	u_int8_t	ses_flags;
  151: 	union ccb	ses_saved_ccb;
  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)       (minor((x)))
  159: #define SES_CDEV_MAJOR	110
  160: 
  161: static	d_open_t	sesopen;
  162: static	d_close_t	sesclose;
  163: static	d_ioctl_t	sesioctl;
  164: static	periph_init_t	sesinit;
  165: static  periph_ctor_t	sesregister;
  166: static	periph_oninv_t	sesoninvalidate;
  167: static  periph_dtor_t   sescleanup;
  168: static  periph_start_t  sesstart;
  169: 
  170: static void sesasync(void *, u_int32_t, struct cam_path *, void *);
  171: static void sesdone(struct cam_periph *, union ccb *);
  172: static int seserror(union ccb *, u_int32_t, u_int32_t);
  173: 
  174: static struct periph_driver sesdriver = {
  175: 	sesinit, "ses",
  176: 	TAILQ_HEAD_INITIALIZER(sesdriver.units), /* generation */ 0
  177: };
  178: 
  179: DATA_SET(periphdriver_set, sesdriver);
  180: 
  181: static struct cdevsw ses_cdevsw = {
  182: 	/* name */	"ses",
  183: 	/* maj */	SES_CDEV_MAJOR,
  184: 	/* flags */	0,
  185: 	/* port */      NULL,
  186: 	/* clone */     NULL,
  187: 
  188: 	/* open */	sesopen,
  189: 	/* close */	sesclose,
  190: 	/* read */	noread,
  191: 	/* write */	nowrite,
  192: 	/* ioctl */	sesioctl,
  193: 	/* poll */	nopoll,
  194: 	/* mmap */	nommap,
  195: 	/* strategy */	nostrategy,
  196: 	/* dump */	nodump,
  197: 	/* psize */	nopsize
  198: };
  199: static struct extend_array *sesperiphs;
  200: 
  201: void
  202: sesinit(void)
  203: {
  204: 	cam_status status;
  205: 	struct cam_path *path;
  206: 
  207: 	/*
  208: 	 * Create our extend array for storing the devices we attach to.
  209: 	 */
  210: 	sesperiphs = cam_extend_new();
  211: 	if (sesperiphs == NULL) {
  212: 		printf("ses: Failed to alloc extend array!\n");
  213: 		return;
  214: 	}
  215: 
  216: 	/*
  217: 	 * Install a global async callback.  This callback will
  218: 	 * receive async callbacks like "new device found".
  219: 	 */
  220: 	status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
  221: 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  222: 
  223: 	if (status == CAM_REQ_CMP) {
  224: 		struct ccb_setasync csa;
  225: 
  226:                 xpt_setup_ccb(&csa.ccb_h, path, 5);
  227:                 csa.ccb_h.func_code = XPT_SASYNC_CB;
  228:                 csa.event_enable = AC_FOUND_DEVICE;
  229:                 csa.callback = sesasync;
  230:                 csa.callback_arg = NULL;
  231:                 xpt_action((union ccb *)&csa);
  232: 		status = csa.ccb_h.status;
  233:                 xpt_free_path(path);
  234:         }
  235: 
  236: 	if (status != CAM_REQ_CMP) {
  237: 		printf("ses: Failed to attach master async callback "
  238: 		       "due to status 0x%x!\n", status);
  239: 	}
  240: }
  241: 
  242: static void
  243: sesoninvalidate(struct cam_periph *periph)
  244: {
  245: 	struct ses_softc *softc;
  246: 	struct ccb_setasync csa;
  247: 
  248: 	softc = (struct ses_softc *)periph->softc;
  249: 
  250: 	/*
  251: 	 * Unregister any async callbacks.
  252: 	 */
  253: 	xpt_setup_ccb(&csa.ccb_h, periph->path, 5);
  254: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  255: 	csa.event_enable = 0;
  256: 	csa.callback = sesasync;
  257: 	csa.callback_arg = periph;
  258: 	xpt_action((union ccb *)&csa);
  259: 
  260: 	softc->ses_flags |= SES_FLAG_INVALID;
  261: 
  262: 	xpt_print_path(periph->path);
  263: 	printf("lost device\n");
  264: }
  265: 
  266: static void
  267: sescleanup(struct cam_periph *periph)
  268: {
  269: 	struct ses_softc *softc;
  270: 
  271: 	softc = (struct ses_softc *)periph->softc;
  272: 
  273: 	cam_extend_release(sesperiphs, periph->unit_number);
  274: 	xpt_print_path(periph->path);
  275: 	printf("removing device entry\n");
  276: 	cdevsw_remove(&ses_cdevsw, -1, periph->unit_number);
  277: 	free(softc, M_DEVBUF);
  278: }
  279: 
  280: static void
  281: sesasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  282: {
  283: 	struct cam_periph *periph;
  284: 
  285: 	periph = (struct cam_periph *)callback_arg;
  286: 
  287: 	switch(code) {
  288: 	case AC_FOUND_DEVICE:
  289: 	{
  290: 		cam_status status;
  291: 		struct ccb_getdev *cgd;
  292: 
  293: 		cgd = (struct ccb_getdev *)arg;
  294: 
  295: 		/*
  296: 		 * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS
  297: 		 * PROBLEM: IS A SAF-TE DEVICE.
  298: 		 */
  299: 		switch (ses_type(&cgd->inq_data, cgd->inq_len)) {
  300: 		case SES_SES:
  301: 		case SES_SES_SCSI2:
  302: 		case SES_SES_PASSTHROUGH:
  303: 		case SES_SEN:
  304: 		case SES_SAFT:
  305: 			break;
  306: 		default:
  307: 			return;
  308: 		}
  309: 
  310: 		status = cam_periph_alloc(sesregister, sesoninvalidate,
  311: 		    sescleanup, sesstart, "ses", CAM_PERIPH_BIO,
  312: 		    cgd->ccb_h.path, sesasync, AC_FOUND_DEVICE, cgd);
  313: 
  314: 		if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
  315: 			printf("sesasync: Unable to probe new device due to "
  316: 			    "status 0x%x\n", status);
  317: 		}
  318: 		break;
  319: 	}
  320: 	default:
  321: 		cam_periph_async(periph, code, path, arg);
  322: 		break;
  323: 	}
  324: }
  325: 
  326: static cam_status
  327: sesregister(struct cam_periph *periph, void *arg)
  328: {
  329: 	struct ses_softc *softc;
  330: 	struct ccb_setasync csa;
  331: 	struct ccb_getdev *cgd;
  332: 	char *tname;
  333: 
  334: 	cgd = (struct ccb_getdev *)arg;
  335: 	if (periph == NULL) {
  336: 		printf("sesregister: periph was NULL!!\n");
  337: 		return (CAM_REQ_CMP_ERR);
  338: 	}
  339: 
  340: 	if (cgd == NULL) {
  341: 		printf("sesregister: no getdev CCB, can't register device\n");
  342: 		return (CAM_REQ_CMP_ERR);
  343: 	}
  344: 
  345: 	softc = malloc(sizeof (struct ses_softc), M_DEVBUF, M_INTWAIT | M_ZERO);
  346: 	periph->softc = softc;
  347: 	softc->periph = periph;
  348: 
  349: 	softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data));
  350: 
  351: 	switch (softc->ses_type) {
  352: 	case SES_SES:
  353: 	case SES_SES_SCSI2:
  354:         case SES_SES_PASSTHROUGH:
  355: 		softc->ses_vec.softc_init = ses_softc_init;
  356: 		softc->ses_vec.init_enc = ses_init_enc;
  357: 		softc->ses_vec.get_encstat = ses_get_encstat;
  358: 		softc->ses_vec.set_encstat = ses_set_encstat;
  359: 		softc->ses_vec.get_objstat = ses_get_objstat;
  360: 		softc->ses_vec.set_objstat = ses_set_objstat;
  361: 		break;
  362:         case SES_SAFT:
  363: 		softc->ses_vec.softc_init = safte_softc_init;
  364: 		softc->ses_vec.init_enc = safte_init_enc;
  365: 		softc->ses_vec.get_encstat = safte_get_encstat;
  366: 		softc->ses_vec.set_encstat = safte_set_encstat;
  367: 		softc->ses_vec.get_objstat = safte_get_objstat;
  368: 		softc->ses_vec.set_objstat = safte_set_objstat;
  369: 		break;
  370:         case SES_SEN:
  371: 		break;
  372: 	case SES_NONE:
  373: 	default:
  374: 		free(softc, M_DEVBUF);
  375: 		return (CAM_REQ_CMP_ERR);
  376: 	}
  377: 
  378: 	cam_extend_set(sesperiphs, periph->unit_number, periph);
  379: 
  380: 	cdevsw_add(&ses_cdevsw, -1, periph->unit_number);
  381: 	make_dev(&ses_cdevsw, periph->unit_number,
  382: 		    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
  383: 		    periph->periph_name, periph->unit_number);
  384: 
  385: 	/*
  386: 	 * Add an async callback so that we get
  387: 	 * notified if this device goes away.
  388: 	 */
  389: 	xpt_setup_ccb(&csa.ccb_h, periph->path, 5);
  390: 	csa.ccb_h.func_code = XPT_SASYNC_CB;
  391: 	csa.event_enable = AC_LOST_DEVICE;
  392: 	csa.callback = sesasync;
  393: 	csa.callback_arg = periph;
  394: 	xpt_action((union ccb *)&csa);
  395: 
  396: 	switch (softc->ses_type) {
  397: 	default:
  398: 	case SES_NONE:
  399: 		tname = "No SES device";
  400: 		break;
  401: 	case SES_SES_SCSI2:
  402: 		tname = "SCSI-2 SES Device";
  403: 		break;
  404: 	case SES_SES:
  405: 		tname = "SCSI-3 SES Device";
  406: 		break;
  407:         case SES_SES_PASSTHROUGH:
  408: 		tname = "SES Passthrough Device";
  409: 		break;
  410:         case SES_SEN:
  411: 		tname = "UNISYS SEN Device (NOT HANDLED YET)";
  412: 		break;
  413:         case SES_SAFT:
  414: 		tname = "SAF-TE Compliant Device";
  415: 		break;
  416: 	}
  417: 	xpt_announce_periph(periph, tname);
  418: 	return (CAM_REQ_CMP);
  419: }
  420: 
  421: static int
  422: sesopen(dev_t dev, int flags, int fmt, struct thread *td)
  423: {
  424: 	struct cam_periph *periph;
  425: 	struct ses_softc *softc;
  426: 	int error, s;
  427: 
  428: 	s = splsoftcam();
  429: 	periph = cam_extend_get(sesperiphs, SESUNIT(dev));
  430: 	if (periph == NULL) {
  431: 		splx(s);
  432: 		return (ENXIO);
  433: 	}
  434: 	if ((error = cam_periph_lock(periph, PCATCH)) != 0) {
  435: 		splx(s);
  436: 		return (error);
  437: 	}
  438: 	splx(s);
  439: 
  440: 	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  441: 		cam_periph_unlock(periph);
  442: 		return (ENXIO);
  443: 	}
  444: 
  445: 	softc = (struct ses_softc *)periph->softc;
  446: 
  447: 	if (softc->ses_flags & SES_FLAG_INVALID) {
  448: 		error = ENXIO;
  449: 		goto out;
  450: 	}
  451: 	if (softc->ses_flags & SES_FLAG_OPEN) {
  452: 		error = EBUSY;
  453: 		goto out;
  454: 	}
  455: 	if (softc->ses_vec.softc_init == NULL) {
  456: 		error = ENXIO;
  457: 		goto out;
  458: 	}
  459: 
  460: 	softc->ses_flags |= SES_FLAG_OPEN;
  461: 	if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
  462: 		error = (*softc->ses_vec.softc_init)(softc, 1);
  463: 		if (error)
  464: 			softc->ses_flags &= ~SES_FLAG_OPEN;
  465: 		else
  466: 			softc->ses_flags |= SES_FLAG_INITIALIZED;
  467: 	}
  468: 
  469: out:
  470: 	if (error) {
  471: 		cam_periph_release(periph);
  472: 	}
  473: 	cam_periph_unlock(periph);
  474: 	return (error);
  475: }
  476: 
  477: static int
  478: sesclose(dev_t dev, int flag, int fmt, struct thread *td)
  479: {
  480: 	struct cam_periph *periph;
  481: 	struct ses_softc *softc;
  482: 	int unit, error;
  483: 
  484: 	error = 0;
  485: 
  486: 	unit = SESUNIT(dev);
  487: 	periph = cam_extend_get(sesperiphs, unit);
  488: 	if (periph == NULL)
  489: 		return (ENXIO);
  490: 
  491: 	softc = (struct ses_softc *)periph->softc;
  492: 
  493: 	if ((error = cam_periph_lock(periph, 0)) != 0)
  494: 		return (error);
  495: 
  496: 	softc->ses_flags &= ~SES_FLAG_OPEN;
  497: 
  498: 	cam_periph_unlock(periph);
  499: 	cam_periph_release(periph);
  500: 
  501: 	return (0);
  502: }
  503: 
  504: static void
  505: sesstart(struct cam_periph *p, union ccb *sccb)
  506: {
  507: 	int s = splbio();
  508: 	if (p->immediate_priority <= p->pinfo.priority) {
  509: 		SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
  510: 		p->immediate_priority = CAM_PRIORITY_NONE;
  511: 		wakeup(&p->ccb_list);
  512: 	}
  513: 	splx(s);
  514: }
  515: 
  516: static void
  517: sesdone(struct cam_periph *periph, union ccb *dccb)
  518: {
  519: 	wakeup(&dccb->ccb_h.cbfcnp);
  520: }
  521: 
  522: static int
  523: seserror(union ccb *ccb, u_int32_t cflags, u_int32_t sflags)
  524: {
  525: 	struct ses_softc *softc;
  526: 	struct cam_periph *periph;
  527: 
  528: 	periph = xpt_path_periph(ccb->ccb_h.path);
  529: 	softc = (struct ses_softc *)periph->softc;
  530: 
  531: 	return (cam_periph_error(ccb, cflags, sflags, &softc->ses_saved_ccb));
  532: }
  533: 
  534: static int
  535: sesioctl(dev_t dev, u_long cmd, caddr_t arg_addr, int flag, struct thread *td)
  536: {
  537: 	struct cam_periph *periph;
  538: 	ses_encstat tmp;
  539: 	ses_objstat objs;
  540: 	ses_object obj, *uobj;
  541: 	struct ses_softc *ssc;
  542: 	void *addr;
  543: 	int error, i;
  544: 
  545: 
  546: 	if (arg_addr)
  547: 		addr = *((caddr_t *) arg_addr);
  548: 	else
  549: 		addr = NULL;
  550: 
  551: 	periph = cam_extend_get(sesperiphs, SESUNIT(dev));
  552: 	if (periph == NULL)
  553: 		return (ENXIO);
  554: 
  555: 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n"));
  556: 
  557: 	ssc = (struct ses_softc *)periph->softc;
  558: 
  559: 	/*
  560: 	 * Now check to see whether we're initialized or not.
  561: 	 */
  562: 	if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) {
  563: 		return (ENXIO);
  564: 	}
  565: 
  566: 	error = 0;
  567: 
  568: 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  569: 	    ("trying to do ioctl %#lx\n", cmd));
  570: 
  571: 	/*
  572: 	 * If this command can change the device's state,
  573: 	 * we must have the device open for writing.
  574: 	 */
  575: 	switch (cmd) {
  576: 	case SESIOC_GETNOBJ:
  577: 	case SESIOC_GETOBJMAP:
  578: 	case SESIOC_GETENCSTAT:
  579: 	case SESIOC_GETOBJSTAT:
  580: 		break;
  581: 	default:
  582: 		if ((flag & FWRITE) == 0) {
  583: 			return (EBADF);
  584: 		}
  585: 	}
  586: 
  587: 	switch (cmd) {
  588: 	case SESIOC_GETNOBJ:
  589: 		error = copyout(&ssc->ses_nobjects, addr,
  590: 		    sizeof (ssc->ses_nobjects));
  591: 		break;
  592: 		
  593: 	case SESIOC_GETOBJMAP:
  594: 		for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++, uobj++) {
  595: 			obj.obj_id = i;
  596: 			obj.subencid = ssc->ses_objmap[i].subenclosure;
  597: 			obj.object_type = ssc->ses_objmap[i].enctype;
  598: 			error = copyout(&obj, uobj, sizeof (ses_object));
  599: 			if (error) {
  600: 				break;
  601: 			}
  602: 		}
  603: 		break;
  604: 
  605: 	case SESIOC_GETENCSTAT:
  606: 		error = (*ssc->ses_vec.get_encstat)(ssc, 1);
  607: 		if (error)
  608: 			break;
  609: 		tmp = ssc->ses_encstat & ~ENCI_SVALID;
  610: 		error = copyout(&tmp, addr, sizeof (ses_encstat));
  611: 		ssc->ses_encstat = tmp;
  612: 		break;
  613: 
  614: 	case SESIOC_SETENCSTAT:
  615: 		error = copyin(addr, &tmp, sizeof (ses_encstat));
  616: 		if (error)
  617: 			break;
  618: 		error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1);
  619: 		break;
  620: 
  621: 	case SESIOC_GETOBJSTAT:
  622: 		error = copyin(addr, &objs, sizeof (ses_objstat));
  623: 		if (error)
  624: 			break;
  625: 		if (objs.obj_id >= ssc->ses_nobjects) {
  626: 			error = EINVAL;
  627: 			break;
  628: 		}
  629: 		error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1);
  630: 		if (error)
  631: 			break;
  632: 		error = copyout(&objs, addr, sizeof (ses_objstat));
  633: 		/*
  634: 		 * Always (for now) invalidate entry.
  635: 		 */
  636: 		ssc->ses_objmap[objs.obj_id].svalid = 0;
  637: 		break;
  638: 
  639: 	case SESIOC_SETOBJSTAT:
  640: 		error = copyin(addr, &objs, sizeof (ses_objstat));
  641: 		if (error)
  642: 			break;
  643: 
  644: 		if (objs.obj_id >= ssc->ses_nobjects) {
  645: 			error = EINVAL;
  646: 			break;
  647: 		}
  648: 		error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1);
  649: 
  650: 		/*
  651: 		 * Always (for now) invalidate entry.
  652: 		 */
  653: 		ssc->ses_objmap[objs.obj_id].svalid = 0;
  654: 		break;
  655: 
  656: 	case SESIOC_INIT:
  657: 
  658: 		error = (*ssc->ses_vec.init_enc)(ssc);
  659: 		break;
  660: 
  661: 	default:
  662: 		error = cam_periph_ioctl(periph, cmd, arg_addr, seserror);
  663: 		break;
  664: 	}
  665: 	return (error);
  666: }
  667: 
  668: #define	SES_FLAGS	SF_NO_PRINT | SF_RETRY_SELTO | SF_RETRY_UA
  669: static int
  670: ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp)
  671: {
  672: 	int error, dlen;
  673: 	ccb_flags ddf;
  674: 	union ccb *ccb;
  675: 
  676: 	if (dptr) {
  677: 		if ((dlen = *dlenp) < 0) {
  678: 			dlen = -dlen;
  679: 			ddf = CAM_DIR_OUT;
  680: 		} else {
  681: 			ddf = CAM_DIR_IN;
  682: 		}
  683: 	} else {
  684: 		dlen = 0;
  685: 		ddf = CAM_DIR_NONE;
  686: 	}
  687: 
  688: 	if (cdbl > IOCDBLEN) {
  689: 		cdbl = IOCDBLEN;
  690: 	}
  691: 
  692: 	ccb = cam_periph_getccb(ssc->periph, 1);
  693: 	cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, dptr,
  694: 	    dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000);
  695: 	bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
  696: 
  697: 	error = cam_periph_runccb(ccb, seserror, 0, SES_FLAGS, NULL);
  698: 	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
  699: 		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
  700: 	if (error) {
  701: 		if (dptr) {
  702: 			*dlenp = dlen;
  703: 		}
  704: 	} else {
  705: 		if (dptr) {
  706: 			*dlenp = ccb->csio.resid;
  707: 		}
  708: 	}
  709: 	xpt_release_ccb(ccb);
  710: 	return (error);
  711: }
  712: 
  713: static void
  714: ses_log(struct ses_softc *ssc, const char *fmt, ...)
  715: {
  716: 	__va_list ap;
  717: 
  718: 	printf("%s%d: ", ssc->periph->periph_name, ssc->periph->unit_number);
  719: 	__va_start(ap, fmt);
  720: 	vprintf(fmt, ap);
  721: 	__va_end(ap);
  722: }
  723: 
  724: /*
  725:  * The code after this point runs on many platforms,
  726:  * so forgive the slightly awkward and nonconforming
  727:  * appearance.
  728:  */
  729: 
  730: /*
  731:  * Is this a device that supports enclosure services?
  732:  *
  733:  * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's
  734:  * an SES device. If it happens to be an old UNISYS SEN device, we can
  735:  * handle that too.
  736:  */
  737: 
  738: #define	SAFTE_START	44
  739: #define	SAFTE_END	50
  740: #define	SAFTE_LEN	SAFTE_END-SAFTE_START
  741: 
  742: static enctyp
  743: ses_type(void *buf, int buflen)
  744: {
  745: 	unsigned char *iqd = buf;
  746: 
  747: 	if (buflen == 0)
  748: 		buflen = 256;	/* per SPC-2 */
  749: 
  750: 	if (buflen < 8+SEN_ID_LEN)
  751: 		return (SES_NONE);
  752: 
  753: 	if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
  754: 		if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) {
  755: 			return (SES_SEN);
  756: 		} else if ((iqd[2] & 0x7) > 2) {
  757: 			return (SES_SES);
  758: 		} else {
  759: 			return (SES_SES_SCSI2);
  760: 		}
  761: 		return (SES_NONE);
  762: 	}
  763: 
  764: #ifdef	SES_ENABLE_PASSTHROUGH
  765: 	if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
  766: 		/*
  767: 		 * PassThrough Device.
  768: 		 */
  769: 		return (SES_SES_PASSTHROUGH);
  770: 	}
  771: #endif
  772: 
  773: 	/*
  774: 	 * The comparison is short for a reason-
  775: 	 * some vendors were chopping it short.
  776: 	 */
  777: 
  778: 	if (buflen < SAFTE_END - 2) {
  779: 		return (SES_NONE);
  780: 	}
  781: 
  782: 	if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
  783: 		return (SES_SAFT);
  784: 	}
  785: 	return (SES_NONE);
  786: }
  787: 
  788: /*
  789:  * SES Native Type Device Support
  790:  */
  791: 
  792: /*
  793:  * SES Diagnostic Page Codes
  794:  */
  795: 
  796: typedef enum {
  797: 	SesConfigPage = 0x1,
  798: 	SesControlPage,
  799: #define	SesStatusPage SesControlPage
  800: 	SesHelpTxt,
  801: 	SesStringOut,
  802: #define	SesStringIn	SesStringOut
  803: 	SesThresholdOut,
  804: #define	SesThresholdIn SesThresholdOut
  805: 	SesArrayControl,
  806: #define	SesArrayStatus	SesArrayControl
  807: 	SesElementDescriptor,
  808: 	SesShortStatus
  809: } SesDiagPageCodes;
  810: 
  811: /*
  812:  * minimal amounts
  813:  */
  814: 
  815: /*
  816:  * Minimum amount of data, starting from byte 0, to have
  817:  * the config header.
  818:  */
  819: #define	SES_CFGHDR_MINLEN	12
  820: 
  821: /*
  822:  * Minimum amount of data, starting from byte 0, to have
  823:  * the config header and one enclosure header.
  824:  */
  825: #define	SES_ENCHDR_MINLEN	48
  826: 
  827: /*
  828:  * Take this value, subtract it from VEnclen and you know
  829:  * the length of the vendor unique bytes.
  830:  */
  831: #define	SES_ENCHDR_VMIN		36
  832: 
  833: /*
  834:  * SES Data Structures
  835:  */
  836: 
  837: typedef struct {
  838: 	uint32_t GenCode;	/* Generation Code */
  839: 	uint8_t	Nsubenc;	/* Number of Subenclosures */
  840: } SesCfgHdr;
  841: 
  842: typedef struct {
  843: 	uint8_t	Subencid;	/* SubEnclosure Identifier */
  844: 	uint8_t	Ntypes;		/* # of supported types */
  845: 	uint8_t	VEnclen;	/* Enclosure Descriptor Length */
  846: } SesEncHdr;
  847: 
  848: typedef struct {
  849: 	uint8_t	encWWN[8];	/* XXX- Not Right Yet */
  850: 	uint8_t	encVid[8];
  851: 	uint8_t	encPid[16];
  852: 	uint8_t	encRev[4];
  853: 	uint8_t	encVen[1];
  854: } SesEncDesc;
  855: 
  856: typedef struct {
  857: 	uint8_t	enc_type;		/* type of element */
  858: 	uint8_t	enc_maxelt;		/* maximum supported */
  859: 	uint8_t	enc_subenc;		/* in SubEnc # N */
  860: 	uint8_t	enc_tlen;		/* Type Descriptor Text Length */
  861: } SesThdr;
  862: 
  863: typedef struct {
  864: 	uint8_t	comstatus;
  865: 	uint8_t	comstat[3];
  866: } SesComStat;
  867: 
  868: struct typidx {
  869: 	int ses_tidx;
  870: 	int ses_oidx;
  871: };
  872: 
  873: struct sscfg {
  874: 	uint8_t ses_ntypes;	/* total number of types supported */
  875: 
  876: 	/*
  877: 	 * We need to keep a type index as well as an
  878: 	 * object index for each object in an enclosure.
  879: 	 */
  880: 	struct typidx *ses_typidx;
  881: 
  882: 	/*
  883: 	 * We also need to keep track of the number of elements
  884: 	 * per type of element. This is needed later so that we
  885: 	 * can find precisely in the returned status data the
  886: 	 * status for the Nth element of the Kth type.
  887: 	 */
  888: 	uint8_t *	ses_eltmap;
  889: };
  890: 
  891: 
  892: /*
  893:  * (de)canonicalization defines
  894:  */
  895: #define	sbyte(x, byte)		((((uint32_t)(x)) >> (byte * 8)) & 0xff)
  896: #define	sbit(x, bit)		(((uint32_t)(x)) << bit)
  897: #define	sset8(outp, idx, sval)	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  898: 
  899: #define	sset16(outp, idx, sval)	\
  900: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  901: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  902: 
  903: 
  904: #define	sset24(outp, idx, sval)	\
  905: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
  906: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  907: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  908: 
  909: 
  910: #define	sset32(outp, idx, sval)	\
  911: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \
  912: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \
  913: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \
  914: 	(((uint8_t *)(outp))[idx++]) = sbyte(sval, 0)
  915: 
  916: #define	gbyte(x, byte)	((((uint32_t)(x)) & 0xff) << (byte * 8))
  917: #define	gbit(lv, in, idx, shft, mask)	lv = ((in[idx] >> shft) & mask)
  918: #define	sget8(inp, idx, lval)	lval = (((uint8_t *)(inp))[idx++])
  919: #define	gget8(inp, idx, lval)	lval = (((uint8_t *)(inp))[idx])
  920: 
  921: #define	sget16(inp, idx, lval)	\
  922: 	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
  923: 		(((uint8_t *)(inp))[idx+1]), idx += 2
  924: 
  925: #define	gget16(inp, idx, lval)	\
  926: 	lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \
  927: 		(((uint8_t *)(inp))[idx+1])
  928: 
  929: #define	sget24(inp, idx, lval)	\
  930: 	lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
  931: 		gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
  932: 			(((uint8_t *)(inp))[idx+2]), idx += 3
  933: 
  934: #define	gget24(inp, idx, lval)	\
  935: 	lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \
  936: 		gbyte((((uint8_t *)(inp))[idx+1]), 1) | \
  937: 			(((uint8_t *)(inp))[idx+2])
  938: 
  939: #define	sget32(inp, idx, lval)	\
  940: 	lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
  941: 		gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
  942: 		gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
  943: 			(((uint8_t *)(inp))[idx+3]), idx += 4
  944: 
  945: #define	gget32(inp, idx, lval)	\
  946: 	lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \
  947: 		gbyte((((uint8_t *)(inp))[idx+1]), 2) | \
  948: 		gbyte((((uint8_t *)(inp))[idx+2]), 1) | \
  949: 			(((uint8_t *)(inp))[idx+3])
  950: 
  951: #define	SCSZ	0x2000
  952: #define	CFLEN	(256 + SES_ENCHDR_MINLEN)
  953: 
  954: /*
  955:  * Routines specific && private to SES only
  956:  */
  957: 
  958: static int ses_getconfig(ses_softc_t *);
  959: static int ses_getputstat(ses_softc_t *, int, SesComStat *, int, int);
  960: static int ses_cfghdr(uint8_t *, int, SesCfgHdr *);
  961: static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr *);
  962: static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc *);
  963: static int ses_getthdr(uint8_t *, int,  int, SesThdr *);
  964: static int ses_decode(char *, int, uint8_t *, int, int, SesComStat *);
  965: static int ses_encode(char *, int, uint8_t *, int, int, SesComStat *);
  966: 
  967: static int
  968: ses_softc_init(ses_softc_t *ssc, int doinit)
  969: {
  970: 	if (doinit == 0) {
  971: 		struct sscfg *cc;
  972: 		if (ssc->ses_nobjects) {
  973: 			SES_FREE(ssc->ses_objmap,
  974: 			    ssc->ses_nobjects * sizeof (encobj));
  975: 			ssc->ses_objmap = NULL;
  976: 		}
  977: 		if ((cc = ssc->ses_private) != NULL) {
  978: 			if (cc->ses_eltmap && cc->ses_ntypes) {
  979: 				SES_FREE(cc->ses_eltmap, cc->ses_ntypes);
  980: 				cc->ses_eltmap = NULL;
  981: 				cc->ses_ntypes = 0;
  982: 			}
  983: 			if (cc->ses_typidx && ssc->ses_nobjects) {
  984: 				SES_FREE(cc->ses_typidx,
  985: 				    ssc->ses_nobjects * sizeof (struct typidx));
  986: 				cc->ses_typidx = NULL;
  987: 			}
  988: 			SES_FREE(cc, sizeof (struct sscfg));
  989: 			ssc->ses_private = NULL;
  990: 		}
  991: 		ssc->ses_nobjects = 0;
  992: 		return (0);
  993: 	}
  994: 	if (ssc->ses_private == NULL) {
  995: 		ssc->ses_private = SES_MALLOC(sizeof (struct sscfg));
  996: 	}
  997: 	if (ssc->ses_private == NULL) {
  998: 		return (ENOMEM);
  999: 	}
 1000: 	ssc->ses_nobjects = 0;
 1001: 	ssc->ses_encstat = 0;
 1002: 	return (ses_getconfig(ssc));
 1003: }
 1004: 
 1005: static int
 1006: ses_init_enc(ses_softc_t *ssc)
 1007: {
 1008: 	return (0);
 1009: }
 1010: 
 1011: static int
 1012: ses_get_encstat(ses_softc_t *ssc, int slpflag)
 1013: {
 1014: 	SesComStat ComStat;
 1015: 	int status;
 1016: 
 1017: 	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) {
 1018: 		return (status);
 1019: 	}
 1020: 	ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID;
 1021: 	return (0);
 1022: }
 1023: 
 1024: static int
 1025: ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag)
 1026: {
 1027: 	SesComStat ComStat;
 1028: 	int status;
 1029: 
 1030: 	ComStat.comstatus = encstat & 0xf;
 1031: 	if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) {
 1032: 		return (status);
 1033: 	}
 1034: 	ssc->ses_encstat = encstat & 0xf;	/* note no SVALID set */
 1035: 	return (0);
 1036: }
 1037: 
 1038: static int
 1039: ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
 1040: {
 1041: 	int i = (int)obp->obj_id;
 1042: 
 1043: 	if (ssc->ses_objmap[i].svalid == 0) {
 1044: 		SesComStat ComStat;
 1045: 		int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1);
 1046: 		if (err)
 1047: 			return (err);
 1048: 		ssc->ses_objmap[i].encstat[0] = ComStat.comstatus;
 1049: 		ssc->ses_objmap[i].encstat[1] = ComStat.comstat[0];
 1050: 		ssc->ses_objmap[i].encstat[2] = ComStat.comstat[1];
 1051: 		ssc->ses_objmap[i].encstat[3] = ComStat.comstat[2];
 1052: 		ssc->ses_objmap[i].svalid = 1;
 1053: 	}
 1054: 	obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
 1055: 	obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
 1056: 	obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
 1057: 	obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
 1058: 	return (0);
 1059: }
 1060: 
 1061: static int
 1062: ses_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag)
 1063: {
 1064: 	SesComStat ComStat;
 1065: 	int err;
 1066: 	/*
 1067: 	 * If this is clear, we don't do diddly.
 1068: 	 */
 1069: 	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
 1070: 		return (0);
 1071: 	}
 1072: 	ComStat.comstatus = obp->cstat[0];
 1073: 	ComStat.comstat[0] = obp->cstat[1];
 1074: 	ComStat.comstat[1] = obp->cstat[2];
 1075: 	ComStat.comstat[2] = obp->cstat[3];
 1076: 	err = ses_getputstat(ssc, (int)obp->obj_id, &ComStat, slpflag, 0);
 1077: 	ssc->ses_objmap[(int)obp->obj_id].svalid = 0;
 1078: 	return (err);
 1079: }
 1080: 
 1081: static int
 1082: ses_getconfig(ses_softc_t *ssc)
 1083: {
 1084: 	struct sscfg *cc;
 1085: 	SesCfgHdr cf;
 1086: 	SesEncHdr hd;
 1087: 	SesEncDesc *cdp;
 1088: 	SesThdr thdr;
 1089: 	int err, amt, i, nobj, ntype, maxima;
 1090: 	char storage[CFLEN], *sdata;
 1091: 	static char cdb[6] = {
 1092: 	    RECEIVE_DIAGNOSTIC, 0x1, SesConfigPage, SCSZ >> 8, SCSZ & 0xff, 0
 1093: 	};
 1094: 
 1095: 	cc = ssc->ses_private;
 1096: 	if (cc == NULL) {
 1097: 		return (ENXIO);
 1098: 	}
 1099: 
 1100: 	sdata = SES_MALLOC(SCSZ);
 1101: 	if (sdata == NULL)
 1102: 		return (ENOMEM);
 1103: 
 1104: 	amt = SCSZ;
 1105: 	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
 1106: 	if (err) {
 1107: 		SES_FREE(sdata, SCSZ);
 1108: 		return (err);
 1109: 	}
 1110: 	amt = SCSZ - amt;
 1111: 
 1112: 	if (ses_cfghdr((uint8_t *) sdata, amt, &cf)) {
 1113: 		SES_LOG(ssc, "Unable to parse SES Config Header\n");
 1114: 		SES_FREE(sdata, SCSZ);
 1115: 		return (EIO);
 1116: 	}
 1117: 	if (amt < SES_ENCHDR_MINLEN) {
 1118: 		SES_LOG(ssc, "runt enclosure length (%d)\n", amt);
 1119: 		SES_FREE(sdata, SCSZ);
 1120: 		return (EIO);
 1121: 	}
 1122: 
 1123: 	SES_VLOG(ssc, "GenCode %x %d Subenclosures\n", cf.GenCode, cf.Nsubenc);
 1124: 
 1125: 	/*
 1126: 	 * Now waltz through all the subenclosures toting up the
 1127: 	 * number of types available in each. For this, we only
 1128: 	 * really need the enclosure header. However, we get the
 1129: 	 * enclosure descriptor for debug purposes, as well
 1130: 	 * as self-consistency checking purposes.
 1131: 	 */
 1132: 
 1133: 	maxima = cf.Nsubenc + 1;
 1134: 	cdp = (SesEncDesc *) storage;
 1135: 	for (ntype = i = 0; i < maxima; i++) {
 1136: 		MEMZERO((caddr_t)cdp, sizeof (*cdp));
 1137: 		if (ses_enchdr((uint8_t *) sdata, amt, i, &hd)) {
 1138: 			SES_LOG(ssc, "Cannot Extract Enclosure Header %d\n", i);
 1139: 			SES_FREE(sdata, SCSZ);
 1140: 			return (EIO);
 1141: 		}
 1142: 		SES_VLOG(ssc, " SubEnclosure ID %d, %d Types With this ID, En"
 1143: 		    "closure Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen);
 1144: 
 1145: 		if (ses_encdesc((uint8_t *)sdata, amt, i, cdp)) {
 1146: 			SES_LOG(ssc, "Can't get Enclosure Descriptor %d\n", i);
 1147: 			SES_FREE(sdata, SCSZ);
 1148: 			return (EIO);
 1149: 		}
 1150: 		SES_VLOG(ssc, " WWN: %02x%02x%02x%02x%02x%02x%02x%02x\n",
 1151: 		    cdp->encWWN[0], cdp->encWWN[1], cdp->encWWN[2],
 1152: 		    cdp->encWWN[3], cdp->encWWN[4], cdp->encWWN[5],
 1153: 		    cdp->encWWN[6], cdp->encWWN[7]);
 1154: 		ntype += hd.Ntypes;
 1155: 	}
 1156: 
 1157: 	/*
 1158: 	 * Now waltz through all the types that are available, getting
 1159: 	 * the type header so we can start adding up the number of
 1160: 	 * objects available.
 1161: 	 */
 1162: 	for (nobj = i = 0; i < ntype; i++) {
 1163: 		if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
 1164: 			SES_LOG(ssc, "Can't get Enclosure Type Header %d\n", i);
 1165: 			SES_FREE(sdata, SCSZ);
 1166: 			return (EIO);
 1167: 		}
 1168: 		SES_LOG(ssc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
 1169: 		    "%d, Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt,
 1170: 		    thdr.enc_subenc, thdr.enc_tlen);
 1171: 		nobj += thdr.enc_maxelt;
 1172: 	}
 1173: 
 1174: 
 1175: 	/*
 1176: 	 * Now allocate the object array and type map.
 1177: 	 */
 1178: 
 1179: 	ssc->ses_objmap = SES_MALLOC(nobj * sizeof (encobj));
 1180: 	cc->ses_typidx = SES_MALLOC(nobj * sizeof (struct typidx));
 1181: 	cc->ses_eltmap = SES_MALLOC(ntype);
 1182: 
 1183: 	if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL ||
 1184: 	    cc->ses_eltmap == NULL) {
 1185: 		if (ssc->ses_objmap) {
 1186: 			SES_FREE(ssc->ses_objmap, (nobj * sizeof (encobj)));
 1187: 			ssc->ses_objmap = NULL;
 1188: 		}
 1189: 		if (cc->ses_typidx) {
 1190: 			SES_FREE(cc->ses_typidx,
 1191: 			    (nobj * sizeof (struct typidx)));
 1192: 			cc->ses_typidx = NULL;
 1193: 		}
 1194: 		if (cc->ses_eltmap) {
 1195: 			SES_FREE(cc->ses_eltmap, ntype);
 1196: 			cc->ses_eltmap = NULL;
 1197: 		}
 1198: 		SES_FREE(sdata, SCSZ);
 1199: 		return (ENOMEM);
 1200: 	}
 1201: 	MEMZERO(ssc->ses_objmap, nobj * sizeof (encobj));
 1202: 	MEMZERO(cc->ses_typidx, nobj * sizeof (struct typidx));
 1203: 	MEMZERO(cc->ses_eltmap, ntype);
 1204: 	cc->ses_ntypes = (uint8_t) ntype;
 1205: 	ssc->ses_nobjects = nobj;
 1206: 
 1207: 	/*
 1208: 	 * Now waltz through the # of types again to fill in the types
 1209: 	 * (and subenclosure ids) of the allocated objects.
 1210: 	 */
 1211: 	nobj = 0;
 1212: 	for (i = 0; i < ntype; i++) {
 1213: 		int j;
 1214: 		if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) {
 1215: 			continue;
 1216: 		}
 1217: 		cc->ses_eltmap[i] = thdr.enc_maxelt;
 1218: 		for (j = 0; j < thdr.enc_maxelt; j++) {
 1219: 			cc->ses_typidx[nobj].ses_tidx = i;
 1220: 			cc->ses_typidx[nobj].ses_oidx = j;
 1221: 			ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc;
 1222: 			ssc->ses_objmap[nobj++].enctype = thdr.enc_type;
 1223: 		}
 1224: 	}
 1225: 	SES_FREE(sdata, SCSZ);
 1226: 	return (0);
 1227: }
 1228: 
 1229: static int
 1230: ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, int in)
 1231: {
 1232: 	struct sscfg *cc;
 1233: 	int err, amt, bufsiz, tidx, oidx;
 1234: 	char cdb[6], *sdata;
 1235: 
 1236: 	cc = ssc->ses_private;
 1237: 	if (cc == NULL) {
 1238: 		return (ENXIO);
 1239: 	}
 1240: 
 1241: 	/*
 1242: 	 * If we're just getting overall enclosure status,
 1243: 	 * we only need 2 bytes of data storage.
 1244: 	 *
 1245: 	 * If we're getting anything else, we know how much
 1246: 	 * storage we need by noting that starting at offset
 1247: 	 * 8 in returned data, all object status bytes are 4
 1248: 	 * bytes long, and are stored in chunks of types(M)
 1249: 	 * and nth+1 instances of type M.
 1250: 	 */
 1251: 	if (objid == -1) {
 1252: 		bufsiz = 2;
 1253: 	} else {
 1254: 		bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8;
 1255: 	}
 1256: 	sdata = SES_MALLOC(bufsiz);
 1257: 	if (sdata == NULL)
 1258: 		return (ENOMEM);
 1259: 
 1260: 	cdb[0] = RECEIVE_DIAGNOSTIC;
 1261: 	cdb[1] = 1;
 1262: 	cdb[2] = SesStatusPage;
 1263: 	cdb[3] = bufsiz >> 8;
 1264: 	cdb[4] = bufsiz & 0xff;
 1265: 	cdb[5] = 0;
 1266: 	amt = bufsiz;
 1267: 	err = ses_runcmd(ssc, cdb, 6, sdata, &amt);
 1268: 	if (err) {
 1269: 		SES_FREE(sdata, bufsiz);
 1270: 		return (err);
 1271: 	}
 1272: 	amt = bufsiz - amt;
 1273: 
 1274: 	if (objid == -1) {
 1275: 		tidx = -1;
 1276: 		oidx = -1;
 1277: 	} else {
 1278: 		tidx = cc->ses_typidx[objid].ses_tidx;
 1279: 		oidx = cc->ses_typidx[objid].ses_oidx;
 1280: 	}
 1281: 	if (in) {
 1282: 		if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
 1283: 			err = ENODEV;
 1284: 		}
 1285: 	} else {
 1286: 		if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) {
 1287: 			err = ENODEV;
 1288: 		} else {
 1289: 			cdb[0] = SEND_DIAGNOSTIC;
 1290: 			cdb[1] = 0x10;
 1291: 			cdb[2] = 0;
 1292: 			cdb[3] = bufsiz >> 8;
 1293: 			cdb[4] = bufsiz & 0xff;
 1294: 			cdb[5] = 0;
 1295: 			amt = -bufsiz;
 1296: 			err = ses_runcmd(ssc, cdb, 6, sdata, &amt);   
 1297: 		}
 1298: 	}
 1299: 	SES_FREE(sdata, bufsiz);
 1300: 	return (0);
 1301: }
 1302: 
 1303: 
 1304: /*
 1305:  * Routines to parse returned SES data structures.
 1306:  * Architecture and compiler independent.
 1307:  */
 1308: 
 1309: static int
 1310: ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp)
 1311: {
 1312: 	if (buflen < SES_CFGHDR_MINLEN) {
 1313: 		return (-1);
 1314: 	}
 1315: 	gget8(buffer, 1, cfp->Nsubenc);
 1316: 	gget32(buffer, 4, cfp->GenCode);
 1317: 	return (0);
 1318: }
 1319: 
 1320: static int
 1321: ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp)
 1322: {
 1323: 	int s, off = 8;
 1324: 	for (s = 0; s < SubEncId; s++) {
 1325: 		if (off + 3 > amt)
 1326: 			return (-1);
 1327: 		off += buffer[off+3] + 4;
 1328: 	}
 1329: 	if (off + 3 > amt) {
 1330: 		return (-1);
 1331: 	}
 1332: 	gget8(buffer, off+1, chp->Subencid);
 1333: 	gget8(buffer, off+2, chp->Ntypes);
 1334: 	gget8(buffer, off+3, chp->VEnclen);
 1335: 	return (0);
 1336: }
 1337: 
 1338: static int
 1339: ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp)
 1340: {
 1341: 	int s, e, enclen, off = 8;
 1342: 	for (s = 0; s < SubEncId; s++) {
 1343: 		if (off + 3 > amt)
 1344: 			return (-1);
 1345: 		off += buffer[off+3] + 4;
 1346: 	}
 1347: 	if (off + 3 > amt) {
 1348: 		return (-1);
 1349: 	}
 1350: 	gget8(buffer, off+3, enclen);
 1351: 	off += 4;
 1352: 	if (off  >= amt)
 1353: 		return (-1);
 1354: 
 1355: 	e = off + enclen;
 1356: 	if (e > amt) {
 1357: 		e = amt;
 1358: 	}
 1359: 	MEMCPY(cdp, &buffer[off], e - off);
 1360: 	return (0);
 1361: }
 1362: 
 1363: static int
 1364: ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp)
 1365: {
 1366: 	int s, off = 8;
 1367: 
 1368: 	if (amt < SES_CFGHDR_MINLEN) {
 1369: 		return (-1);
 1370: 	}
 1371: 	for (s = 0; s < buffer[1]; s++) {
 1372: 		if (off + 3 > amt)
 1373: 			return (-1);
 1374: 		off += buffer[off+3] + 4;
 1375: 	}
 1376: 	if (off + 3 > amt) {
 1377: 		return (-1);
 1378: 	}
 1379: 	off += buffer[off+3] + 4 + (nth * 4);
 1380: 	if (amt < (off + 4))
 1381: 		return (-1);
 1382: 
 1383: 	gget8(buffer, off++, thp->enc_type);
 1384: 	gget8(buffer, off++, thp->enc_maxelt);
 1385: 	gget8(buffer, off++, thp->enc_subenc);
 1386: 	gget8(buffer, off, thp->enc_tlen);
 1387: 	return (0);
 1388: }
 1389: 
 1390: /*
 1391:  * This function needs a little explanation.
 1392:  *
 1393:  * The arguments are:
 1394:  *
 1395:  *
 1396:  *	char *b, int amt
 1397:  *
 1398:  *		These describes the raw input SES status data and length.
 1399:  *
 1400:  *	uint8_t *ep
 1401:  *
 1402:  *		This is a map of the number of types for each element type
 1403:  *		in the enclosure.
 1404:  *
 1405:  *	int elt
 1406:  *
 1407:  *		This is the element type being sought. If elt is -1,
 1408:  *		then overall enclosure status is being sought.
 1409:  *
 1410:  *	int elm
 1411:  *
 1412:  *		This is the ordinal Mth element of type elt being sought.
 1413:  *
 1414:  *	SesComStat *sp
 1415:  *
 1416:  *		This is the output area to store the status for
 1417:  *		the Mth element of type Elt.
 1418:  */
 1419: 
 1420: static int
 1421: ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
 1422: {
 1423: 	int idx, i;
 1424: 
 1425: 	/*
 1426: 	 * If it's overall enclosure status being sought, get that.
 1427: 	 * We need at least 2 bytes of status data to get that.
 1428: 	 */
 1429: 	if (elt == -1) {
 1430: 		if (amt < 2)
 1431: 			return (-1);
 1432: 		gget8(b, 1, sp->comstatus);
 1433: 		sp->comstat[0] = 0;
 1434: 		sp->comstat[1] = 0;
 1435: 		sp->comstat[2] = 0;
 1436: 		return (0);
 1437: 	}
 1438: 
 1439: 	/*
 1440: 	 * Check to make sure that the Mth element is legal for type Elt.
 1441: 	 */
 1442: 
 1443: 	if (elm >= ep[elt])
 1444: 		return (-1);
 1445: 
 1446: 	/*
 1447: 	 * Starting at offset 8, start skipping over the storage
 1448: 	 * for the element types we're not interested in.
 1449: 	 */
 1450: 	for (idx = 8, i = 0; i < elt; i++) {
 1451: 		idx += ((ep[i] + 1) * 4);
 1452: 	}
 1453: 
 1454: 	/*
 1455: 	 * Skip over Overall status for this element type.
 1456: 	 */
 1457: 	idx += 4;
 1458: 
 1459: 	/*
 1460: 	 * And skip to the index for the Mth element that we're going for.
 1461: 	 */
 1462: 	idx += (4 * elm);
 1463: 
 1464: 	/*
 1465: 	 * Make sure we haven't overflowed the buffer.
 1466: 	 */
 1467: 	if (idx+4 > amt)
 1468: 		return (-1);
 1469: 
 1470: 	/*
 1471: 	 * Retrieve the status.
 1472: 	 */
 1473: 	gget8(b, idx++, sp->comstatus);
 1474: 	gget8(b, idx++, sp->comstat[0]);
 1475: 	gget8(b, idx++, sp->comstat[1]);
 1476: 	gget8(b, idx++, sp->comstat[2]);
 1477: #if	0
 1478: 	PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4);
 1479: #endif
 1480: 	return (0);
 1481: }
 1482: 
 1483: /*
 1484:  * This is the mirror function to ses_decode, but we set the 'select'
 1485:  * bit for the object which we're interested in. All other objects,
 1486:  * after a status fetch, should have that bit off. Hmm. It'd be easy
 1487:  * enough to ensure this, so we will.
 1488:  */
 1489: 
 1490: static int
 1491: ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp)
 1492: {
 1493: 	int idx, i;
 1494: 
 1495: 	/*
 1496: 	 * If it's overall enclosure status being sought, get that.
 1497: 	 * We need at least 2 bytes of status data to get that.
 1498: 	 */
 1499: 	if (elt == -1) {
 1500: 		if (amt < 2)
 1501: 			return (-1);
 1502: 		i = 0;
 1503: 		sset8(b, i, 0);
 1504: 		sset8(b, i, sp->comstatus & 0xf);
 1505: #if	0
 1506: 		PRINTF("set EncStat %x\n", sp->comstatus);
 1507: #endif
 1508: 		return (0);
 1509: 	}
 1510: 
 1511: 	/*
 1512: 	 * Check to make sure that the Mth element is legal for type Elt.
 1513: 	 */
 1514: 
 1515: 	if (elm >= ep[elt])
 1516: 		return (-1);
 1517: 
 1518: 	/*
 1519: 	 * Starting at offset 8, start skipping over the storage
 1520: 	 * for the element types we're not interested in.
 1521: 	 */
 1522: 	for (idx = 8, i = 0; i < elt; i++) {
 1523: 		idx += ((ep[i] + 1) * 4);
 1524: 	}
 1525: 
 1526: 	/*
 1527: 	 * Skip over Overall status for this element type.
 1528: 	 */
 1529: 	idx += 4;
 1530: 
 1531: 	/*
 1532: 	 * And skip to the index for the Mth element that we're going for.
 1533: 	 */
 1534: 	idx += (4 * elm);
 1535: 
 1536: 	/*
 1537: 	 * Make sure we haven't overflowed the buffer.
 1538: 	 */
 1539: 	if (idx+4 > amt)
 1540: 		return (-1);
 1541: 
 1542: 	/*
 1543: 	 * Set the status.
 1544: 	 */
 1545: 	sset8(b, idx, sp->comstatus);
 1546: 	sset8(b, idx, sp->comstat[0]);
 1547: 	sset8(b, idx, sp->comstat[1]);
 1548: 	sset8(b, idx, sp->comstat[2]);
 1549: 	idx -= 4;
 1550: 
 1551: #if	0
 1552: 	PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n",
 1553: 	    elt, elm, idx, sp->comstatus, sp->comstat[0],
 1554: 	    sp->comstat[1], sp->comstat[2]);
 1555: #endif
 1556: 
 1557: 	/*
 1558: 	 * Now make sure all other 'Select' bits are off.
 1559: 	 */
 1560: 	for (i = 8; i < amt; i += 4) {
 1561: 		if (i != idx)
 1562: 			b[i] &= ~0x80;
 1563: 	}
 1564: 	/*
 1565: 	 * And make sure the INVOP bit is clear.
 1566: 	 */
 1567: 	b[2] &= ~0x10;
 1568: 
 1569: 	return (0);
 1570: }
 1571: 
 1572: /*
 1573:  * SAF-TE Type Device Emulation
 1574:  */
 1575: 
 1576: static int safte_getconfig(ses_softc_t *);
 1577: static int safte_rdstat(ses_softc_t *, int);;
 1578: static int set_objstat_sel(ses_softc_t *, ses_objstat *, int);
 1579: static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int);
 1580: static void wrslot_stat(ses_softc_t *, int);
 1581: static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int);
 1582: 
 1583: #define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
 1584: 	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
 1585: /*
 1586:  * SAF-TE specific defines- Mandatory ones only...
 1587:  */
 1588: 
 1589: /*
 1590:  * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb
 1591:  */
 1592: #define	SAFTE_RD_RDCFG	0x00	/* read enclosure configuration */
 1593: #define	SAFTE_RD_RDESTS	0x01	/* read enclosure status */
 1594: #define	SAFTE_RD_RDDSTS	0x04	/* read drive slot status */
 1595: 
 1596: /*
 1597:  * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf
 1598:  */
 1599: #define	SAFTE_WT_DSTAT	0x10	/* write device slot status */
 1600: #define	SAFTE_WT_SLTOP	0x12	/* perform slot operation */
 1601: #define	SAFTE_WT_FANSPD	0x13	/* set fan speed */
 1602: #define	SAFTE_WT_ACTPWS	0x14	/* turn on/off power supply */
 1603: #define	SAFTE_WT_GLOBAL	0x15	/* send global command */
 1604: 
 1605: 
 1606: #define	SAFT_SCRATCH	64
 1607: #define	NPSEUDO_THERM	16
 1608: #define	NPSEUDO_ALARM	1
 1609: struct scfg {
 1610: 	/*
 1611: 	 * Cached Configuration
 1612: 	 */
 1613: 	uint8_t	Nfans;		/* Number of Fans */
 1614: 	uint8_t	Npwr;		/* Number of Power Supplies */
 1615: 	uint8_t	Nslots;		/* Number of Device Slots */
 1616: 	uint8_t	DoorLock;	/* Door Lock Installed */
 1617: 	uint8_t	Ntherm;		/* Number of Temperature Sensors */
 1618: 	uint8_t	Nspkrs;		/* Number of Speakers */
 1619: 	uint8_t Nalarm;		/* Number of Alarms (at least one) */
 1620: 	/*
 1621: 	 * Cached Flag Bytes for Global Status
 1622: 	 */
 1623: 	uint8_t	flag1;
 1624: 	uint8_t	flag2;
 1625: 	/*
 1626: 	 * What object index ID is where various slots start.
 1627: 	 */
 1628: 	uint8_t	pwroff;
 1629: 	uint8_t	slotoff;
 1630: #define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
 1631: };
 1632: 
 1633: #define	SAFT_FLG1_ALARM		0x1
 1634: #define	SAFT_FLG1_GLOBFAIL	0x2
 1635: #define	SAFT_FLG1_GLOBWARN	0x4
 1636: #define	SAFT_FLG1_ENCPWROFF	0x8
 1637: #define	SAFT_FLG1_ENCFANFAIL	0x10
 1638: #define	SAFT_FLG1_ENCPWRFAIL	0x20
 1639: #define	SAFT_FLG1_ENCDRVFAIL	0x40
 1640: #define	SAFT_FLG1_ENCDRVWARN	0x80
 1641: 
 1642: #define	SAFT_FLG2_LOCKDOOR	0x4
 1643: #define	SAFT_PRIVATE		sizeof (struct scfg)
 1644: 
 1645: static char *safte_2little = "Too Little Data Returned (%d) at line %d\n";
 1646: #define	SAFT_BAIL(r, x, k, l)	\
 1647: 	if (r >= x) { \
 1648: 		SES_LOG(ssc, safte_2little, x, __LINE__);\
 1649: 		SES_FREE(k, l); \
 1650: 		return (EIO); \
 1651: 	}
 1652: 
 1653: 
 1654: int
 1655: safte_softc_init(ses_softc_t *ssc, int doinit)
 1656: {
 1657: 	int err, i, r;
 1658: 	struct scfg *cc;
 1659: 
 1660: 	if (doinit == 0) {
 1661: 		if (ssc->ses_nobjects) {
 1662: 			if (ssc->ses_objmap) {
 1663: 				SES_FREE(ssc->ses_objmap,
 1664: 				    ssc->ses_nobjects * sizeof (encobj));
 1665: 				ssc->ses_objmap = NULL;
 1666: 			}
 1667: 			ssc->ses_nobjects = 0;
 1668: 		}
 1669: 		if (ssc->ses_private) {
 1670: 			SES_FREE(ssc->ses_private, SAFT_PRIVATE);
 1671: 			ssc->ses_private = NULL;
 1672: 		}
 1673: 		return (0);
 1674: 	}
 1675: 
 1676: 	if (ssc->ses_private == NULL) {
 1677: 		ssc->ses_private = SES_MALLOC(SAFT_PRIVATE);
 1678: 		if (ssc->ses_private == NULL) {
 1679: 			return (ENOMEM);
 1680: 		}
 1681: 		MEMZERO(ssc->ses_private, SAFT_PRIVATE);
 1682: 	}
 1683: 
 1684: 	ssc->ses_nobjects = 0;
 1685: 	ssc->ses_encstat = 0;
 1686: 
 1687: 	if ((err = safte_getconfig(ssc)) != 0) {
 1688: 		return (err);
 1689: 	}
 1690: 
 1691: 	/*
 1692: 	 * The number of objects here, as well as that reported by the
 1693: 	 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15)
 1694: 	 * that get reported during READ_BUFFER/READ_ENC_STATUS.
 1695: 	 */
 1696: 	cc = ssc->ses_private;
 1697: 	ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock +
 1698: 	    cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM;
 1699: 	ssc->ses_objmap = (encobj *)
 1700: 	    SES_MALLOC(ssc->ses_nobjects * sizeof (encobj));
 1701: 	if (ssc->ses_objmap == NULL) {
 1702: 		return (ENOMEM);
 1703: 	}
 1704: 	MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj));
 1705: 
 1706: 	r = 0;
 1707: 	/*
 1708: 	 * Note that this is all arranged for the convenience
 1709: 	 * in later fetches of status.
 1710: 	 */
 1711: 	for (i = 0; i < cc->Nfans; i++)
 1712: 		ssc->ses_objmap[r++].enctype = SESTYP_FAN;
 1713: 	cc->pwroff = (uint8_t) r;
 1714: 	for (i = 0; i < cc->Npwr; i++)
 1715: 		ssc->ses_objmap[r++].enctype = SESTYP_POWER;
 1716: 	for (i = 0; i < cc->DoorLock; i++)
 1717: 		ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK;
 1718: 	for (i = 0; i < cc->Nspkrs; i++)
 1719: 		ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 1720: 	for (i = 0; i < cc->Ntherm; i++)
 1721: 		ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 1722: 	for (i = 0; i < NPSEUDO_THERM; i++)
 1723: 		ssc->ses_objmap[r++].enctype = SESTYP_THERM;
 1724: 	ssc->ses_objmap[r++].enctype = SESTYP_ALARM;
 1725: 	cc->slotoff = (uint8_t) r;
 1726: 	for (i = 0; i < cc->Nslots; i++)
 1727: 		ssc->ses_objmap[r++].enctype = SESTYP_DEVICE;
 1728: 	return (0);
 1729: }
 1730: 
 1731: int
 1732: safte_init_enc(ses_softc_t *ssc)
 1733: {
 1734: 	int err;
 1735: 	static char cdb0[6] = { SEND_DIAGNOSTIC };
 1736: 
 1737: 	err = ses_runcmd(ssc, cdb0, 6, NULL, 0);
 1738: 	if (err) {
 1739: 		return (err);
 1740: 	}
 1741: 	DELAY(5000);
 1742: 	err = wrbuf16(ssc, SAFTE_WT_GLOBAL, 0, 0, 0, 1);
 1743: 	return (err);
 1744: }
 1745: 
 1746: int
 1747: safte_get_encstat(ses_softc_t *ssc, int slpflg)
 1748: {
 1749: 	return (safte_rdstat(ssc, slpflg));
 1750: }
 1751: 
 1752: int
 1753: safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg)
 1754: {
 1755: 	struct scfg *cc = ssc->ses_private;
 1756: 	if (cc == NULL)
 1757: 		return (0);
 1758: 	/*
 1759: 	 * Since SAF-TE devices aren't necessarily sticky in terms
 1760: 	 * of state, make our soft copy of enclosure status 'sticky'-
 1761: 	 * that is, things set in enclosure status stay set (as implied
 1762: 	 * by conditions set in reading object status) until cleared.
 1763: 	 */
 1764: 	ssc->ses_encstat &= ~ALL_ENC_STAT;
 1765: 	ssc->ses_encstat |= (encstat & ALL_ENC_STAT);
 1766: 	ssc->ses_encstat |= ENCI_SVALID;
 1767: 	cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
 1768: 	if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) {
 1769: 		cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL;
 1770: 	} else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) {
 1771: 		cc->flag1 |= SAFT_FLG1_GLOBWARN;
 1772: 	}
 1773: 	return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
 1774: }
 1775: 
 1776: int
 1777: safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg)
 1778: {
 1779: 	int i = (int)obp->obj_id;
 1780: 
 1781: 	if ((ssc->ses_encstat & ENCI_SVALID) == 0 ||
 1782: 	    (ssc->ses_objmap[i].svalid) == 0) {
 1783: 		int err = safte_rdstat(ssc, slpflg);
 1784: 		if (err)
 1785: 			return (err);
 1786: 	}
 1787: 	obp->cstat[0] = ssc->ses_objmap[i].encstat[0];
 1788: 	obp->cstat[1] = ssc->ses_objmap[i].encstat[1];
 1789: 	obp->cstat[2] = ssc->ses_objmap[i].encstat[2];
 1790: 	obp->cstat[3] = ssc->ses_objmap[i].encstat[3];
 1791: 	return (0);
 1792: }
 1793: 
 1794: 
 1795: int
 1796: safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp)
 1797: {
 1798: 	int idx, err;
 1799: 	encobj *ep;
 1800: 	struct scfg *cc;
 1801: 
 1802: 
 1803: 	SES_DLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n",
 1804: 	    (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2],
 1805: 	    obp->cstat[3]);
 1806: 
 1807: 	/*
 1808: 	 * If this is clear, we don't do diddly.
 1809: 	 */
 1810: 	if ((obp->cstat[0] & SESCTL_CSEL) == 0) {
 1811: 		return (0);
 1812: 	}
 1813: 
 1814: 	err = 0;
 1815: 	/*
 1816: 	 * Check to see if the common bits are set and do them first.
 1817: 	 */
 1818: 	if (obp->cstat[0] & ~SESCTL_CSEL) {
 1819: 		err = set_objstat_sel(ssc, obp, slp);
 1820: 		if (err)
 1821: 			return (err);
 1822: 	}
 1823: 
 1824: 	cc = ssc->ses_private;
 1825: 	if (cc == NULL)
 1826: 		return (0);
 1827: 
 1828: 	idx = (int)obp->obj_id;
 1829: 	ep = &ssc->ses_objmap[idx];
 1830: 
 1831: 	switch (ep->enctype) {
 1832: 	case SESTYP_DEVICE:
 1833: 	{
 1834: 		uint8_t slotop = 0;
 1835: 		/*
 1836: 		 * XXX: I should probably cache the previous state
 1837: 		 * XXX: of SESCTL_DEVOFF so that when it goes from
 1838: 		 * XXX: true to false I can then set PREPARE FOR OPERATION
 1839: 		 * XXX: flag in PERFORM SLOT OPERATION write buffer command.
 1840: 		 */
 1841: 		if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
 1842: 			slotop |= 0x2;
 1843: 		}
 1844: 		if (obp->cstat[2] & SESCTL_RQSID) {
 1845: 			slotop |= 0x4;
 1846: 		}
 1847: 		err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff,
 1848: 		    slotop, slp);
 1849: 		if (err)
 1850: 			return (err);
 1851: 		if (obp->cstat[3] & SESCTL_RQSFLT) {
 1852: 			ep->priv |= 0x2;
 1853: 		} else {
 1854: 			ep->priv &= ~0x2;
 1855: 		}
 1856: 		if (ep->priv & 0xc6) {
 1857: 			ep->priv &= ~0x1;
 1858: 		} else {
 1859: 			ep->priv |= 0x1;	/* no errors */
 1860: 		}
 1861: 		wrslot_stat(ssc, slp);
 1862: 		break;
 1863: 	}
 1864: 	case SESTYP_POWER:
 1865: 		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 1866: 			cc->flag1 |= SAFT_FLG1_ENCPWRFAIL;
 1867: 		} else {
 1868: 			cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
 1869: 		}
 1870: 		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1871: 		    cc->flag2, 0, slp);
 1872: 		if (err)
 1873: 			return (err);
 1874: 		if (obp->cstat[3] & SESCTL_RQSTON) {
 1875: 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 1876: 				idx - cc->pwroff, 0, 0, slp);
 1877: 		} else {
 1878: 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 1879: 				idx - cc->pwroff, 0, 1, slp);
 1880: 		}
 1881: 		break;
 1882: 	case SESTYP_FAN:
 1883: 		if (obp->cstat[3] & SESCTL_RQSTFAIL) {
 1884: 			cc->flag1 |= SAFT_FLG1_ENCFANFAIL;
 1885: 		} else {
 1886: 			cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
 1887: 		}
 1888: 		err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1889: 		    cc->flag2, 0, slp);
 1890: 		if (err)
 1891: 			return (err);
 1892: 		if (obp->cstat[3] & SESCTL_RQSTON) {
 1893: 			uint8_t fsp;
 1894: 			if ((obp->cstat[3] & 0x7) == 7) {
 1895: 				fsp = 4;
 1896: 			} else if ((obp->cstat[3] & 0x7) == 6) {
 1897: 				fsp = 3;
 1898: 			} else if ((obp->cstat[3] & 0x7) == 4) {
 1899: 				fsp = 2;
 1900: 			} else {
 1901: 				fsp = 1;
 1902: 			}
 1903: 			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
 1904: 		} else {
 1905: 			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 1906: 		}
 1907: 		break;
 1908: 	case SESTYP_DOORLOCK:
 1909: 		if (obp->cstat[3] & 0x1) {
 1910: 			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
 1911: 		} else {
 1912: 			cc->flag2 |= SAFT_FLG2_LOCKDOOR;
 1913: 		}
 1914: 		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1915: 		    cc->flag2, 0, slp);
 1916: 		break;
 1917: 	case SESTYP_ALARM:
 1918: 		/*
 1919: 		 * On all nonzero but the 'muted' bit, we turn on the alarm,
 1920: 		 */
 1921: 		obp->cstat[3] &= ~0xa;
 1922: 		if (obp->cstat[3] & 0x40) {
 1923: 			cc->flag2 &= ~SAFT_FLG1_ALARM;
 1924: 		} else if (obp->cstat[3] != 0) {
 1925: 			cc->flag2 |= SAFT_FLG1_ALARM;
 1926: 		} else {
 1927: 			cc->flag2 &= ~SAFT_FLG1_ALARM;
 1928: 		}
 1929: 		ep->priv = obp->cstat[3];
 1930: 		(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 1931: 			cc->flag2, 0, slp);
 1932: 		break;
 1933: 	default:
 1934: 		break;
 1935: 	}
 1936: 	ep->svalid = 0;
 1937: 	return (0);
 1938: }
 1939: 
 1940: static int
 1941: safte_getconfig(ses_softc_t *ssc)
 1942: {
 1943: 	struct scfg *cfg;
 1944: 	int err, amt;
 1945: 	char *sdata;
 1946: 	static char cdb[10] =
 1947: 	    { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
 1948: 
 1949: 	cfg = ssc->ses_private;
 1950: 	if (cfg == NULL)
 1951: 		return (ENXIO);
 1952: 
 1953: 	sdata = SES_MALLOC(SAFT_SCRATCH);
 1954: 	if (sdata == NULL)
 1955: 		return (ENOMEM);
 1956: 
 1957: 	amt = SAFT_SCRATCH;
 1958: 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 1959: 	if (err) {
 1960: 		SES_FREE(sdata, SAFT_SCRATCH);
 1961: 		return (err);
 1962: 	}
 1963: 	amt = SAFT_SCRATCH - amt;
 1964: 	if (amt < 6) {
 1965: 		SES_LOG(ssc, "too little data (%d) for configuration\n", amt);
 1966: 		SES_FREE(sdata, SAFT_SCRATCH);
 1967: 		return (EIO);
 1968: 	}
 1969: 	SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n",
 1970: 	    sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]);
 1971: 	cfg->Nfans = sdata[0];
 1972: 	cfg->Npwr = sdata[1];
 1973: 	cfg->Nslots = sdata[2];
 1974: 	cfg->DoorLock = sdata[3];
 1975: 	cfg->Ntherm = sdata[4];
 1976: 	cfg->Nspkrs = sdata[5];
 1977: 	cfg->Nalarm = NPSEUDO_ALARM;
 1978: 	SES_FREE(sdata, SAFT_SCRATCH);
 1979: 	return (0);
 1980: }
 1981: 
 1982: static int
 1983: safte_rdstat(ses_softc_t *ssc, int slpflg)
 1984: {
 1985: 	int err, oid, r, i, hiwater, nitems, amt;
 1986: 	uint16_t tempflags;
 1987: 	size_t buflen;
 1988: 	uint8_t status, oencstat;
 1989: 	char *sdata, cdb[10];
 1990: 	struct scfg *cc = ssc->ses_private;
 1991: 
 1992: 
 1993: 	/*
 1994: 	 * The number of objects overstates things a bit,
 1995: 	 * both for the bogus 'thermometer' entries and
 1996: 	 * the drive status (which isn't read at the same
 1997: 	 * time as the enclosure status), but that's okay.
 1998: 	 */
 1999: 	buflen = 4 * cc->Nslots;
 2000: 	if (ssc->ses_nobjects > buflen)
 2001: 		buflen = ssc->ses_nobjects;
 2002: 	sdata = SES_MALLOC(buflen);
 2003: 	if (sdata == NULL)
 2004: 		return (ENOMEM);
 2005: 
 2006: 	cdb[0] = READ_BUFFER;
 2007: 	cdb[1] = 1;
 2008: 	cdb[2] = SAFTE_RD_RDESTS;
 2009: 	cdb[3] = 0;
 2010: 	cdb[4] = 0;
 2011: 	cdb[5] = 0;
 2012: 	cdb[6] = 0;
 2013: 	cdb[7] = (buflen >> 8) & 0xff;
 2014: 	cdb[8] = buflen & 0xff;
 2015: 	cdb[9] = 0;
 2016: 	amt = buflen;
 2017: 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2018: 	if (err) {
 2019: 		SES_FREE(sdata, buflen);
 2020: 		return (err);
 2021: 	}
 2022: 	hiwater = buflen - amt;
 2023: 
 2024: 
 2025: 	/*
 2026: 	 * invalidate all status bits.
 2027: 	 */
 2028: 	for (i = 0; i < ssc->ses_nobjects; i++)
 2029: 		ssc->ses_objmap[i].svalid = 0;
 2030: 	oencstat = ssc->ses_encstat & ALL_ENC_STAT;
 2031: 	ssc->ses_encstat = 0;
 2032: 
 2033: 
 2034: 	/*
 2035: 	 * Now parse returned buffer.
 2036: 	 * If we didn't get enough data back,
 2037: 	 * that's considered a fatal error.
 2038: 	 */
 2039: 	oid = r = 0;
 2040: 
 2041: 	for (nitems = i = 0; i < cc->Nfans; i++) {
 2042: 		SAFT_BAIL(r, hiwater, sdata, buflen);
 2043: 		/*
 2044: 		 * 0 = Fan Operational
 2045: 		 * 1 = Fan is malfunctioning
 2046: 		 * 2 = Fan is not present
 2047: 		 * 0x80 = Unknown or Not Reportable Status
 2048: 		 */
 2049: 		ssc->ses_objmap[oid].encstat[1] = 0;	/* resvd */
 2050: 		ssc->ses_objmap[oid].encstat[2] = 0;	/* resvd */
 2051: 		switch ((int)(uint8_t)sdata[r]) {
 2052: 		case 0:
 2053: 			nitems++;
 2054: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2055: 			/*
 2056: 			 * We could get fancier and cache
 2057: 			 * fan speeds that we have set, but
 2058: 			 * that isn't done now.
 2059: 			 */
 2060: 			ssc->ses_objmap[oid].encstat[3] = 7;
 2061: 			break;
 2062: 
 2063: 		case 1:
 2064: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2065: 			/*
 2066: 			 * FAIL and FAN STOPPED synthesized
 2067: 			 */
 2068: 			ssc->ses_objmap[oid].encstat[3] = 0x40;
 2069: 			/*
 2070: 			 * Enclosure marked with CRITICAL error
 2071: 			 * if only one fan or no thermometers,
 2072: 			 * else the NONCRITICAL error is set.
 2073: 			 */
 2074: 			if (cc->Nfans == 1 || cc->Ntherm == 0)
 2075: 				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2076: 			else
 2077: 				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2078: 			break;
 2079: 		case 2:
 2080: 			ssc->ses_objmap[oid].encstat[0] =
 2081: 			    SES_OBJSTAT_NOTINSTALLED;
 2082: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2083: 			/*
 2084: 			 * Enclosure marked with CRITICAL error
 2085: 			 * if only one fan or no thermometers,
 2086: 			 * else the NONCRITICAL error is set.
 2087: 			 */
 2088: 			if (cc->Nfans == 1)
 2089: 				ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2090: 			else
 2091: 				ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2092: 			break;
 2093: 		case 0x80:
 2094: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2095: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2096: 			ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2097: 			break;
 2098: 		default:
 2099: 			ssc->ses_objmap[oid].encstat[0] =
 2100: 			    SES_OBJSTAT_UNSUPPORTED;
 2101: 			SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i,
 2102: 			    sdata[r] & 0xff);
 2103: 			break;
 2104: 		}
 2105: 		ssc->ses_objmap[oid++].svalid = 1;
 2106: 		r++;
 2107: 	}
 2108: 
 2109: 	/*
 2110: 	 * No matter how you cut it, no cooling elements when there
 2111: 	 * should be some there is critical.
 2112: 	 */
 2113: 	if (cc->Nfans && nitems == 0) {
 2114: 		ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2115: 	}
 2116: 
 2117: 
 2118: 	for (i = 0; i < cc->Npwr; i++) {
 2119: 		SAFT_BAIL(r, hiwater, sdata, buflen);
 2120: 		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2121: 		ssc->ses_objmap[oid].encstat[1] = 0;	/* resvd */
 2122: 		ssc->ses_objmap[oid].encstat[2] = 0;	/* resvd */
 2123: 		ssc->ses_objmap[oid].encstat[3] = 0x20;	/* requested on */
 2124: 		switch ((uint8_t)sdata[r]) {
 2125: 		case 0x00:	/* pws operational and on */
 2126: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2127: 			break;
 2128: 		case 0x01:	/* pws operational and off */
 2129: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2130: 			ssc->ses_objmap[oid].encstat[3] = 0x10;
 2131: 			ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2132: 			break;
 2133: 		case 0x10:	/* pws is malfunctioning and commanded on */
 2134: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2135: 			ssc->ses_objmap[oid].encstat[3] = 0x61;
 2136: 			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2137: 			break;
 2138: 
 2139: 		case 0x11:	/* pws is malfunctioning and commanded off */
 2140: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
 2141: 			ssc->ses_objmap[oid].encstat[3] = 0x51;
 2142: 			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2143: 			break;
 2144: 		case 0x20:	/* pws is not present */
 2145: 			ssc->ses_objmap[oid].encstat[0] =
 2146: 			    SES_OBJSTAT_NOTINSTALLED;
 2147: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2148: 			ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2149: 			break;
 2150: 		case 0x21:	/* pws is present */
 2151: 			/*
 2152: 			 * This is for enclosures that cannot tell whether the
 2153: 			 * device is on or malfunctioning, but know that it is
 2154: 			 * present. Just fall through.
 2155: 			 */
 2156: 			/* FALLTHROUGH */
 2157: 		case 0x80:	/* Unknown or Not Reportable Status */
 2158: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2159: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2160: 			ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2161: 			break;
 2162: 		default:
 2163: 			SES_LOG(ssc, "unknown power supply %d status (0x%x)\n",
 2164: 			    i, sdata[r] & 0xff);
 2165: 			break;
 2166: 		}
 2167: 		ssc->ses_objmap[oid++].svalid = 1;
 2168: 		r++;
 2169: 	}
 2170: 
 2171: 	/*
 2172: 	 * Skip over Slot SCSI IDs
 2173: 	 */
 2174: 	r += cc->Nslots;
 2175: 
 2176: 	/*
 2177: 	 * We always have doorlock status, no matter what,
 2178: 	 * but we only save the status if we have one.
 2179: 	 */
 2180: 	SAFT_BAIL(r, hiwater, sdata, buflen);
 2181: 	if (cc->DoorLock) {
 2182: 		/*
 2183: 		 * 0 = Door Locked
 2184: 		 * 1 = Door Unlocked, or no Lock Installed
 2185: 		 * 0x80 = Unknown or Not Reportable Status
 2186: 		 */
 2187: 		ssc->ses_objmap[oid].encstat[1] = 0;
 2188: 		ssc->ses_objmap[oid].encstat[2] = 0;
 2189: 		switch ((uint8_t)sdata[r]) {
 2190: 		case 0:
 2191: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2192: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2193: 			break;
 2194: 		case 1:
 2195: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2196: 			ssc->ses_objmap[oid].encstat[3] = 1;
 2197: 			break;
 2198: 		case 0x80:
 2199: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 2200: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2201: 			ssc->ses_encstat |= SES_ENCSTAT_INFO;
 2202: 			break;
 2203: 		default:
 2204: 			ssc->ses_objmap[oid].encstat[0] =
 2205: 			    SES_OBJSTAT_UNSUPPORTED;
 2206: 			SES_LOG(ssc, "unknown lock status 0x%x\n",
 2207: 			    sdata[r] & 0xff);
 2208: 			break;
 2209: 		}
 2210: 		ssc->ses_objmap[oid++].svalid = 1;
 2211: 	}
 2212: 	r++;
 2213: 
 2214: 	/*
 2215: 	 * We always have speaker status, no matter what,
 2216: 	 * but we only save the status if we have one.
 2217: 	 */
 2218: 	SAFT_BAIL(r, hiwater, sdata, buflen);
 2219: 	if (cc->Nspkrs) {
 2220: 		ssc->ses_objmap[oid].encstat[1] = 0;
 2221: 		ssc->ses_objmap[oid].encstat[2] = 0;
 2222: 		if (sdata[r] == 1) {
 2223: 			/*
 2224: 			 * We need to cache tone urgency indicators.
 2225: 			 * Someday.
 2226: 			 */
 2227: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
 2228: 			ssc->ses_objmap[oid].encstat[3] = 0x8;
 2229: 			ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL;
 2230: 		} else if (sdata[r] == 0) {
 2231: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2232: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2233: 		} else {
 2234: 			ssc->ses_objmap[oid].encstat[0] =
 2235: 			    SES_OBJSTAT_UNSUPPORTED;
 2236: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2237: 			SES_LOG(ssc, "unknown spkr status 0x%x\n",
 2238: 			    sdata[r] & 0xff);
 2239: 		}
 2240: 		ssc->ses_objmap[oid++].svalid = 1;
 2241: 	}
 2242: 	r++;
 2243: 
 2244: 	for (i = 0; i < cc->Ntherm; i++) {
 2245: 		SAFT_BAIL(r, hiwater, sdata, buflen);
 2246: 		/*
 2247: 		 * Status is a range from -10 to 245 deg Celsius,
 2248: 		 * which we need to normalize to -20 to -245 according
 2249: 		 * to the latest SCSI spec, which makes little
 2250: 		 * sense since this would overflow an 8bit value.
 2251: 		 * Well, still, the base normalization is -20,
 2252: 		 * not -10, so we have to adjust.
 2253: 		 *
 2254: 		 * So what's over and under temperature?
 2255: 		 * Hmm- we'll state that 'normal' operating
 2256: 		 * is 10 to 40 deg Celsius.
 2257: 		 */
 2258: 
 2259: 		/*
 2260: 		 * Actually.... All of the units that people out in the world
 2261: 		 * seem to have do not come even close to setting a value that
 2262: 		 * complies with this spec.
 2263: 		 *
 2264: 		 * The closest explanation I could find was in an
 2265: 		 * LSI-Logic manual, which seemed to indicate that
 2266: 		 * this value would be set by whatever the I2C code
 2267: 		 * would interpolate from the output of an LM75
 2268: 		 * temperature sensor.
 2269: 		 *
 2270: 		 * This means that it is impossible to use the actual
 2271: 		 * numeric value to predict anything. But we don't want
 2272: 		 * to lose the value. So, we'll propagate the *uncorrected*
 2273: 		 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the
 2274: 		 * temperature flags for warnings.
 2275: 		 */
 2276: 		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL;
 2277: 		ssc->ses_objmap[oid].encstat[1] = 0;
 2278: 		ssc->ses_objmap[oid].encstat[2] = sdata[r];
 2279: 		ssc->ses_objmap[oid].encstat[3] = 0;;
 2280: 		ssc->ses_objmap[oid++].svalid = 1;
 2281: 		r++;
 2282: 	}
 2283: 
 2284: 	/*
 2285: 	 * Now, for "pseudo" thermometers, we have two bytes
 2286: 	 * of information in enclosure status- 16 bits. Actually,
 2287: 	 * the MSB is a single TEMP ALERT flag indicating whether
 2288: 	 * any other bits are set, but, thanks to fuzzy thinking,
 2289: 	 * in the SAF-TE spec, this can also be set even if no
 2290: 	 * other bits are set, thus making this really another
 2291: 	 * binary temperature sensor.
 2292: 	 */
 2293: 
 2294: 	SAFT_BAIL(r, hiwater, sdata, buflen);
 2295: 	tempflags = sdata[r++];
 2296: 	SAFT_BAIL(r, hiwater, sdata, buflen);
 2297: 	tempflags |= (tempflags << 8) | sdata[r++];
 2298: 
 2299: 	for (i = 0; i < NPSEUDO_THERM; i++) {
 2300: 		ssc->ses_objmap[oid].encstat[1] = 0;
 2301: 		if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) {
 2302: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT;
 2303: 			ssc->ses_objmap[4].encstat[2] = 0xff;
 2304: 			/*
 2305: 			 * Set 'over temperature' failure.
 2306: 			 */
 2307: 			ssc->ses_objmap[oid].encstat[3] = 8;
 2308: 			ssc->ses_encstat |= SES_ENCSTAT_CRITICAL;
 2309: 		} else {
 2310: 			/*
 2311: 			 * We used to say 'not available' and synthesize a
 2312: 			 * nominal 30 deg (C)- that was wrong. Actually,
 2313: 			 * Just say 'OK', and use the reserved value of
 2314: 			 * zero.
 2315: 			 */
 2316: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2317: 			ssc->ses_objmap[oid].encstat[2] = 0;
 2318: 			ssc->ses_objmap[oid].encstat[3] = 0;
 2319: 		}
 2320: 		ssc->ses_objmap[oid++].svalid = 1;
 2321: 	}
 2322: 
 2323: 	/*
 2324: 	 * Get alarm status.
 2325: 	 */
 2326: 	ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2327: 	ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv;
 2328: 	ssc->ses_objmap[oid++].svalid = 1;
 2329: 
 2330: 	/*
 2331: 	 * Now get drive slot status
 2332: 	 */
 2333: 	cdb[2] = SAFTE_RD_RDDSTS;
 2334: 	amt = buflen;
 2335: 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2336: 	if (err) {
 2337: 		SES_FREE(sdata, buflen);
 2338: 		return (err);
 2339: 	}
 2340: 	hiwater = buflen - amt;
 2341: 	for (r = i = 0; i < cc->Nslots; i++, r += 4) {
 2342: 		SAFT_BAIL(r+3, hiwater, sdata, buflen);
 2343: 		ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
 2344: 		ssc->ses_objmap[oid].encstat[1] = (uint8_t) i;
 2345: 		ssc->ses_objmap[oid].encstat[2] = 0;
 2346: 		ssc->ses_objmap[oid].encstat[3] = 0;
 2347: 		status = sdata[r+3];
 2348: 		if ((status & 0x1) == 0) {	/* no device */
 2349: 			ssc->ses_objmap[oid].encstat[0] =
 2350: 			    SES_OBJSTAT_NOTINSTALLED;
 2351: 		} else {
 2352: 			ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK;
 2353: 		}
 2354: 		if (status & 0x2) {
 2355: 			ssc->ses_objmap[oid].encstat[2] = 0x8;
 2356: 		}
 2357: 		if ((status & 0x4) == 0) {
 2358: 			ssc->ses_objmap[oid].encstat[3] = 0x10;
 2359: 		}
 2360: 		ssc->ses_objmap[oid++].svalid = 1;
 2361: 	}
 2362: 	/* see comment below about sticky enclosure status */
 2363: 	ssc->ses_encstat |= ENCI_SVALID | oencstat;
 2364: 	SES_FREE(sdata, buflen);
 2365: 	return (0);
 2366: }
 2367: 
 2368: static int
 2369: set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp)
 2370: {
 2371: 	int idx;
 2372: 	encobj *ep;
 2373: 	struct scfg *cc = ssc->ses_private;
 2374: 
 2375: 	if (cc == NULL)
 2376: 		return (0);
 2377: 
 2378: 	idx = (int)obp->obj_id;
 2379: 	ep = &ssc->ses_objmap[idx];
 2380: 
 2381: 	switch (ep->enctype) {
 2382: 	case SESTYP_DEVICE:
 2383: 		if (obp->cstat[0] & SESCTL_PRDFAIL) {
 2384: 			ep->priv |= 0x40;
 2385: 		}
 2386: 		/* SESCTL_RSTSWAP has no correspondence in SAF-TE */
 2387: 		if (obp->cstat[0] & SESCTL_DISABLE) {
 2388: 			ep->priv |= 0x80;
 2389: 			/*
 2390: 			 * Hmm. Try to set the 'No Drive' flag.
 2391: 			 * Maybe that will count as a 'disable'.
 2392: 			 */
 2393: 		}
 2394: 		if (ep->priv & 0xc6) {
 2395: 			ep->priv &= ~0x1;
 2396: 		} else {
 2397: 			ep->priv |= 0x1;	/* no errors */
 2398: 		}
 2399: 		wrslot_stat(ssc, slp);
 2400: 		break;
 2401: 	case SESTYP_POWER:
 2402: 		/*
 2403: 		 * Okay- the only one that makes sense here is to
 2404: 		 * do the 'disable' for a power supply.
 2405: 		 */
 2406: 		if (obp->cstat[0] & SESCTL_DISABLE) {
 2407: 			(void) wrbuf16(ssc, SAFTE_WT_ACTPWS,
 2408: 				idx - cc->pwroff, 0, 0, slp);
 2409: 		}
 2410: 		break;
 2411: 	case SESTYP_FAN:
 2412: 		/*
 2413: 		 * Okay- the only one that makes sense here is to
 2414: 		 * set fan speed to zero on disable.
 2415: 		 */
 2416: 		if (obp->cstat[0] & SESCTL_DISABLE) {
 2417: 			/* remember- fans are the first items, so idx works */
 2418: 			(void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
 2419: 		}
 2420: 		break;
 2421: 	case SESTYP_DOORLOCK:
 2422: 		/*
 2423: 		 * Well, we can 'disable' the lock.
 2424: 		 */
 2425: 		if (obp->cstat[0] & SESCTL_DISABLE) {
 2426: 			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
 2427: 			(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 2428: 				cc->flag2, 0, slp);
 2429: 		}
 2430: 		break;
 2431: 	case SESTYP_ALARM:
 2432: 		/*
 2433: 		 * Well, we can 'disable' the alarm.
 2434: 		 */
 2435: 		if (obp->cstat[0] & SESCTL_DISABLE) {
 2436: 			cc->flag2 &= ~SAFT_FLG1_ALARM;
 2437: 			ep->priv |= 0x40;	/* Muted */
 2438: 			(void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1,
 2439: 				cc->flag2, 0, slp);
 2440: 		}
 2441: 		break;
 2442: 	default:
 2443: 		break;
 2444: 	}
 2445: 	ep->svalid = 0;
 2446: 	return (0);
 2447: }
 2448: 
 2449: /*
 2450:  * This function handles all of the 16 byte WRITE BUFFER commands.
 2451:  */
 2452: static int
 2453: wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2,
 2454:     uint8_t b3, int slp)
 2455: {
 2456: 	int err, amt;
 2457: 	char *sdata;
 2458: 	struct scfg *cc = ssc->ses_private;
 2459: 	static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 };
 2460: 
 2461: 	if (cc == NULL)
 2462: 		return (0);
 2463: 
 2464: 	sdata = SES_MALLOC(16);
 2465: 	if (sdata == NULL)
 2466: 		return (ENOMEM);
 2467: 
 2468: 	SES_DLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3);
 2469: 
 2470: 	sdata[0] = op;
 2471: 	sdata[1] = b1;
 2472: 	sdata[2] = b2;
 2473: 	sdata[3] = b3;
 2474: 	MEMZERO(&sdata[4], 12);
 2475: 	amt = -16;
 2476: 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2477: 	SES_FREE(sdata, 16);
 2478: 	return (err);
 2479: }
 2480: 
 2481: /*
 2482:  * This function updates the status byte for the device slot described.
 2483:  *
 2484:  * Since this is an optional SAF-TE command, there's no point in
 2485:  * returning an error.
 2486:  */
 2487: static void
 2488: wrslot_stat(ses_softc_t *ssc, int slp)
 2489: {
 2490: 	int i, amt;
 2491: 	encobj *ep;
 2492: 	char cdb[10], *sdata;
 2493: 	struct scfg *cc = ssc->ses_private;
 2494: 
 2495: 	if (cc == NULL)
 2496: 		return;
 2497: 
 2498: 	SES_DLOG(ssc, "saf_wrslot\n");
 2499: 	cdb[0] = WRITE_BUFFER;
 2500: 	cdb[1] = 1;
 2501: 	cdb[2] = 0;
 2502: 	cdb[3] = 0;
 2503: 	cdb[4] = 0;
 2504: 	cdb[5] = 0;
 2505: 	cdb[6] = 0;
 2506: 	cdb[7] = 0;
 2507: 	cdb[8] = cc->Nslots * 3 + 1;
 2508: 	cdb[9] = 0;
 2509: 
 2510: 	sdata = SES_MALLOC(cc->Nslots * 3 + 1);
 2511: 	if (sdata == NULL)
 2512: 		return;
 2513: 	MEMZERO(sdata, cc->Nslots * 3 + 1);
 2514: 
 2515: 	sdata[0] = SAFTE_WT_DSTAT;
 2516: 	for (i = 0; i < cc->Nslots; i++) {
 2517: 		ep = &ssc->ses_objmap[cc->slotoff + i];
 2518: 		SES_DLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff);
 2519: 		sdata[1 + (3 * i)] = ep->priv & 0xff;
 2520: 	}
 2521: 	amt = -(cc->Nslots * 3 + 1);
 2522: 	(void) ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2523: 	SES_FREE(sdata, cc->Nslots * 3 + 1);
 2524: }
 2525: 
 2526: /*
 2527:  * This function issues the "PERFORM SLOT OPERATION" command.
 2528:  */
 2529: static int
 2530: perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp)
 2531: {
 2532: 	int err, amt;
 2533: 	char *sdata;
 2534: 	struct scfg *cc = ssc->ses_private;
 2535: 	static char cdb[10] =
 2536: 	    { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
 2537: 
 2538: 	if (cc == NULL)
 2539: 		return (0);
 2540: 
 2541: 	sdata = SES_MALLOC(SAFT_SCRATCH);
 2542: 	if (sdata == NULL)
 2543: 		return (ENOMEM);
 2544: 	MEMZERO(sdata, SAFT_SCRATCH);
 2545: 
 2546: 	sdata[0] = SAFTE_WT_SLTOP;
 2547: 	sdata[1] = slot;
 2548: 	sdata[2] = opflag;
 2549: 	SES_DLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag);
 2550: 	amt = -SAFT_SCRATCH;
 2551: 	err = ses_runcmd(ssc, cdb, 10, sdata, &amt);
 2552: 	SES_FREE(sdata, SAFT_SCRATCH);
 2553: 	return (err);
 2554: }