Esempio n. 1
0
int pcie_read_config_byte(struct pci_controller *hose,pci_dev_t dev,int offset,u8 *val)
{
	u32 v;
	int rv;

	rv =  pcie_read_config(hose, dev, offset, 1, &v);
	*val = (u8)v;
	return rv;
}
Esempio n. 2
0
int pcie_read_config_dword(struct pci_controller *hose,pci_dev_t dev,int offset,u32 *val)
{
	u32 v;
	int rv;

	rv = pcie_read_config(hose, dev, offset, 3, &v);
	*val = (u32)v;
	return rv;
}
Esempio n. 3
0
static uint32_t
nvme_link_kBps(struct nvme_controller *ctrlr)
{
	uint32_t speed, lanes, link[] = { 1, 250000, 500000, 985000, 1970000 };
	uint32_t status;

	status = pcie_read_config(ctrlr->dev, PCIER_LINK_STA, 2);
	speed = status & PCIEM_LINK_STA_SPEED;
	lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4;
	/*
	 * Failsafe on link speed indicator. If it is insane report the number of
	 * lanes as the speed. Not 100% accurate, but may be diagnostic.
	 */
	if (speed >= nitems(link))
		speed = 0;
	return link[speed] * lanes;
}
Esempio n. 4
0
static void
nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
{
	struct nvme_controller *ctrlr;

	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
	    ("nvme_sim_action: func= %#x\n",
		ccb->ccb_h.func_code));

	ctrlr = sim2ctrlr(sim);

	mtx_assert(&ctrlr->lock, MA_OWNED);

	switch (ccb->ccb_h.func_code) {
	case XPT_CALC_GEOMETRY:		/* Calculate Geometry Totally nuts ? XXX */
		/* 
		 * Only meaningful for old-school SCSI disks since only the SCSI
		 * da driver generates them. Reject all these that slip through.
		 */
		/*FALLTHROUGH*/
	case XPT_ABORT:			/* Abort the specified CCB */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	case XPT_SET_TRAN_SETTINGS:
		/*
		 * NVMe doesn't really have different transfer settings, but
		 * other parts of CAM think failure here is a big deal.
		 */
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq	*cpi = &ccb->cpi;
		device_t		dev = ctrlr->dev;

		/*
		 * NVMe may have multiple LUNs on the same path. Current generation
		 * of NVMe devives support only a single name space. Multiple name
		 * space drives are coming, but it's unclear how we should report
		 * them up the stack.
		 */
		cpi->version_num = 1;
		cpi->hba_inquiry = 0;
		cpi->target_sprt = 0;
		cpi->hba_misc =  PIM_UNMAPPED | PIM_NOSCAN;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 0;
		cpi->max_lun = ctrlr->cdata.nn;
		cpi->maxio = ctrlr->max_xfer_size;
		cpi->initiator_id = 0;
		cpi->bus_id = cam_sim_bus(sim);
		cpi->base_transfer_speed = nvme_link_kBps(ctrlr);
		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN);
		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
		cpi->transport = XPORT_NVME;		/* XXX XPORT_PCIE ? */
		cpi->transport_version = nvme_mmio_read_4(ctrlr, vs);
		cpi->protocol = PROTO_NVME;
		cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs);
		cpi->xport_specific.nvme.nsid = xpt_path_lun_id(ccb->ccb_h.path);
		cpi->xport_specific.nvme.domain = pci_get_domain(dev);
		cpi->xport_specific.nvme.bus = pci_get_bus(dev);
		cpi->xport_specific.nvme.slot = pci_get_slot(dev);
		cpi->xport_specific.nvme.function = pci_get_function(dev);
		cpi->xport_specific.nvme.extra = 0;
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_GET_TRAN_SETTINGS:	/* Get transport settings */
	{
		struct ccb_trans_settings	*cts;
		struct ccb_trans_settings_nvme	*nvmep;
		struct ccb_trans_settings_nvme	*nvmex;
		device_t dev;
		uint32_t status, caps;

		dev = ctrlr->dev;
		cts = &ccb->cts;
		nvmex = &cts->xport_specific.nvme;
		nvmep = &cts->proto_specific.nvme;

		status = pcie_read_config(dev, PCIER_LINK_STA, 2);
		caps = pcie_read_config(dev, PCIER_LINK_CAP, 2);
		nvmex->valid = CTS_NVME_VALID_SPEC | CTS_NVME_VALID_LINK;
		nvmex->spec = nvme_mmio_read_4(ctrlr, vs);
		nvmex->speed = status & PCIEM_LINK_STA_SPEED;
		nvmex->lanes = (status & PCIEM_LINK_STA_WIDTH) >> 4;
		nvmex->max_speed = caps & PCIEM_LINK_CAP_MAX_SPEED;
		nvmex->max_lanes = (caps & PCIEM_LINK_CAP_MAX_WIDTH) >> 4;

		/* XXX these should be something else maybe ? */
		nvmep->valid = 1;
		nvmep->spec = nvmex->spec;

		cts->transport = XPORT_NVME;
		cts->protocol = PROTO_NVME;
		cts->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_TERM_IO:		/* Terminate the I/O process */
		/*
		 * every driver handles this, but nothing generates it. Assume
		 * it's OK to just say 'that worked'.
		 */
		/*FALLTHROUGH*/
	case XPT_RESET_DEV:		/* Bus Device Reset the specified device */
	case XPT_RESET_BUS:		/* Reset the specified bus */
		/*
		 * NVMe doesn't really support physically resetting the bus. It's part
		 * of the bus scanning dance, so return sucess to tell the process to
		 * proceed.
		 */
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_NVME_IO:		/* Execute the requested I/O operation */
	case XPT_NVME_ADMIN:		/* or Admin operation */
		nvme_sim_nvmeio(sim, ccb);
		return;			/* no done */
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	}
	xpt_done(ccb);
}