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