1881d588aSDmitry Fleytman /*
2881d588aSDmitry Fleytman * QEMU VMWARE PVSCSI paravirtual SCSI bus
3881d588aSDmitry Fleytman *
4881d588aSDmitry Fleytman * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
5881d588aSDmitry Fleytman *
6881d588aSDmitry Fleytman * Developed by Daynix Computing LTD (http://www.daynix.com)
7881d588aSDmitry Fleytman *
8881d588aSDmitry Fleytman * Based on implementation by Paolo Bonzini
9881d588aSDmitry Fleytman * http://lists.gnu.org/archive/html/qemu-devel/2011-08/msg00729.html
10881d588aSDmitry Fleytman *
11881d588aSDmitry Fleytman * Authors:
12881d588aSDmitry Fleytman * Paolo Bonzini <pbonzini@redhat.com>
13881d588aSDmitry Fleytman * Dmitry Fleytman <dmitry@daynix.com>
14881d588aSDmitry Fleytman * Yan Vugenfirer <yan@daynix.com>
15881d588aSDmitry Fleytman *
16881d588aSDmitry Fleytman * This work is licensed under the terms of the GNU GPL, version 2.
17881d588aSDmitry Fleytman * See the COPYING file in the top-level directory.
18881d588aSDmitry Fleytman *
19881d588aSDmitry Fleytman * NOTE about MSI-X:
20881d588aSDmitry Fleytman * MSI-X support has been removed for the moment because it leads Windows OS
21881d588aSDmitry Fleytman * to crash on startup. The crash happens because Windows driver requires
22881d588aSDmitry Fleytman * MSI-X shared memory to be part of the same BAR used for rings state
23881d588aSDmitry Fleytman * registers, etc. This is not supported by QEMU infrastructure so separate
24881d588aSDmitry Fleytman * BAR created from MSI-X purposes. Windows driver fails to deal with 2 BARs.
25881d588aSDmitry Fleytman *
26881d588aSDmitry Fleytman */
27881d588aSDmitry Fleytman
28a4ab4792SPeter Maydell #include "qemu/osdep.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30db725815SMarkus Armbruster #include "qemu/main-loop.h"
310b8fa32fSMarkus Armbruster #include "qemu/module.h"
32881d588aSDmitry Fleytman #include "hw/scsi/scsi.h"
33d6454270SMarkus Armbruster #include "migration/vmstate.h"
3408e2c9f1SPaolo Bonzini #include "scsi/constants.h"
35881d588aSDmitry Fleytman #include "hw/pci/msi.h"
36a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
37881d588aSDmitry Fleytman #include "vmw_pvscsi.h"
38881d588aSDmitry Fleytman #include "trace.h"
39db1015e9SEduardo Habkost #include "qom/object.h"
40881d588aSDmitry Fleytman
41881d588aSDmitry Fleytman
42881d588aSDmitry Fleytman #define PVSCSI_USE_64BIT (true)
43881d588aSDmitry Fleytman #define PVSCSI_PER_VECTOR_MASK (false)
44881d588aSDmitry Fleytman
45881d588aSDmitry Fleytman #define PVSCSI_MAX_DEVS (64)
46881d588aSDmitry Fleytman #define PVSCSI_MSIX_NUM_VECTORS (1)
47881d588aSDmitry Fleytman
4849adc5d3SPrasad J Pandit #define PVSCSI_MAX_SG_ELEM 2048
4949adc5d3SPrasad J Pandit
50881d588aSDmitry Fleytman #define PVSCSI_MAX_CMD_DATA_WORDS \
51881d588aSDmitry Fleytman (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t))
52881d588aSDmitry Fleytman
534a63054bSPhilippe Mathieu-Daudé #define RS_GET_FIELD(pval, m, field) \
544a63054bSPhilippe Mathieu-Daudé ldl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
55398f9a84SPhilippe Mathieu-Daudé (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), \
564a63054bSPhilippe Mathieu-Daudé pval, MEMTXATTRS_UNSPECIFIED)
570dc40f28SPaolo Bonzini #define RS_SET_FIELD(m, field, val) \
580dc40f28SPaolo Bonzini (stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
59a423a1b5SPhilippe Mathieu-Daudé (m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val, \
60a423a1b5SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED))
61881d588aSDmitry Fleytman
62db1015e9SEduardo Habkost struct PVSCSIClass {
63e2d4f3f7SShmulik Ladkani PCIDeviceClass parent_class;
641dd1305eSShmulik Ladkani DeviceRealize parent_dc_realize;
65db1015e9SEduardo Habkost };
66e2d4f3f7SShmulik Ladkani
67881d588aSDmitry Fleytman #define TYPE_PVSCSI "pvscsi"
68a489d195SEduardo Habkost OBJECT_DECLARE_TYPE(PVSCSIState, PVSCSIClass, PVSCSI)
69881d588aSDmitry Fleytman
70e2d4f3f7SShmulik Ladkani
7116c04166SPhilippe Mathieu-Daudé #define PVSCSI_MSI_OFFSET (0x7c)
721dd1305eSShmulik Ladkani #define PVSCSI_EXP_EP_OFFSET (0x40)
73d29d4ff8SShmulik Ladkani
74881d588aSDmitry Fleytman typedef struct PVSCSIRingInfo {
75881d588aSDmitry Fleytman uint64_t rs_pa;
76881d588aSDmitry Fleytman uint32_t txr_len_mask;
77881d588aSDmitry Fleytman uint32_t rxr_len_mask;
78881d588aSDmitry Fleytman uint32_t msg_len_mask;
79881d588aSDmitry Fleytman uint64_t req_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
80881d588aSDmitry Fleytman uint64_t cmp_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
81881d588aSDmitry Fleytman uint64_t msg_ring_pages_pa[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES];
82881d588aSDmitry Fleytman uint64_t consumed_ptr;
83881d588aSDmitry Fleytman uint64_t filled_cmp_ptr;
84881d588aSDmitry Fleytman uint64_t filled_msg_ptr;
85881d588aSDmitry Fleytman } PVSCSIRingInfo;
86881d588aSDmitry Fleytman
87881d588aSDmitry Fleytman typedef struct PVSCSISGState {
88881d588aSDmitry Fleytman hwaddr elemAddr;
89881d588aSDmitry Fleytman hwaddr dataAddr;
90881d588aSDmitry Fleytman uint32_t resid;
91881d588aSDmitry Fleytman } PVSCSISGState;
92881d588aSDmitry Fleytman
93881d588aSDmitry Fleytman typedef QTAILQ_HEAD(, PVSCSIRequest) PVSCSIRequestList;
94881d588aSDmitry Fleytman
95db1015e9SEduardo Habkost struct PVSCSIState {
96881d588aSDmitry Fleytman PCIDevice parent_obj;
97881d588aSDmitry Fleytman MemoryRegion io_space;
98881d588aSDmitry Fleytman SCSIBus bus;
99881d588aSDmitry Fleytman QEMUBH *completion_worker;
100881d588aSDmitry Fleytman PVSCSIRequestList pending_queue;
101881d588aSDmitry Fleytman PVSCSIRequestList completion_queue;
102881d588aSDmitry Fleytman
103881d588aSDmitry Fleytman uint64_t reg_interrupt_status; /* Interrupt status register value */
104881d588aSDmitry Fleytman uint64_t reg_interrupt_enabled; /* Interrupt mask register value */
105881d588aSDmitry Fleytman uint64_t reg_command_status; /* Command status register value */
106881d588aSDmitry Fleytman
107881d588aSDmitry Fleytman /* Command data adoption mechanism */
108881d588aSDmitry Fleytman uint64_t curr_cmd; /* Last command arrived */
109881d588aSDmitry Fleytman uint32_t curr_cmd_data_cntr; /* Amount of data for last command */
110881d588aSDmitry Fleytman
111881d588aSDmitry Fleytman /* Collector for current command data */
112881d588aSDmitry Fleytman uint32_t curr_cmd_data[PVSCSI_MAX_CMD_DATA_WORDS];
113881d588aSDmitry Fleytman
114881d588aSDmitry Fleytman uint8_t rings_info_valid; /* Whether data rings initialized */
115881d588aSDmitry Fleytman uint8_t msg_ring_info_valid; /* Whether message ring initialized */
116881d588aSDmitry Fleytman uint8_t use_msg; /* Whether to use message ring */
117881d588aSDmitry Fleytman
118269fe4c3SCao jin uint8_t msi_used; /* For migration compatibility */
119881d588aSDmitry Fleytman PVSCSIRingInfo rings; /* Data transfer rings manager */
120881d588aSDmitry Fleytman uint32_t resetting; /* Reset in progress */
121db1015e9SEduardo Habkost };
122881d588aSDmitry Fleytman
123881d588aSDmitry Fleytman typedef struct PVSCSIRequest {
124881d588aSDmitry Fleytman SCSIRequest *sreq;
125881d588aSDmitry Fleytman PVSCSIState *dev;
126881d588aSDmitry Fleytman uint8_t sense_key;
127881d588aSDmitry Fleytman uint8_t completed;
128881d588aSDmitry Fleytman int lun;
129881d588aSDmitry Fleytman QEMUSGList sgl;
130881d588aSDmitry Fleytman PVSCSISGState sg;
131881d588aSDmitry Fleytman struct PVSCSIRingReqDesc req;
132881d588aSDmitry Fleytman struct PVSCSIRingCmpDesc cmp;
133881d588aSDmitry Fleytman QTAILQ_ENTRY(PVSCSIRequest) next;
134881d588aSDmitry Fleytman } PVSCSIRequest;
135881d588aSDmitry Fleytman
136881d588aSDmitry Fleytman /* Integer binary logarithm */
137881d588aSDmitry Fleytman static int
pvscsi_log2(uint32_t input)138881d588aSDmitry Fleytman pvscsi_log2(uint32_t input)
139881d588aSDmitry Fleytman {
140881d588aSDmitry Fleytman int log = 0;
141881d588aSDmitry Fleytman assert(input > 0);
142881d588aSDmitry Fleytman while (input >> ++log) {
143881d588aSDmitry Fleytman }
144881d588aSDmitry Fleytman return log;
145881d588aSDmitry Fleytman }
146881d588aSDmitry Fleytman
1477f61f469SPrasad J Pandit static void
pvscsi_ring_init_data(PVSCSIRingInfo * m,PVSCSICmdDescSetupRings * ri)148881d588aSDmitry Fleytman pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
149881d588aSDmitry Fleytman {
150881d588aSDmitry Fleytman int i;
151881d588aSDmitry Fleytman uint32_t txr_len_log2, rxr_len_log2;
152881d588aSDmitry Fleytman uint32_t req_ring_size, cmp_ring_size;
153881d588aSDmitry Fleytman m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT;
154881d588aSDmitry Fleytman
155881d588aSDmitry Fleytman req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
156881d588aSDmitry Fleytman cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
157881d588aSDmitry Fleytman txr_len_log2 = pvscsi_log2(req_ring_size - 1);
158881d588aSDmitry Fleytman rxr_len_log2 = pvscsi_log2(cmp_ring_size - 1);
159881d588aSDmitry Fleytman
160881d588aSDmitry Fleytman m->txr_len_mask = MASK(txr_len_log2);
161881d588aSDmitry Fleytman m->rxr_len_mask = MASK(rxr_len_log2);
162881d588aSDmitry Fleytman
163881d588aSDmitry Fleytman m->consumed_ptr = 0;
164881d588aSDmitry Fleytman m->filled_cmp_ptr = 0;
165881d588aSDmitry Fleytman
166881d588aSDmitry Fleytman for (i = 0; i < ri->reqRingNumPages; i++) {
167881d588aSDmitry Fleytman m->req_ring_pages_pa[i] = ri->reqRingPPNs[i] << VMW_PAGE_SHIFT;
168881d588aSDmitry Fleytman }
169881d588aSDmitry Fleytman
170881d588aSDmitry Fleytman for (i = 0; i < ri->cmpRingNumPages; i++) {
171881d588aSDmitry Fleytman m->cmp_ring_pages_pa[i] = ri->cmpRingPPNs[i] << VMW_PAGE_SHIFT;
172881d588aSDmitry Fleytman }
173881d588aSDmitry Fleytman
1740dc40f28SPaolo Bonzini RS_SET_FIELD(m, reqProdIdx, 0);
1750dc40f28SPaolo Bonzini RS_SET_FIELD(m, reqConsIdx, 0);
1760dc40f28SPaolo Bonzini RS_SET_FIELD(m, reqNumEntriesLog2, txr_len_log2);
177881d588aSDmitry Fleytman
1780dc40f28SPaolo Bonzini RS_SET_FIELD(m, cmpProdIdx, 0);
1790dc40f28SPaolo Bonzini RS_SET_FIELD(m, cmpConsIdx, 0);
1800dc40f28SPaolo Bonzini RS_SET_FIELD(m, cmpNumEntriesLog2, rxr_len_log2);
181881d588aSDmitry Fleytman
182881d588aSDmitry Fleytman trace_pvscsi_ring_init_data(txr_len_log2, rxr_len_log2);
183881d588aSDmitry Fleytman
184881d588aSDmitry Fleytman /* Flush ring state page changes */
185881d588aSDmitry Fleytman smp_wmb();
186881d588aSDmitry Fleytman }
187881d588aSDmitry Fleytman
1883e831b40SPrasad J Pandit static int
pvscsi_ring_init_msg(PVSCSIRingInfo * m,PVSCSICmdDescSetupMsgRing * ri)189881d588aSDmitry Fleytman pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri)
190881d588aSDmitry Fleytman {
191881d588aSDmitry Fleytman int i;
192881d588aSDmitry Fleytman uint32_t len_log2;
193881d588aSDmitry Fleytman uint32_t ring_size;
194881d588aSDmitry Fleytman
195f6882698SP J P if (!ri->numPages || ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
1963e831b40SPrasad J Pandit return -1;
1973e831b40SPrasad J Pandit }
198881d588aSDmitry Fleytman ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
199881d588aSDmitry Fleytman len_log2 = pvscsi_log2(ring_size - 1);
200881d588aSDmitry Fleytman
201881d588aSDmitry Fleytman m->msg_len_mask = MASK(len_log2);
202881d588aSDmitry Fleytman
203881d588aSDmitry Fleytman m->filled_msg_ptr = 0;
204881d588aSDmitry Fleytman
205881d588aSDmitry Fleytman for (i = 0; i < ri->numPages; i++) {
206881d588aSDmitry Fleytman m->msg_ring_pages_pa[i] = ri->ringPPNs[i] << VMW_PAGE_SHIFT;
207881d588aSDmitry Fleytman }
208881d588aSDmitry Fleytman
2090dc40f28SPaolo Bonzini RS_SET_FIELD(m, msgProdIdx, 0);
2100dc40f28SPaolo Bonzini RS_SET_FIELD(m, msgConsIdx, 0);
2110dc40f28SPaolo Bonzini RS_SET_FIELD(m, msgNumEntriesLog2, len_log2);
212881d588aSDmitry Fleytman
213881d588aSDmitry Fleytman trace_pvscsi_ring_init_msg(len_log2);
214881d588aSDmitry Fleytman
215881d588aSDmitry Fleytman /* Flush ring state page changes */
216881d588aSDmitry Fleytman smp_wmb();
2173e831b40SPrasad J Pandit
2183e831b40SPrasad J Pandit return 0;
219881d588aSDmitry Fleytman }
220881d588aSDmitry Fleytman
221881d588aSDmitry Fleytman static void
pvscsi_ring_cleanup(PVSCSIRingInfo * mgr)222881d588aSDmitry Fleytman pvscsi_ring_cleanup(PVSCSIRingInfo *mgr)
223881d588aSDmitry Fleytman {
224881d588aSDmitry Fleytman mgr->rs_pa = 0;
225881d588aSDmitry Fleytman mgr->txr_len_mask = 0;
226881d588aSDmitry Fleytman mgr->rxr_len_mask = 0;
227881d588aSDmitry Fleytman mgr->msg_len_mask = 0;
228881d588aSDmitry Fleytman mgr->consumed_ptr = 0;
229881d588aSDmitry Fleytman mgr->filled_cmp_ptr = 0;
230881d588aSDmitry Fleytman mgr->filled_msg_ptr = 0;
231881d588aSDmitry Fleytman memset(mgr->req_ring_pages_pa, 0, sizeof(mgr->req_ring_pages_pa));
232881d588aSDmitry Fleytman memset(mgr->cmp_ring_pages_pa, 0, sizeof(mgr->cmp_ring_pages_pa));
233881d588aSDmitry Fleytman memset(mgr->msg_ring_pages_pa, 0, sizeof(mgr->msg_ring_pages_pa));
234881d588aSDmitry Fleytman }
235881d588aSDmitry Fleytman
236881d588aSDmitry Fleytman static hwaddr
pvscsi_ring_pop_req_descr(PVSCSIRingInfo * mgr)237881d588aSDmitry Fleytman pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr)
238881d588aSDmitry Fleytman {
2394a63054bSPhilippe Mathieu-Daudé uint32_t ready_ptr;
240d251157aSPrasad J Pandit uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING
241d251157aSPrasad J Pandit * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
242881d588aSDmitry Fleytman
2434a63054bSPhilippe Mathieu-Daudé RS_GET_FIELD(&ready_ptr, mgr, reqProdIdx);
244d251157aSPrasad J Pandit if (ready_ptr != mgr->consumed_ptr
245d251157aSPrasad J Pandit && ready_ptr - mgr->consumed_ptr < ring_size) {
246881d588aSDmitry Fleytman uint32_t next_ready_ptr =
247881d588aSDmitry Fleytman mgr->consumed_ptr++ & mgr->txr_len_mask;
248881d588aSDmitry Fleytman uint32_t next_ready_page =
249881d588aSDmitry Fleytman next_ready_ptr / PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
250881d588aSDmitry Fleytman uint32_t inpage_idx =
251881d588aSDmitry Fleytman next_ready_ptr % PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
252881d588aSDmitry Fleytman
253881d588aSDmitry Fleytman return mgr->req_ring_pages_pa[next_ready_page] +
254881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingReqDesc);
255881d588aSDmitry Fleytman } else {
256881d588aSDmitry Fleytman return 0;
257881d588aSDmitry Fleytman }
258881d588aSDmitry Fleytman }
259881d588aSDmitry Fleytman
260881d588aSDmitry Fleytman static void
pvscsi_ring_flush_req(PVSCSIRingInfo * mgr)261881d588aSDmitry Fleytman pvscsi_ring_flush_req(PVSCSIRingInfo *mgr)
262881d588aSDmitry Fleytman {
2630dc40f28SPaolo Bonzini RS_SET_FIELD(mgr, reqConsIdx, mgr->consumed_ptr);
264881d588aSDmitry Fleytman }
265881d588aSDmitry Fleytman
266881d588aSDmitry Fleytman static hwaddr
pvscsi_ring_pop_cmp_descr(PVSCSIRingInfo * mgr)267881d588aSDmitry Fleytman pvscsi_ring_pop_cmp_descr(PVSCSIRingInfo *mgr)
268881d588aSDmitry Fleytman {
269881d588aSDmitry Fleytman /*
270881d588aSDmitry Fleytman * According to Linux driver code it explicitly verifies that number
271881d588aSDmitry Fleytman * of requests being processed by device is less then the size of
272881d588aSDmitry Fleytman * completion queue, so device may omit completion queue overflow
273881d588aSDmitry Fleytman * conditions check. We assume that this is true for other (Windows)
274881d588aSDmitry Fleytman * drivers as well.
275881d588aSDmitry Fleytman */
276881d588aSDmitry Fleytman
277881d588aSDmitry Fleytman uint32_t free_cmp_ptr =
278881d588aSDmitry Fleytman mgr->filled_cmp_ptr++ & mgr->rxr_len_mask;
279881d588aSDmitry Fleytman uint32_t free_cmp_page =
280881d588aSDmitry Fleytman free_cmp_ptr / PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
281881d588aSDmitry Fleytman uint32_t inpage_idx =
282881d588aSDmitry Fleytman free_cmp_ptr % PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
283881d588aSDmitry Fleytman return mgr->cmp_ring_pages_pa[free_cmp_page] +
284881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingCmpDesc);
285881d588aSDmitry Fleytman }
286881d588aSDmitry Fleytman
287881d588aSDmitry Fleytman static hwaddr
pvscsi_ring_pop_msg_descr(PVSCSIRingInfo * mgr)288881d588aSDmitry Fleytman pvscsi_ring_pop_msg_descr(PVSCSIRingInfo *mgr)
289881d588aSDmitry Fleytman {
290881d588aSDmitry Fleytman uint32_t free_msg_ptr =
291881d588aSDmitry Fleytman mgr->filled_msg_ptr++ & mgr->msg_len_mask;
292881d588aSDmitry Fleytman uint32_t free_msg_page =
293881d588aSDmitry Fleytman free_msg_ptr / PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
294881d588aSDmitry Fleytman uint32_t inpage_idx =
295881d588aSDmitry Fleytman free_msg_ptr % PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
296881d588aSDmitry Fleytman return mgr->msg_ring_pages_pa[free_msg_page] +
297881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingMsgDesc);
298881d588aSDmitry Fleytman }
299881d588aSDmitry Fleytman
300881d588aSDmitry Fleytman static void
pvscsi_ring_flush_cmp(PVSCSIRingInfo * mgr)301881d588aSDmitry Fleytman pvscsi_ring_flush_cmp(PVSCSIRingInfo *mgr)
302881d588aSDmitry Fleytman {
303881d588aSDmitry Fleytman /* Flush descriptor changes */
304881d588aSDmitry Fleytman smp_wmb();
305881d588aSDmitry Fleytman
306881d588aSDmitry Fleytman trace_pvscsi_ring_flush_cmp(mgr->filled_cmp_ptr);
307881d588aSDmitry Fleytman
3080dc40f28SPaolo Bonzini RS_SET_FIELD(mgr, cmpProdIdx, mgr->filled_cmp_ptr);
309881d588aSDmitry Fleytman }
310881d588aSDmitry Fleytman
311881d588aSDmitry Fleytman static bool
pvscsi_ring_msg_has_room(PVSCSIRingInfo * mgr)312881d588aSDmitry Fleytman pvscsi_ring_msg_has_room(PVSCSIRingInfo *mgr)
313881d588aSDmitry Fleytman {
3144a63054bSPhilippe Mathieu-Daudé uint32_t prodIdx;
3154a63054bSPhilippe Mathieu-Daudé uint32_t consIdx;
3164a63054bSPhilippe Mathieu-Daudé
3174a63054bSPhilippe Mathieu-Daudé RS_GET_FIELD(&prodIdx, mgr, msgProdIdx);
3184a63054bSPhilippe Mathieu-Daudé RS_GET_FIELD(&consIdx, mgr, msgConsIdx);
319881d588aSDmitry Fleytman
320881d588aSDmitry Fleytman return (prodIdx - consIdx) < (mgr->msg_len_mask + 1);
321881d588aSDmitry Fleytman }
322881d588aSDmitry Fleytman
323881d588aSDmitry Fleytman static void
pvscsi_ring_flush_msg(PVSCSIRingInfo * mgr)324881d588aSDmitry Fleytman pvscsi_ring_flush_msg(PVSCSIRingInfo *mgr)
325881d588aSDmitry Fleytman {
326881d588aSDmitry Fleytman /* Flush descriptor changes */
327881d588aSDmitry Fleytman smp_wmb();
328881d588aSDmitry Fleytman
329881d588aSDmitry Fleytman trace_pvscsi_ring_flush_msg(mgr->filled_msg_ptr);
330881d588aSDmitry Fleytman
3310dc40f28SPaolo Bonzini RS_SET_FIELD(mgr, msgProdIdx, mgr->filled_msg_ptr);
332881d588aSDmitry Fleytman }
333881d588aSDmitry Fleytman
334881d588aSDmitry Fleytman static void
pvscsi_reset_state(PVSCSIState * s)335881d588aSDmitry Fleytman pvscsi_reset_state(PVSCSIState *s)
336881d588aSDmitry Fleytman {
337881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST;
338881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0;
339881d588aSDmitry Fleytman s->reg_command_status = PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
340881d588aSDmitry Fleytman s->reg_interrupt_status = 0;
341881d588aSDmitry Fleytman pvscsi_ring_cleanup(&s->rings);
342881d588aSDmitry Fleytman s->rings_info_valid = FALSE;
343881d588aSDmitry Fleytman s->msg_ring_info_valid = FALSE;
344881d588aSDmitry Fleytman QTAILQ_INIT(&s->pending_queue);
345881d588aSDmitry Fleytman QTAILQ_INIT(&s->completion_queue);
346881d588aSDmitry Fleytman }
347881d588aSDmitry Fleytman
348881d588aSDmitry Fleytman static void
pvscsi_update_irq_status(PVSCSIState * s)349881d588aSDmitry Fleytman pvscsi_update_irq_status(PVSCSIState *s)
350881d588aSDmitry Fleytman {
351881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s);
352881d588aSDmitry Fleytman bool should_raise = s->reg_interrupt_enabled & s->reg_interrupt_status;
353881d588aSDmitry Fleytman
354881d588aSDmitry Fleytman trace_pvscsi_update_irq_level(should_raise, s->reg_interrupt_enabled,
355881d588aSDmitry Fleytman s->reg_interrupt_status);
356881d588aSDmitry Fleytman
357269fe4c3SCao jin if (msi_enabled(d)) {
358881d588aSDmitry Fleytman if (should_raise) {
359881d588aSDmitry Fleytman trace_pvscsi_update_irq_msi();
360881d588aSDmitry Fleytman msi_notify(d, PVSCSI_VECTOR_COMPLETION);
361881d588aSDmitry Fleytman }
362881d588aSDmitry Fleytman return;
363881d588aSDmitry Fleytman }
364881d588aSDmitry Fleytman
3659e64f8a3SMarcel Apfelbaum pci_set_irq(d, !!should_raise);
366881d588aSDmitry Fleytman }
367881d588aSDmitry Fleytman
368881d588aSDmitry Fleytman static void
pvscsi_raise_completion_interrupt(PVSCSIState * s)369881d588aSDmitry Fleytman pvscsi_raise_completion_interrupt(PVSCSIState *s)
370881d588aSDmitry Fleytman {
371881d588aSDmitry Fleytman s->reg_interrupt_status |= PVSCSI_INTR_CMPL_0;
372881d588aSDmitry Fleytman
373881d588aSDmitry Fleytman /* Memory barrier to flush interrupt status register changes*/
374881d588aSDmitry Fleytman smp_wmb();
375881d588aSDmitry Fleytman
376881d588aSDmitry Fleytman pvscsi_update_irq_status(s);
377881d588aSDmitry Fleytman }
378881d588aSDmitry Fleytman
379881d588aSDmitry Fleytman static void
pvscsi_raise_message_interrupt(PVSCSIState * s)380881d588aSDmitry Fleytman pvscsi_raise_message_interrupt(PVSCSIState *s)
381881d588aSDmitry Fleytman {
382881d588aSDmitry Fleytman s->reg_interrupt_status |= PVSCSI_INTR_MSG_0;
383881d588aSDmitry Fleytman
384881d588aSDmitry Fleytman /* Memory barrier to flush interrupt status register changes*/
385881d588aSDmitry Fleytman smp_wmb();
386881d588aSDmitry Fleytman
387881d588aSDmitry Fleytman pvscsi_update_irq_status(s);
388881d588aSDmitry Fleytman }
389881d588aSDmitry Fleytman
390881d588aSDmitry Fleytman static void
pvscsi_cmp_ring_put(PVSCSIState * s,struct PVSCSIRingCmpDesc * cmp_desc)391881d588aSDmitry Fleytman pvscsi_cmp_ring_put(PVSCSIState *s, struct PVSCSIRingCmpDesc *cmp_desc)
392881d588aSDmitry Fleytman {
393881d588aSDmitry Fleytman hwaddr cmp_descr_pa;
394881d588aSDmitry Fleytman
395881d588aSDmitry Fleytman cmp_descr_pa = pvscsi_ring_pop_cmp_descr(&s->rings);
396881d588aSDmitry Fleytman trace_pvscsi_cmp_ring_put(cmp_descr_pa);
3970eeef0a4SPhilippe Mathieu-Daudé cpu_physical_memory_write(cmp_descr_pa, cmp_desc, sizeof(*cmp_desc));
398881d588aSDmitry Fleytman }
399881d588aSDmitry Fleytman
400881d588aSDmitry Fleytman static void
pvscsi_msg_ring_put(PVSCSIState * s,struct PVSCSIRingMsgDesc * msg_desc)401881d588aSDmitry Fleytman pvscsi_msg_ring_put(PVSCSIState *s, struct PVSCSIRingMsgDesc *msg_desc)
402881d588aSDmitry Fleytman {
403881d588aSDmitry Fleytman hwaddr msg_descr_pa;
404881d588aSDmitry Fleytman
405881d588aSDmitry Fleytman msg_descr_pa = pvscsi_ring_pop_msg_descr(&s->rings);
406881d588aSDmitry Fleytman trace_pvscsi_msg_ring_put(msg_descr_pa);
4070eeef0a4SPhilippe Mathieu-Daudé cpu_physical_memory_write(msg_descr_pa, msg_desc, sizeof(*msg_desc));
408881d588aSDmitry Fleytman }
409881d588aSDmitry Fleytman
410881d588aSDmitry Fleytman static void
pvscsi_process_completion_queue(void * opaque)411881d588aSDmitry Fleytman pvscsi_process_completion_queue(void *opaque)
412881d588aSDmitry Fleytman {
413881d588aSDmitry Fleytman PVSCSIState *s = opaque;
414881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req;
415881d588aSDmitry Fleytman bool has_completed = false;
416881d588aSDmitry Fleytman
417881d588aSDmitry Fleytman while (!QTAILQ_EMPTY(&s->completion_queue)) {
418881d588aSDmitry Fleytman pvscsi_req = QTAILQ_FIRST(&s->completion_queue);
419881d588aSDmitry Fleytman QTAILQ_REMOVE(&s->completion_queue, pvscsi_req, next);
420881d588aSDmitry Fleytman pvscsi_cmp_ring_put(s, &pvscsi_req->cmp);
421881d588aSDmitry Fleytman g_free(pvscsi_req);
422dcb07809SStefan Weil has_completed = true;
423881d588aSDmitry Fleytman }
424881d588aSDmitry Fleytman
425881d588aSDmitry Fleytman if (has_completed) {
426881d588aSDmitry Fleytman pvscsi_ring_flush_cmp(&s->rings);
427881d588aSDmitry Fleytman pvscsi_raise_completion_interrupt(s);
428881d588aSDmitry Fleytman }
429881d588aSDmitry Fleytman }
430881d588aSDmitry Fleytman
431881d588aSDmitry Fleytman static void
pvscsi_reset_adapter(PVSCSIState * s)432881d588aSDmitry Fleytman pvscsi_reset_adapter(PVSCSIState *s)
433881d588aSDmitry Fleytman {
434881d588aSDmitry Fleytman s->resetting++;
4354a5fc890SPeter Maydell bus_cold_reset(BUS(&s->bus));
436881d588aSDmitry Fleytman s->resetting--;
437881d588aSDmitry Fleytman pvscsi_process_completion_queue(s);
438881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->pending_queue));
439881d588aSDmitry Fleytman pvscsi_reset_state(s);
440881d588aSDmitry Fleytman }
441881d588aSDmitry Fleytman
442881d588aSDmitry Fleytman static void
pvscsi_schedule_completion_processing(PVSCSIState * s)443881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(PVSCSIState *s)
444881d588aSDmitry Fleytman {
445881d588aSDmitry Fleytman /* Try putting more complete requests on the ring. */
446881d588aSDmitry Fleytman if (!QTAILQ_EMPTY(&s->completion_queue)) {
447881d588aSDmitry Fleytman qemu_bh_schedule(s->completion_worker);
448881d588aSDmitry Fleytman }
449881d588aSDmitry Fleytman }
450881d588aSDmitry Fleytman
451881d588aSDmitry Fleytman static void
pvscsi_complete_request(PVSCSIState * s,PVSCSIRequest * r)452881d588aSDmitry Fleytman pvscsi_complete_request(PVSCSIState *s, PVSCSIRequest *r)
453881d588aSDmitry Fleytman {
454881d588aSDmitry Fleytman assert(!r->completed);
455881d588aSDmitry Fleytman
456881d588aSDmitry Fleytman trace_pvscsi_complete_request(r->cmp.context, r->cmp.dataLen,
457881d588aSDmitry Fleytman r->sense_key);
458881d588aSDmitry Fleytman if (r->sreq != NULL) {
459881d588aSDmitry Fleytman scsi_req_unref(r->sreq);
460881d588aSDmitry Fleytman r->sreq = NULL;
461881d588aSDmitry Fleytman }
462881d588aSDmitry Fleytman r->completed = 1;
463881d588aSDmitry Fleytman QTAILQ_REMOVE(&s->pending_queue, r, next);
464881d588aSDmitry Fleytman QTAILQ_INSERT_TAIL(&s->completion_queue, r, next);
465881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(s);
466881d588aSDmitry Fleytman }
467881d588aSDmitry Fleytman
pvscsi_get_sg_list(SCSIRequest * r)468881d588aSDmitry Fleytman static QEMUSGList *pvscsi_get_sg_list(SCSIRequest *r)
469881d588aSDmitry Fleytman {
470881d588aSDmitry Fleytman PVSCSIRequest *req = r->hba_private;
471881d588aSDmitry Fleytman
472881d588aSDmitry Fleytman trace_pvscsi_get_sg_list(req->sgl.nsg, req->sgl.size);
473881d588aSDmitry Fleytman
474881d588aSDmitry Fleytman return &req->sgl;
475881d588aSDmitry Fleytman }
476881d588aSDmitry Fleytman
477881d588aSDmitry Fleytman static void
pvscsi_get_next_sg_elem(PVSCSISGState * sg)478881d588aSDmitry Fleytman pvscsi_get_next_sg_elem(PVSCSISGState *sg)
479881d588aSDmitry Fleytman {
480881d588aSDmitry Fleytman struct PVSCSISGElement elem;
481881d588aSDmitry Fleytman
4820eeef0a4SPhilippe Mathieu-Daudé cpu_physical_memory_read(sg->elemAddr, &elem, sizeof(elem));
483881d588aSDmitry Fleytman if ((elem.flags & ~PVSCSI_KNOWN_FLAGS) != 0) {
484881d588aSDmitry Fleytman /*
485881d588aSDmitry Fleytman * There is PVSCSI_SGE_FLAG_CHAIN_ELEMENT flag described in
486881d588aSDmitry Fleytman * header file but its value is unknown. This flag requires
487881d588aSDmitry Fleytman * additional processing, so we put warning here to catch it
488881d588aSDmitry Fleytman * some day and make proper implementation
489881d588aSDmitry Fleytman */
490881d588aSDmitry Fleytman trace_pvscsi_get_next_sg_elem(elem.flags);
491881d588aSDmitry Fleytman }
492881d588aSDmitry Fleytman
493881d588aSDmitry Fleytman sg->elemAddr += sizeof(elem);
494881d588aSDmitry Fleytman sg->dataAddr = elem.addr;
495881d588aSDmitry Fleytman sg->resid = elem.length;
496881d588aSDmitry Fleytman }
497881d588aSDmitry Fleytman
498881d588aSDmitry Fleytman static void
pvscsi_write_sense(PVSCSIRequest * r,uint8_t * sense,int len)499881d588aSDmitry Fleytman pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
500881d588aSDmitry Fleytman {
501881d588aSDmitry Fleytman r->cmp.senseLen = MIN(r->req.senseLen, len);
502881d588aSDmitry Fleytman r->sense_key = sense[(sense[0] & 2) ? 1 : 2];
503881d588aSDmitry Fleytman cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
504881d588aSDmitry Fleytman }
505881d588aSDmitry Fleytman
506881d588aSDmitry Fleytman static void
pvscsi_command_failed(SCSIRequest * req)507f3126d65SHannes Reinecke pvscsi_command_failed(SCSIRequest *req)
508f3126d65SHannes Reinecke {
509f3126d65SHannes Reinecke PVSCSIRequest *pvscsi_req = req->hba_private;
510f3126d65SHannes Reinecke PVSCSIState *s;
511f3126d65SHannes Reinecke
512f3126d65SHannes Reinecke if (!pvscsi_req) {
513f3126d65SHannes Reinecke trace_pvscsi_command_complete_not_found(req->tag);
514f3126d65SHannes Reinecke return;
515f3126d65SHannes Reinecke }
516f3126d65SHannes Reinecke s = pvscsi_req->dev;
517f3126d65SHannes Reinecke
518f3126d65SHannes Reinecke switch (req->host_status) {
519f3126d65SHannes Reinecke case SCSI_HOST_NO_LUN:
520f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_LUNMISMATCH;
521f3126d65SHannes Reinecke break;
522f3126d65SHannes Reinecke case SCSI_HOST_BUSY:
523f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
524f3126d65SHannes Reinecke break;
525f3126d65SHannes Reinecke case SCSI_HOST_TIME_OUT:
526f3126d65SHannes Reinecke case SCSI_HOST_ABORTED:
527f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_SENTRST;
528f3126d65SHannes Reinecke break;
529f3126d65SHannes Reinecke case SCSI_HOST_BAD_RESPONSE:
530f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_SELTIMEO;
531f3126d65SHannes Reinecke break;
532f3126d65SHannes Reinecke case SCSI_HOST_RESET:
533f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
534f3126d65SHannes Reinecke break;
535f3126d65SHannes Reinecke default:
536f3126d65SHannes Reinecke pvscsi_req->cmp.hostStatus = BTSTAT_HASOFTWARE;
537f3126d65SHannes Reinecke break;
538f3126d65SHannes Reinecke }
539f3126d65SHannes Reinecke pvscsi_req->cmp.scsiStatus = GOOD;
540f3126d65SHannes Reinecke qemu_sglist_destroy(&pvscsi_req->sgl);
541f3126d65SHannes Reinecke pvscsi_complete_request(s, pvscsi_req);
542f3126d65SHannes Reinecke }
543f3126d65SHannes Reinecke
544f3126d65SHannes Reinecke static void
pvscsi_command_complete(SCSIRequest * req,size_t resid)54517ea26c2SHannes Reinecke pvscsi_command_complete(SCSIRequest *req, size_t resid)
546881d588aSDmitry Fleytman {
547881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req = req->hba_private;
548b0f49d13SPrasad Joshi PVSCSIState *s;
549881d588aSDmitry Fleytman
550881d588aSDmitry Fleytman if (!pvscsi_req) {
551881d588aSDmitry Fleytman trace_pvscsi_command_complete_not_found(req->tag);
552881d588aSDmitry Fleytman return;
553881d588aSDmitry Fleytman }
554b0f49d13SPrasad Joshi s = pvscsi_req->dev;
555881d588aSDmitry Fleytman
556881d588aSDmitry Fleytman if (resid) {
557881d588aSDmitry Fleytman /* Short transfer. */
558881d588aSDmitry Fleytman trace_pvscsi_command_complete_data_run();
559881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_DATARUN;
560881d588aSDmitry Fleytman }
561881d588aSDmitry Fleytman
56217ea26c2SHannes Reinecke pvscsi_req->cmp.scsiStatus = req->status;
563881d588aSDmitry Fleytman if (pvscsi_req->cmp.scsiStatus == CHECK_CONDITION) {
564881d588aSDmitry Fleytman uint8_t sense[SCSI_SENSE_BUF_SIZE];
565881d588aSDmitry Fleytman int sense_len =
566881d588aSDmitry Fleytman scsi_req_get_sense(pvscsi_req->sreq, sense, sizeof(sense));
567881d588aSDmitry Fleytman
568881d588aSDmitry Fleytman trace_pvscsi_command_complete_sense_len(sense_len);
569881d588aSDmitry Fleytman pvscsi_write_sense(pvscsi_req, sense, sense_len);
570881d588aSDmitry Fleytman }
571881d588aSDmitry Fleytman qemu_sglist_destroy(&pvscsi_req->sgl);
572881d588aSDmitry Fleytman pvscsi_complete_request(s, pvscsi_req);
573881d588aSDmitry Fleytman }
574881d588aSDmitry Fleytman
575881d588aSDmitry Fleytman static void
pvscsi_send_msg(PVSCSIState * s,SCSIDevice * dev,uint32_t msg_type)576881d588aSDmitry Fleytman pvscsi_send_msg(PVSCSIState *s, SCSIDevice *dev, uint32_t msg_type)
577881d588aSDmitry Fleytman {
578881d588aSDmitry Fleytman if (s->msg_ring_info_valid && pvscsi_ring_msg_has_room(&s->rings)) {
579881d588aSDmitry Fleytman PVSCSIMsgDescDevStatusChanged msg = {0};
580881d588aSDmitry Fleytman
581881d588aSDmitry Fleytman msg.type = msg_type;
582881d588aSDmitry Fleytman msg.bus = dev->channel;
583881d588aSDmitry Fleytman msg.target = dev->id;
584881d588aSDmitry Fleytman msg.lun[1] = dev->lun;
585881d588aSDmitry Fleytman
586881d588aSDmitry Fleytman pvscsi_msg_ring_put(s, (PVSCSIRingMsgDesc *)&msg);
587881d588aSDmitry Fleytman pvscsi_ring_flush_msg(&s->rings);
588881d588aSDmitry Fleytman pvscsi_raise_message_interrupt(s);
589881d588aSDmitry Fleytman }
590881d588aSDmitry Fleytman }
591881d588aSDmitry Fleytman
592881d588aSDmitry Fleytman static void
pvscsi_hotplug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)59391c8daadSIgor Mammedov pvscsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
594881d588aSDmitry Fleytman {
59591c8daadSIgor Mammedov PVSCSIState *s = PVSCSI(hotplug_dev);
59691c8daadSIgor Mammedov
59791c8daadSIgor Mammedov pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_ADDED);
598881d588aSDmitry Fleytman }
599881d588aSDmitry Fleytman
600881d588aSDmitry Fleytman static void
pvscsi_hot_unplug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)60191c8daadSIgor Mammedov pvscsi_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
602881d588aSDmitry Fleytman {
60391c8daadSIgor Mammedov PVSCSIState *s = PVSCSI(hotplug_dev);
60491c8daadSIgor Mammedov
60591c8daadSIgor Mammedov pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_REMOVED);
60691c8daadSIgor Mammedov qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
607881d588aSDmitry Fleytman }
608881d588aSDmitry Fleytman
609881d588aSDmitry Fleytman static void
pvscsi_request_cancelled(SCSIRequest * req)610881d588aSDmitry Fleytman pvscsi_request_cancelled(SCSIRequest *req)
611881d588aSDmitry Fleytman {
612881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req = req->hba_private;
613881d588aSDmitry Fleytman PVSCSIState *s = pvscsi_req->dev;
614881d588aSDmitry Fleytman
615881d588aSDmitry Fleytman if (pvscsi_req->completed) {
616881d588aSDmitry Fleytman return;
617881d588aSDmitry Fleytman }
618881d588aSDmitry Fleytman
619881d588aSDmitry Fleytman if (pvscsi_req->dev->resetting) {
620881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
621881d588aSDmitry Fleytman } else {
622881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
623881d588aSDmitry Fleytman }
624881d588aSDmitry Fleytman
625881d588aSDmitry Fleytman pvscsi_complete_request(s, pvscsi_req);
626881d588aSDmitry Fleytman }
627881d588aSDmitry Fleytman
628881d588aSDmitry Fleytman static SCSIDevice*
pvscsi_device_find(PVSCSIState * s,int channel,int target,uint8_t * requested_lun,uint8_t * target_lun)629881d588aSDmitry Fleytman pvscsi_device_find(PVSCSIState *s, int channel, int target,
630881d588aSDmitry Fleytman uint8_t *requested_lun, uint8_t *target_lun)
631881d588aSDmitry Fleytman {
632881d588aSDmitry Fleytman if (requested_lun[0] || requested_lun[2] || requested_lun[3] ||
633881d588aSDmitry Fleytman requested_lun[4] || requested_lun[5] || requested_lun[6] ||
634881d588aSDmitry Fleytman requested_lun[7] || (target > PVSCSI_MAX_DEVS)) {
635881d588aSDmitry Fleytman return NULL;
636881d588aSDmitry Fleytman } else {
637881d588aSDmitry Fleytman *target_lun = requested_lun[1];
638881d588aSDmitry Fleytman return scsi_device_find(&s->bus, channel, target, *target_lun);
639881d588aSDmitry Fleytman }
640881d588aSDmitry Fleytman }
641881d588aSDmitry Fleytman
642881d588aSDmitry Fleytman static PVSCSIRequest *
pvscsi_queue_pending_descriptor(PVSCSIState * s,SCSIDevice ** d,struct PVSCSIRingReqDesc * descr)643881d588aSDmitry Fleytman pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d,
644881d588aSDmitry Fleytman struct PVSCSIRingReqDesc *descr)
645881d588aSDmitry Fleytman {
646881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req;
647881d588aSDmitry Fleytman uint8_t lun;
648881d588aSDmitry Fleytman
649881d588aSDmitry Fleytman pvscsi_req = g_malloc0(sizeof(*pvscsi_req));
650881d588aSDmitry Fleytman pvscsi_req->dev = s;
651881d588aSDmitry Fleytman pvscsi_req->req = *descr;
652881d588aSDmitry Fleytman pvscsi_req->cmp.context = pvscsi_req->req.context;
653881d588aSDmitry Fleytman QTAILQ_INSERT_TAIL(&s->pending_queue, pvscsi_req, next);
654881d588aSDmitry Fleytman
655881d588aSDmitry Fleytman *d = pvscsi_device_find(s, descr->bus, descr->target, descr->lun, &lun);
656881d588aSDmitry Fleytman if (*d) {
657881d588aSDmitry Fleytman pvscsi_req->lun = lun;
658881d588aSDmitry Fleytman }
659881d588aSDmitry Fleytman
660881d588aSDmitry Fleytman return pvscsi_req;
661881d588aSDmitry Fleytman }
662881d588aSDmitry Fleytman
663881d588aSDmitry Fleytman static void
pvscsi_convert_sglist(PVSCSIRequest * r)664881d588aSDmitry Fleytman pvscsi_convert_sglist(PVSCSIRequest *r)
665881d588aSDmitry Fleytman {
66649adc5d3SPrasad J Pandit uint32_t chunk_size, elmcnt = 0;
667881d588aSDmitry Fleytman uint64_t data_length = r->req.dataLen;
668881d588aSDmitry Fleytman PVSCSISGState sg = r->sg;
66949adc5d3SPrasad J Pandit while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) {
67049adc5d3SPrasad J Pandit while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) {
671881d588aSDmitry Fleytman pvscsi_get_next_sg_elem(&sg);
672881d588aSDmitry Fleytman trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr,
673881d588aSDmitry Fleytman r->sg.resid);
674881d588aSDmitry Fleytman }
67549adc5d3SPrasad J Pandit chunk_size = MIN(data_length, sg.resid);
676881d588aSDmitry Fleytman if (chunk_size) {
677881d588aSDmitry Fleytman qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size);
678881d588aSDmitry Fleytman }
679881d588aSDmitry Fleytman
680881d588aSDmitry Fleytman sg.dataAddr += chunk_size;
681881d588aSDmitry Fleytman data_length -= chunk_size;
682881d588aSDmitry Fleytman sg.resid -= chunk_size;
683881d588aSDmitry Fleytman }
684881d588aSDmitry Fleytman }
685881d588aSDmitry Fleytman
686881d588aSDmitry Fleytman static void
pvscsi_build_sglist(PVSCSIState * s,PVSCSIRequest * r)687881d588aSDmitry Fleytman pvscsi_build_sglist(PVSCSIState *s, PVSCSIRequest *r)
688881d588aSDmitry Fleytman {
689881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s);
690881d588aSDmitry Fleytman
691df32fd1cSPaolo Bonzini pci_dma_sglist_init(&r->sgl, d, 1);
692881d588aSDmitry Fleytman if (r->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) {
693881d588aSDmitry Fleytman pvscsi_convert_sglist(r);
694881d588aSDmitry Fleytman } else {
695881d588aSDmitry Fleytman qemu_sglist_add(&r->sgl, r->req.dataAddr, r->req.dataLen);
696881d588aSDmitry Fleytman }
697881d588aSDmitry Fleytman }
698881d588aSDmitry Fleytman
699881d588aSDmitry Fleytman static void
pvscsi_process_request_descriptor(PVSCSIState * s,struct PVSCSIRingReqDesc * descr)700881d588aSDmitry Fleytman pvscsi_process_request_descriptor(PVSCSIState *s,
701881d588aSDmitry Fleytman struct PVSCSIRingReqDesc *descr)
702881d588aSDmitry Fleytman {
703881d588aSDmitry Fleytman SCSIDevice *d;
704881d588aSDmitry Fleytman PVSCSIRequest *r = pvscsi_queue_pending_descriptor(s, &d, descr);
705881d588aSDmitry Fleytman int64_t n;
706881d588aSDmitry Fleytman
707881d588aSDmitry Fleytman trace_pvscsi_process_req_descr(descr->cdb[0], descr->context);
708881d588aSDmitry Fleytman
709881d588aSDmitry Fleytman if (!d) {
710881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_SELTIMEO;
711881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_unknown_device();
712881d588aSDmitry Fleytman pvscsi_complete_request(s, r);
713881d588aSDmitry Fleytman return;
714881d588aSDmitry Fleytman }
715881d588aSDmitry Fleytman
716881d588aSDmitry Fleytman if (descr->flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) {
717881d588aSDmitry Fleytman r->sg.elemAddr = descr->dataAddr;
718881d588aSDmitry Fleytman }
719881d588aSDmitry Fleytman
720fe9d8927SJohn Millikin r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, descr->cdbLen, r);
721881d588aSDmitry Fleytman if (r->sreq->cmd.mode == SCSI_XFER_FROM_DEV &&
722881d588aSDmitry Fleytman (descr->flags & PVSCSI_FLAG_CMD_DIR_TODEVICE)) {
723881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_BADMSG;
724881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_invalid_dir();
725881d588aSDmitry Fleytman scsi_req_cancel(r->sreq);
726881d588aSDmitry Fleytman return;
727881d588aSDmitry Fleytman }
728881d588aSDmitry Fleytman if (r->sreq->cmd.mode == SCSI_XFER_TO_DEV &&
729881d588aSDmitry Fleytman (descr->flags & PVSCSI_FLAG_CMD_DIR_TOHOST)) {
730881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_BADMSG;
731881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_invalid_dir();
732881d588aSDmitry Fleytman scsi_req_cancel(r->sreq);
733881d588aSDmitry Fleytman return;
734881d588aSDmitry Fleytman }
735881d588aSDmitry Fleytman
736881d588aSDmitry Fleytman pvscsi_build_sglist(s, r);
737881d588aSDmitry Fleytman n = scsi_req_enqueue(r->sreq);
738881d588aSDmitry Fleytman
739881d588aSDmitry Fleytman if (n) {
740881d588aSDmitry Fleytman scsi_req_continue(r->sreq);
741881d588aSDmitry Fleytman }
742881d588aSDmitry Fleytman }
743881d588aSDmitry Fleytman
744881d588aSDmitry Fleytman static void
pvscsi_process_io(PVSCSIState * s)745881d588aSDmitry Fleytman pvscsi_process_io(PVSCSIState *s)
746881d588aSDmitry Fleytman {
747881d588aSDmitry Fleytman PVSCSIRingReqDesc descr;
748881d588aSDmitry Fleytman hwaddr next_descr_pa;
749881d588aSDmitry Fleytman
750e7ebf057SElazar Leibovich if (!s->rings_info_valid) {
751e7ebf057SElazar Leibovich return;
752e7ebf057SElazar Leibovich }
753e7ebf057SElazar Leibovich
754881d588aSDmitry Fleytman while ((next_descr_pa = pvscsi_ring_pop_req_descr(&s->rings)) != 0) {
755881d588aSDmitry Fleytman
756881d588aSDmitry Fleytman /* Only read after production index verification */
757881d588aSDmitry Fleytman smp_rmb();
758881d588aSDmitry Fleytman
759881d588aSDmitry Fleytman trace_pvscsi_process_io(next_descr_pa);
760881d588aSDmitry Fleytman cpu_physical_memory_read(next_descr_pa, &descr, sizeof(descr));
761881d588aSDmitry Fleytman pvscsi_process_request_descriptor(s, &descr);
762881d588aSDmitry Fleytman }
763881d588aSDmitry Fleytman
764881d588aSDmitry Fleytman pvscsi_ring_flush_req(&s->rings);
765881d588aSDmitry Fleytman }
766881d588aSDmitry Fleytman
767881d588aSDmitry Fleytman static void
pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings * rc)768881d588aSDmitry Fleytman pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc)
769881d588aSDmitry Fleytman {
770881d588aSDmitry Fleytman int i;
771881d588aSDmitry Fleytman trace_pvscsi_tx_rings_ppn("Rings State", rc->ringsStatePPN);
772881d588aSDmitry Fleytman
773881d588aSDmitry Fleytman trace_pvscsi_tx_rings_num_pages("Request Ring", rc->reqRingNumPages);
774881d588aSDmitry Fleytman for (i = 0; i < rc->reqRingNumPages; i++) {
775881d588aSDmitry Fleytman trace_pvscsi_tx_rings_ppn("Request Ring", rc->reqRingPPNs[i]);
776881d588aSDmitry Fleytman }
777881d588aSDmitry Fleytman
778881d588aSDmitry Fleytman trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages);
779881d588aSDmitry Fleytman for (i = 0; i < rc->cmpRingNumPages; i++) {
7807f61f469SPrasad J Pandit trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->cmpRingPPNs[i]);
781881d588aSDmitry Fleytman }
782881d588aSDmitry Fleytman }
783881d588aSDmitry Fleytman
784881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_config(PVSCSIState * s)785881d588aSDmitry Fleytman pvscsi_on_cmd_config(PVSCSIState *s)
786881d588aSDmitry Fleytman {
787881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_CONFIG");
788881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
789881d588aSDmitry Fleytman }
790881d588aSDmitry Fleytman
791881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_unplug(PVSCSIState * s)792881d588aSDmitry Fleytman pvscsi_on_cmd_unplug(PVSCSIState *s)
793881d588aSDmitry Fleytman {
794881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_DEVICE_UNPLUG");
795881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
796881d588aSDmitry Fleytman }
797881d588aSDmitry Fleytman
798881d588aSDmitry Fleytman static uint64_t
pvscsi_on_issue_scsi(PVSCSIState * s)799881d588aSDmitry Fleytman pvscsi_on_issue_scsi(PVSCSIState *s)
800881d588aSDmitry Fleytman {
801881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_ISSUE_SCSI");
802881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
803881d588aSDmitry Fleytman }
804881d588aSDmitry Fleytman
805881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_setup_rings(PVSCSIState * s)806881d588aSDmitry Fleytman pvscsi_on_cmd_setup_rings(PVSCSIState *s)
807881d588aSDmitry Fleytman {
808881d588aSDmitry Fleytman PVSCSICmdDescSetupRings *rc =
809881d588aSDmitry Fleytman (PVSCSICmdDescSetupRings *) s->curr_cmd_data;
810881d588aSDmitry Fleytman
811881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS");
812881d588aSDmitry Fleytman
8137f61f469SPrasad J Pandit if (!rc->reqRingNumPages
8147f61f469SPrasad J Pandit || rc->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
8157f61f469SPrasad J Pandit || !rc->cmpRingNumPages
8167f61f469SPrasad J Pandit || rc->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) {
8173e831b40SPrasad J Pandit return PVSCSI_COMMAND_PROCESSING_FAILED;
8183e831b40SPrasad J Pandit }
8193e831b40SPrasad J Pandit
8207f61f469SPrasad J Pandit pvscsi_dbg_dump_tx_rings_config(rc);
8217f61f469SPrasad J Pandit pvscsi_ring_init_data(&s->rings, rc);
8227f61f469SPrasad J Pandit
823881d588aSDmitry Fleytman s->rings_info_valid = TRUE;
824881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
825881d588aSDmitry Fleytman }
826881d588aSDmitry Fleytman
827881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_abort(PVSCSIState * s)828881d588aSDmitry Fleytman pvscsi_on_cmd_abort(PVSCSIState *s)
829881d588aSDmitry Fleytman {
830881d588aSDmitry Fleytman PVSCSICmdDescAbortCmd *cmd = (PVSCSICmdDescAbortCmd *) s->curr_cmd_data;
831881d588aSDmitry Fleytman PVSCSIRequest *r, *next;
832881d588aSDmitry Fleytman
833881d588aSDmitry Fleytman trace_pvscsi_on_cmd_abort(cmd->context, cmd->target);
834881d588aSDmitry Fleytman
835881d588aSDmitry Fleytman QTAILQ_FOREACH_SAFE(r, &s->pending_queue, next, next) {
836881d588aSDmitry Fleytman if (r->req.context == cmd->context) {
837881d588aSDmitry Fleytman break;
838881d588aSDmitry Fleytman }
839881d588aSDmitry Fleytman }
840881d588aSDmitry Fleytman if (r) {
841881d588aSDmitry Fleytman assert(!r->completed);
842881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_ABORTQUEUE;
843881d588aSDmitry Fleytman scsi_req_cancel(r->sreq);
844881d588aSDmitry Fleytman }
845881d588aSDmitry Fleytman
846881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
847881d588aSDmitry Fleytman }
848881d588aSDmitry Fleytman
849881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_unknown(PVSCSIState * s)850881d588aSDmitry Fleytman pvscsi_on_cmd_unknown(PVSCSIState *s)
851881d588aSDmitry Fleytman {
852881d588aSDmitry Fleytman trace_pvscsi_on_cmd_unknown_data(s->curr_cmd_data[0]);
853881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
854881d588aSDmitry Fleytman }
855881d588aSDmitry Fleytman
856881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_reset_device(PVSCSIState * s)857881d588aSDmitry Fleytman pvscsi_on_cmd_reset_device(PVSCSIState *s)
858881d588aSDmitry Fleytman {
859881d588aSDmitry Fleytman uint8_t target_lun = 0;
860881d588aSDmitry Fleytman struct PVSCSICmdDescResetDevice *cmd =
861881d588aSDmitry Fleytman (struct PVSCSICmdDescResetDevice *) s->curr_cmd_data;
862881d588aSDmitry Fleytman SCSIDevice *sdev;
863881d588aSDmitry Fleytman
864881d588aSDmitry Fleytman sdev = pvscsi_device_find(s, 0, cmd->target, cmd->lun, &target_lun);
865881d588aSDmitry Fleytman
866881d588aSDmitry Fleytman trace_pvscsi_on_cmd_reset_dev(cmd->target, (int) target_lun, sdev);
867881d588aSDmitry Fleytman
868881d588aSDmitry Fleytman if (sdev != NULL) {
869881d588aSDmitry Fleytman s->resetting++;
8708b5335e3SPeter Maydell device_cold_reset(&sdev->qdev);
871881d588aSDmitry Fleytman s->resetting--;
872881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
873881d588aSDmitry Fleytman }
874881d588aSDmitry Fleytman
875881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
876881d588aSDmitry Fleytman }
877881d588aSDmitry Fleytman
878881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_reset_bus(PVSCSIState * s)879881d588aSDmitry Fleytman pvscsi_on_cmd_reset_bus(PVSCSIState *s)
880881d588aSDmitry Fleytman {
881881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS");
882881d588aSDmitry Fleytman
883881d588aSDmitry Fleytman s->resetting++;
8844a5fc890SPeter Maydell bus_cold_reset(BUS(&s->bus));
885881d588aSDmitry Fleytman s->resetting--;
886881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
887881d588aSDmitry Fleytman }
888881d588aSDmitry Fleytman
889881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_setup_msg_ring(PVSCSIState * s)890881d588aSDmitry Fleytman pvscsi_on_cmd_setup_msg_ring(PVSCSIState *s)
891881d588aSDmitry Fleytman {
892881d588aSDmitry Fleytman PVSCSICmdDescSetupMsgRing *rc =
893881d588aSDmitry Fleytman (PVSCSICmdDescSetupMsgRing *) s->curr_cmd_data;
894881d588aSDmitry Fleytman
895881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_MSG_RING");
896881d588aSDmitry Fleytman
897881d588aSDmitry Fleytman if (!s->use_msg) {
898881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED;
899881d588aSDmitry Fleytman }
900881d588aSDmitry Fleytman
901881d588aSDmitry Fleytman if (s->rings_info_valid) {
9023e831b40SPrasad J Pandit if (pvscsi_ring_init_msg(&s->rings, rc) < 0) {
9033e831b40SPrasad J Pandit return PVSCSI_COMMAND_PROCESSING_FAILED;
9043e831b40SPrasad J Pandit }
905881d588aSDmitry Fleytman s->msg_ring_info_valid = TRUE;
906881d588aSDmitry Fleytman }
907881d588aSDmitry Fleytman return sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(uint32_t);
908881d588aSDmitry Fleytman }
909881d588aSDmitry Fleytman
910881d588aSDmitry Fleytman static uint64_t
pvscsi_on_cmd_adapter_reset(PVSCSIState * s)911881d588aSDmitry Fleytman pvscsi_on_cmd_adapter_reset(PVSCSIState *s)
912881d588aSDmitry Fleytman {
913881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_ADAPTER_RESET");
914881d588aSDmitry Fleytman
915881d588aSDmitry Fleytman pvscsi_reset_adapter(s);
916881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
917881d588aSDmitry Fleytman }
918881d588aSDmitry Fleytman
919881d588aSDmitry Fleytman static const struct {
920881d588aSDmitry Fleytman int data_size;
921881d588aSDmitry Fleytman uint64_t (*handler_fn)(PVSCSIState *s);
922881d588aSDmitry Fleytman } pvscsi_commands[] = {
923881d588aSDmitry Fleytman [PVSCSI_CMD_FIRST] = {
924881d588aSDmitry Fleytman .data_size = 0,
925881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_unknown,
926881d588aSDmitry Fleytman },
927881d588aSDmitry Fleytman
928881d588aSDmitry Fleytman /* Not implemented, data size defined based on what arrives on windows */
929881d588aSDmitry Fleytman [PVSCSI_CMD_CONFIG] = {
930881d588aSDmitry Fleytman .data_size = 6 * sizeof(uint32_t),
931881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_config,
932881d588aSDmitry Fleytman },
933881d588aSDmitry Fleytman
934881d588aSDmitry Fleytman /* Command not implemented, data size is unknown */
935881d588aSDmitry Fleytman [PVSCSI_CMD_ISSUE_SCSI] = {
936881d588aSDmitry Fleytman .data_size = 0,
937881d588aSDmitry Fleytman .handler_fn = pvscsi_on_issue_scsi,
938881d588aSDmitry Fleytman },
939881d588aSDmitry Fleytman
940881d588aSDmitry Fleytman /* Command not implemented, data size is unknown */
941881d588aSDmitry Fleytman [PVSCSI_CMD_DEVICE_UNPLUG] = {
942881d588aSDmitry Fleytman .data_size = 0,
943881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_unplug,
944881d588aSDmitry Fleytman },
945881d588aSDmitry Fleytman
946881d588aSDmitry Fleytman [PVSCSI_CMD_SETUP_RINGS] = {
947881d588aSDmitry Fleytman .data_size = sizeof(PVSCSICmdDescSetupRings),
948881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_setup_rings,
949881d588aSDmitry Fleytman },
950881d588aSDmitry Fleytman
951881d588aSDmitry Fleytman [PVSCSI_CMD_RESET_DEVICE] = {
952881d588aSDmitry Fleytman .data_size = sizeof(struct PVSCSICmdDescResetDevice),
953881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_reset_device,
954881d588aSDmitry Fleytman },
955881d588aSDmitry Fleytman
956881d588aSDmitry Fleytman [PVSCSI_CMD_RESET_BUS] = {
957881d588aSDmitry Fleytman .data_size = 0,
958881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_reset_bus,
959881d588aSDmitry Fleytman },
960881d588aSDmitry Fleytman
961881d588aSDmitry Fleytman [PVSCSI_CMD_SETUP_MSG_RING] = {
962881d588aSDmitry Fleytman .data_size = sizeof(PVSCSICmdDescSetupMsgRing),
963881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_setup_msg_ring,
964881d588aSDmitry Fleytman },
965881d588aSDmitry Fleytman
966881d588aSDmitry Fleytman [PVSCSI_CMD_ADAPTER_RESET] = {
967881d588aSDmitry Fleytman .data_size = 0,
968881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_adapter_reset,
969881d588aSDmitry Fleytman },
970881d588aSDmitry Fleytman
971881d588aSDmitry Fleytman [PVSCSI_CMD_ABORT_CMD] = {
972881d588aSDmitry Fleytman .data_size = sizeof(struct PVSCSICmdDescAbortCmd),
973881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_abort,
974881d588aSDmitry Fleytman },
975881d588aSDmitry Fleytman };
976881d588aSDmitry Fleytman
977881d588aSDmitry Fleytman static void
pvscsi_do_command_processing(PVSCSIState * s)978881d588aSDmitry Fleytman pvscsi_do_command_processing(PVSCSIState *s)
979881d588aSDmitry Fleytman {
980881d588aSDmitry Fleytman size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t);
981881d588aSDmitry Fleytman
982881d588aSDmitry Fleytman assert(s->curr_cmd < PVSCSI_CMD_LAST);
983881d588aSDmitry Fleytman if (bytes_arrived >= pvscsi_commands[s->curr_cmd].data_size) {
984881d588aSDmitry Fleytman s->reg_command_status = pvscsi_commands[s->curr_cmd].handler_fn(s);
985881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST;
986881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0;
987881d588aSDmitry Fleytman }
988881d588aSDmitry Fleytman }
989881d588aSDmitry Fleytman
990881d588aSDmitry Fleytman static void
pvscsi_on_command_data(PVSCSIState * s,uint32_t value)991881d588aSDmitry Fleytman pvscsi_on_command_data(PVSCSIState *s, uint32_t value)
992881d588aSDmitry Fleytman {
993881d588aSDmitry Fleytman size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t);
994881d588aSDmitry Fleytman
995881d588aSDmitry Fleytman assert(bytes_arrived < sizeof(s->curr_cmd_data));
996881d588aSDmitry Fleytman s->curr_cmd_data[s->curr_cmd_data_cntr++] = value;
997881d588aSDmitry Fleytman
998881d588aSDmitry Fleytman pvscsi_do_command_processing(s);
999881d588aSDmitry Fleytman }
1000881d588aSDmitry Fleytman
1001881d588aSDmitry Fleytman static void
pvscsi_on_command(PVSCSIState * s,uint64_t cmd_id)1002881d588aSDmitry Fleytman pvscsi_on_command(PVSCSIState *s, uint64_t cmd_id)
1003881d588aSDmitry Fleytman {
1004881d588aSDmitry Fleytman if ((cmd_id > PVSCSI_CMD_FIRST) && (cmd_id < PVSCSI_CMD_LAST)) {
1005881d588aSDmitry Fleytman s->curr_cmd = cmd_id;
1006881d588aSDmitry Fleytman } else {
1007881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST;
1008881d588aSDmitry Fleytman trace_pvscsi_on_cmd_unknown(cmd_id);
1009881d588aSDmitry Fleytman }
1010881d588aSDmitry Fleytman
1011881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0;
1012881d588aSDmitry Fleytman s->reg_command_status = PVSCSI_COMMAND_NOT_ENOUGH_DATA;
1013881d588aSDmitry Fleytman
1014881d588aSDmitry Fleytman pvscsi_do_command_processing(s);
1015881d588aSDmitry Fleytman }
1016881d588aSDmitry Fleytman
1017881d588aSDmitry Fleytman static void
pvscsi_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)1018881d588aSDmitry Fleytman pvscsi_io_write(void *opaque, hwaddr addr,
1019881d588aSDmitry Fleytman uint64_t val, unsigned size)
1020881d588aSDmitry Fleytman {
1021881d588aSDmitry Fleytman PVSCSIState *s = opaque;
1022881d588aSDmitry Fleytman
1023881d588aSDmitry Fleytman switch (addr) {
1024881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND:
1025881d588aSDmitry Fleytman pvscsi_on_command(s, val);
1026881d588aSDmitry Fleytman break;
1027881d588aSDmitry Fleytman
1028881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND_DATA:
1029881d588aSDmitry Fleytman pvscsi_on_command_data(s, (uint32_t) val);
1030881d588aSDmitry Fleytman break;
1031881d588aSDmitry Fleytman
1032881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_STATUS:
1033881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_STATUS", val);
1034881d588aSDmitry Fleytman s->reg_interrupt_status &= ~val;
1035881d588aSDmitry Fleytman pvscsi_update_irq_status(s);
1036881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(s);
1037881d588aSDmitry Fleytman break;
1038881d588aSDmitry Fleytman
1039881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_MASK:
1040881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_MASK", val);
1041881d588aSDmitry Fleytman s->reg_interrupt_enabled = val;
1042881d588aSDmitry Fleytman pvscsi_update_irq_status(s);
1043881d588aSDmitry Fleytman break;
1044881d588aSDmitry Fleytman
1045881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_KICK_NON_RW_IO:
1046881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_NON_RW_IO", val);
1047881d588aSDmitry Fleytman pvscsi_process_io(s);
1048881d588aSDmitry Fleytman break;
1049881d588aSDmitry Fleytman
1050881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_KICK_RW_IO:
1051881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_RW_IO", val);
1052881d588aSDmitry Fleytman pvscsi_process_io(s);
1053881d588aSDmitry Fleytman break;
1054881d588aSDmitry Fleytman
1055881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_DEBUG:
1056881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_DEBUG", val);
1057881d588aSDmitry Fleytman break;
1058881d588aSDmitry Fleytman
1059881d588aSDmitry Fleytman default:
1060881d588aSDmitry Fleytman trace_pvscsi_io_write_unknown(addr, size, val);
1061881d588aSDmitry Fleytman break;
1062881d588aSDmitry Fleytman }
1063881d588aSDmitry Fleytman
1064881d588aSDmitry Fleytman }
1065881d588aSDmitry Fleytman
1066881d588aSDmitry Fleytman static uint64_t
pvscsi_io_read(void * opaque,hwaddr addr,unsigned size)1067881d588aSDmitry Fleytman pvscsi_io_read(void *opaque, hwaddr addr, unsigned size)
1068881d588aSDmitry Fleytman {
1069881d588aSDmitry Fleytman PVSCSIState *s = opaque;
1070881d588aSDmitry Fleytman
1071881d588aSDmitry Fleytman switch (addr) {
1072881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_STATUS:
1073881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_STATUS",
1074881d588aSDmitry Fleytman s->reg_interrupt_status);
1075881d588aSDmitry Fleytman return s->reg_interrupt_status;
1076881d588aSDmitry Fleytman
1077881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_MASK:
1078881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_MASK",
1079881d588aSDmitry Fleytman s->reg_interrupt_status);
1080881d588aSDmitry Fleytman return s->reg_interrupt_enabled;
1081881d588aSDmitry Fleytman
1082881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND_STATUS:
1083881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_COMMAND_STATUS",
1084881d588aSDmitry Fleytman s->reg_interrupt_status);
1085881d588aSDmitry Fleytman return s->reg_command_status;
1086881d588aSDmitry Fleytman
1087881d588aSDmitry Fleytman default:
1088881d588aSDmitry Fleytman trace_pvscsi_io_read_unknown(addr, size);
1089881d588aSDmitry Fleytman return 0;
1090881d588aSDmitry Fleytman }
1091881d588aSDmitry Fleytman }
1092881d588aSDmitry Fleytman
1093881d588aSDmitry Fleytman
1094b2e1fffbSCao jin static void
pvscsi_init_msi(PVSCSIState * s)1095881d588aSDmitry Fleytman pvscsi_init_msi(PVSCSIState *s)
1096881d588aSDmitry Fleytman {
1097881d588aSDmitry Fleytman int res;
1098881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s);
1099881d588aSDmitry Fleytman
110016c04166SPhilippe Mathieu-Daudé res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS,
11011108b2f8SCao jin PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK, NULL);
1102881d588aSDmitry Fleytman if (res < 0) {
1103881d588aSDmitry Fleytman trace_pvscsi_init_msi_fail(res);
1104881d588aSDmitry Fleytman s->msi_used = false;
1105881d588aSDmitry Fleytman } else {
1106881d588aSDmitry Fleytman s->msi_used = true;
1107881d588aSDmitry Fleytman }
1108881d588aSDmitry Fleytman }
1109881d588aSDmitry Fleytman
1110881d588aSDmitry Fleytman static void
pvscsi_cleanup_msi(PVSCSIState * s)1111881d588aSDmitry Fleytman pvscsi_cleanup_msi(PVSCSIState *s)
1112881d588aSDmitry Fleytman {
1113881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s);
1114881d588aSDmitry Fleytman
1115881d588aSDmitry Fleytman msi_uninit(d);
1116881d588aSDmitry Fleytman }
1117881d588aSDmitry Fleytman
1118881d588aSDmitry Fleytman static const MemoryRegionOps pvscsi_ops = {
1119881d588aSDmitry Fleytman .read = pvscsi_io_read,
1120881d588aSDmitry Fleytman .write = pvscsi_io_write,
1121881d588aSDmitry Fleytman .endianness = DEVICE_LITTLE_ENDIAN,
1122881d588aSDmitry Fleytman .impl = {
1123881d588aSDmitry Fleytman .min_access_size = 4,
1124881d588aSDmitry Fleytman .max_access_size = 4,
1125881d588aSDmitry Fleytman },
1126881d588aSDmitry Fleytman };
1127881d588aSDmitry Fleytman
1128881d588aSDmitry Fleytman static const struct SCSIBusInfo pvscsi_scsi_info = {
1129881d588aSDmitry Fleytman .tcq = true,
1130881d588aSDmitry Fleytman .max_target = PVSCSI_MAX_DEVS,
1131881d588aSDmitry Fleytman .max_channel = 0,
1132881d588aSDmitry Fleytman .max_lun = 0,
1133881d588aSDmitry Fleytman
1134881d588aSDmitry Fleytman .get_sg_list = pvscsi_get_sg_list,
1135881d588aSDmitry Fleytman .complete = pvscsi_command_complete,
1136881d588aSDmitry Fleytman .cancel = pvscsi_request_cancelled,
1137f3126d65SHannes Reinecke .fail = pvscsi_command_failed,
1138881d588aSDmitry Fleytman };
1139881d588aSDmitry Fleytman
1140fafeb41cSMao Zhongyi static void
pvscsi_realizefn(PCIDevice * pci_dev,Error ** errp)1141fafeb41cSMao Zhongyi pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
1142881d588aSDmitry Fleytman {
1143881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(pci_dev);
1144881d588aSDmitry Fleytman
1145881d588aSDmitry Fleytman trace_pvscsi_state("init");
1146881d588aSDmitry Fleytman
1147d29d4ff8SShmulik Ladkani /* PCI subsystem ID, subsystem vendor ID, revision */
1148d29d4ff8SShmulik Ladkani pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
1149d29d4ff8SShmulik Ladkani PCI_VENDOR_ID_VMWARE);
1150d29d4ff8SShmulik Ladkani pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
1151d29d4ff8SShmulik Ladkani PCI_DEVICE_ID_VMWARE_PVSCSI);
1152d29d4ff8SShmulik Ladkani pci_config_set_revision(pci_dev->config, 0x2);
1153881d588aSDmitry Fleytman
1154881d588aSDmitry Fleytman /* PCI latency timer = 255 */
1155881d588aSDmitry Fleytman pci_dev->config[PCI_LATENCY_TIMER] = 0xff;
1156881d588aSDmitry Fleytman
1157881d588aSDmitry Fleytman /* Interrupt pin A */
1158881d588aSDmitry Fleytman pci_config_set_interrupt_pin(pci_dev->config, 1);
1159881d588aSDmitry Fleytman
116029776739SPaolo Bonzini memory_region_init_io(&s->io_space, OBJECT(s), &pvscsi_ops, s,
1161881d588aSDmitry Fleytman "pvscsi-io", PVSCSI_MEM_SPACE_SIZE);
1162881d588aSDmitry Fleytman pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_space);
1163881d588aSDmitry Fleytman
1164881d588aSDmitry Fleytman pvscsi_init_msi(s);
1165881d588aSDmitry Fleytman
1166fd56e061SDavid Gibson if (pci_is_express(pci_dev) && pci_bus_is_express(pci_get_bus(pci_dev))) {
11671dd1305eSShmulik Ladkani pcie_endpoint_cap_init(pci_dev, PVSCSI_EXP_EP_OFFSET);
11681dd1305eSShmulik Ladkani }
11691dd1305eSShmulik Ladkani
1170f63192b0SAlexander Bulekov s->completion_worker = qemu_bh_new_guarded(pvscsi_process_completion_queue, s,
1171f63192b0SAlexander Bulekov &DEVICE(pci_dev)->mem_reentrancy_guard);
1172881d588aSDmitry Fleytman
1173739e95f5SPeter Maydell scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(pci_dev), &pvscsi_scsi_info);
117491c8daadSIgor Mammedov /* override default SCSI bus hotplug-handler, with pvscsi's one */
11759bc6bfdfSMarkus Armbruster qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(s));
1176881d588aSDmitry Fleytman pvscsi_reset_state(s);
1177881d588aSDmitry Fleytman }
1178881d588aSDmitry Fleytman
1179881d588aSDmitry Fleytman static void
pvscsi_uninit(PCIDevice * pci_dev)1180881d588aSDmitry Fleytman pvscsi_uninit(PCIDevice *pci_dev)
1181881d588aSDmitry Fleytman {
1182881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(pci_dev);
1183881d588aSDmitry Fleytman
1184881d588aSDmitry Fleytman trace_pvscsi_state("uninit");
1185881d588aSDmitry Fleytman qemu_bh_delete(s->completion_worker);
1186881d588aSDmitry Fleytman
1187881d588aSDmitry Fleytman pvscsi_cleanup_msi(s);
1188881d588aSDmitry Fleytman }
1189881d588aSDmitry Fleytman
1190881d588aSDmitry Fleytman static void
pvscsi_reset(DeviceState * dev)1191881d588aSDmitry Fleytman pvscsi_reset(DeviceState *dev)
1192881d588aSDmitry Fleytman {
1193881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(dev);
1194881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(d);
1195881d588aSDmitry Fleytman
1196881d588aSDmitry Fleytman trace_pvscsi_state("reset");
1197881d588aSDmitry Fleytman pvscsi_reset_adapter(s);
1198881d588aSDmitry Fleytman }
1199881d588aSDmitry Fleytman
120044b1ff31SDr. David Alan Gilbert static int
pvscsi_pre_save(void * opaque)1201881d588aSDmitry Fleytman pvscsi_pre_save(void *opaque)
1202881d588aSDmitry Fleytman {
1203881d588aSDmitry Fleytman PVSCSIState *s = (PVSCSIState *) opaque;
1204881d588aSDmitry Fleytman
1205881d588aSDmitry Fleytman trace_pvscsi_state("presave");
1206881d588aSDmitry Fleytman
1207881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->pending_queue));
1208881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->completion_queue));
120944b1ff31SDr. David Alan Gilbert
121044b1ff31SDr. David Alan Gilbert return 0;
1211881d588aSDmitry Fleytman }
1212881d588aSDmitry Fleytman
1213881d588aSDmitry Fleytman static int
pvscsi_post_load(void * opaque,int version_id)1214881d588aSDmitry Fleytman pvscsi_post_load(void *opaque, int version_id)
1215881d588aSDmitry Fleytman {
1216881d588aSDmitry Fleytman trace_pvscsi_state("postload");
1217881d588aSDmitry Fleytman return 0;
1218881d588aSDmitry Fleytman }
1219881d588aSDmitry Fleytman
12201dd1305eSShmulik Ladkani static const VMStateDescription vmstate_pvscsi_pcie_device = {
12211dd1305eSShmulik Ladkani .name = "pvscsi/pcie",
12222d7b39a6SRichard Henderson .fields = (const VMStateField[]) {
122320daa90aSDr. David Alan Gilbert VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState),
12241dd1305eSShmulik Ladkani VMSTATE_END_OF_LIST()
12251dd1305eSShmulik Ladkani }
12261dd1305eSShmulik Ladkani };
12271dd1305eSShmulik Ladkani
1228881d588aSDmitry Fleytman static const VMStateDescription vmstate_pvscsi = {
12296783ecf1SPeter Maydell .name = "pvscsi",
1230881d588aSDmitry Fleytman .version_id = 0,
1231881d588aSDmitry Fleytman .minimum_version_id = 0,
1232881d588aSDmitry Fleytman .pre_save = pvscsi_pre_save,
1233881d588aSDmitry Fleytman .post_load = pvscsi_post_load,
12342d7b39a6SRichard Henderson .fields = (const VMStateField[]) {
1235881d588aSDmitry Fleytman VMSTATE_UINT8(msi_used, PVSCSIState),
1236881d588aSDmitry Fleytman VMSTATE_UINT32(resetting, PVSCSIState),
1237881d588aSDmitry Fleytman VMSTATE_UINT64(reg_interrupt_status, PVSCSIState),
1238881d588aSDmitry Fleytman VMSTATE_UINT64(reg_interrupt_enabled, PVSCSIState),
1239881d588aSDmitry Fleytman VMSTATE_UINT64(reg_command_status, PVSCSIState),
1240881d588aSDmitry Fleytman VMSTATE_UINT64(curr_cmd, PVSCSIState),
1241881d588aSDmitry Fleytman VMSTATE_UINT32(curr_cmd_data_cntr, PVSCSIState),
1242881d588aSDmitry Fleytman VMSTATE_UINT32_ARRAY(curr_cmd_data, PVSCSIState,
1243881d588aSDmitry Fleytman ARRAY_SIZE(((PVSCSIState *)NULL)->curr_cmd_data)),
1244881d588aSDmitry Fleytman VMSTATE_UINT8(rings_info_valid, PVSCSIState),
1245881d588aSDmitry Fleytman VMSTATE_UINT8(msg_ring_info_valid, PVSCSIState),
1246881d588aSDmitry Fleytman VMSTATE_UINT8(use_msg, PVSCSIState),
1247881d588aSDmitry Fleytman
1248881d588aSDmitry Fleytman VMSTATE_UINT64(rings.rs_pa, PVSCSIState),
1249881d588aSDmitry Fleytman VMSTATE_UINT32(rings.txr_len_mask, PVSCSIState),
1250881d588aSDmitry Fleytman VMSTATE_UINT32(rings.rxr_len_mask, PVSCSIState),
1251881d588aSDmitry Fleytman VMSTATE_UINT64_ARRAY(rings.req_ring_pages_pa, PVSCSIState,
1252881d588aSDmitry Fleytman PVSCSI_SETUP_RINGS_MAX_NUM_PAGES),
1253881d588aSDmitry Fleytman VMSTATE_UINT64_ARRAY(rings.cmp_ring_pages_pa, PVSCSIState,
1254881d588aSDmitry Fleytman PVSCSI_SETUP_RINGS_MAX_NUM_PAGES),
1255881d588aSDmitry Fleytman VMSTATE_UINT64(rings.consumed_ptr, PVSCSIState),
1256881d588aSDmitry Fleytman VMSTATE_UINT64(rings.filled_cmp_ptr, PVSCSIState),
1257881d588aSDmitry Fleytman
1258881d588aSDmitry Fleytman VMSTATE_END_OF_LIST()
12591dd1305eSShmulik Ladkani },
12602d7b39a6SRichard Henderson .subsections = (const VMStateDescription * const []) {
12611dd1305eSShmulik Ladkani &vmstate_pvscsi_pcie_device,
12621dd1305eSShmulik Ladkani NULL
1263881d588aSDmitry Fleytman }
1264881d588aSDmitry Fleytman };
1265881d588aSDmitry Fleytman
1266ec7630a2SRichard Henderson static const Property pvscsi_properties[] = {
1267881d588aSDmitry Fleytman DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
1268881d588aSDmitry Fleytman };
1269881d588aSDmitry Fleytman
pvscsi_instance_init(Object * obj)1270*3763d163SPhilippe Mathieu-Daudé static void pvscsi_instance_init(Object *obj)
12711dd1305eSShmulik Ladkani {
1272*3763d163SPhilippe Mathieu-Daudé PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
12731dd1305eSShmulik Ladkani }
12741dd1305eSShmulik Ladkani
pvscsi_class_init(ObjectClass * klass,const void * data)127512d1a768SPhilippe Mathieu-Daudé static void pvscsi_class_init(ObjectClass *klass, const void *data)
1276881d588aSDmitry Fleytman {
1277881d588aSDmitry Fleytman DeviceClass *dc = DEVICE_CLASS(klass);
1278881d588aSDmitry Fleytman PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
127991c8daadSIgor Mammedov HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
1280881d588aSDmitry Fleytman
1281fafeb41cSMao Zhongyi k->realize = pvscsi_realizefn;
1282881d588aSDmitry Fleytman k->exit = pvscsi_uninit;
1283881d588aSDmitry Fleytman k->vendor_id = PCI_VENDOR_ID_VMWARE;
1284881d588aSDmitry Fleytman k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
1285881d588aSDmitry Fleytman k->class_id = PCI_CLASS_STORAGE_SCSI;
1286881d588aSDmitry Fleytman k->subsystem_id = 0x1000;
1287e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pvscsi_reset);
1288881d588aSDmitry Fleytman dc->vmsd = &vmstate_pvscsi;
12894f67d30bSMarc-André Lureau device_class_set_props(dc, pvscsi_properties);
1290125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
129191c8daadSIgor Mammedov hc->unplug = pvscsi_hot_unplug;
129291c8daadSIgor Mammedov hc->plug = pvscsi_hotplug;
1293881d588aSDmitry Fleytman }
1294881d588aSDmitry Fleytman
1295881d588aSDmitry Fleytman static const TypeInfo pvscsi_info = {
12966783ecf1SPeter Maydell .name = TYPE_PVSCSI,
1297881d588aSDmitry Fleytman .parent = TYPE_PCI_DEVICE,
1298e2d4f3f7SShmulik Ladkani .class_size = sizeof(PVSCSIClass),
1299881d588aSDmitry Fleytman .instance_size = sizeof(PVSCSIState),
1300881d588aSDmitry Fleytman .class_init = pvscsi_class_init,
1301*3763d163SPhilippe Mathieu-Daudé .instance_init = pvscsi_instance_init,
13022cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
130391c8daadSIgor Mammedov { TYPE_HOTPLUG_HANDLER },
1304a5fa336fSEduardo Habkost { INTERFACE_PCIE_DEVICE },
1305a5fa336fSEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
130691c8daadSIgor Mammedov { }
130791c8daadSIgor Mammedov }
1308881d588aSDmitry Fleytman };
1309881d588aSDmitry Fleytman
1310881d588aSDmitry Fleytman static void
pvscsi_register_types(void)1311881d588aSDmitry Fleytman pvscsi_register_types(void)
1312881d588aSDmitry Fleytman {
1313881d588aSDmitry Fleytman type_register_static(&pvscsi_info);
1314881d588aSDmitry Fleytman }
1315881d588aSDmitry Fleytman
1316881d588aSDmitry Fleytman type_init(pvscsi_register_types);
1317