/* * smp_probe: probe device and create inquiry-like properties. */ int smp_probe(struct smp_device *smp_sd) { smp_pkt_t *smp_pkt; smp_pkt_t smp_pkt_data; smp_request_frame_t *srq; smp_response_frame_t *srs; smp_report_manufacturer_info_resp_t *srmir; int ilen, clen; char *component; uint8_t srq_buf[SMP_REQ_MINLEN]; uint8_t srs_buf[SMP_RESP_MINLEN + sizeof (*srmir)]; srq = (smp_request_frame_t *)srq_buf; bzero(srq, sizeof (srq_buf)); srq->srf_frame_type = SMP_FRAME_TYPE_REQUEST; srq->srf_function = SMP_FUNC_REPORT_MANUFACTURER_INFO; smp_pkt = &smp_pkt_data; bzero(smp_pkt, sizeof (*smp_pkt)); smp_pkt->smp_pkt_address = &smp_sd->smp_sd_address; smp_pkt->smp_pkt_req = (caddr_t)srq; smp_pkt->smp_pkt_reqsize = sizeof (srq_buf); smp_pkt->smp_pkt_rsp = (caddr_t)srs_buf; smp_pkt->smp_pkt_rspsize = sizeof (srs_buf); smp_pkt->smp_pkt_timeout = SMP_DEFAULT_TIMEOUT; bzero(srs_buf, sizeof (srs_buf)); if (smp_transport(smp_pkt) != DDI_SUCCESS) { /* * The EOVERFLOW should be excluded here, because it indicates * the buffer (defined according to SAS1.1 Spec) to store * response is shorter than transferred message frame. * In this case, the smp device is alive and should be * enumerated. */ if (smp_pkt->smp_pkt_reason != EOVERFLOW) return (DDI_PROBE_FAILURE); } /* * NOTE: Deal with old drivers (mpt, mpt_sas) that allocate * 'struct smp_device' on the stack. When these drivers convert to * SCSAv3, the check for a NULL smp_sd_dev can be removed. */ if (smp_sd->smp_sd_dev == NULL) return (DDI_PROBE_SUCCESS); /* Save raw response data for devid */ srs = (smp_response_frame_t *)srs_buf; if (srs->srf_result != SMP_RES_FUNCTION_ACCEPTED) return (DDI_PROBE_SUCCESS); /* * Convert smp_report_manufacturer_info_resp_t data into properties. * NOTE: since things show up in the oposite order in prtconf, we are * going from detailed information to generic here. */ srmir = (smp_report_manufacturer_info_resp_t *)&srs->srf_data[0]; if (srmir->srmir_sas_1_1_format) { /* Establish 'component' property. */ ilen = scsi_ascii_inquiry_len( srmir->srmir_component_vendor_identification, sizeof (srmir->srmir_component_vendor_identification)); if (ilen > 0) { /* component value format is '%s.%05d.%03d' */ clen = ilen + 1 + 5 + 1 + 3 + 1; component = kmem_zalloc(clen, KM_SLEEP); bcopy(srmir->srmir_component_vendor_identification, component, ilen); (void) snprintf(&component[ilen], clen - ilen, ".%05d.%03d", BE_16(srmir->srmir_component_id), srmir->srmir_component_revision_level); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "component") == 0) (void) ndi_prop_update_string(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, "component", component); kmem_free(component, clen); } } /* First one to define the property wins */ if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_REVISION_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_REVISION_ID, srmir->srmir_product_revision_level, sizeof (srmir->srmir_product_revision_level)); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_PRODUCT_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_PRODUCT_ID, srmir->srmir_product_identification, sizeof (srmir->srmir_product_identification)); if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_VENDOR_ID) == 0) (void) smp_device_prop_update_inqstring(smp_sd, INQUIRY_VENDOR_ID, srmir->srmir_vendor_identification, sizeof (srmir->srmir_vendor_identification)); /* NOTE: SMP_PROP_REPORT_MANUFACTURER is deleted after devid created */ if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SMP_PROP_REPORT_MANUFACTURER) == 0) (void) ndi_prop_update_byte_array(DDI_DEV_T_NONE, smp_sd->smp_sd_dev, SMP_PROP_REPORT_MANUFACTURER, (uchar_t *)srs, sizeof (srs_buf)); return (DDI_PROBE_SUCCESS); }
/* * vdds_new_niu_node -- callback function to create a new NIU Hybrid node. */ static int vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags) { vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg; char *compat[] = { "SUNW,niusl" }; uint8_t macaddrbytes[ETHERADDRL]; int interrupts[VDDS_MAX_VRINTRS]; vdds_ranges_t *prng; vdds_ranges_t *prp; vdds_reg_t reg; dev_info_t *pdip; uint64_t start; uint64_t size; int prnglen; int nintr = 0; int nrng; int rnum; int rv; DBG1(NULL, "Called dip=0x%p flags=0x%X", dip, flags); pdip = ddi_get_parent(dip); if (pdip == NULL) { DWARN(NULL, "Failed to get parent dip(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* create "network" property */ if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "network") != DDI_SUCCESS) { DERR(NULL, "Failed to create name property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* * create "niutype" property, it is set to n2niu to * indicate NIU Hybrid node. */ if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "niutype", "n2niu") != DDI_SUCCESS) { DERR(NULL, "Failed to create niuopmode property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* create "compatible" property */ if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible", compat, 1) != DDI_SUCCESS) { DERR(NULL, "Failed to create compatible property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* create "device_type" property */ if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "device_type", "network") != DDI_SUCCESS) { DERR(NULL, "Failed to create device_type property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* create "reg" property */ if (vdds_hv_niu_vr_getinfo(HVCOOKIE(cba->cookie), &start, &size) != H_EOK) { DERR(NULL, "Failed to get vrinfo for cookie(0x%lX)", cba->cookie); return (DDI_WALK_ERROR); } reg.addr_hi = HVCOOKIE(cba->cookie); reg.addr_lo = 0; reg.size_hi = 0; reg.size_lo = size; if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg", (int *)®, sizeof (reg) / sizeof (int)) != DDI_SUCCESS) { DERR(NULL, "Failed to create reg property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* * Modify the parent's ranges property to map the "reg" property * of the new child. */ if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) { DERR(NULL, "Failed to get parent's ranges property(pdip=0x%p) rv=%d", pdip, rv); return (DDI_WALK_ERROR); } nrng = prnglen/(sizeof (vdds_ranges_t)); /* * First scan all ranges to see if a range corresponding * to this virtual NIU exists already. */ for (rnum = 0; rnum < nrng; rnum++) { prp = &prng[rnum]; if (prp->child_hi == HVCOOKIE(cba->cookie)) { break; } } if (rnum == nrng) { /* Now to try to find an empty range */ for (rnum = 0; rnum < nrng; rnum++) { prp = &prng[rnum]; if (prp->child_hi == 0) { break; } } } if (rnum == nrng) { DERR(NULL, "No free ranges entry found"); return (DDI_WALK_ERROR); } /* * child_hi will have HV cookie as HV cookie is more like * a port in the HybridIO. */ prp->child_hi = HVCOOKIE(cba->cookie); prp->child_lo = 0; prp->parent_hi = 0x80000000 | (start >> 32); prp->parent_lo = start & 0x00000000FFFFFFFF; prp->size_hi = (size >> 32); prp->size_lo = size & 0x00000000FFFFFFFF; if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip, "ranges", (int *)prng, (nrng * 6)) != DDI_SUCCESS) { DERR(NULL, "Failed to update parent ranges prop(pdip=0x%p)", pdip); return (DDI_WALK_ERROR); } kmem_free((void *)prng, prnglen); vnet_macaddr_ultostr(cba->macaddr, macaddrbytes); /* * create "local-mac-address" property, this will be same as * the vnet's mac-address. */ if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "local-mac-address", macaddrbytes, ETHERADDRL) != DDI_SUCCESS) { DERR(NULL, "Failed to update mac-addresses property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } rv = vdds_get_interrupts(cba->cookie, rnum, interrupts, &nintr); if (rv != 0) { DERR(NULL, "Failed to get interrupts for cookie=0x%lx", cba->cookie); return (DDI_WALK_ERROR); } /* create "interrupts" property */ if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupts", interrupts, nintr) != DDI_SUCCESS) { DERR(NULL, "Failed to update interrupts property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } /* create "max_frame_size" property */ if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "max-frame-size", cba->max_frame_size) != DDI_SUCCESS) { DERR(NULL, "Failed to update max-frame-size property(dip=0x%p)", dip); return (DDI_WALK_ERROR); } cba->dip = dip; DBG1(NULL, "Returning dip=0x%p", dip); return (DDI_WALK_TERMINATE); }
/* * Save the configuration registers for cdip as a property * so that it persists after detach/uninitchild. */ int pci_save_config_regs(dev_info_t *dip) { ddi_acc_handle_t confhdl; pci_config_header_state_t *chsp; pci_cap_save_desc_t *pci_cap_descp; int ret; uint32_t i, ncaps, nwords; uint32_t *regbuf, *p; uint8_t *maskbuf; size_t maskbufsz, regbufsz, capbufsz; ddi_acc_hdl_t *hp; off_t offset = 0; uint8_t cap_ptr, cap_id; int pcie = 0; PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip), ddi_get_instance(dip))) if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d can't get config handle", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* * Determine if it is a pci express device. If it is, save entire * 4k config space treating it as a array of 32 bit integers. * If it is not, do it in a usual PCI way. */ cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); /* * Walk the capabilities searching for pci express capability */ while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { cap_id = pci_config_get8(confhdl, cap_ptr + PCI_CAP_ID); if (cap_id == PCI_CAP_ID_PCI_E) { pcie = 1; break; } cap_ptr = pci_config_get8(confhdl, cap_ptr + PCI_CAP_NEXT_PTR); } if (pcie) { /* PCI express device. Can have data in all 4k space */ regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE, KM_SLEEP); p = regbuf; /* * Allocate space for mask. * mask size is 128 bytes (4096 / 4 / 8 ) */ maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >> INDEX_SHIFT); maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP); hp = impl_acc_hdl_get(confhdl); for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) { if (ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset), (int32_t *)p) == DDI_SUCCESS) { /* it is readable register. set the bit */ maskbuf[i >> INDEX_SHIFT] |= (uint8_t)(1 << (i & BITMASK)); } p++; offset += sizeof (uint32_t); } if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf, maskbufsz)) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "couldn't create %s property while" "saving config space for %s@%d\n", SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip), ddi_get_instance(dip)); } else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf, (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) { (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK); cmn_err(CE_WARN, "%s%d can't update prop %s", ddi_driver_name(dip), ddi_get_instance(dip), SAVED_CONFIG_REGS); } kmem_free(maskbuf, (size_t)maskbufsz); kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE); } else {