di_return_t dryice_get_tamper_event(uint32_t *events, uint32_t *timestamp,
				    int flags)
{
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	if (di_state() == DI_STATE_VALID) {
		rc = DI_ERR_STATE;
		goto err;
	}
	if (events == NULL) {
		rc = DI_ERR_INVAL;
		goto err;
	}
		*events = di_read(DSR) & DSR_TAMPER_BITS;
	if (timestamp) {
		if (di_state() == DI_STATE_NON_VALID)
			*timestamp = di_read(DTCMR);
		else
			*timestamp = 0;
	}
err:
	di_busy_clear();
	return rc;
}
di_return_t dryice_set_random_key(int flags)
{
	uint32_t dcr;
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	if (di_state() == DI_STATE_FAILURE) {
		rc = DI_ERR_STATE;
		goto err;
	}
	dcr = di_read(DCR);
	if (dcr & DCR_RKHL) {
		rc = DI_ERR_HLOCK;
		goto err;
	}
	if (dcr & DCR_RKSL) {
		rc = DI_ERR_SLOCK;
		goto err;
	}
	todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0);

	/* clear Random Key Error bit, if set */
	if (di_read(DSR) & DSR_RKE)
		todo_write_val(DSR_RKE, DCR);

	/* load random key */
	todo_write_val(DKCR_LRK, DKCR);

	/* wait for RKV (valid) or RKE (error) */
	todo_wait_rkg();

	if (flags & DI_FUNC_LOCK_FLAGS) {
		dcr = di_read(DCR);
		if (flags & DI_FUNC_FLAG_WRITE_LOCK) {
			if (flags & DI_FUNC_FLAG_HARD_LOCK)
				dcr |= DCR_RKHL;
			else
				dcr |= DCR_RKSL;
		}
		todo_write_val(dcr, DCR);
	}
	todo_start();

	if (flags & DI_FUNC_FLAG_ASYNC)
		return 0;

	rc = todo_wait_done();
err:
	di_busy_clear();
	return rc;
}
di_return_t dryice_get_programmed_key(uint8_t *key_data, int key_bits)
{
	int reg, byte, key_bytes;
	uint32_t dcr, dpkr;
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	if (key_data == NULL) {
		rc = DI_ERR_INVAL;
		goto err;
	}
	if (key_bits < 0 || key_bits > MAX_KEY_LEN || key_bits % 8) {
		rc = DI_ERR_INVAL;
		goto err;
	}
	#if 0
	if (!di->key_programmed) {
		rc = DI_ERR_UNSET;
		goto err;
	}
	#endif
	if (di_state() == DI_STATE_FAILURE) {
		rc = DI_ERR_STATE;
		goto err;
	}
	dcr = di_read(DCR);
	if (dcr & DCR_PKRHL) {
		rc = DI_ERR_HLOCK;
		goto err;
	}
	if (dcr & DCR_PKRSL) {
		rc = DI_ERR_SLOCK;
		goto err;
	}
	key_bytes = key_bits / 8;

	/* read key */
	for (reg = 0; reg < MAX_KEY_WORDS; reg++) {
		if (reg < (MAX_KEY_BYTES - key_bytes) / 4)
			continue;
		dpkr = di_read(DPKR7 - reg * 4);

		for (byte = 0; byte < 4; byte++) {
			if (reg * 4 + byte >= MAX_KEY_BYTES - key_bytes) {
				int shift = 24 - byte * 8;
				*key_data++ = (dpkr >> shift) & 0xff;
			}
		}
		dpkr = 0;	/* cleared for security */
	}
di_return_t dryice_check_key(di_key_t *key)
{
	uint32_t dksr;
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	if (key == NULL) {
		rc = DI_ERR_INVAL;
		goto err;
	}

	dksr = di_read(DKSR);

	if (di_state() != DI_STATE_VALID) {
		dksr = DKSR_IIM_KEY;
		rc = DI_ERR_STATE;
	} else if (dksr == DI_KEY_RK || dksr == DI_KEY_FRK) {
		if (!(di_read(DSR) & DSR_RKV)) {
			dksr = DKSR_IIM_KEY;
			rc = DI_ERR_UNSET;
		}
	}
	switch (dksr) {
	case DKSR_IIM_KEY:
		*key = DI_KEY_FK;
		break;
	case DKSR_PROG_KEY:
		*key = DI_KEY_PK;
		break;
	case DKSR_RAND_KEY:
		*key = DI_KEY_RK;
		break;
	case DKSR_PROG_XOR_IIM_KEY:
		*key = DI_KEY_FPK;
		break;
	case DKSR_RAND_XOR_IIM_KEY:
		*key = DI_KEY_FRK;
		break;
	}
err:
	di_busy_clear();
	return rc;
}
Пример #5
0
int
emulex_update(char *file)
{

	int		fd, retval = 0;
	int		devcnt = 0;
	uint_t		state = 0, fflag = 0;
	static uchar_t	bootpath[PATH_MAX];
	int		fcode_fd = -1;
	static struct	utmpx *utmpp = NULL;
	di_node_t	root;
	di_node_t	node, sib_node, count_node;
	di_minor_t	minor_node;
	char		phys_path[PATH_MAX], *path;
	int		errnum = 0, fcio_errno = 0;
	static uchar_t	prom_ver_data[MAXNAMELEN];
	static char	ver_file[EMULEX_FCODE_VERSION_LENGTH];
	void		(*sigint)();
	int		prop_entries = -1;
	int		*port_data = NULL;

	if (file) {
		/* set the fcode download flag */
		fflag++;

		/* check for a valid file */
		if ((fcode_fd = open(file, O_RDONLY)) < 0) {
			(void) fprintf(stderr,
			    MSGSTR(21118, "Error: Could not open %s, failed "
				    "with errno %d\n"), file, errno);
			return (1);
		}

		/* check for single user mode */
		while ((utmpp = getutxent()) != NULL) {
			if (strstr(utmpp->ut_line, "run-level") &&
				(strcmp(utmpp->ut_line, "run-level S") &&
				strcmp(utmpp->ut_line, "run-level 1"))) {
				if (q_warn(1)) {
					(void) endutxent();
					(void) close(fcode_fd);
					return (1);
				}
				break;
			}
		}
		(void) endutxent();

		/* get bootpath */
		if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
		    getenv("_LUX_D_DEBUG") != NULL) {
			(void) fprintf(stdout, "  Bootpath: %s\n", bootpath);
		}
	}

	/*
	 * Download the Fcode to all the emulex cards found
	 */

	/* Create a snapshot of the kernel device tree */
	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
		(void) fprintf(stderr, MSGSTR(21114,
		"Error: Could not get /devices path to "
		"Emulex Devices.\n"));
		retval++;
	}

	/* point to first node which matches emulex driver */
	node = di_drv_first_node("emlxs", root);

	if (node == DI_NODE_NIL) {
		/*
		 * Could not find any emulex cards
		 */
		(void) di_fini(root);
		(void) fprintf(stderr, MSGSTR(21115,
		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
		retval++;
	} else {
		count_node = node;
		while (count_node != DI_NODE_NIL) {
			state = di_state(count_node);
			if ((state & DI_DRIVER_DETACHED)
			    != DI_DRIVER_DETACHED) {
				sib_node = di_child_node(count_node);
				while (sib_node != DI_NODE_NIL) {
					state = di_state(sib_node);
					if ((state & DI_DRIVER_DETACHED) !=
					    DI_DRIVER_DETACHED) {
						/* Found an attached node */
						prop_entries =
						    di_prop_lookup_ints(
						    DDI_DEV_T_ANY, sib_node,
						    "port", &port_data);
						if (prop_entries != -1) {
							devcnt++;
							break;
						}
					}

					sib_node = di_sibling_node(sib_node);
				}
			}
			count_node = di_drv_next_node(count_node);
		}
		(void) fprintf(stdout, MSGSTR(21116,
		"\n  Found Path to %d Emulex Devices.\n"), devcnt);
	}


	/*
	 * Traverse device tree to find all emulex cards
	 */
	while (node != DI_NODE_NIL) {

		state = di_state(node);
		if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) {
			node = di_drv_next_node(node);
			continue;
		}

		sib_node = di_child_node(node);
		while (sib_node != DI_NODE_NIL) {
			state = di_state(sib_node);
			if ((state & DI_DRIVER_DETACHED) !=
			    DI_DRIVER_DETACHED) {

				/* Found an attached node */
				prop_entries = di_prop_lookup_ints(
				    DDI_DEV_T_ANY, sib_node,
				    "port", &port_data);
				if (prop_entries != -1) {

					/* Found a node with "port" property */
					minor_node = di_minor_next(sib_node,
					    DI_MINOR_NIL);
					break;
				}
			}
			sib_node = di_sibling_node(sib_node);
		}

		if (sib_node == DI_NODE_NIL) {
			goto try_next;
		}

		path = di_devfs_path(sib_node);
		(void) strcpy(phys_path, "/devices");
		(void) strncat(phys_path, path, strlen(path));
		di_devfs_path_free(path);

		if (fflag && (strstr((char *)bootpath,
		    (char *)phys_path) != NULL)) {
			(void) fprintf(stderr,
			    MSGSTR(21117, "Ignoring %s (bootpath)\n"),
			    phys_path);
			node = di_drv_next_node(node);
			continue;
		}

		if (minor_node) {
			(void) strncat(phys_path, ":", 1);
			(void) strncat(phys_path,
				di_minor_name(minor_node),
				strlen(di_minor_name(minor_node)));
		}

		(void) fprintf(stdout,
				MSGSTR(21107, "\n  Opening Device: %s\n"),
				phys_path);

		/* Check if the device is valid */
		if ((fd = open(phys_path, O_RDWR)) < 0) {
			(void) fprintf(stderr,
			    MSGSTR(21121, "Error: Could not open %s, failed "
				    "with errno %d\n"), phys_path, errno);
			retval++;
			node = di_drv_next_node(node);
			continue;
		}

		(void) close(fd);

		/*
		 * Check FCode version present on the adapter
		 * (at last boot)
		 */
		memset(prom_ver_data, 0, sizeof (prom_ver_data));
		if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0])
		    == 0) {
			errnum = 0;
			if (strlen((char *)prom_ver_data) == 0) {
				(void) fprintf(stdout, MSGSTR(21108,
	"  Detected FCode Version:\tNo version available for this FCode\n"));
			} else {
				(void) fprintf(stdout, MSGSTR(21109,
				    "  Detected FCode Version:\t%s\n"),
				    prom_ver_data);
			}
		} else {
			errnum = 2; /* can't get prom properties */
			retval++;
		}

		if (fflag) {

			memset(ver_file, 0, sizeof (ver_file));
			if (emulex_fcode_reader(fcode_fd, "fcode-version",
				    ver_file, sizeof (ver_file)) == 0) {
				(void) fprintf(stdout, MSGSTR(21110,
					    "  New FCode Version:\t\t%s\n"),
					    ver_file);
			} else {
				di_fini(root);
				(void) close(fcode_fd);
				return (1);
			}

			/*
			 * Load the New FCode
			 * Give warning if file doesn't appear to be correct
			 */
			if (!q_warn(errnum)) {
				/* Disable user-interrupt Control-C */
				sigint =
				    (void (*)(int)) signal(SIGINT, SIG_IGN);
				/* Load FCode */
				(void) fprintf(stdout, MSGSTR(21111,
					"  Loading FCode: %s\n"), file);
				if (fcode_load_file(fcode_fd, phys_path,
					    &fcio_errno) == FCODE_SUCCESS) {
					(void) fprintf(stdout, MSGSTR(21112,
					"  Successful FCode download: %s\n"),
					phys_path);
				} else {
					handle_emulex_error(fcio_errno,
					    phys_path);
					retval++;
				}

				/* Restore SIGINT (user interrupt) setting */
				(void) signal(SIGINT, sigint);
			}
		}

	try_next:
		node = di_drv_next_node(node);
	}

	di_fini(root);
	(void) fprintf(stdout, "  ");
	(void) fprintf(stdout, MSGSTR(125, "Complete\n"));
	if (fcode_fd != -1)
		(void) close(fcode_fd);
	return (retval);

}
di_return_t dryice_select_key(di_key_t key, int flags)
{
	uint32_t dcr, dksr;
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	switch (key) {
	case DI_KEY_FK:
		dksr = DKSR_IIM_KEY;
		break;
	case DI_KEY_PK:
		dksr = DKSR_PROG_KEY;
		break;
	case DI_KEY_RK:
		dksr = DKSR_RAND_KEY;
		break;
	case DI_KEY_FPK:
		dksr = DKSR_PROG_XOR_IIM_KEY;
		break;
	case DI_KEY_FRK:
		dksr = DKSR_RAND_XOR_IIM_KEY;
		break;
	default:
		rc = DI_ERR_INVAL;
		goto err;
	}
	if (di->key_selected) {
		rc = DI_ERR_INUSE;
		goto err;
	}
	if (di_state() != DI_STATE_VALID) {
		rc = DI_ERR_STATE;
		goto err;
	}
	dcr = di_read(DCR);
	if (dcr & DCR_KSHL) {
		rc = DI_ERR_HLOCK;
		goto err;
	}
	if (dcr & DCR_KSSL) {
		rc = DI_ERR_SLOCK;
		goto err;
	}
	todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0);

	/* select key */
	todo_write_val(dksr, DKSR);

	todo_assign(di->key_selected, 1);

	if (flags & DI_FUNC_LOCK_FLAGS) {
		dcr = di_read(DCR);
		if (flags & DI_FUNC_FLAG_WRITE_LOCK) {
			if (flags & DI_FUNC_FLAG_HARD_LOCK)
				dcr |= DCR_KSHL;
			else
				dcr |= DCR_KSSL;
		}
		todo_write_val(dcr, DCR);
	}
	todo_start();

	if (flags & DI_FUNC_FLAG_ASYNC)
		return 0;

	rc = todo_wait_done();
err:
	di_busy_clear();
	return rc;
}
di_return_t dryice_set_programmed_key(const void *key_data, int key_bits,
				      int flags)
{
	uint32_t dcr;
	int key_bytes, reg;
	di_return_t rc = 0;

	if (di_busy_set())
		return DI_ERR_BUSY;

	if (key_data == NULL) {
		rc = DI_ERR_INVAL;
		goto err;
	}
	if (key_bits < 0 || key_bits > MAX_KEY_LEN || key_bits % 8) {
		rc = DI_ERR_INVAL;
		goto err;
	}
	if (flags & DI_FUNC_FLAG_WORD_KEY) {
		if (key_bits % 32 || (uint32_t)key_data & 0x3) {
			rc = DI_ERR_INVAL;
			goto err;
		}
	}
	if (di->key_programmed) {
		rc = DI_ERR_INUSE;
		goto err;
	}
	if (di_state() == DI_STATE_FAILURE) {
		rc = DI_ERR_STATE;
		goto err;
	}
	dcr = di_read(DCR);
	if (dcr & DCR_PKWHL) {
		rc = DI_ERR_HLOCK;
		goto err;
	}
	if (dcr & DCR_PKWSL) {
		rc = DI_ERR_SLOCK;
		goto err;
	}
	key_bytes = key_bits / 8;

	todo_init((flags & DI_FUNC_FLAG_ASYNC) != 0);

	/* accomodate busses that can only do 32-bit transfers */
	if (flags & DI_FUNC_FLAG_WORD_KEY) {
		uint32_t *keyp = (void *)key_data;

		for (reg = 0; reg < MAX_KEY_WORDS; reg++) {
			if (reg < MAX_KEY_WORDS - key_bytes / 4)
				todo_write_val(0, DPKR7 - reg * 4);
			else {
				todo_write_ptr32(keyp, DPKR7 - reg * 4);
				keyp++;
			}
		}
	} else {
		uint8_t *keyp = (void *)key_data;

		for (reg = 0; reg < MAX_KEY_WORDS; reg++) {
			int size = key_bytes - (MAX_KEY_WORDS - reg - 1) * 4;
			if (size <= 0)
				todo_write_val(0, DPKR7 - reg * 4);
			else {
				if (size > 4)
					size = 4;
				todo_write_ptr(keyp, DPKR7 - reg * 4, size);
				keyp += size;
			}
		}
	}
	todo_assign(di->key_programmed, 1);

	if (flags & DI_FUNC_LOCK_FLAGS) {
		dcr = di_read(DCR);
		if (flags & DI_FUNC_FLAG_READ_LOCK) {
			if (flags & DI_FUNC_FLAG_HARD_LOCK)
				dcr |= DCR_PKRHL;
			else
				dcr |= DCR_PKRSL;
		}
		if (flags & DI_FUNC_FLAG_WRITE_LOCK) {
			if (flags & DI_FUNC_FLAG_HARD_LOCK)
				dcr |= DCR_PKWHL;
			else
				dcr |= DCR_PKWSL;
		}
		todo_write_val(dcr, DCR);
	}
	todo_start();

	if (flags & DI_FUNC_FLAG_ASYNC)
		return 0;

	rc = todo_wait_done();
err:
	di_busy_clear();
	return rc;
}