Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Aug 2011 22:46:18 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r225155 - projects/zfsd/head/sys/cam/scsi
Message-ID:  <201108242246.p7OMkIQK073780@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Wed Aug 24 22:46:18 2011
New Revision: 225155
URL: http://svn.freebsd.org/changeset/base/225155

Log:
  Completely rewrite SAF-TE write operations, using new fsm-based model.
  Change some SES emulation aspects, trying to be closer to the specs.

Modified:
  projects/zfsd/head/sys/cam/scsi/scsi_enc_safte.c

Modified: projects/zfsd/head/sys/cam/scsi/scsi_enc_safte.c
==============================================================================
--- projects/zfsd/head/sys/cam/scsi/scsi_enc_safte.c	Wed Aug 24 22:14:55 2011	(r225154)
+++ projects/zfsd/head/sys/cam/scsi/scsi_enc_safte.c	Wed Aug 24 22:46:18 2011	(r225155)
@@ -53,10 +53,7 @@ __FBSDID("$FreeBSD: head/sys/cam/scsi/sc
  * SAF-TE Type Device Emulation
  */
 
-static int set_elm_status_sel(enc_softc_t *, encioc_elm_status_t *, int);
 static int wrbuf16(enc_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int);
-static void wrslot_stat(enc_softc_t *, int);
-static int perf_slotop(enc_softc_t *, uint8_t, uint8_t, int);
 
 #define	ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \
 	SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
@@ -90,14 +87,17 @@ typedef enum {
 	SAFTE_UPDATE_READGFLAGS,
 	SAFTE_UPDATE_READENCSTATUS,
 	SAFTE_UPDATE_READSLOTSTATUS,
+	SAFTE_PROCESS_CONTROL_REQS,
 	SAFTE_NUM_UPDATE_STATES
 } safte_update_action;
 
 static fsm_fill_handler_t safte_fill_read_buf_io;
+static fsm_fill_handler_t safte_fill_control_request;
 static fsm_done_handler_t safte_process_config;
 static fsm_done_handler_t safte_process_gflags;
 static fsm_done_handler_t safte_process_status;
 static fsm_done_handler_t safte_process_slotstatus;
+static fsm_done_handler_t safte_process_control_request;
 
 static struct enc_fsm_state enc_fsm_states[SAFTE_NUM_UPDATE_STATES] =
 {
@@ -137,10 +137,30 @@ static struct enc_fsm_state enc_fsm_stat
 		safte_fill_read_buf_io,
 		safte_process_slotstatus,
 		enc_error
+	},
+	{
+		"SAFTE_PROCESS_CONTROL_REQS",
+		0,
+		SCSZ,
+		60 * 1000,
+		safte_fill_control_request,
+		safte_process_control_request,
+		enc_error
 	}
 };
 
-#define	NPSEUDO_ALARM	1
+typedef struct safte_control_request {
+	int	elm_idx;
+	uint8_t	elm_stat[4];
+	int	result;
+	TAILQ_ENTRY(safte_control_request) links;
+} safte_control_request_t;
+TAILQ_HEAD(safte_control_reqlist, safte_control_request);
+typedef struct safte_control_reqlist safte_control_reqlist_t;
+enum {
+	SES_SETSTATUS_ENC_IDX = -1
+};
+
 struct scfg {
 	/*
 	 * Cached Configuration
@@ -151,7 +171,6 @@ struct scfg {
 	uint8_t	DoorLock;	/* Door Lock Installed */
 	uint8_t	Ntherm;		/* Number of Temperature Sensors */
 	uint8_t	Nspkrs;		/* Number of Speakers */
-	uint8_t Nalarm;		/* Number of Alarms (at least one) */
 	uint8_t	Ntstats;	/* Number of Thermostats */
 	/*
 	 * Cached Flag Bytes for Global Status
@@ -164,6 +183,15 @@ struct scfg {
 	uint8_t	pwroff;
 	uint8_t	slotoff;
 #define	SAFT_ALARM_OFFSET(cc)	(cc)->slotoff - 1
+
+	encioc_enc_status_t	adm_status;
+	encioc_enc_status_t	enc_status;
+	encioc_enc_status_t	slot_status;
+
+	safte_control_reqlist_t	requests;
+	safte_control_request_t	*current_request;
+	int			current_request_stage;
+	int			current_request_stages;
 };
 
 #define	SAFT_FLG1_ALARM		0x1
@@ -233,7 +261,6 @@ safte_process_config(enc_softc_t *enc, s
 	cfg->DoorLock = buf[3];
 	cfg->Ntherm = buf[4];
 	cfg->Nspkrs = buf[5];
-	cfg->Nalarm = NPSEUDO_ALARM;
 	if (xfer_len >= 7)
 		cfg->Ntstats = buf[6] & 0x0f;
 	else
@@ -244,8 +271,7 @@ safte_process_config(enc_softc_t *enc, s
 	    cfg->Nspkrs, cfg->Ntstats);
 
 	enc->enc_cache.nelms = cfg->Nfans + cfg->Npwr + cfg->Nslots +
-	    cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1 +
-	    NPSEUDO_ALARM;
+	    cfg->DoorLock + cfg->Ntherm + cfg->Nspkrs + cfg->Ntstats + 1;
 	ENC_FREE_AND_NULL(enc->enc_cache.elm_map);
 	enc->enc_cache.elm_map =
 	    ENC_MALLOCZ(enc->enc_cache.nelms * sizeof(enc_element_t));
@@ -266,13 +292,12 @@ safte_process_config(enc_softc_t *enc, s
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER;
 	for (i = 0; i < cfg->DoorLock; i++)
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK;
-	for (i = 0; i < cfg->Nspkrs; i++)
+	if (cfg->Nspkrs > 0)
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM;
 	for (i = 0; i < cfg->Ntherm; i++)
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
 	for (i = 0; i <= cfg->Ntstats; i++)
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
-	enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM;
 	cfg->slotoff = (uint8_t) r;
 	for (i = 0; i < cfg->Nslots; i++)
 		enc->enc_cache.elm_map[r++].enctype = ELMTYP_DEVICE;
@@ -299,6 +324,12 @@ safte_process_gflags(enc_softc_t *enc, s
 	cfg->flag1 = buf[1];
 	cfg->flag2 = buf[2];
 
+	cfg->adm_status = 0;
+	if (cfg->flag1 & SAFT_FLG1_GLOBFAIL)
+		cfg->adm_status |= SES_ENCSTAT_CRITICAL;
+	else if (cfg->flag1 & SAFT_FLG1_GLOBWARN)
+		cfg->adm_status |= SES_ENCSTAT_NONCRITICAL;
+
 	return (0);
 }
 
@@ -317,6 +348,7 @@ safte_process_status(enc_softc_t *enc, s
 		return (ENXIO);
 
 	oid = r = 0;
+	cfg->enc_status = 0;
 
 	for (nitems = i = 0; i < cfg->Nfans; i++) {
 		SAFT_BAIL(r, xfer_len);
@@ -328,16 +360,16 @@ safte_process_status(enc_softc_t *enc, s
 		 */
 		cache->elm_map[oid].encstat[1] = 0;	/* resvd */
 		cache->elm_map[oid].encstat[2] = 0;	/* resvd */
+		if (cfg->flag1 & SAFT_FLG1_ENCFANFAIL)
+			cache->elm_map[oid].encstat[3] |= 0x40;
+		else
+			cache->elm_map[oid].encstat[3] &= ~0x40;
 		switch ((int)buf[r]) {
 		case 0:
 			nitems++;
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
-			/*
-			 * We could get fancier and cache
-			 * fan speeds that we have set, but
-			 * that isn't done now.
-			 */
-			cache->elm_map[oid].encstat[3] = 7;
+			if ((cache->elm_map[oid].encstat[3] & 0x37) == 0)
+				cache->elm_map[oid].encstat[3] |= 0x27;
 			break;
 
 		case 1:
@@ -346,35 +378,37 @@ safte_process_status(enc_softc_t *enc, s
 			/*
 			 * FAIL and FAN STOPPED synthesized
 			 */
-			cache->elm_map[oid].encstat[3] = 0x40;
+			cache->elm_map[oid].encstat[3] |= 0x10;
+			cache->elm_map[oid].encstat[3] &= ~0x07;
 			/*
 			 * Enclosure marked with CRITICAL error
 			 * if only one fan or no thermometers,
 			 * else the NONCRITICAL error is set.
 			 */
 			if (cfg->Nfans == 1 || (cfg->Ntherm + cfg->Ntstats) == 0)
-				cache->enc_status |= SES_ENCSTAT_CRITICAL;
+				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
 			else
-				cache->enc_status |= SES_ENCSTAT_NONCRITICAL;
+				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
 			break;
 		case 2:
 			cache->elm_map[oid].encstat[0] =
 			    SES_OBJSTAT_NOTINSTALLED;
-			cache->elm_map[oid].encstat[3] = 0;
+			cache->elm_map[oid].encstat[3] |= 0x10;
+			cache->elm_map[oid].encstat[3] &= ~0x07;
 			/*
 			 * Enclosure marked with CRITICAL error
 			 * if only one fan or no thermometers,
 			 * else the NONCRITICAL error is set.
 			 */
 			if (cfg->Nfans == 1)
-				cache->enc_status |= SES_ENCSTAT_CRITICAL;
+				cfg->enc_status |= SES_ENCSTAT_CRITICAL;
 			else
-				cache->enc_status |= SES_ENCSTAT_NONCRITICAL;
+				cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
 			break;
 		case 0x80:
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 			cache->elm_map[oid].encstat[3] = 0;
-			cache->enc_status |= SES_ENCSTAT_INFO;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
 			break;
 		default:
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
@@ -390,10 +424,8 @@ safte_process_status(enc_softc_t *enc, s
 	 * No matter how you cut it, no cooling elements when there
 	 * should be some there is critical.
 	 */
-	if (cfg->Nfans && nitems == 0) {
-		cache->enc_status |= SES_ENCSTAT_CRITICAL;
-	}
-
+	if (cfg->Nfans && nitems == 0)
+		cfg->enc_status |= SES_ENCSTAT_CRITICAL;
 
 	for (i = 0; i < cfg->Npwr; i++) {
 		SAFT_BAIL(r, xfer_len);
@@ -408,24 +440,24 @@ safte_process_status(enc_softc_t *enc, s
 		case 0x01:	/* pws operational and off */
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
 			cache->elm_map[oid].encstat[3] = 0x10;
-			cache->enc_status |= SES_ENCSTAT_INFO;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
 			break;
 		case 0x10:	/* pws is malfunctioning and commanded on */
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
 			cache->elm_map[oid].encstat[3] = 0x61;
-			cache->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
 			break;
 
 		case 0x11:	/* pws is malfunctioning and commanded off */
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
 			cache->elm_map[oid].encstat[3] = 0x51;
-			cache->enc_status |= SES_ENCSTAT_NONCRITICAL;
+			cfg->enc_status |= SES_ENCSTAT_NONCRITICAL;
 			break;
 		case 0x20:	/* pws is not present */
 			cache->elm_map[oid].encstat[0] =
 			    SES_OBJSTAT_NOTINSTALLED;
 			cache->elm_map[oid].encstat[3] = 0;
-			cache->enc_status |= SES_ENCSTAT_INFO;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
 			break;
 		case 0x21:	/* pws is present */
 			/*
@@ -437,7 +469,7 @@ safte_process_status(enc_softc_t *enc, s
 		case 0x80:	/* Unknown or Not Reportable Status */
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 			cache->elm_map[oid].encstat[3] = 0;
-			cache->enc_status |= SES_ENCSTAT_INFO;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
 			break;
 		default:
 			ENC_LOG(enc, "unknown power supply %d status (0x%x)\n",
@@ -449,9 +481,13 @@ safte_process_status(enc_softc_t *enc, s
 	}
 
 	/*
-	 * Skip over Slot SCSI IDs
+	 * Copy Slot SCSI IDs
 	 */
-	r += cfg->Nslots;
+	for (i = 0; i < cfg->Nslots; i++) {
+		SAFT_BAIL(r, xfer_len);
+		cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r];
+		r++;
+	}
 
 	/*
 	 * We always have doorlock status, no matter what,
@@ -478,7 +514,7 @@ safte_process_status(enc_softc_t *enc, s
 		case 0x80:
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNKNOWN;
 			cache->elm_map[oid].encstat[3] = 0;
-			cache->enc_status |= SES_ENCSTAT_INFO;
+			cfg->enc_status |= SES_ENCSTAT_INFO;
 			break;
 		default:
 			cache->elm_map[oid].encstat[0] =
@@ -497,24 +533,12 @@ safte_process_status(enc_softc_t *enc, s
 	 */
 	SAFT_BAIL(r, xfer_len);
 	if (cfg->Nspkrs) {
+		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
 		cache->elm_map[oid].encstat[1] = 0;
 		cache->elm_map[oid].encstat[2] = 0;
-		if (buf[r] == 1) {
-			/*
-			 * We need to cache tone urgency indicators.
-			 * Someday.
-			 */
-			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
-			cache->elm_map[oid].encstat[3] = 0x8;
-			cache->enc_status |= SES_ENCSTAT_NONCRITICAL;
-		} else if (buf[r] == 0) {
-			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
-			cache->elm_map[oid].encstat[3] = 0;
-		} else {
-			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
-			cache->elm_map[oid].encstat[3] = 0;
-			ENC_LOG(enc, "unknown spkr status 0x%x\n",
-			    buf[r] & 0xff);
+		if (buf[r] == 0) {
+			cache->elm_map[oid].encstat[0] |= SESCTL_DISABLE;
+			cache->elm_map[oid].encstat[3] |= 0x40;
 		}
 		cache->elm_map[oid++].svalid = 1;
 	}
@@ -569,7 +593,7 @@ safte_process_status(enc_softc_t *enc, s
 		 */
 		if (tempflags & (1 << i)) {
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
-			cache->enc_status |= SES_ENCSTAT_CRITICAL;
+			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
 		} else
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
 		cache->elm_map[oid].encstat[1] = 0;
@@ -589,7 +613,7 @@ safte_process_status(enc_softc_t *enc, s
 			 * Set 'over temperature' failure.
 			 */
 			cache->elm_map[oid].encstat[3] = 8;
-			cache->enc_status |= SES_ENCSTAT_CRITICAL;
+			cfg->enc_status |= SES_ENCSTAT_CRITICAL;
 		} else {
 			/*
 			 * We used to say 'not available' and synthesize a
@@ -610,13 +634,8 @@ safte_process_status(enc_softc_t *enc, s
 	}
 	r += 2;
 
-	/*
-	 * Get alarm status.
-	 */
-	cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
-	cache->elm_map[oid].encstat[3] = cache->elm_map[oid].priv;
-	cache->elm_map[oid++].svalid = 1;
-
+	cache->enc_status =
+	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
 	return (0);
 }
 
@@ -628,119 +647,281 @@ safte_process_slotstatus(enc_softc_t *en
 	uint8_t *buf = *bufp;
 	enc_cache_t *cache = &enc->enc_cache;
 	int oid, r, i;
-	uint8_t status;
 
 	cfg = enc->enc_private;
 	if (cfg == NULL)
 		return (ENXIO);
 
+	cfg->slot_status = 0;
 	oid = cfg->slotoff;
 	for (r = i = 0; i < cfg->Nslots; i++, r += 4) {
 		SAFT_BAIL(r+3, xfer_len);
-		cache->elm_map[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED;
-		cache->elm_map[oid].encstat[1] = (uint8_t) i;
-		cache->elm_map[oid].encstat[2] = 0;
+		cache->elm_map[oid].encstat[2] &= SESCTL_RQSID;
 		cache->elm_map[oid].encstat[3] = 0;
-		status = buf[r+3];
-		if ((status & 0x1) == 0) {	/* no device */
-			cache->elm_map[oid].encstat[0] =
-			    SES_OBJSTAT_NOTINSTALLED;
+		if ((buf[r+3] & 0x01) == 0) {	/* no device */
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NOTINSTALLED;
+		} else if (buf[r+0] & 0x02) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_CRIT;
+			cfg->slot_status |= SES_ENCSTAT_CRITICAL;
+		} else if (buf[r+0] & 0x40) {
+			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_NONCRIT;
+			cfg->slot_status |= SES_ENCSTAT_NONCRITICAL;
 		} else {
 			cache->elm_map[oid].encstat[0] = SES_OBJSTAT_OK;
 		}
-		if (status & 0x2) {
-			cache->elm_map[oid].encstat[2] = 0x8;
-		}
-		if ((status & 0x4) == 0) {
-			cache->elm_map[oid].encstat[3] = 0x10;
+		if (buf[r+3] & 0x2) {
+			if (buf[r+3] & 0x01)
+				cache->elm_map[oid].encstat[2] |= SESCTL_RQSRMV;
+			else
+				cache->elm_map[oid].encstat[2] |= SESCTL_RQSINS;
 		}
+		if ((buf[r+3] & 0x04) == 0)
+			cache->elm_map[oid].encstat[3] |= SESCTL_DEVOFF;
+		if (buf[r+0] & 0x02)
+			cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT;
+		if (buf[r+0] & 0x40)
+			cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL;
 		cache->elm_map[oid++].svalid = 1;
 	}
+
+	cache->enc_status =
+	    cfg->enc_status | cfg->slot_status | cfg->adm_status;
 	return (0);
 }
 
 static int
-set_elm_status_sel(enc_softc_t *enc, encioc_elm_status_t *elms, int slp)
+safte_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+		       union ccb *ccb, uint8_t *buf)
 {
-	int idx;
-	enc_element_t *ep;
-	struct scfg *cc = enc->enc_private;
+	struct scfg *cfg;
+	enc_element_t *ep, *ep1;
+	safte_control_request_t *req;
+	int i, idx, xfer_len;
 
-	if (cc == NULL)
-		return (0);
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
 
-	idx = (int)elms->elm_idx;
-	ep = &enc->enc_cache.elm_map[idx];
+	if (enc->enc_cache.nelms == 0) {
+		enc_update_request(enc, SAFTE_UPDATE_READCONFIG);
+		return (-1);
+	}
 
-	switch (ep->enctype) {
-	case ELMTYP_DEVICE:
-		if (elms->cstat[0] & SESCTL_PRDFAIL) {
-			ep->priv |= 0x40;
-		} else {
-			ep->priv &= ~0x40;
-		}
-		/* SESCTL_RSTSWAP has no correspondence in SAF-TE */
-		if (elms->cstat[0] & SESCTL_DISABLE) {
-			ep->priv |= 0x80;
-			/*
-			 * Hmm. Try to set the 'No Drive' flag.
-			 * Maybe that will count as a 'disable'.
-			 */
-		} else {
-			ep->priv &= ~0x80;
-		}
-		if (ep->priv & 0xc6) {
-			ep->priv &= ~0x1;
-		} else {
-			ep->priv |= 0x1;	/* no errors */
-		}
-		wrslot_stat(enc, slp);
-		break;
-	case ELMTYP_POWER:
-		/*
-		 * Okay- the only one that makes sense here is to
-		 * do the 'disable' for a power supply.
-		 */
-		if (elms->cstat[0] & SESCTL_DISABLE) {
-			(void) wrbuf16(enc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 0, slp);
-		}
-		break;
-	case ELMTYP_FAN:
-		/*
-		 * Okay- the only one that makes sense here is to
-		 * set fan speed to zero on disable.
-		 */
-		if (elms->cstat[0] & SESCTL_DISABLE) {
-			/* remember- fans are the first items, so idx works */
-			(void) wrbuf16(enc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
-		}
-		break;
-	case ELMTYP_DOORLOCK:
-		/*
-		 * Well, we can 'disable' the lock.
-		 */
-		if (elms->cstat[0] & SESCTL_DISABLE) {
-			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
-			(void) wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-				cc->flag2, 0, slp);
-		}
-		break;
-	case ELMTYP_ALARM:
-		/*
-		 * Well, we can 'disable' the alarm.
-		 */
-		if (elms->cstat[0] & SESCTL_DISABLE) {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-			ep->priv |= 0x40;	/* Muted */
-			(void) wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-				cc->flag2, 0, slp);
+	if (cfg->current_request == NULL) {
+		cfg->current_request = TAILQ_FIRST(&cfg->requests);
+		TAILQ_REMOVE(&cfg->requests, cfg->current_request, links);
+		cfg->current_request_stage = 0;
+		cfg->current_request_stages = 1;
+	}
+	req = cfg->current_request;
+
+	idx = (int)req->elm_idx;
+	if (req->elm_idx == SES_SETSTATUS_ENC_IDX) {
+		cfg->adm_status = req->elm_stat[0] & ALL_ENC_STAT;
+		cfg->flag1 &= ~(SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
+		if (req->elm_stat[0] & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV))
+			cfg->flag1 |= SAFT_FLG1_GLOBFAIL;
+		else if (req->elm_stat[0] & SES_ENCSTAT_NONCRITICAL)
+			cfg->flag1 |= SAFT_FLG1_GLOBWARN;
+		buf[0] = SAFTE_WT_GLOBAL;
+		buf[1] = cfg->flag1;
+		buf[2] = cfg->flag2;
+		buf[3] = 0;
+		xfer_len = 16;
+	} else {
+		ep = &enc->enc_cache.elm_map[idx];
+
+		switch (ep->enctype) {
+		case ELMTYP_DEVICE:
+			switch (cfg->current_request_stage) {
+			case 0:
+				ep->priv = 0;
+				if (req->elm_stat[0] & SESCTL_PRDFAIL)
+					ep->priv |= 0x40;
+				if (req->elm_stat[3] & SESCTL_RQSFLT)
+					ep->priv |= 0x02;
+				if ((ep->priv & 0x46) == 0)
+					ep->priv |= 0x01;	/* no errors */
+
+				buf[0] = SAFTE_WT_DSTAT;
+				for (i = 0; i < cfg->Nslots; i++) {
+					ep1 = &enc->enc_cache.elm_map[cfg->slotoff + i];
+					buf[1 + (3 * i)] = ep1->priv;
+					buf[2 + (3 * i)] = ep1->priv >> 8;
+				}
+				xfer_len = cfg->Nslots * 3 + 1;
+#define DEVON(x)	(!(((x)[2] & SESCTL_RQSINS) |	\
+			   ((x)[2] & SESCTL_RQSRMV) |	\
+			   ((x)[3] & SESCTL_DEVOFF)))
+				if (DEVON(req->elm_stat) != DEVON(ep->encstat))
+					cfg->current_request_stages++;
+#define IDON(x)		(!!((x)[2] & SESCTL_RQSID))
+				if (IDON(req->elm_stat) != IDON(ep->encstat))
+					cfg->current_request_stages++;
+				break;
+			case 1:
+			case 2:
+				buf[0] = SAFTE_WT_SLTOP;
+				buf[1] = idx - cfg->slotoff;
+				if (cfg->current_request_stage == 1 &&
+				    DEVON(req->elm_stat) != DEVON(ep->encstat)) {
+					if (DEVON(req->elm_stat))
+						buf[2] = 0x01;
+					else
+						buf[2] = 0x02;
+				} else {
+					if (IDON(req->elm_stat))
+						buf[2] = 0x04;
+					else
+						buf[2] = 0x00;
+					ep->encstat[2] &= ~SESCTL_RQSID;
+					ep->encstat[2] |= req->elm_stat[2] &
+					    SESCTL_RQSID;
+				}
+				xfer_len = 64;
+				break;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_POWER:
+			cfg->current_request_stages = 2;
+			switch (cfg->current_request_stage) {
+			case 0:
+				if (req->elm_stat[3] & SESCTL_RQSTFAIL) {
+					cfg->flag1 |= SAFT_FLG1_ENCPWRFAIL;
+				} else {
+					cfg->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
+				}
+				buf[0] = SAFTE_WT_GLOBAL;
+				buf[1] = cfg->flag1;
+				buf[2] = cfg->flag2;
+				buf[3] = 0;
+				xfer_len = 16;
+				break;
+			case 1:
+				buf[0] = SAFTE_WT_ACTPWS;
+				buf[1] = idx - cfg->pwroff;
+				if (req->elm_stat[3] & SESCTL_RQSTON)
+					buf[2] = 0x01;
+				else
+					buf[2] = 0x00;
+				buf[3] = 0;
+				xfer_len = 16;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_FAN:
+			if ((req->elm_stat[3] & 0x7) != 0)
+				cfg->current_request_stages = 2;
+			switch (cfg->current_request_stage) {
+			case 0:
+				if (req->elm_stat[3] & SESCTL_RQSTFAIL)
+					cfg->flag1 |= SAFT_FLG1_ENCFANFAIL;
+				else
+					cfg->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
+				buf[0] = SAFTE_WT_GLOBAL;
+				buf[1] = cfg->flag1;
+				buf[2] = cfg->flag2;
+				buf[3] = 0;
+				xfer_len = 16;
+				break;
+			case 1:
+				buf[0] = SAFTE_WT_FANSPD;
+				buf[1] = idx;
+				if (req->elm_stat[3] & SESCTL_RQSTON) {
+					if ((req->elm_stat[3] & 0x7) == 7)
+						buf[2] = 4;
+					else if ((req->elm_stat[3] & 0x7) >= 5)
+						buf[2] = 3;
+					else if ((req->elm_stat[3] & 0x7) >= 3)
+						buf[2] = 2;
+					else
+						buf[2] = 1;
+				} else
+					buf[2] = 0;
+				buf[3] = 0;
+				xfer_len = 16;
+				ep->encstat[3] = req->elm_stat[3] & 0x67;
+			default:
+				return (EINVAL);
+			}
+			break;
+		case ELMTYP_DOORLOCK:
+			if (req->elm_stat[3] & 0x1)
+				cfg->flag2 &= ~SAFT_FLG2_LOCKDOOR;
+			else
+				cfg->flag2 |= SAFT_FLG2_LOCKDOOR;
+			buf[0] = SAFTE_WT_GLOBAL;
+			buf[1] = cfg->flag1;
+			buf[2] = cfg->flag2;
+			buf[3] = 0;
+			xfer_len = 16;
+			break;
+		case ELMTYP_ALARM:
+			if ((req->elm_stat[0] & SESCTL_DISABLE) ||
+			    (req->elm_stat[3] & 0x40)) {
+				cfg->flag2 &= ~SAFT_FLG1_ALARM;
+			} else if ((req->elm_stat[3] & 0x0f) != 0) {
+				cfg->flag2 |= SAFT_FLG1_ALARM;
+			} else {
+				cfg->flag2 &= ~SAFT_FLG1_ALARM;
+			}
+			buf[0] = SAFTE_WT_GLOBAL;
+			buf[1] = cfg->flag1;
+			buf[2] = cfg->flag2;
+			buf[3] = 0;
+			xfer_len = 16;
+			ep->encstat[3] = req->elm_stat[3];
+			break;
+		default:
+			return (EINVAL);
 		}
-		break;
-	default:
-		break;
 	}
-	ep->svalid = 0;
+
+	if (enc->enc_type == ENC_SEMB_SAFT) {
+		semb_write_buffer(&ccb->ataio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG,
+				buf, xfer_len, state->timeout);
+	} else {
+		scsi_write_buffer(&ccb->csio, /*retries*/5,
+				enc_done, MSG_SIMPLE_Q_TAG, 1,
+				0, 0, buf, xfer_len,
+				SSD_FULL_SIZE, state->timeout);
+	}
+	return (0);
+}
+
+static int
+safte_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
+		   union ccb *ccb, uint8_t **bufp, int xfer_len)
+{
+	struct scfg *cfg;
+	safte_control_request_t *req;
+	int idx, type;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	if (++cfg->current_request_stage >= cfg->current_request_stages) {
+		req = cfg->current_request;
+		idx = req->elm_idx;
+		if (idx == SES_SETSTATUS_ENC_IDX)
+			type = -1;
+		else
+			type = enc->enc_cache.elm_map[idx].enctype;
+		if (type == ELMTYP_DEVICE)
+			enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
+		else
+			enc_update_request(enc, SAFTE_UPDATE_READENCSTATUS);
+		cfg->current_request = NULL;
+		req->result = 0;
+		wakeup(req);
+	} else {
+		enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	}
 	return (0);
 }
 
@@ -775,79 +956,6 @@ wrbuf16(enc_softc_t *enc, uint8_t op, ui
 	return (err);
 }
 
-/*
- * This function updates the status byte for the device slot described.
- *
- * Since this is an optional SAF-TE command, there's no point in
- * returning an error.
- */
-static void
-wrslot_stat(enc_softc_t *enc, int slp)
-{
-	int i, amt;
-	enc_element_t *ep;
-	char cdb[10], *sdata;
-	struct scfg *cc = enc->enc_private;
-
-	if (cc == NULL)
-		return;
-
-	ENC_DLOG(enc, "saf_wrslot\n");
-	cdb[0] = WRITE_BUFFER;
-	cdb[1] = 1;
-	cdb[2] = 0;
-	cdb[3] = 0;
-	cdb[4] = 0;
-	cdb[5] = 0;
-	cdb[6] = 0;
-	cdb[7] = 0;
-	cdb[8] = cc->Nslots * 3 + 1;
-	cdb[9] = 0;
-
-	sdata = ENC_MALLOCZ(cc->Nslots * 3 + 1);
-	if (sdata == NULL)
-		return;
-
-	sdata[0] = SAFTE_WT_DSTAT;
-	for (i = 0; i < cc->Nslots; i++) {
-		ep = &enc->enc_cache.elm_map[cc->slotoff + i];
-		ENC_DLOG(enc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff);
-		sdata[1 + (3 * i)] = ep->priv & 0xff;
-	}
-	amt = -(cc->Nslots * 3 + 1);
-	(void) enc_runcmd(enc, cdb, 10, sdata, &amt);
-	ENC_FREE(sdata);
-}
-
-/*
- * This function issues the "PERFORM SLOT OPERATION" command.
- */
-static int
-perf_slotop(enc_softc_t *enc, uint8_t slot, uint8_t opflag, int slp)
-{
-	int err, amt;
-	char *sdata;
-	struct scfg *cc = enc->enc_private;
-	static char cdb[10] =
-	    { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 };
-
-	if (cc == NULL)
-		return (0);
-
-	sdata = ENC_MALLOCZ(SAFT_SCRATCH);
-	if (sdata == NULL)
-		return (ENOMEM);
-
-	sdata[0] = SAFTE_WT_SLTOP;
-	sdata[1] = slot;
-	sdata[2] = opflag;
-	ENC_DLOG(enc, "saf_slotop slot %d op %x\n", slot, opflag);
-	amt = -SAFT_SCRATCH;
-	err = enc_runcmd(enc, cdb, 10, sdata, &amt);
-	ENC_FREE(sdata);
-	return (err);
-}
-
 static void
 safte_softc_cleanup(struct cam_periph *periph)
 {
@@ -882,26 +990,23 @@ safte_get_enc_status(enc_softc_t *enc, i
 }
 
 static int
-safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflg)
+safte_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag)
 {
-	struct scfg *cc = enc->enc_private;
-	if (cc == NULL)
-		return (0);
-	/*
-	 * Since SAF-TE devices aren't necessarily sticky in terms
-	 * of state, make our soft copy of enclosure status 'sticky'-
-	 * that is, things set in enclosure status stay set (as implied
-	 * by conditions set in reading object status) until cleared.
-	 */
-	enc->enc_cache.enc_status &= ~ALL_ENC_STAT;
-	enc->enc_cache.enc_status |= (encstat & ALL_ENC_STAT);
-	cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN);
-	if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) {
-		cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL;
-	} else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) {
-		cc->flag1 |= SAFT_FLG1_GLOBWARN;
-	}
-	return (wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg));
+	struct scfg *cfg;
+	safte_control_request_t req;
+
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
+
+	req.elm_idx = SES_SETSTATUS_ENC_IDX;
+	req.elm_stat[0] = encstat & 0xf;
+	
+	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
+	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
+
+	return (req.result);
 }
 
 static int
@@ -916,150 +1021,28 @@ safte_get_elm_status(enc_softc_t *enc, e
 	return (0);
 }
 
-
 static int
-safte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slp)
+safte_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
 {
-	int idx, err;
-	enc_element_t *ep;
-	struct scfg *cc;
-
+	struct scfg *cfg;
+	safte_control_request_t req;
 
-	ENC_DLOG(enc, "safte_set_objstat(%d): %x %x %x %x\n",
-	    (int)elms->elm_idx, elms->cstat[0], elms->cstat[1], elms->cstat[2],
-	    elms->cstat[3]);
+	cfg = enc->enc_private;
+	if (cfg == NULL)
+		return (ENXIO);
 
-	/*
-	 * If this is clear, we don't do diddly.
-	 */
-	if ((elms->cstat[0] & SESCTL_CSEL) == 0) {
+	/* If this is clear, we don't do diddly.  */
+	if ((elms->cstat[0] & SESCTL_CSEL) == 0)
 		return (0);
-	}
 
-	err = 0;
-	/*
-	 * Check to see if the common bits are set and do them first.
-	 */
-	if (elms->cstat[0] & ~SESCTL_CSEL) {
-		err = set_elm_status_sel(enc, elms, slp);
-		if (err)
-			return (err);
-	}
-
-	cc = enc->enc_private;
-	if (cc == NULL)
-		return (0);
+	req.elm_idx = elms->elm_idx;
+	memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat));
 
-	idx = (int)elms->elm_idx;
-	ep = &enc->enc_cache.elm_map[idx];
+	TAILQ_INSERT_TAIL(&cfg->requests, &req, links);
+	enc_update_request(enc, SAFTE_PROCESS_CONTROL_REQS);
+	cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
 
-	switch (ep->enctype) {
-	case ELMTYP_DEVICE:
-	{
-		uint8_t slotop = 0;
-		/*
-		 * XXX: I should probably cache the previous state
-		 * XXX: of SESCTL_DEVOFF so that when it goes from
-		 * XXX: true to false I can then set PREPARE FOR OPERATION
-		 * XXX: flag in PERFORM SLOT OPERATION write buffer command.
-		 */
-		if (elms->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) {
-			slotop |= 0x2;
-		}
-		if (elms->cstat[2] & SESCTL_RQSID) {
-			slotop |= 0x4;
-		}
-		err = perf_slotop(enc, (uint8_t) idx - (uint8_t) cc->slotoff,
-		    slotop, slp);
-		if (err)
-			return (err);
-		if (elms->cstat[3] & SESCTL_RQSFLT) {
-			ep->priv |= 0x2;
-		} else {
-			ep->priv &= ~0x2;
-		}
-		if (ep->priv & 0xc6) {
-			ep->priv &= ~0x1;
-		} else {
-			ep->priv |= 0x1;	/* no errors */
-		}
-		wrslot_stat(enc, slp);
-		break;
-	}
-	case ELMTYP_POWER:
-		if (elms->cstat[3] & SESCTL_RQSTFAIL) {
-			cc->flag1 |= SAFT_FLG1_ENCPWRFAIL;
-		} else {
-			cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL;
-		}
-		err = wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		if (err)
-			return (err);
-		if (elms->cstat[3] & SESCTL_RQSTON) {
-			(void) wrbuf16(enc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 0, slp);
-		} else {
-			(void) wrbuf16(enc, SAFTE_WT_ACTPWS,
-				idx - cc->pwroff, 0, 1, slp);
-		}
-		break;
-	case ELMTYP_FAN:
-		if (elms->cstat[3] & SESCTL_RQSTFAIL) {
-			cc->flag1 |= SAFT_FLG1_ENCFANFAIL;
-		} else {
-			cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL;
-		}
-		err = wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		if (err)
-			return (err);
-		if (elms->cstat[3] & SESCTL_RQSTON) {
-			uint8_t fsp;
-			if ((elms->cstat[3] & 0x7) == 7) {
-				fsp = 4;
-			} else if ((elms->cstat[3] & 0x7) == 6) {
-				fsp = 3;
-			} else if ((elms->cstat[3] & 0x7) == 4) {
-				fsp = 2;
-			} else {
-				fsp = 1;
-			}
-			(void) wrbuf16(enc, SAFTE_WT_FANSPD, idx, fsp, 0, slp);
-		} else {
-			(void) wrbuf16(enc, SAFTE_WT_FANSPD, idx, 0, 0, slp);
-		}
-		break;
-	case ELMTYP_DOORLOCK:
-		if (elms->cstat[3] & 0x1) {
-			cc->flag2 &= ~SAFT_FLG2_LOCKDOOR;
-		} else {
-			cc->flag2 |= SAFT_FLG2_LOCKDOOR;
-		}
-		(void) wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-		    cc->flag2, 0, slp);
-		break;
-	case ELMTYP_ALARM:
-		/*
-		 * On all nonzero but the 'muted' bit, we turn on the alarm,
-		 */
-		elms->cstat[3] &= ~0xa;
-		if (elms->cstat[3] & 0x40) {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-		} else if (elms->cstat[3] != 0) {
-			cc->flag2 |= SAFT_FLG1_ALARM;
-		} else {
-			cc->flag2 &= ~SAFT_FLG1_ALARM;
-		}
-		ep->priv = elms->cstat[3];
-		(void) wrbuf16(enc, SAFTE_WT_GLOBAL, cc->flag1,
-			cc->flag2, 0, slp);
-		break;
-	default:
-		break;
-	}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108242246.p7OMkIQK073780>