summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4/io/efcode/fcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/sun4/io/efcode/fcode.c')
-rw-r--r--usr/src/uts/sun4/io/efcode/fcode.c65
1 files changed, 63 insertions, 2 deletions
diff --git a/usr/src/uts/sun4/io/efcode/fcode.c b/usr/src/uts/sun4/io/efcode/fcode.c
index 0f0b4b54f1..f98ed8db01 100644
--- a/usr/src/uts/sun4/io/efcode/fcode.c
+++ b/usr/src/uts/sun4/io/efcode/fcode.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,6 +59,7 @@ static struct fc_state {
#define FC_STATE_READ_DONE 2 /* blocking read done */
#define FC_STATE_IN_PROGRESS 3 /* FC_GET_PARAMETERS done, active */
#define FC_STATE_VALIDATED 4 /* FC_VALIDATE done, active */
+#define FC_STATE_ERROR_SET 5 /* FC_SET_FCODE_ERROR done, active */
#define FC_STATE_ACTIVE(s) ((s) != 0)
#define FC_STATE_AVAILABLE(s) ((s) == FC_STATE_INACTIVE)
@@ -79,6 +80,7 @@ static int fc_get_my_args(dev_t, intptr_t, int, cred_t *, int *);
static int fc_run_priv(dev_t, intptr_t, int, cred_t *, int *);
static int fc_validate(dev_t, intptr_t, int, cred_t *, int *);
static int fc_get_fcode(dev_t, intptr_t, int, cred_t *, int *);
+static int fc_set_fcode_error(dev_t, intptr_t, int, cred_t *, int *);
static struct cb_ops fc_cb_ops = {
fc_open, /* open */
@@ -335,7 +337,13 @@ fc_close(dev_t dev, int flag, int otype, cred_t *cred_p)
"fc_close: Send invalidate cmd\n");
cp->svc_name = fc_ptr2cell(FC_SVC_INVALIDATE);
(void) fp->ap_ops(fp->ap_dip, fp->handle, cp);
- fp->error = FC_ERROR;
+ if ((st->state != FC_STATE_ERROR_SET) ||
+ (fp->error == FC_SUCCESS)) {
+ fp->error = FC_ERROR;
+ }
+ /*
+ * else - fp->error already set by userland interpreter
+ */
}
bzero(cp, sizeof (struct fc_client_interface));
@@ -464,6 +472,12 @@ fc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
*/
return (fc_get_fcode(dev, arg, mode, credp, rvalp));
+
+ case FC_SET_FCODE_ERROR:
+ /*
+ * Copy in interpreter error status
+ */
+ return (fc_set_fcode_error(dev, arg, mode, credp, rvalp));
}
/*
* Invalid ioctl command
@@ -859,3 +873,50 @@ fc_get_fcode(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp)
return (0);
}
+
+/*
+ * fc_set_fcode_error: Copy in fcode error.
+ * The input 'arg' is a pointer to int which
+ * should have the appropriate error code set.
+ */
+
+/*ARGSUSED*/
+static int
+fc_set_fcode_error(dev_t dev, intptr_t arg, int mode, cred_t *credp, int *rvalp)
+{
+ struct fc_state *st;
+ struct fc_request *fp;
+ int m = (int)getminor(dev) - 1;
+ int status;
+
+ st = fc_states + m;
+ ASSERT(m < fc_max_opens && FC_STATE_ACTIVE(st->state));
+
+ ASSERT(st->req != NULL);
+ fp = st->req;
+
+ FC_DEBUG1(3, CE_CONT, "fc_ioctl: fc_set_fcode_error fp: %p\n", fp);
+
+ /*
+ * Get the error code from userland.
+ * We expect these to be negative values to denote
+ * interpreter errors.
+ */
+ if (copyin((void *)arg, &status, sizeof (int))) {
+ FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_set_fcode_error "
+ "fault copying in status from %p\n", arg);
+ return (EFAULT);
+ }
+
+ if (!FC_ERROR_VALID(status)) {
+ FC_DEBUG1(1, CE_CONT, "fc_ioctl: fc_set_fcode_error "
+ "invalid error code specified %i\n", status);
+ return (EINVAL);
+ }
+ fp->error = status;
+ mutex_enter(&fc_open_lock);
+ st->state = FC_STATE_ERROR_SET;
+ mutex_exit(&fc_open_lock);
+
+ return (0);
+}