/* * hci1394_tlabel_register() * Register an opaque command with an alloc()'d tlabel. Each nodeID has it's * own tlabel list. */ void hci1394_tlabel_register(hci1394_tlabel_handle_t tlabel_handle, hci1394_tlabel_info_t *tlabel_info, void *cmd) { uint_t node_number; uint_t tlabel; ASSERT(tlabel_handle != NULL); ASSERT(tlabel_info != NULL); ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); TNF_PROBE_0_DEBUG(hci1394_tlabel_register_enter, HCI1394_TNF_HAL_STACK, ""); /* figure out what node and tlabel we are using */ node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); tlabel = tlabel_info->tbi_tlabel; mutex_enter(&tlabel_handle->tb_mutex); /* enter the (void *) into the lookup table */ tlabel_handle->tb_lookup[node_number][tlabel] = cmd; mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_0_DEBUG(hci1394_tlabel_register_exit, HCI1394_TNF_HAL_STACK, ""); }
/* * hci1394_tlabel_bad() * Register the specified tlabel as bad. tlabel_lookup() will no longer * return a registered opaque command and this tlabel will not be returned * from alloc() until > reclaim_time has passed. See set_reclaim_time() for * more info. */ void hci1394_tlabel_bad(hci1394_tlabel_handle_t tlabel_handle, hci1394_tlabel_info_t *tlabel_info) { uint_t node_number; uint_t tlabel; ASSERT(tlabel_handle != NULL); ASSERT(tlabel_info != NULL); TNF_PROBE_0_DEBUG(hci1394_tlabel_bad_enter, HCI1394_TNF_HAL_STACK, ""); /* figure out what node and tlabel we are using */ node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); tlabel = tlabel_info->tbi_tlabel & TLABEL_MASK; mutex_enter(&tlabel_handle->tb_mutex); TNF_PROBE_2(hci1394_tlabel_timeout, HCI1394_TNF_HAL_ERROR, "", tnf_uint, nodeid, node_number, tnf_uint, bad_tlabel, tlabel_info->tbi_tlabel); /* * Put the tlabel in the bad list and NULL out the (void *) in the * lookup structure. We may see this tlabel shortly if the device is * late in responding. We want to make sure to drop the message if we * do. Set the bad timestamp to the current time plus the reclaim time. * This is the "new" time when all of the bad tlabels for this node will * be free'd. */ tlabel_handle->tb_bad_timestamp[node_number] = gethrtime() + tlabel_handle->tb_reclaim_time; tlabel_handle->tb_bad[node_number] |= ((uint64_t)1 << tlabel); tlabel_handle->tb_lookup[node_number][tlabel] = NULL; mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_0_DEBUG(hci1394_tlabel_bad_exit, HCI1394_TNF_HAL_STACK, ""); }
/* * hci1394_tlabel_lookup() * returns (in cmd) the opaque command which was registered with the * specified tlabel from alloc(). If a tlabel was not registered, cmd ='s * NULL. */ void hci1394_tlabel_lookup(hci1394_tlabel_handle_t tlabel_handle, hci1394_tlabel_info_t *tlabel_info, void **cmd) { uint_t node_number; uint_t tlabel; ASSERT(tlabel_handle != NULL); ASSERT(tlabel_info != NULL); ASSERT(cmd != NULL); ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); TNF_PROBE_0_DEBUG(hci1394_tlabel_lookup_enter, HCI1394_TNF_HAL_STACK, ""); /* figure out what node and tlabel we are using */ node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); tlabel = tlabel_info->tbi_tlabel; mutex_enter(&tlabel_handle->tb_mutex); /* * fetch the (void *) from the lookup table. The case where the pointer * equals NULL will be handled by the layer above. */ *cmd = tlabel_handle->tb_lookup[node_number][tlabel]; mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_2_DEBUG(hci1394_tlabel_lookup, HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, node_number, tnf_uint, lookup_tlabel, tlabel_info->tbi_tlabel); TNF_PROBE_0_DEBUG(hci1394_tlabel_lookup_exit, HCI1394_TNF_HAL_STACK, ""); }
/* * hci1394_tlabel_free() * free the previously alloc()'d tlabel. Once a tlabel has been free'd, it * can be used again when alloc() is called. */ void hci1394_tlabel_free(hci1394_tlabel_handle_t tlabel_handle, hci1394_tlabel_info_t *tlabel_info) { uint_t node_number; uint_t tlabel; ASSERT(tlabel_handle != NULL); ASSERT(tlabel_info != NULL); ASSERT(tlabel_info->tbi_tlabel <= TLABEL_MASK); TNF_PROBE_0_DEBUG(hci1394_tlabel_free_enter, HCI1394_TNF_HAL_STACK, ""); /* figure out what node and tlabel we are using */ node_number = IEEE1394_NODE_NUM(tlabel_info->tbi_destination); tlabel = tlabel_info->tbi_tlabel; TNF_PROBE_2_DEBUG(hci1394_tlabel_free, HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, node_number, tnf_uint, freed_tlabel, tlabel_info->tbi_tlabel); mutex_enter(&tlabel_handle->tb_mutex); /* * Put the tlabel back in the free list and NULL out the (void *) in the * lookup structure. You wouldn't expect to have to null out the lookup * structure, but we know first hand that bad HW will send invalid * tlabels which could really mess things up if you didn't :-) */ tlabel_handle->tb_lookup[node_number][tlabel] = NULL; tlabel_handle->tb_free[node_number] |= ((uint64_t)1 << tlabel); mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_0_DEBUG(hci1394_tlabel_free_exit, HCI1394_TNF_HAL_STACK, ""); }
/* * hci1394_tlabel_alloc() * alloc a tlabel based on the node id. If alloc fails, we are out of * tlabels for that node. See comments before set_reclaim_time() on when * bad tlabel's are free to be used again. */ int hci1394_tlabel_alloc(hci1394_tlabel_handle_t tlabel_handle, uint_t destination, hci1394_tlabel_info_t *tlabel_info) { uint_t node_number; uint_t index; uint64_t bad; uint64_t free; hrtime_t time; uint8_t last; ASSERT(tlabel_handle != NULL); ASSERT(tlabel_info != NULL); TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_enter, HCI1394_TNF_HAL_STACK, ""); /* copy destination into tlabel_info */ tlabel_info->tbi_destination = destination; /* figure out what node we are going to */ node_number = IEEE1394_NODE_NUM(destination); mutex_enter(&tlabel_handle->tb_mutex); /* * Keep track of if we have sent out a broadcast request and what the * maximum # node we have sent to for reset processing optimization */ if (node_number == IEEE1394_BROADCAST_NODEID) { tlabel_handle->tb_bcast_sent = B_TRUE; } else if (node_number > tlabel_handle->tb_max_node) { tlabel_handle->tb_max_node = node_number; } /* setup copies so we don't take up so much space :-) */ bad = tlabel_handle->tb_bad[node_number]; free = tlabel_handle->tb_free[node_number]; time = tlabel_handle->tb_bad_timestamp[node_number]; last = tlabel_handle->tb_last[node_number]; /* * If there are any bad tlabels, see if the last bad tlabel recorded for * this nodeid is now good to use. If so, add all bad tlabels for that * node id back into the free list * * NOTE: This assumes that bad tlabels are infrequent. */ if (bad != 0) { if (gethrtime() > time) { /* add the bad tlabels back into the free list */ free |= bad; /* clear the bad list */ bad = 0; TNF_PROBE_1(hci1394_tlabel_free_bad, HCI1394_TNF_HAL_ERROR, "", tnf_uint, nodeid, node_number); } } /* * Find a free tlabel. This will break out of the loop once it finds a * tlabel. There are a total of TLABEL_RANGE tlabels. The alloc * rotates the check so that we don't always use the same tlabel. It * stores the last tlabel used in last. */ for (index = 0; index < TLABEL_RANGE; index++) { /* if the next tlabel to check is free */ if ((free & ((uint64_t)1 << last)) != 0) { /* we are using this tlabel */ tlabel_info->tbi_tlabel = last; TNF_PROBE_2_DEBUG(hci1394_tlabel_alloc, HCI1394_TNF_HAL_TLABEL, "", tnf_uint, nodeid, node_number, tnf_uint, alloced_tlabel, tlabel_info->tbi_tlabel); /* take it out of the free list */ free = free & ~((uint64_t)1 << last); /* * increment the last count so we start checking on the * next tlabel next alloc(). Note the rollover at * TLABEL_RANGE since we only have TLABEL_RANGE tlabels. */ (last)++; if (last >= TLABEL_RANGE) { last = 0; } /* Copy the copies back */ tlabel_handle->tb_bad[node_number] = bad; tlabel_handle->tb_free[node_number] = free; tlabel_handle->tb_bad_timestamp[node_number] = time; tlabel_handle->tb_last[node_number] = last; /* unlock the tlabel structure */ mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_SUCCESS); } /* * This tlabel is not free, lets go to the next one. Note the * rollover at TLABEL_RANGE since we only have TLABEL_RANGE * tlabels. */ (last)++; if (last >= TLABEL_RANGE) { last = 0; } } /* Copy the copies back */ tlabel_handle->tb_bad[node_number] = bad; tlabel_handle->tb_free[node_number] = free; tlabel_handle->tb_bad_timestamp[node_number] = time; tlabel_handle->tb_last[node_number] = last; mutex_exit(&tlabel_handle->tb_mutex); TNF_PROBE_1(hci1394_tlabel_alloc_empty, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "No more tlabels left to alloc"); TNF_PROBE_0_DEBUG(hci1394_tlabel_alloc_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_FAILURE); }
/* * print_node_info() * is used to do the actual printing, given a HAL pointer. */ static int print_node_info(s1394_hal_t *hal) { s1394_node_t node[IEEE1394_MAX_NODES]; uint32_t cfgrom[IEEE1394_CONFIG_ROM_QUAD_SZ]; char str[512], tmp[512]; uint_t hal_node_num, num_nodes; int i, j; num_nodes = hal->number_of_nodes; if (mdb_vread(node, (num_nodes * sizeof (s1394_node_t)), (uintptr_t)hal->topology_tree) == -1) { mdb_warn("failed to read the node structures"); return (DCMD_ERR); } hal_node_num = IEEE1394_NODE_NUM(hal->node_id); mdb_printf("Speed Map:\n"); (void) strcpy(str, " |"); for (i = 0; i < num_nodes; i++) { (void) mdb_snprintf(tmp, sizeof (tmp), " %2d ", i); (void) strcat(str, tmp); } (void) strcat(str, " | GUID\n"); mdb_printf("%s", str); (void) strcpy(str, "----|"); for (i = 0; i < hal->number_of_nodes; i++) { (void) mdb_snprintf(tmp, sizeof (tmp), "----"); (void) strcat(str, tmp); } (void) strcat(str, "--|------------------\n"); mdb_printf("%s", str); for (i = 0; i < num_nodes; i++) { if (node[i].cfgrom != NULL) { if (mdb_vread(&cfgrom, IEEE1394_CONFIG_ROM_SZ, (uintptr_t)node[i].cfgrom) == -1) { mdb_warn("failed to read Config ROM"); return (DCMD_ERR); } } (void) mdb_snprintf(str, sizeof (str), " %2d |", i); for (j = 0; j < num_nodes; j++) { (void) mdb_snprintf(tmp, sizeof (tmp), " %3d", hal->speed_map[i][j]); (void) strcat(str, tmp); } if (i == hal_node_num) { (void) strcat(str, " | Local OHCI Card\n"); } else if (node[i].link_active == 0) { (void) strcat(str, " | Link off\n"); } else if (CFGROM_BIB_READ(&node[i])) { (void) mdb_snprintf(tmp, sizeof (tmp), " | %08x%08x\n", cfgrom[3], cfgrom[4]); (void) strcat(str, tmp); } else { (void) strcat(str, " | ????????????????\n"); } mdb_printf("%s", str); } mdb_printf("\n"); return (DCMD_OK); }
/* * hci1394_isr_self_id() * Process the selfid complete interrupt. The bus reset has completed * and the 1394 HW has finished it's bus enumeration. The SW needs to * see what's changed and handle any hotplug conditions. */ static void hci1394_isr_self_id(hci1394_state_t *soft_state) { int status; uint_t node_id; uint_t selfid_size; uint_t quadlet_count; uint_t index; uint32_t *selfid_buf_p; boolean_t selfid_error; boolean_t nodeid_error; boolean_t saw_error = B_FALSE; uint_t phy_status; ASSERT(soft_state != NULL); TNF_PROBE_0_DEBUG(hci1394_isr_self_id_enter, HCI1394_TNF_HAL_STACK, ""); soft_state->drvinfo.di_stats.st_selfid_count++; /* * check for the bizarre case that we got both a bus reset and self id * complete after checking for a bus reset */ if (hci1394_state(&soft_state->drvinfo) != HCI1394_BUS_RESET) { hci1394_isr_bus_reset(soft_state); } /* * Clear any set PHY error status bits set. The PHY status bits * may always be set (i.e. we removed cable power) so we do not want * to clear them when we handle the interrupt. We will clear them * every selfid complete interrupt so worst case we will get 1 PHY event * interrupt every bus reset. */ status = hci1394_ohci_phy_read(soft_state->ohci, 5, &phy_status); if (status != DDI_SUCCESS) { TNF_PROBE_0(hci1394_isr_self_id_pr_fail, HCI1394_TNF_HAL_ERROR, ""); } else { phy_status |= OHCI_PHY_LOOP_ERR | OHCI_PHY_PWRFAIL_ERR | OHCI_PHY_TIMEOUT_ERR | OHCI_PHY_PORTEVT_ERR; status = hci1394_ohci_phy_write(soft_state->ohci, 5, phy_status); if (status != DDI_SUCCESS) { TNF_PROBE_0(hci1394_isr_self_id_pw_fail, HCI1394_TNF_HAL_ERROR, ""); } else { /* * Re-enable PHY interrupt. We disable the PHY interrupt * when we get one so that we do not get stuck in the * ISR. */ hci1394_ohci_intr_enable(soft_state->ohci, OHCI_INTR_PHY); } } /* See if either AT active bit is set */ if (hci1394_ohci_at_active(soft_state->ohci) == B_TRUE) { TNF_PROBE_1(hci1394_isr_self_id_as_fail, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "AT ACTIVE still set"); saw_error = B_TRUE; } /* Clear busReset and selfIdComplete interrupts */ hci1394_ohci_intr_clear(soft_state->ohci, (OHCI_INTR_BUS_RESET | OHCI_INTR_SELFID_CMPLT)); /* Read node info and test for Invalid Node ID */ hci1394_ohci_nodeid_info(soft_state->ohci, &node_id, &nodeid_error); if (nodeid_error == B_TRUE) { TNF_PROBE_1(hci1394_isr_self_id_ni_fail, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "saw invalid NodeID"); saw_error = B_TRUE; } /* Sync Selfid Buffer */ hci1394_ohci_selfid_sync(soft_state->ohci); /* store away selfid info */ hci1394_ohci_selfid_info(soft_state->ohci, &soft_state->drvinfo.di_gencnt, &selfid_size, &selfid_error); /* Test for selfid error */ if (selfid_error == B_TRUE) { TNF_PROBE_1(hci1394_isr_self_id_si_fail, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "saw invalid SelfID"); saw_error = B_TRUE; } /* * selfid size could be 0 if a bus reset has occurred. If this occurs, * we should have another selfid int coming later. */ if ((saw_error == B_FALSE) && (selfid_size == 0)) { TNF_PROBE_0_DEBUG(hci1394_isr_self_id_exit, HCI1394_TNF_HAL_STACK, ""); return; } /* * make sure generation count in buffer matches generation * count in register. */ if (hci1394_ohci_selfid_buf_current(soft_state->ohci) == B_FALSE) { TNF_PROBE_0_DEBUG(hci1394_isr_self_id_exit, HCI1394_TNF_HAL_STACK, ""); return; } /* * Skip over first quadlet in selfid buffer, this is OpenHCI specific * data. */ selfid_size = selfid_size - IEEE1394_QUADLET; quadlet_count = selfid_size >> 2; /* Copy selfid buffer to Services Layer buffer */ for (index = 0; index < quadlet_count; index++) { hci1394_ohci_selfid_read(soft_state->ohci, index + 1, &soft_state->sl_selfid_buf[index]); } /* * Put our selfID info into the Services Layer's selfid buffer if we * have a 1394-1995 PHY. */ if (soft_state->halinfo.phy == H1394_PHY_1995) { selfid_buf_p = (uint32_t *)( (uintptr_t)soft_state->sl_selfid_buf + (uintptr_t)selfid_size); status = hci1394_ohci_phy_info(soft_state->ohci, &selfid_buf_p[0]); if (status != DDI_SUCCESS) { /* * If we fail reading from PHY, put invalid data into * the selfid buffer so the SL will reset the bus again. */ TNF_PROBE_0(hci1394_isr_self_id_pi_fail, HCI1394_TNF_HAL_ERROR, ""); selfid_buf_p[0] = 0xFFFFFFFF; selfid_buf_p[1] = 0xFFFFFFFF; } else { selfid_buf_p[1] = ~selfid_buf_p[0]; } selfid_size = selfid_size + 8; } /* Flush out async DMA Q's */ hci1394_async_flush(soft_state->async); /* * Make sure generation count is still valid. i.e. we have not gotten * another bus reset since the last time we checked. If we have gotten * another bus reset, we should have another selfid interrupt coming. */ if (soft_state->drvinfo.di_gencnt != hci1394_ohci_current_busgen(soft_state->ohci)) { TNF_PROBE_0_DEBUG(hci1394_isr_self_id_exit, HCI1394_TNF_HAL_STACK, ""); return; } /* * do whatever CSR register processing that needs to be done. */ hci1394_csr_bus_reset(soft_state->csr); /* * do whatever management may be necessary for the CYCLE_LOST and * CYCLE_INCONSISTENT interrupts. */ hci1394_isoch_error_ints_enable(soft_state); /* * See if we saw an error. If we did, tell the services layer that we * finished selfid processing and give them an illegal selfid buffer * size of 0. The Services Layer will try to reset the bus again to * see if we can recover from this problem. It will threshold after * a finite number of errors. */ if (saw_error == B_TRUE) { h1394_self_ids(soft_state->drvinfo.di_sl_private, soft_state->sl_selfid_buf, 0, node_id, soft_state->drvinfo.di_gencnt); /* * Take ourself out of Bus Reset processing mode * * Set the driver state to normal. If we cannot, we have been * shutdown. The only way we can get in this code is if we have * a multi-processor machine and the HAL is shutdown by one * processor running in base context while this interrupt * handler runs in another processor. We will disable all * interrupts and just return. We shouldn't have to disable * the interrupts, but we will just in case. */ status = hci1394_state_set(&soft_state->drvinfo, HCI1394_NORMAL); if (status != DDI_SUCCESS) { hci1394_ohci_intr_master_disable(soft_state->ohci); return; } } else if (IEEE1394_NODE_NUM(node_id) != 63) { /* * Notify services layer about self-id-complete. Don't notify * the services layer if there are too many devices on the bus. */ h1394_self_ids(soft_state->drvinfo.di_sl_private, soft_state->sl_selfid_buf, selfid_size, node_id, soft_state->drvinfo.di_gencnt); /* * Take ourself out of Bus Reset processing mode * * Set the driver state to normal. If we cannot, we have been * shutdown. The only way we can get in this code is if we have * a multi-processor machine and the HAL is shutdown by one * processor running in base context while this interrupt * handler runs in another processor. We will disable all * interrupts and just return. We shouldn't have to disable * the interrupts, but we will just in case. */ status = hci1394_state_set(&soft_state->drvinfo, HCI1394_NORMAL); if (status != DDI_SUCCESS) { hci1394_ohci_intr_master_disable(soft_state->ohci); return; } } else { cmn_err(CE_NOTE, "hci1394(%d): Too many devices on the 1394 " "bus", soft_state->drvinfo.di_instance); } /* enable bus reset interrupt */ hci1394_ohci_intr_enable(soft_state->ohci, OHCI_INTR_BUS_RESET); TNF_PROBE_0_DEBUG(hci1394_isr_self_id_exit, HCI1394_TNF_HAL_STACK, ""); }