VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/virtio.c@ 89168

Last change on this file since 89168 was 89168, checked in by vboxsync, 4 years ago

Devices/PC/BIOS: Implement basic BusLogic and LsiLogic drivers to be able to get rid of the crappy VBoxSCSI interface, bugref:4841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1/* $Id: virtio.c 89168 2021-05-19 13:35:28Z vboxsync $ */
2/** @file
3 * VirtIO-SCSI host adapter driver to boot from disks.
4 */
5
6/*
7 * Copyright (C) 2019-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <stdint.h>
19#include <string.h>
20#include "biosint.h"
21#include "ebda.h"
22#include "inlines.h"
23#include "pciutil.h"
24#include "vds.h"
25#include "scsi.h"
26
27//#define DEBUG_VIRTIO 1
28#if DEBUG_VIRTIO
29# define DBG_VIRTIO(...) BX_INFO(__VA_ARGS__)
30#else
31# define DBG_VIRTIO(...)
32#endif
33
34/* The maximum CDB size. */
35#define VIRTIO_SCSI_CDB_SZ 16
36/** Maximum sense data to return. */
37#define VIRTIO_SCSI_SENSE_SZ 32
38
39#define VIRTIO_SCSI_RING_ELEM 3
40
41/**
42 * VirtIO queue descriptor.
43 */
44typedef struct
45{
46 /** 64bit guest physical address of the buffer, split into high and low part because we work in real mode. */
47 uint32_t GCPhysBufLow;
48 uint32_t GCPhysBufHigh;
49 /** Length of the buffer in bytes. */
50 uint32_t cbBuf;
51 /** Flags for the buffer. */
52 uint16_t fFlags;
53 /** Next field where the buffer is continued if _NEXT flag is set. */
54 uint16_t idxNext;
55} virtio_q_desc_t;
56
57#define VIRTIO_Q_DESC_F_NEXT 0x1
58#define VIRTIO_Q_DESC_F_WRITE 0x2
59#define VIRTIO_Q_DESC_F_INDIRECT 0x4
60
61/**
62 * VirtIO available ring.
63 */
64typedef struct
65{
66 /** Flags. */
67 volatile uint16_t fFlags;
68 /** Next index to write an available buffer by the driver. */
69 volatile uint16_t idxNextFree;
70 /** The ring - we only provide one entry. */
71 volatile uint16_t au16Ring[VIRTIO_SCSI_RING_ELEM];
72 /** Used event index. */
73 volatile uint16_t u16EvtUsed;
74} virtio_q_avail_t;
75
76/**
77 * VirtIO queue used element.
78 */
79typedef struct
80{
81 /** Index of the start of the descriptor chain. */
82 uint32_t u32Id;
83 /** Number of bytes used in the descriptor chain. */
84 uint32_t cbUsed;
85} virtio_q_used_elem_t;
86
87/**
88 * VirtIo used ring.
89 */
90typedef struct
91{
92 /** Flags. */
93 volatile uint16_t fFlags;
94 /** Index where the next entry would be written by the device. */
95 volatile uint16_t idxNextUsed;
96 /** The used ring. */
97 virtio_q_used_elem_t aRing[VIRTIO_SCSI_RING_ELEM];
98} virtio_q_used_t;
99
100/**
101 * VirtIO queue structure we are using, needs to be aligned on a 16byte boundary.
102 */
103typedef struct
104{
105 /** The descriptor table, using 5 max. */
106 virtio_q_desc_t aDescTbl[5];
107 /** Available ring. */
108 virtio_q_avail_t AvailRing;
109 /** Used ring. */
110 virtio_q_used_t UsedRing;
111 /** The notification offset for the queue. */
112 uint32_t offNotify;
113} virtio_q_t;
114
115/**
116 * VirtIO SCSI request structure passed in the queue.
117 */
118typedef struct
119{
120 /** The LUN to address. */
121 uint8_t au8Lun[8];
122 /** Request ID - split into low and high part. */
123 uint32_t u32IdLow;
124 uint32_t u32IdHigh;
125 /** Task attributes. */
126 uint8_t u8TaskAttr;
127 /** Priority. */
128 uint8_t u8Prio;
129 /** CRN value, usually 0. */
130 uint8_t u8Crn;
131 /** The CDB. */
132 uint8_t abCdb[VIRTIO_SCSI_CDB_SZ];
133} virtio_scsi_req_hdr_t;
134
135/**
136 * VirtIO SCSI status structure filled by the device.
137 */
138typedef struct
139{
140 /** Returned sense length. */
141 uint32_t cbSense;
142 /** Residual amount of bytes left. */
143 uint32_t cbResidual;
144 /** Status qualifier. */
145 uint16_t u16StatusQual;
146 /** Status code. */
147 uint8_t u8Status;
148 /** Response code. */
149 uint8_t u8Response;
150 /** Sense data. */
151 uint8_t abSense[VIRTIO_SCSI_SENSE_SZ];
152} virtio_scsi_req_sts_t;
153
154/**
155 * VirtIO config for the different data structures.
156 */
157typedef struct
158{
159 /** BAR where to find it. */
160 uint8_t u8Bar;
161 /** Padding. */
162 uint8_t abPad[3];
163 /** Offset within the bar. */
164 uint32_t u32Offset;
165 /** Length of the structure in bytes. */
166 uint32_t u32Length;
167} virtio_bar_cfg_t;
168
169/**
170 * VirtIO PCI capability structure.
171 */
172typedef struct
173{
174 /** Capability typem should always be PCI_CAP_ID_VNDR*/
175 uint8_t u8PciCapId;
176 /** Offset where to find the next capability or 0 if last capability. */
177 uint8_t u8PciCapNext;
178 /** Size of the capability in bytes. */
179 uint8_t u8PciCapLen;
180 /** VirtIO capability type. */
181 uint8_t u8VirtIoCfgType;
182 /** BAR where to find it. */
183 uint8_t u8Bar;
184 /** Padding. */
185 uint8_t abPad[3];
186 /** Offset within the bar. */
187 uint32_t u32Offset;
188 /** Length of the structure in bytes. */
189 uint32_t u32Length;
190} virtio_pci_cap_t;
191
192/**
193 * VirtIO-SCSI controller data.
194 */
195typedef struct
196{
197 /** The queue used - must be first for alignment reasons. */
198 virtio_q_t Queue;
199 /** The BAR configs read from the PCI configuration space, see VIRTIO_PCI_CAP_*_CFG,
200 * only use 4 because VIRTIO_PCI_CAP_PCI_CFG is not part of this. */
201 virtio_bar_cfg_t aBarCfgs[4];
202 /** The start offset in the PCI configuration space where to find the VIRTIO_PCI_CAP_PCI_CFG
203 * capability for the alternate access method to the registers. */
204 uint8_t u8PciCfgOff;
205 /** The notification offset multiplier. */
206 uint32_t u32NotifyOffMult;
207 /** PCI bus where the device is located. */
208 uint8_t u8Bus;
209 /** Device/Function number. */
210 uint8_t u8DevFn;
211 /** Saved high bits of EAX. */
212 uint16_t saved_eax_hi;
213 /** The current executed command structure. */
214 virtio_scsi_req_hdr_t ScsiReqHdr;
215 virtio_scsi_req_sts_t ScsiReqSts;
216} virtio_t;
217
218/* The VirtIO specific data must fit into 1KB (statically allocated). */
219ct_assert(sizeof(virtio_t) <= 1024);
220
221/** PCI configuration fields. */
222#define PCI_CONFIG_CAP 0x34
223
224#define PCI_CAP_ID_VNDR 0x09
225
226#define VBOX_VIRTIO_NIL_CFG 0xff
227
228#define VIRTIO_PCI_CAP_COMMON_CFG 0x01
229#define VIRTIO_PCI_CAP_NOTIFY_CFG 0x02
230#define VIRTIO_PCI_CAP_ISR_CFG 0x03
231#define VIRTIO_PCI_CAP_DEVICE_CFG 0x04
232#define VIRTIO_PCI_CAP_PCI_CFG 0x05
233
234#define RT_BIT_32(bit) ((uint32_t)(1L << (bit)))
235
236#define VIRTIO_COMMON_REG_DEV_FEAT_SLCT 0x00
237#define VIRTIO_COMMON_REG_DEV_FEAT 0x04
238# define VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT 0x01
239#define VIRTIO_COMMON_REG_DRV_FEAT_SLCT 0x08
240#define VIRTIO_COMMON_REG_DRV_FEAT 0x0c
241#define VIRTIO_COMMON_REG_MSIX_CFG 0x10
242#define VIRTIO_COMMON_REG_NUM_QUEUES 0x12
243#define VIRTIO_COMMON_REG_DEV_STS 0x14
244# define VIRTIO_CMN_REG_DEV_STS_F_RST 0x00
245# define VIRTIO_CMN_REG_DEV_STS_F_ACK 0x01
246# define VIRTIO_CMN_REG_DEV_STS_F_DRV 0x02
247# define VIRTIO_CMN_REG_DEV_STS_F_DRV_OK 0x04
248# define VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK 0x08
249# define VIRTIO_CMN_REG_DEV_STS_F_DEV_RST 0x40
250# define VIRTIO_CMN_REG_DEV_STS_F_FAILED 0x80
251#define VIRTIO_COMMON_REG_CFG_GEN 0x15
252
253#define VIRTIO_COMMON_REG_Q_SELECT 0x16
254#define VIRTIO_COMMON_REG_Q_SIZE 0x18
255#define VIRTIO_COMMON_REG_Q_MSIX_VEC 0x1a
256#define VIRTIO_COMMON_REG_Q_ENABLE 0x1c
257#define VIRTIO_COMMON_REG_Q_NOTIFY_OFF 0x1e
258#define VIRTIO_COMMON_REG_Q_DESC 0x20
259#define VIRTIO_COMMON_REG_Q_DRIVER 0x28
260#define VIRTIO_COMMON_REG_Q_DEVICE 0x30
261
262#define VIRTIO_DEV_CFG_REG_Q_NUM 0x00
263#define VIRTIO_DEV_CFG_REG_SEG_MAX 0x04
264#define VIRTIO_DEV_CFG_REG_SECT_MAX 0x08
265#define VIRTIO_DEV_CFG_REG_CMD_PER_LUN 0x0c
266#define VIRTIO_DEV_CFG_REG_EVT_INFO_SZ 0x10
267#define VIRTIO_DEV_CFG_REG_SENSE_SZ 0x14
268#define VIRTIO_DEV_CFG_REG_CDB_SZ 0x18
269#define VIRTIO_DEV_CFG_REG_MAX_CHANNEL 0x1c
270#define VIRTIO_DEV_CFG_REG_MAX_TGT 0x1e
271#define VIRTIO_DEV_CFG_REG_MAX_LUN 0x20
272
273#define VIRTIO_SCSI_Q_CONTROL 0x00
274#define VIRTIO_SCSI_Q_EVENT 0x01
275#define VIRTIO_SCSI_Q_REQUEST 0x02
276
277#define VIRTIO_SCSI_STS_RESPONSE_OK 0x00
278
279static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint32_t cb)
280{
281 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 4, u8Bar);
282 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 8, offReg);
283 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 12, cb);
284}
285
286static void virtio_reg_common_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
287{
288 virtio_reg_set_bar_offset_length(virtio,
289 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u8Bar,
290 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u32Offset + offReg,
291 cbAcc);
292}
293
294static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
295{
296 virtio_reg_set_bar_offset_length(virtio,
297 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u8Bar,
298 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u32Offset + offReg,
299 cbAcc);
300}
301
302static void virtio_reg_notify_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
303{
304 virtio_reg_set_bar_offset_length(virtio,
305 virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u8Bar,
306 virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u32Offset + offReg,
307 cbAcc);
308}
309
310static void virtio_reg_isr_prepare(virtio_t __far *virtio, uint32_t cbAcc)
311{
312 virtio_reg_set_bar_offset_length(virtio,
313 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u8Bar,
314 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u32Offset,
315 cbAcc);
316}
317
318static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg)
319{
320 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t));
321 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
322}
323
324static void virtio_reg_common_write_u8(virtio_t __far *virtio, uint16_t offReg, uint8_t u8Val)
325{
326 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t));
327 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u8Val);
328}
329
330static uint16_t virtio_reg_common_read_u16(virtio_t __far *virtio, uint16_t offReg)
331{
332 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t));
333 return pci_read_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
334}
335
336static void virtio_reg_common_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val)
337{
338 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t));
339 pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val);
340}
341
342static void virtio_reg_common_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val)
343{
344 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint32_t));
345 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val);
346}
347
348static uint32_t virtio_reg_dev_cfg_read_u32(virtio_t __far *virtio, uint16_t offReg)
349{
350 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t));
351 return pci_read_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
352}
353
354static void virtio_reg_dev_cfg_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val)
355{
356 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t));
357 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val);
358}
359
360static void virtio_reg_notify_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val)
361{
362 virtio_reg_notify_access_prepare(virtio, offReg, sizeof(uint16_t));
363 pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val);
364}
365
366static uint8_t virtio_reg_isr_read_u8(virtio_t __far *virtio)
367{
368 virtio_reg_isr_prepare(virtio, sizeof(uint8_t));
369 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
370}
371
372/**
373 * Converts a segment:offset pair into a 32bit physical address.
374 */
375static uint32_t virtio_addr_to_phys(void __far *ptr)
376{
377 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
378}
379
380int virtio_scsi_cmd_data_out(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
381 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
382{
383 virtio_t __far *virtio = (virtio_t __far *)pvHba;
384 uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
385
386 _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
387 _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts));
388
389 virtio->ScsiReqHdr.au8Lun[0] = 0x1;
390 virtio->ScsiReqHdr.au8Lun[1] = idTgt;
391 virtio->ScsiReqHdr.au8Lun[2] = 0;
392 virtio->ScsiReqHdr.au8Lun[3] = 0;
393 _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB);
394
395 /* Fill in the descriptors. */
396 virtio->Queue.aDescTbl[0].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqHdr);
397 virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0;
398 virtio->Queue.aDescTbl[0].cbBuf = sizeof(virtio->ScsiReqHdr);
399 virtio->Queue.aDescTbl[0].fFlags = VIRTIO_Q_DESC_F_NEXT;
400 virtio->Queue.aDescTbl[0].idxNext = 1;
401
402 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(buffer);
403 virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0;
404 virtio->Queue.aDescTbl[1].cbBuf = length;
405 virtio->Queue.aDescTbl[1].fFlags = VIRTIO_Q_DESC_F_NEXT;
406 virtio->Queue.aDescTbl[1].idxNext = 2;
407
408 virtio->Queue.aDescTbl[2].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts);
409 virtio->Queue.aDescTbl[2].GCPhysBufHigh = 0;
410 virtio->Queue.aDescTbl[2].cbBuf = sizeof(virtio->ScsiReqSts);
411 virtio->Queue.aDescTbl[2].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
412 virtio->Queue.aDescTbl[2].idxNext = 0;
413
414 /* Put it into the queue. */
415 virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree % VIRTIO_SCSI_RING_ELEM] = 0;
416 virtio->Queue.AvailRing.idxNextFree++;
417
418 /* Notify the device about the new command. */
419 DBG_VIRTIO("VirtIO: Submitting new request, Queue.offNotify=0x%x\n", virtio->Queue.offNotify);
420 virtio_reg_notify_write_u16(virtio, virtio->Queue.offNotify, VIRTIO_SCSI_Q_REQUEST);
421
422 /* Wait for it to complete. */
423 while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed);
424
425 DBG_VIRTIO("VirtIO: Request complete u8Response=%u\n", virtio->ScsiReqSts.u8Response);
426
427 /* Read ISR register to de-assert the interrupt, don't need to do anything with it. */
428 virtio_reg_isr_read_u8(virtio);
429
430 if (virtio->ScsiReqSts.u8Response != VIRTIO_SCSI_STS_RESPONSE_OK)
431 return 4;
432
433 return 0;
434}
435
436int virtio_scsi_cmd_data_in(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
437 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length, uint16_t skip_a,
438 uint16_t skip_b)
439{
440 virtio_t __far *virtio = (virtio_t __far *)pvHba;
441 uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
442 uint8_t idxDesc = 0;
443
444 _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
445 _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts));
446
447 virtio->ScsiReqHdr.au8Lun[0] = 0x1;
448 virtio->ScsiReqHdr.au8Lun[1] = idTgt;
449 virtio->ScsiReqHdr.au8Lun[2] = 0;
450 virtio->ScsiReqHdr.au8Lun[3] = 0;
451 _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB);
452
453 /* Fill in the descriptors. */
454 virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqHdr);
455 virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
456 virtio->Queue.aDescTbl[idxDesc].cbBuf = sizeof(virtio->ScsiReqHdr);
457 virtio->Queue.aDescTbl[idxDesc].fFlags = VIRTIO_Q_DESC_F_NEXT;
458 virtio->Queue.aDescTbl[idxDesc].idxNext = 1;
459 idxDesc++;
460
461 /* No data out buffer, the status comes right after this in the next descriptor. */
462 virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts);
463 virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
464 virtio->Queue.aDescTbl[idxDesc].cbBuf = sizeof(virtio->ScsiReqSts);
465 virtio->Queue.aDescTbl[idxDesc].fFlags = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
466 virtio->Queue.aDescTbl[idxDesc].idxNext = 2;
467 idxDesc++;
468
469 /* Prepend a sinkhole if data is skipped upfront. */
470 if (skip_b)
471 {
472 virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow = 0; /* See ahci.c:sink_buf_phys */
473 virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
474 virtio->Queue.aDescTbl[idxDesc].cbBuf = skip_b;
475 virtio->Queue.aDescTbl[idxDesc].fFlags = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
476 virtio->Queue.aDescTbl[idxDesc].idxNext = idxDesc + 1;
477 idxDesc++;
478 }
479
480 virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow = virtio_addr_to_phys(buffer);
481 virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
482 virtio->Queue.aDescTbl[idxDesc].cbBuf = length;
483 virtio->Queue.aDescTbl[idxDesc].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
484 virtio->Queue.aDescTbl[idxDesc].idxNext = skip_a ? idxDesc + 1 : 0;
485 idxDesc++;
486
487 /* Append a sinkhole if data is skipped at the end. */
488 if (skip_a)
489 {
490 virtio->Queue.aDescTbl[idxDesc - 1].fFlags |= VIRTIO_Q_DESC_F_NEXT;
491 virtio->Queue.aDescTbl[idxDesc - 1].idxNext = idxDesc;
492
493 virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow = 0; /* See ahci.c:sink_buf_phys */
494 virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
495 virtio->Queue.aDescTbl[idxDesc].cbBuf = skip_a;
496 virtio->Queue.aDescTbl[idxDesc].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
497 virtio->Queue.aDescTbl[idxDesc].idxNext = 0;
498 }
499
500 /* Put it into the queue, the index is supposed to be free-running and clipped to the ring size
501 * internally. The free running index is what the driver sees. */
502 virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree % VIRTIO_SCSI_RING_ELEM] = 0;
503 virtio->Queue.AvailRing.idxNextFree++;
504
505 /* Notify the device about the new command. */
506 DBG_VIRTIO("VirtIO: Submitting new request, Queue.offNotify=0x%x\n", virtio->Queue.offNotify);
507 virtio_reg_notify_write_u16(virtio, virtio->Queue.offNotify, VIRTIO_SCSI_Q_REQUEST);
508
509 /* Wait for it to complete. */
510 while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed);
511
512 DBG_VIRTIO("VirtIO: Request complete u8Response=%u\n", virtio->ScsiReqSts.u8Response);
513
514 /* Read ISR register to de-assert the interrupt, don't need to do anything with it. */
515 virtio_reg_isr_read_u8(virtio);
516
517 if (virtio->ScsiReqSts.u8Response != VIRTIO_SCSI_STS_RESPONSE_OK)
518 return 4;
519
520 return 0;
521}
522
523/**
524 * Initializes the VirtIO SCSI HBA and detects attached devices.
525 */
526static int virtio_scsi_hba_init(virtio_t __far *virtio, uint8_t u8Bus, uint8_t u8DevFn, uint8_t u8PciCapOffVirtIo)
527{
528 uint8_t u8PciCapOff;
529 uint8_t u8DevStat;
530
531 virtio->u8Bus = u8Bus;
532 virtio->u8DevFn = u8DevFn;
533
534 /*
535 * Go through the config space again, read the complete config capabilities
536 * this time and fill in the data.
537 */
538 u8PciCapOff = u8PciCapOffVirtIo;
539 while (u8PciCapOff != 0)
540 {
541 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
542 uint8_t cbPciCap = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 2); /* Capability length. */
543
544 DBG_VIRTIO("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
545
546 if ( u8PciCapId == PCI_CAP_ID_VNDR
547 && cbPciCap >= sizeof(virtio_pci_cap_t))
548 {
549 /* Read in the config type and see what we got. */
550 uint8_t u8PciVirtioCfg = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 3);
551
552 DBG_VIRTIO("VirtIO: CFG ID 0x%x\n", u8PciVirtioCfg);
553 switch (u8PciVirtioCfg)
554 {
555 case VIRTIO_PCI_CAP_COMMON_CFG:
556 case VIRTIO_PCI_CAP_NOTIFY_CFG:
557 case VIRTIO_PCI_CAP_ISR_CFG:
558 case VIRTIO_PCI_CAP_DEVICE_CFG:
559 {
560 virtio_bar_cfg_t __far *pBarCfg = &virtio->aBarCfgs[u8PciVirtioCfg - 1];
561
562 pBarCfg->u8Bar = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 4);
563 pBarCfg->u32Offset = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 8);
564 pBarCfg->u32Length = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 12);
565 if (u8PciVirtioCfg == VIRTIO_PCI_CAP_NOTIFY_CFG)
566 {
567 virtio->u32NotifyOffMult = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 16);
568 DBG_VIRTIO("VirtIO: u32NotifyOffMult 0x%x\n", virtio->u32NotifyOffMult);
569 }
570 break;
571 }
572 case VIRTIO_PCI_CAP_PCI_CFG:
573 virtio->u8PciCfgOff = u8PciCapOff;
574 DBG_VIRTIO("VirtIO PCI CAP window offset: %x\n", u8PciCapOff);
575 break;
576 default:
577 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", u8PciVirtioCfg);
578 break;
579 }
580 }
581
582 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
583 }
584
585 /* Reset the device. */
586 u8DevStat = VIRTIO_CMN_REG_DEV_STS_F_RST;
587 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
588 /* Acknowledge presence. */
589 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_ACK;
590 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
591 /* Our driver knows how to operate the device. */
592 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV;
593 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
594
595#if 0
596 /* Read the feature bits and only program the VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT bit if available. */
597 fFeatures = virtio_reg_common_read_u32(virtio, VIRTIO_COMMON_REG_DEV_FEAT);
598 fFeatures &= VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT;
599#endif
600
601 /* Check that the device is sane. */
602 if ( virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_Q_NUM) < 1
603 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ) < 16
604 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ) < 32
605 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SECT_MAX) < 1)
606 {
607 DBG_VIRTIO("VirtIO-SCSI: Invalid SCSI device configuration, ignoring device\n");
608 return 1;
609 }
610
611 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_DRV_FEAT, VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT);
612
613 /* Set the features OK bit. */
614 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK;
615 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
616
617 /* Read again and check the the okay bit is still set. */
618 if (!(virtio_reg_common_read_u8(virtio, VIRTIO_COMMON_REG_DEV_STS) & VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK))
619 {
620 DBG_VIRTIO("VirtIO-SCSI: Device doesn't accept our feature set, ignoring device\n");
621 return 1;
622 }
623
624 /* Disable event and control queue. */
625 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_CONTROL);
626 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0);
627 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0);
628
629 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_EVENT);
630 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0);
631 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0);
632
633 /* Setup the request queue. */
634 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_REQUEST);
635 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, VIRTIO_SCSI_RING_ELEM);
636 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 1);
637
638 /* Set queue area addresses (only low part, leave high part 0). */
639 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC, virtio_addr_to_phys(&virtio->Queue.aDescTbl[0]));
640 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC + 4, 0);
641
642 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER, virtio_addr_to_phys(&virtio->Queue.AvailRing));
643 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER + 4, 0);
644
645 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE, virtio_addr_to_phys(&virtio->Queue.UsedRing));
646 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE + 4, 0);
647
648 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ, VIRTIO_SCSI_CDB_SZ);
649 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ, VIRTIO_SCSI_SENSE_SZ);
650
651 DBG_VIRTIO("VirtIO: Q notify offset 0x%x\n", virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF));
652 virtio->Queue.offNotify = virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF) * virtio->u32NotifyOffMult;
653
654 /* Bring the device into operational mode. */
655 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV_OK;
656 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
657
658 return 0;
659}
660
661/**
662 * Init the VirtIO SCSI driver and detect attached disks.
663 */
664int virtio_scsi_init(void __far *pvHba, uint8_t u8Bus, uint8_t u8DevFn)
665{
666 virtio_t __far *virtio = (virtio_t __far *)pvHba;
667 uint8_t u8PciCapOff;
668 uint8_t u8PciCapOffVirtIo = VBOX_VIRTIO_NIL_CFG;
669 uint8_t u8PciCapVirtioSeen = 0;
670
671 /* Examine the capability list and search for the VirtIO specific capabilities. */
672 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, PCI_CONFIG_CAP);
673
674 while (u8PciCapOff != 0)
675 {
676 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
677 uint8_t cbPciCap = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 2); /* Capability length. */
678
679 DBG_VIRTIO("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
680
681 if ( u8PciCapId == PCI_CAP_ID_VNDR
682 && cbPciCap >= sizeof(virtio_pci_cap_t))
683 {
684 /* Read in the config type and see what we got. */
685 uint8_t u8PciVirtioCfg = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 3);
686
687 if (u8PciCapOffVirtIo == VBOX_VIRTIO_NIL_CFG)
688 u8PciCapOffVirtIo = u8PciCapOff;
689
690 DBG_VIRTIO("VirtIO: CFG ID 0x%x\n", u8PciVirtioCfg);
691 switch (u8PciVirtioCfg)
692 {
693 case VIRTIO_PCI_CAP_COMMON_CFG:
694 case VIRTIO_PCI_CAP_NOTIFY_CFG:
695 case VIRTIO_PCI_CAP_ISR_CFG:
696 case VIRTIO_PCI_CAP_DEVICE_CFG:
697 case VIRTIO_PCI_CAP_PCI_CFG:
698 u8PciCapVirtioSeen |= 1 << (u8PciVirtioCfg - 1);
699 break;
700 default:
701 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", u8PciVirtioCfg);
702 }
703 }
704
705 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
706 }
707
708 /* Initialize the controller if all required PCI capabilities where found. */
709 if ( u8PciCapOffVirtIo != VBOX_VIRTIO_NIL_CFG
710 && u8PciCapVirtioSeen == 0x1f)
711 {
712 DBG_VIRTIO("VirtIO SCSI HBA with all required capabilities at 0x%x\n", u8PciCapOffVirtIo);
713
714 /* Enable PCI memory, I/O, bus mastering access in command register. */
715 pci_write_config_word(u8Bus, u8DevFn, 4, 0x7);
716
717 return virtio_scsi_hba_init(virtio, u8Bus, u8DevFn, u8PciCapOffVirtIo);
718 }
719 else
720 DBG_VIRTIO("VirtIO SCSI HBA with no usable PCI config access!\n");
721
722 return 1;
723}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette