/*
 * 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);
}
Пример #2
0
/*
 * 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 *)&reg, 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);
}
Пример #3
0
/*
 * 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 {