예제 #1
0
파일: vmw_pvscsi.c 프로젝트: 19Dan01/linux
static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter,
				      bool enable)
{
	u32 val;

	if (!pvscsi_use_req_threshold)
		return false;

	pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND,
			 PVSCSI_CMD_SETUP_REQCALLTHRESHOLD);
	val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS);
	if (val == -1) {
		printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n");
		return false;
	} else {
		struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 };
		cmd_msg.enable = enable;
		printk(KERN_INFO
		       "vmw_pvscsi: %sabling reqCallThreshold\n",
			enable ? "en" : "dis");
		pvscsi_write_cmd_desc(adapter,
				      PVSCSI_CMD_SETUP_REQCALLTHRESHOLD,
				      &cmd_msg, sizeof(cmd_msg));
		return pvscsi_reg_read(adapter,
				       PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0;
	}
}
예제 #2
0
static void
pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc)
{
    struct PVSCSICmdDescSetupRings cmd = {0,};

    struct pvscsi_ring_dsc_s *dsc = memalign_high(PAGE_SIZE, sizeof(*dsc));
    if (!dsc) {
        warn_noalloc();
        return;
    }

    dsc->ring_state =
        (struct PVSCSIRingsState *)memalign_high(PAGE_SIZE, PAGE_SIZE);
    dsc->ring_reqs =
        (struct PVSCSIRingReqDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
    dsc->ring_cmps =
        (struct PVSCSIRingCmpDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
    if (!dsc->ring_state || !dsc->ring_reqs || !dsc->ring_cmps) {
        warn_noalloc();
        return;
    }
    memset(dsc->ring_state, 0, PAGE_SIZE);
    memset(dsc->ring_reqs, 0, PAGE_SIZE);
    memset(dsc->ring_cmps, 0, PAGE_SIZE);

    cmd.reqRingNumPages = 1;
    cmd.cmpRingNumPages = 1;
    cmd.ringsStatePPN = virt_to_phys(dsc->ring_state) >> PAGE_SHIFT;
    cmd.reqRingPPNs[0] = virt_to_phys(dsc->ring_reqs) >> PAGE_SHIFT;
    cmd.cmpRingPPNs[0] = virt_to_phys(dsc->ring_cmps) >> PAGE_SHIFT;

    pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_SETUP_RINGS,
                          &cmd, sizeof(cmd));
    *ring_dsc = dsc;
}
static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
{
	struct PVSCSICmdDescSetupRings cmd = { 0 };
	dma_addr_t base;
	unsigned i;

	cmd.ringsStatePPN   = adapter->ringStatePA >> PAGE_SHIFT;
	cmd.reqRingNumPages = adapter->req_pages;
	cmd.cmpRingNumPages = adapter->cmp_pages;

	base = adapter->reqRingPA;
	for (i = 0; i < adapter->req_pages; i++) {
		cmd.reqRingPPNs[i] = base >> PAGE_SHIFT;
		base += PAGE_SIZE;
	}

	base = adapter->cmpRingPA;
	for (i = 0; i < adapter->cmp_pages; i++) {
		cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT;
		base += PAGE_SIZE;
	}

	memset(adapter->rings_state, 0, PAGE_SIZE);
	memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE);
	memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE);

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS,
			      &cmd, sizeof(cmd));

	if (adapter->use_msg) {
		struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 };

		cmd_msg.numPages = adapter->msg_pages;

		base = adapter->msgRingPA;
		for (i = 0; i < adapter->msg_pages; i++) {
			cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT;
			base += PAGE_SIZE;
		}
		memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE);

		pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING,
				      &cmd_msg, sizeof(cmd_msg));
	}
}
static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter,
			     const struct pvscsi_ctx *ctx)
{
	struct PVSCSICmdDescAbortCmd cmd = { 0 };

	cmd.target = ctx->cmd->device->id;
	cmd.context = pvscsi_map_context(adapter, ctx);

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd));
}
static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target)
{
	struct PVSCSICmdDescResetDevice cmd = { 0 };

	dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target);

	cmd.target = target;

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE,
			      &cmd, sizeof(cmd));
}
예제 #6
0
파일: vmw_pvscsi.c 프로젝트: 19Dan01/linux
/*
 * Query the device, fetch the config info and return the
 * maximum number of targets on the adapter. In case of
 * failure due to any reason return default i.e. 16.
 */
static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter)
{
	struct PVSCSICmdDescConfigCmd cmd;
	struct PVSCSIConfigPageHeader *header;
	struct device *dev;
	dma_addr_t configPagePA;
	void *config_page;
	u32 numPhys = 16;

	dev = pvscsi_dev(adapter);
	config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
					   &configPagePA);
	if (!config_page) {
		dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n");
		goto exit;
	}
	BUG_ON(configPagePA & ~PAGE_MASK);

	/* Fetch config info from the device. */
	cmd.configPageAddress = ((u64)PVSCSI_CONFIG_CONTROLLER_ADDRESS) << 32;
	cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER;
	cmd.cmpAddr = configPagePA;
	cmd._pad = 0;

	/*
	 * Mark the completion page header with error values. If the device
	 * completes the command successfully, it sets the status values to
	 * indicate success.
	 */
	header = config_page;
	memset(header, 0, sizeof *header);
	header->hostStatus = BTSTAT_INVPARAM;
	header->scsiStatus = SDSTAT_CHECK;

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_CONFIG, &cmd, sizeof cmd);

	if (header->hostStatus == BTSTAT_SUCCESS &&
	    header->scsiStatus == SDSTAT_GOOD) {
		struct PVSCSIConfigPageController *config;

		config = config_page;
		numPhys = config->numPhys;
	} else
		dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n",
			 header->hostStatus, header->scsiStatus);
	pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA);
exit:
	return numPhys;
}
예제 #7
0
static void
init_pvscsi(void *data)
{
    struct pci_device *pci = data;
    void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
    if (!iobase)
        return;
    pci_enable_busmaster(pci);

    dprintf(1, "found pvscsi at %pP, io @ %p\n", pci, iobase);

    pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);

    struct pvscsi_ring_dsc_s *ring_dsc = NULL;
    pvscsi_init_rings(iobase, &ring_dsc);
    int i;
    for (i = 0; i < 7; i++)
        pvscsi_scan_target(pci, iobase, ring_dsc, i);
}
예제 #8
0
static void
init_pvscsi(struct pci_device *pci)
{
    struct pvscsi_ring_dsc_s *ring_dsc = NULL;
    int i;
    u16 bdf = pci->bdf;
    void *iobase = (void*)(pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
                           & PCI_BASE_ADDRESS_MEM_MASK);

    pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);

    dprintf(1, "found pvscsi at %02x:%02x.%x, io @ %p\n",
            pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
            pci_bdf_to_fn(bdf), iobase);

    pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);

    pvscsi_init_rings(iobase, &ring_dsc);
    for (i = 0; i < 7; i++)
        pvscsi_scan_target(pci, iobase, ring_dsc, i);

    return;
}
static void ll_bus_reset(const struct pvscsi_adapter *adapter)
{
	dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter);

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0);
}
static void ll_adapter_reset(const struct pvscsi_adapter *adapter)
{
	dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter);

	pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
}