VirtualBox

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

Last change on this file since 94155 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: virtio.c 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtIO-SCSI host adapter driver to boot from disks.
4 */
5
6/*
7 * Copyright (C) 2019-2022 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 3 max. */
106 virtio_q_desc_t aDescTbl[3];
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 /** The current executed command structure. */
212 virtio_scsi_req_hdr_t ScsiReqHdr;
213 virtio_scsi_req_sts_t ScsiReqSts;
214} virtio_t;
215
216/* The VirtIO specific data must fit into 1KB (statically allocated). */
217ct_assert(sizeof(virtio_t) <= 1024);
218
219/** PCI configuration fields. */
220#define PCI_CONFIG_CAP 0x34
221
222#define PCI_CAP_ID_VNDR 0x09
223
224#define VBOX_VIRTIO_NIL_CFG 0xff
225
226#define VIRTIO_PCI_CAP_COMMON_CFG 0x01
227#define VIRTIO_PCI_CAP_NOTIFY_CFG 0x02
228#define VIRTIO_PCI_CAP_ISR_CFG 0x03
229#define VIRTIO_PCI_CAP_DEVICE_CFG 0x04
230#define VIRTIO_PCI_CAP_PCI_CFG 0x05
231
232#define RT_BIT_32(bit) ((uint32_t)(1L << (bit)))
233
234#define VIRTIO_COMMON_REG_DEV_FEAT_SLCT 0x00
235#define VIRTIO_COMMON_REG_DEV_FEAT 0x04
236# define VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT 0x01
237#define VIRTIO_COMMON_REG_DRV_FEAT_SLCT 0x08
238#define VIRTIO_COMMON_REG_DRV_FEAT 0x0c
239#define VIRTIO_COMMON_REG_MSIX_CFG 0x10
240#define VIRTIO_COMMON_REG_NUM_QUEUES 0x12
241#define VIRTIO_COMMON_REG_DEV_STS 0x14
242# define VIRTIO_CMN_REG_DEV_STS_F_RST 0x00
243# define VIRTIO_CMN_REG_DEV_STS_F_ACK 0x01
244# define VIRTIO_CMN_REG_DEV_STS_F_DRV 0x02
245# define VIRTIO_CMN_REG_DEV_STS_F_DRV_OK 0x04
246# define VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK 0x08
247# define VIRTIO_CMN_REG_DEV_STS_F_DEV_RST 0x40
248# define VIRTIO_CMN_REG_DEV_STS_F_FAILED 0x80
249#define VIRTIO_COMMON_REG_CFG_GEN 0x15
250
251#define VIRTIO_COMMON_REG_Q_SELECT 0x16
252#define VIRTIO_COMMON_REG_Q_SIZE 0x18
253#define VIRTIO_COMMON_REG_Q_MSIX_VEC 0x1a
254#define VIRTIO_COMMON_REG_Q_ENABLE 0x1c
255#define VIRTIO_COMMON_REG_Q_NOTIFY_OFF 0x1e
256#define VIRTIO_COMMON_REG_Q_DESC 0x20
257#define VIRTIO_COMMON_REG_Q_DRIVER 0x28
258#define VIRTIO_COMMON_REG_Q_DEVICE 0x30
259
260#define VIRTIO_DEV_CFG_REG_Q_NUM 0x00
261#define VIRTIO_DEV_CFG_REG_SEG_MAX 0x04
262#define VIRTIO_DEV_CFG_REG_SECT_MAX 0x08
263#define VIRTIO_DEV_CFG_REG_CMD_PER_LUN 0x0c
264#define VIRTIO_DEV_CFG_REG_EVT_INFO_SZ 0x10
265#define VIRTIO_DEV_CFG_REG_SENSE_SZ 0x14
266#define VIRTIO_DEV_CFG_REG_CDB_SZ 0x18
267#define VIRTIO_DEV_CFG_REG_MAX_CHANNEL 0x1c
268#define VIRTIO_DEV_CFG_REG_MAX_TGT 0x1e
269#define VIRTIO_DEV_CFG_REG_MAX_LUN 0x20
270
271#define VIRTIO_SCSI_Q_CONTROL 0x00
272#define VIRTIO_SCSI_Q_EVENT 0x01
273#define VIRTIO_SCSI_Q_REQUEST 0x02
274
275#define VIRTIO_SCSI_STS_RESPONSE_OK 0x00
276
277static void virtio_reg_set_bar_offset_length(virtio_t __far *virtio, uint8_t u8Bar, uint32_t offReg, uint32_t cb)
278{
279 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 4, u8Bar);
280 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 8, offReg);
281 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + 12, cb);
282}
283
284static void virtio_reg_common_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
285{
286 virtio_reg_set_bar_offset_length(virtio,
287 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u8Bar,
288 virtio->aBarCfgs[VIRTIO_PCI_CAP_COMMON_CFG - 1].u32Offset + offReg,
289 cbAcc);
290}
291
292static void virtio_reg_dev_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
293{
294 virtio_reg_set_bar_offset_length(virtio,
295 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u8Bar,
296 virtio->aBarCfgs[VIRTIO_PCI_CAP_DEVICE_CFG - 1].u32Offset + offReg,
297 cbAcc);
298}
299
300static void virtio_reg_notify_access_prepare(virtio_t __far *virtio, uint16_t offReg, uint32_t cbAcc)
301{
302 virtio_reg_set_bar_offset_length(virtio,
303 virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u8Bar,
304 virtio->aBarCfgs[VIRTIO_PCI_CAP_NOTIFY_CFG - 1].u32Offset + offReg,
305 cbAcc);
306}
307
308static void virtio_reg_isr_prepare(virtio_t __far *virtio, uint32_t cbAcc)
309{
310 virtio_reg_set_bar_offset_length(virtio,
311 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u8Bar,
312 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u32Offset,
313 cbAcc);
314}
315
316static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg)
317{
318 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t));
319 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
320}
321
322static void virtio_reg_common_write_u8(virtio_t __far *virtio, uint16_t offReg, uint8_t u8Val)
323{
324 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint8_t));
325 pci_write_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u8Val);
326}
327
328static uint16_t virtio_reg_common_read_u16(virtio_t __far *virtio, uint16_t offReg)
329{
330 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t));
331 return pci_read_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
332}
333
334static void virtio_reg_common_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val)
335{
336 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint16_t));
337 pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val);
338}
339
340static void virtio_reg_common_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val)
341{
342 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint32_t));
343 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val);
344}
345
346static uint32_t virtio_reg_dev_cfg_read_u32(virtio_t __far *virtio, uint16_t offReg)
347{
348 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t));
349 return pci_read_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
350}
351
352static void virtio_reg_dev_cfg_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val)
353{
354 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint32_t));
355 pci_write_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u32Val);
356}
357
358static void virtio_reg_notify_write_u16(virtio_t __far *virtio, uint16_t offReg, uint16_t u16Val)
359{
360 virtio_reg_notify_access_prepare(virtio, offReg, sizeof(uint16_t));
361 pci_write_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t), u16Val);
362}
363
364static uint8_t virtio_reg_isr_read_u8(virtio_t __far *virtio)
365{
366 virtio_reg_isr_prepare(virtio, sizeof(uint8_t));
367 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));
368}
369
370/**
371 * Converts a segment:offset pair into a 32bit physical address.
372 */
373static uint32_t virtio_addr_to_phys(void __far *ptr)
374{
375 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
376}
377
378int virtio_scsi_cmd_data_out(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
379 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
380{
381 virtio_t __far *virtio = (virtio_t __far *)pvHba;
382 uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
383
384 _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
385 _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts));
386
387 virtio->ScsiReqHdr.au8Lun[0] = 0x1;
388 virtio->ScsiReqHdr.au8Lun[1] = idTgt;
389 virtio->ScsiReqHdr.au8Lun[2] = 0;
390 virtio->ScsiReqHdr.au8Lun[3] = 0;
391 _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB);
392
393 /* Fill in the descriptors. */
394 virtio->Queue.aDescTbl[0].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqHdr);
395 virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0;
396 virtio->Queue.aDescTbl[0].cbBuf = sizeof(virtio->ScsiReqHdr);
397 virtio->Queue.aDescTbl[0].fFlags = VIRTIO_Q_DESC_F_NEXT;
398 virtio->Queue.aDescTbl[0].idxNext = 1;
399
400 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(buffer);
401 virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0;
402 virtio->Queue.aDescTbl[1].cbBuf = length;
403 virtio->Queue.aDescTbl[1].fFlags = VIRTIO_Q_DESC_F_NEXT;
404 virtio->Queue.aDescTbl[1].idxNext = 2;
405
406 virtio->Queue.aDescTbl[2].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts);
407 virtio->Queue.aDescTbl[2].GCPhysBufHigh = 0;
408 virtio->Queue.aDescTbl[2].cbBuf = sizeof(virtio->ScsiReqSts);
409 virtio->Queue.aDescTbl[2].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
410 virtio->Queue.aDescTbl[2].idxNext = 0;
411
412 /* Put it into the queue. */
413 virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree % VIRTIO_SCSI_RING_ELEM] = 0;
414 virtio->Queue.AvailRing.idxNextFree++;
415
416 /* Notify the device about the new command. */
417 DBG_VIRTIO("VirtIO: Submitting new request, Queue.offNotify=0x%x\n", virtio->Queue.offNotify);
418 virtio_reg_notify_write_u16(virtio, virtio->Queue.offNotify, VIRTIO_SCSI_Q_REQUEST);
419
420 /* Wait for it to complete. */
421 while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed);
422
423 DBG_VIRTIO("VirtIO: Request complete u8Response=%u\n", virtio->ScsiReqSts.u8Response);
424
425 /* Read ISR register to de-assert the interrupt, don't need to do anything with it. */
426 virtio_reg_isr_read_u8(virtio);
427
428 if (virtio->ScsiReqSts.u8Response != VIRTIO_SCSI_STS_RESPONSE_OK)
429 return 4;
430
431 return 0;
432}
433
434int virtio_scsi_cmd_data_in(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
435 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
436{
437 virtio_t __far *virtio = (virtio_t __far *)pvHba;
438 uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
439
440 _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
441 _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts));
442
443 virtio->ScsiReqHdr.au8Lun[0] = 0x1;
444 virtio->ScsiReqHdr.au8Lun[1] = idTgt;
445 virtio->ScsiReqHdr.au8Lun[2] = 0;
446 virtio->ScsiReqHdr.au8Lun[3] = 0;
447 _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB);
448
449 /* Fill in the descriptors. */
450 virtio->Queue.aDescTbl[0].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqHdr);
451 virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0;
452 virtio->Queue.aDescTbl[0].cbBuf = sizeof(virtio->ScsiReqHdr);
453 virtio->Queue.aDescTbl[0].fFlags = VIRTIO_Q_DESC_F_NEXT;
454 virtio->Queue.aDescTbl[0].idxNext = 1;
455
456 /* No data out buffer, the status comes right after this in the next descriptor. */
457 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts);
458 virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0;
459 virtio->Queue.aDescTbl[1].cbBuf = sizeof(virtio->ScsiReqSts);
460 virtio->Queue.aDescTbl[1].fFlags = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
461 virtio->Queue.aDescTbl[1].idxNext = 2;
462
463 virtio->Queue.aDescTbl[2].GCPhysBufLow = virtio_addr_to_phys(buffer);
464 virtio->Queue.aDescTbl[2].GCPhysBufHigh = 0;
465 virtio->Queue.aDescTbl[2].cbBuf = length;
466 virtio->Queue.aDescTbl[2].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
467 virtio->Queue.aDescTbl[2].idxNext = 0;
468
469 /* Put it into the queue, the index is supposed to be free-running and clipped to the ring size
470 * internally. The free running index is what the driver sees. */
471 virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree % VIRTIO_SCSI_RING_ELEM] = 0;
472 virtio->Queue.AvailRing.idxNextFree++;
473
474 /* Notify the device about the new command. */
475 DBG_VIRTIO("VirtIO: Submitting new request, Queue.offNotify=0x%x\n", virtio->Queue.offNotify);
476 virtio_reg_notify_write_u16(virtio, virtio->Queue.offNotify, VIRTIO_SCSI_Q_REQUEST);
477
478 /* Wait for it to complete. */
479 while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed);
480
481 DBG_VIRTIO("VirtIO: Request complete u8Response=%u\n", virtio->ScsiReqSts.u8Response);
482
483 /* Read ISR register to de-assert the interrupt, don't need to do anything with it. */
484 virtio_reg_isr_read_u8(virtio);
485
486 if (virtio->ScsiReqSts.u8Response != VIRTIO_SCSI_STS_RESPONSE_OK)
487 return 4;
488
489 return 0;
490}
491
492/**
493 * Initializes the VirtIO SCSI HBA and detects attached devices.
494 */
495static int virtio_scsi_hba_init(virtio_t __far *virtio, uint8_t u8Bus, uint8_t u8DevFn, uint8_t u8PciCapOffVirtIo)
496{
497 uint8_t u8PciCapOff;
498 uint8_t u8DevStat;
499
500 virtio->u8Bus = u8Bus;
501 virtio->u8DevFn = u8DevFn;
502
503 /*
504 * Go through the config space again, read the complete config capabilities
505 * this time and fill in the data.
506 */
507 u8PciCapOff = u8PciCapOffVirtIo;
508 while (u8PciCapOff != 0)
509 {
510 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
511 uint8_t cbPciCap = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 2); /* Capability length. */
512
513 DBG_VIRTIO("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
514
515 if ( u8PciCapId == PCI_CAP_ID_VNDR
516 && cbPciCap >= sizeof(virtio_pci_cap_t))
517 {
518 /* Read in the config type and see what we got. */
519 uint8_t u8PciVirtioCfg = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 3);
520
521 DBG_VIRTIO("VirtIO: CFG ID 0x%x\n", u8PciVirtioCfg);
522 switch (u8PciVirtioCfg)
523 {
524 case VIRTIO_PCI_CAP_COMMON_CFG:
525 case VIRTIO_PCI_CAP_NOTIFY_CFG:
526 case VIRTIO_PCI_CAP_ISR_CFG:
527 case VIRTIO_PCI_CAP_DEVICE_CFG:
528 {
529 virtio_bar_cfg_t __far *pBarCfg = &virtio->aBarCfgs[u8PciVirtioCfg - 1];
530
531 pBarCfg->u8Bar = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 4);
532 pBarCfg->u32Offset = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 8);
533 pBarCfg->u32Length = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 12);
534 if (u8PciVirtioCfg == VIRTIO_PCI_CAP_NOTIFY_CFG)
535 {
536 virtio->u32NotifyOffMult = pci_read_config_dword(u8Bus, u8DevFn, u8PciCapOff + 16);
537 DBG_VIRTIO("VirtIO: u32NotifyOffMult 0x%x\n", virtio->u32NotifyOffMult);
538 }
539 break;
540 }
541 case VIRTIO_PCI_CAP_PCI_CFG:
542 virtio->u8PciCfgOff = u8PciCapOff;
543 DBG_VIRTIO("VirtIO PCI CAP window offset: %x\n", u8PciCapOff);
544 break;
545 default:
546 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", u8PciVirtioCfg);
547 break;
548 }
549 }
550
551 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
552 }
553
554 /* Reset the device. */
555 u8DevStat = VIRTIO_CMN_REG_DEV_STS_F_RST;
556 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
557 /* Acknowledge presence. */
558 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_ACK;
559 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
560 /* Our driver knows how to operate the device. */
561 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV;
562 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
563
564#if 0
565 /* Read the feature bits and only program the VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT bit if available. */
566 fFeatures = virtio_reg_common_read_u32(virtio, VIRTIO_COMMON_REG_DEV_FEAT);
567 fFeatures &= VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT;
568#endif
569
570 /* Check that the device is sane. */
571 if ( virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_Q_NUM) < 1
572 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ) < 16
573 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ) < 32
574 || virtio_reg_dev_cfg_read_u32(virtio, VIRTIO_DEV_CFG_REG_SECT_MAX) < 1)
575 {
576 DBG_VIRTIO("VirtIO-SCSI: Invalid SCSI device configuration, ignoring device\n");
577 return 1;
578 }
579
580 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_DRV_FEAT, VIRTIO_CMN_REG_DEV_FEAT_SCSI_INOUT);
581
582 /* Set the features OK bit. */
583 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK;
584 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
585
586 /* Read again and check the the okay bit is still set. */
587 if (!(virtio_reg_common_read_u8(virtio, VIRTIO_COMMON_REG_DEV_STS) & VIRTIO_CMN_REG_DEV_STS_F_FEAT_OK))
588 {
589 DBG_VIRTIO("VirtIO-SCSI: Device doesn't accept our feature set, ignoring device\n");
590 return 1;
591 }
592
593 /* Disable event and control queue. */
594 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_CONTROL);
595 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0);
596 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0);
597
598 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_EVENT);
599 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, 0);
600 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 0);
601
602 /* Setup the request queue. */
603 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SELECT, VIRTIO_SCSI_Q_REQUEST);
604 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_SIZE, VIRTIO_SCSI_RING_ELEM);
605 virtio_reg_common_write_u16(virtio, VIRTIO_COMMON_REG_Q_ENABLE, 1);
606
607 /* Set queue area addresses (only low part, leave high part 0). */
608 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC, virtio_addr_to_phys(&virtio->Queue.aDescTbl[0]));
609 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DESC + 4, 0);
610
611 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER, virtio_addr_to_phys(&virtio->Queue.AvailRing));
612 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DRIVER + 4, 0);
613
614 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE, virtio_addr_to_phys(&virtio->Queue.UsedRing));
615 virtio_reg_common_write_u32(virtio, VIRTIO_COMMON_REG_Q_DEVICE + 4, 0);
616
617 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_CDB_SZ, VIRTIO_SCSI_CDB_SZ);
618 virtio_reg_dev_cfg_write_u32(virtio, VIRTIO_DEV_CFG_REG_SENSE_SZ, VIRTIO_SCSI_SENSE_SZ);
619
620 DBG_VIRTIO("VirtIO: Q notify offset 0x%x\n", virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF));
621 virtio->Queue.offNotify = virtio_reg_common_read_u16(virtio, VIRTIO_COMMON_REG_Q_NOTIFY_OFF) * virtio->u32NotifyOffMult;
622
623 /* Bring the device into operational mode. */
624 u8DevStat |= VIRTIO_CMN_REG_DEV_STS_F_DRV_OK;
625 virtio_reg_common_write_u8(virtio, VIRTIO_COMMON_REG_DEV_STS, u8DevStat);
626
627 return 0;
628}
629
630/**
631 * Init the VirtIO SCSI driver and detect attached disks.
632 */
633int virtio_scsi_init(void __far *pvHba, uint8_t u8Bus, uint8_t u8DevFn)
634{
635 virtio_t __far *virtio = (virtio_t __far *)pvHba;
636 uint8_t u8PciCapOff;
637 uint8_t u8PciCapOffVirtIo = VBOX_VIRTIO_NIL_CFG;
638 uint8_t u8PciCapVirtioSeen = 0;
639
640 /* Examine the capability list and search for the VirtIO specific capabilities. */
641 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, PCI_CONFIG_CAP);
642
643 while (u8PciCapOff != 0)
644 {
645 uint8_t u8PciCapId = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
646 uint8_t cbPciCap = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 2); /* Capability length. */
647
648 DBG_VIRTIO("Capability ID 0x%x at 0x%x\n", u8PciCapId, u8PciCapOff);
649
650 if ( u8PciCapId == PCI_CAP_ID_VNDR
651 && cbPciCap >= sizeof(virtio_pci_cap_t))
652 {
653 /* Read in the config type and see what we got. */
654 uint8_t u8PciVirtioCfg = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 3);
655
656 if (u8PciCapOffVirtIo == VBOX_VIRTIO_NIL_CFG)
657 u8PciCapOffVirtIo = u8PciCapOff;
658
659 DBG_VIRTIO("VirtIO: CFG ID 0x%x\n", u8PciVirtioCfg);
660 switch (u8PciVirtioCfg)
661 {
662 case VIRTIO_PCI_CAP_COMMON_CFG:
663 case VIRTIO_PCI_CAP_NOTIFY_CFG:
664 case VIRTIO_PCI_CAP_ISR_CFG:
665 case VIRTIO_PCI_CAP_DEVICE_CFG:
666 case VIRTIO_PCI_CAP_PCI_CFG:
667 u8PciCapVirtioSeen |= 1 << (u8PciVirtioCfg - 1);
668 break;
669 default:
670 DBG_VIRTIO("VirtIO SCSI HBA with unknown PCI capability type 0x%x\n", u8PciVirtioCfg);
671 }
672 }
673
674 u8PciCapOff = pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
675 }
676
677 /* Initialize the controller if all required PCI capabilities where found. */
678 if ( u8PciCapOffVirtIo != VBOX_VIRTIO_NIL_CFG
679 && u8PciCapVirtioSeen == 0x1f)
680 {
681 DBG_VIRTIO("VirtIO SCSI HBA with all required capabilities at 0x%x\n", u8PciCapOffVirtIo);
682
683 /* Enable PCI memory, I/O, bus mastering access in command register. */
684 pci_write_config_word(u8Bus, u8DevFn, 4, 0x7);
685 return virtio_scsi_hba_init(virtio, u8Bus, u8DevFn, u8PciCapOffVirtIo);
686 }
687 else
688 DBG_VIRTIO("VirtIO SCSI HBA with no usable PCI config access!\n");
689
690 return 1;
691}
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