1 // QEMU VMWARE Paravirtualized SCSI boot support.
2 //
3 // Copyright (c) 2013 Ravello Systems LTD (http://ravellosystems.com)
4 //
5 // Authors:
6 // Evgeny Budilovsky <evgeny.budilovsky@ravellosystems.com>
7 //
8 // This file may be distributed under the terms of the GNU LGPLv3 license.
9
10 #include "block.h" // struct drive_s
11 #include "blockcmd.h" // scsi_drive_setup
12 #include "config.h" // CONFIG_*
13 #include "malloc.h" // free
14 #include "memmap.h" // PAGE_SHIFT, virt_to_phys
15 #include "output.h" // dprintf
16 #include "pcidevice.h" // foreachpci
17 #include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
18 #include "pci_regs.h" // PCI_VENDOR_ID
19 #include "pvscsi.h" // pvscsi_setup
20 #include "stacks.h" // run_thread
21 #include "std/disk.h" // DISK_RET_SUCCESS
22 #include "string.h" // memset
23 #include "util.h" // usleep
24 #include "x86.h" // writel
25
26 #define MASK(n) ((1 << (n)) - 1)
27
28 #define SIMPLE_QUEUE_TAG 0x20
29
30 #define PVSCSI_INTR_CMPL_0 (1 << 0)
31 #define PVSCSI_INTR_CMPL_1 (1 << 1)
32 #define PVSCSI_INTR_CMPL_MASK MASK(2)
33
34 #define PVSCSI_INTR_MSG_0 (1 << 2)
35 #define PVSCSI_INTR_MSG_1 (1 << 3)
36 #define PVSCSI_INTR_MSG_MASK (MASK(2) << 2)
37 #define PVSCSI_INTR_ALL_SUPPORTED MASK(4)
38
39 #define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0)
40 #define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1)
41 #define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2)
42 #define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3)
43 #define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4)
44
45 enum PVSCSIRegOffset {
46 PVSCSI_REG_OFFSET_COMMAND = 0x0,
47 PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4,
48 PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8,
49 PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100,
50 PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104,
51 PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108,
52 PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c,
53 PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c,
54 PVSCSI_REG_OFFSET_INTR_MASK = 0x2010,
55 PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
56 PVSCSI_REG_OFFSET_DEBUG = 0x3018,
57 PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018,
58 };
59
60 enum PVSCSICommands {
61 PVSCSI_CMD_FIRST = 0,
62 PVSCSI_CMD_ADAPTER_RESET = 1,
63 PVSCSI_CMD_ISSUE_SCSI = 2,
64 PVSCSI_CMD_SETUP_RINGS = 3,
65 PVSCSI_CMD_RESET_BUS = 4,
66 PVSCSI_CMD_RESET_DEVICE = 5,
67 PVSCSI_CMD_ABORT_CMD = 6,
68 PVSCSI_CMD_CONFIG = 7,
69 PVSCSI_CMD_SETUP_MSG_RING = 8,
70 PVSCSI_CMD_DEVICE_UNPLUG = 9,
71 PVSCSI_CMD_LAST = 10
72 };
73
74 #define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32
75 struct PVSCSICmdDescSetupRings {
76 u32 reqRingNumPages;
77 u32 cmpRingNumPages;
78 u64 ringsStatePPN;
79 u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
80 u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
81 } PACKED;
82
83 struct PVSCSIRingCmpDesc {
84 u64 context;
85 u64 dataLen;
86 u32 senseLen;
87 u16 hostStatus;
88 u16 scsiStatus;
89 u32 pad[2];
90 } PACKED;
91
92 struct PVSCSIRingsState {
93 u32 reqProdIdx;
94 u32 reqConsIdx;
95 u32 reqNumEntriesLog2;
96
97 u32 cmpProdIdx;
98 u32 cmpConsIdx;
99 u32 cmpNumEntriesLog2;
100
101 u8 pad[104];
102
103 u32 msgProdIdx;
104 u32 msgConsIdx;
105 u32 msgNumEntriesLog2;
106 } PACKED;
107
108 struct PVSCSIRingReqDesc {
109 u64 context;
110 u64 dataAddr;
111 u64 dataLen;
112 u64 senseAddr;
113 u32 senseLen;
114 u32 flags;
115 u8 cdb[16];
116 u8 cdbLen;
117 u8 lun[8];
118 u8 tag;
119 u8 bus;
120 u8 target;
121 u8 vcpuHint;
122 u8 unused[59];
123 } PACKED;
124
125 struct pvscsi_ring_dsc_s {
126 struct PVSCSIRingsState *ring_state;
127 struct PVSCSIRingReqDesc *ring_reqs;
128 struct PVSCSIRingCmpDesc *ring_cmps;
129 };
130
131 struct pvscsi_lun_s {
132 struct drive_s drive;
133 void *iobase;
134 u8 target;
135 u8 lun;
136 struct pvscsi_ring_dsc_s *ring_dsc;
137 };
138
139 static void
pvscsi_write_cmd_desc(void * iobase,u32 cmd,const void * desc,size_t len)140 pvscsi_write_cmd_desc(void *iobase, u32 cmd, const void *desc, size_t len)
141 {
142 const u32 *ptr = desc;
143 size_t i;
144
145 len /= sizeof(*ptr);
146 writel(iobase + PVSCSI_REG_OFFSET_COMMAND, cmd);
147 for (i = 0; i < len; i++)
148 writel(iobase + PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]);
149 }
150
151 static void
pvscsi_kick_rw_io(void * iobase)152 pvscsi_kick_rw_io(void *iobase)
153 {
154 writel(iobase + PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
155 }
156
157 static void
pvscsi_wait_intr_cmpl(void * iobase)158 pvscsi_wait_intr_cmpl(void *iobase)
159 {
160 while (!(readl(iobase + PVSCSI_REG_OFFSET_INTR_STATUS) & PVSCSI_INTR_CMPL_MASK))
161 usleep(5);
162 writel(iobase + PVSCSI_REG_OFFSET_INTR_STATUS, PVSCSI_INTR_CMPL_MASK);
163 }
164
165 static void
pvscsi_init_rings(void * iobase,struct pvscsi_ring_dsc_s ** ring_dsc)166 pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc)
167 {
168 struct PVSCSICmdDescSetupRings cmd = {0,};
169
170 struct pvscsi_ring_dsc_s *dsc = malloc_high(sizeof(*dsc));
171 if (!dsc) {
172 warn_noalloc();
173 return;
174 }
175
176 dsc->ring_state =
177 (struct PVSCSIRingsState *)memalign_high(PAGE_SIZE, PAGE_SIZE);
178 dsc->ring_reqs =
179 (struct PVSCSIRingReqDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
180 dsc->ring_cmps =
181 (struct PVSCSIRingCmpDesc *)memalign_high(PAGE_SIZE, PAGE_SIZE);
182 if (!dsc->ring_state || !dsc->ring_reqs || !dsc->ring_cmps) {
183 warn_noalloc();
184 return;
185 }
186 memset(dsc->ring_state, 0, PAGE_SIZE);
187 memset(dsc->ring_reqs, 0, PAGE_SIZE);
188 memset(dsc->ring_cmps, 0, PAGE_SIZE);
189
190 cmd.reqRingNumPages = 1;
191 cmd.cmpRingNumPages = 1;
192 cmd.ringsStatePPN = virt_to_phys(dsc->ring_state) >> PAGE_SHIFT;
193 cmd.reqRingPPNs[0] = virt_to_phys(dsc->ring_reqs) >> PAGE_SHIFT;
194 cmd.cmpRingPPNs[0] = virt_to_phys(dsc->ring_cmps) >> PAGE_SHIFT;
195
196 pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_SETUP_RINGS,
197 &cmd, sizeof(cmd));
198 *ring_dsc = dsc;
199 }
200
201 static u32
pvscsi_get_rsp(struct PVSCSIRingsState * s,struct PVSCSIRingCmpDesc * rsp)202 pvscsi_get_rsp(struct PVSCSIRingsState *s,
203 struct PVSCSIRingCmpDesc *rsp)
204 {
205 u32 status = rsp->hostStatus;
206 s->cmpConsIdx = s->cmpConsIdx + 1;
207 return status;
208 }
209
210 int
pvscsi_process_op(struct disk_op_s * op)211 pvscsi_process_op(struct disk_op_s *op)
212 {
213 if (!CONFIG_PVSCSI)
214 return DISK_RET_EBADTRACK;
215 struct pvscsi_lun_s *plun =
216 container_of(op->drive_fl, struct pvscsi_lun_s, drive);
217 struct pvscsi_ring_dsc_s *ring_dsc = plun->ring_dsc;
218 struct PVSCSIRingsState *s = ring_dsc->ring_state;
219 u32 req_entries = s->reqNumEntriesLog2;
220 u32 cmp_entries = s->cmpNumEntriesLog2;
221 struct PVSCSIRingReqDesc *req;
222 struct PVSCSIRingCmpDesc *rsp;
223 u32 status;
224
225 if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) {
226 dprintf(1, "pvscsi: ring full: reqProdIdx=%d cmpConsIdx=%d\n",
227 s->reqProdIdx, s->cmpConsIdx);
228 return DISK_RET_EBADTRACK;
229 }
230
231 req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries));
232 int blocksize = scsi_fill_cmd(op, req->cdb, 16);
233 if (blocksize < 0)
234 return default_process_op(op);
235 req->bus = 0;
236 req->target = plun->target;
237 memset(req->lun, 0, sizeof(req->lun));
238 req->lun[1] = plun->lun;
239 req->senseLen = 0;
240 req->senseAddr = 0;
241 req->cdbLen = 16;
242 req->vcpuHint = 0;
243 req->tag = SIMPLE_QUEUE_TAG;
244 req->flags = scsi_is_read(op) ?
245 PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE;
246 req->dataLen = op->count * blocksize;
247 req->dataAddr = (u32)op->buf_fl;
248 s->reqProdIdx = s->reqProdIdx + 1;
249
250 pvscsi_kick_rw_io(plun->iobase);
251 pvscsi_wait_intr_cmpl(plun->iobase);
252
253 rsp = ring_dsc->ring_cmps + (s->cmpConsIdx & MASK(cmp_entries));
254 status = pvscsi_get_rsp(s, rsp);
255
256 return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
257 }
258
259 static int
pvscsi_add_lun(struct pci_device * pci,void * iobase,struct pvscsi_ring_dsc_s * ring_dsc,u8 target,u8 lun)260 pvscsi_add_lun(struct pci_device *pci, void *iobase,
261 struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun)
262 {
263 struct pvscsi_lun_s *plun = malloc_fseg(sizeof(*plun));
264 if (!plun) {
265 warn_noalloc();
266 return -1;
267 }
268 memset(plun, 0, sizeof(*plun));
269 plun->drive.type = DTYPE_PVSCSI;
270 plun->drive.cntl_id = pci->bdf;
271 plun->target = target;
272 plun->lun = lun;
273 plun->iobase = iobase;
274 plun->ring_dsc = ring_dsc;
275
276 boot_lchs_find_scsi_device(pci, target, lun, &(plun->drive.lchs));
277 char *name = znprintf(MAXDESCSIZE, "pvscsi %pP %d:%d", pci, target, lun);
278 int prio = bootprio_find_scsi_device(pci, target, lun);
279 int ret = scsi_drive_setup(&plun->drive, name, prio, target, lun);
280 free(name);
281 if (ret)
282 goto fail;
283 return 0;
284
285 fail:
286 free(plun);
287 return -1;
288 }
289
290 static void
pvscsi_scan_target(struct pci_device * pci,void * iobase,struct pvscsi_ring_dsc_s * ring_dsc,u8 target)291 pvscsi_scan_target(struct pci_device *pci, void *iobase,
292 struct pvscsi_ring_dsc_s *ring_dsc, u8 target)
293 {
294 /* pvscsi has no more than a single lun per target */
295 pvscsi_add_lun(pci, iobase, ring_dsc, target, 0);
296 }
297
298 static void
init_pvscsi(void * data)299 init_pvscsi(void *data)
300 {
301 struct pci_device *pci = data;
302 void *iobase = pci_enable_membar(pci, PCI_BASE_ADDRESS_0);
303 if (!iobase)
304 return;
305 pci_enable_busmaster(pci);
306
307 dprintf(1, "found pvscsi at %pP, io @ %p\n", pci, iobase);
308
309 pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
310
311 struct pvscsi_ring_dsc_s *ring_dsc = NULL;
312 pvscsi_init_rings(iobase, &ring_dsc);
313 int i;
314 for (i = 0; i < 64; i++)
315 pvscsi_scan_target(pci, iobase, ring_dsc, i);
316 }
317
318 void
pvscsi_setup(void)319 pvscsi_setup(void)
320 {
321 ASSERT32FLAT();
322 if (! CONFIG_PVSCSI)
323 return;
324
325 dprintf(3, "init pvscsi\n");
326
327 struct pci_device *pci;
328 foreachpci(pci) {
329 if (pci->vendor != PCI_VENDOR_ID_VMWARE
330 || pci->device != PCI_DEVICE_ID_VMWARE_PVSCSI)
331 continue;
332 run_thread(init_pvscsi, pci);
333 }
334 }
335