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; } }
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)); }
/* * 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; }
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); }
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); }