VirtualBox

Changeset 82180 in vbox for trunk/src


Ignore:
Timestamp:
Nov 25, 2019 2:53:03 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
134990
Message:

PC/BIOS: Add support for CD/DVD drives attached to a Virtio SCSI controller, bugref:9440

Location:
trunk/src/VBox/Devices/PC/BIOS
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/BIOS/ebda.h

    r82163 r82180  
    261261extern uint16_t ata_cmd_packet(uint16_t device, uint8_t cmdlen, char __far *cmdbuf,
    262262                               uint16_t header, uint32_t length, uint8_t inout, char __far *buffer);
     263extern uint16_t virtio_scsi_cmd_packet(uint16_t device, uint8_t cmdlen, char __far *cmdbuf,
     264                                       uint16_t skip_b, uint32_t length, uint8_t inout, char __far *buffer);
    263265
    264266extern uint16_t ata_soft_reset(uint16_t device);
  • trunk/src/VBox/Devices/PC/BIOS/eltorito.c

    r76553 r82180  
    121121    [DSK_TYPE_SCSI]   = { scsi_cmd_packet },
    122122#endif
     123#ifdef VBOX_WITH_VIRTIO_SCSI
     124    [DSK_TYPE_VIRTIO_SCSI] = { virtio_scsi_cmd_packet },
     125#endif
    123126};
    124127
  • trunk/src/VBox/Devices/PC/BIOS/virtio.c

    r82176 r82180  
    105105typedef struct
    106106{
    107     /** The descriptor table, using 4 max. */
    108     virtio_q_desc_t      aDescTbl[4];
     107    /** The descriptor table, using 5 max. */
     108    virtio_q_desc_t      aDescTbl[5];
    109109    /** Available ring. */
    110110    virtio_q_avail_t     AvailRing;
     
    489489
    490490int virtio_scsi_cmd_data_in(virtio_t __far *virtio, uint8_t idTgt, uint8_t __far *aCDB,
    491                             uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
     491                            uint8_t cbCDB, uint8_t __far *buffer, uint32_t length, uint16_t skip_a,
     492                            uint16_t skip_b)
    492493{
    493494    uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed;
     495    uint8_t idxDesc = 0;
    494496
    495497    _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr));
     
    503505
    504506    /* Fill in the descriptors. */
    505     virtio->Queue.aDescTbl[0].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqHdr);
    506     virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0;
    507     virtio->Queue.aDescTbl[0].cbBuf         = sizeof(virtio->ScsiReqHdr);
    508     virtio->Queue.aDescTbl[0].fFlags        = VIRTIO_Q_DESC_F_NEXT;
    509     virtio->Queue.aDescTbl[0].idxNext       = 1;
     507    virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqHdr);
     508    virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
     509    virtio->Queue.aDescTbl[idxDesc].cbBuf         = sizeof(virtio->ScsiReqHdr);
     510    virtio->Queue.aDescTbl[idxDesc].fFlags        = VIRTIO_Q_DESC_F_NEXT;
     511    virtio->Queue.aDescTbl[idxDesc].idxNext       = 1;
     512    idxDesc++;
    510513
    511514    /* No data out buffer, the status comes right after this in the next descriptor. */
    512     virtio->Queue.aDescTbl[1].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqSts);
    513     virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0;
    514     virtio->Queue.aDescTbl[1].cbBuf         = sizeof(virtio->ScsiReqSts);
    515     virtio->Queue.aDescTbl[1].fFlags        = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
    516     virtio->Queue.aDescTbl[1].idxNext       = 2;
    517 
    518     virtio->Queue.aDescTbl[2].GCPhysBufLow  = virtio_addr_to_phys(buffer);
    519     virtio->Queue.aDescTbl[2].GCPhysBufHigh = 0;
    520     virtio->Queue.aDescTbl[2].cbBuf         = length;
    521     virtio->Queue.aDescTbl[2].fFlags        = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
    522     virtio->Queue.aDescTbl[2].idxNext       = 0;
     515    virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow  = virtio_addr_to_phys(&virtio->ScsiReqSts);
     516    virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
     517    virtio->Queue.aDescTbl[idxDesc].cbBuf         = sizeof(virtio->ScsiReqSts);
     518    virtio->Queue.aDescTbl[idxDesc].fFlags        = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
     519    virtio->Queue.aDescTbl[idxDesc].idxNext       = 2;
     520    idxDesc++;
     521
     522    /* Prepend a sinkhole if data is skipped upfront. */
     523    if (skip_b)
     524    {
     525        virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow  = 0; /* See ahci.c:sink_buf_phys */
     526        virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
     527        virtio->Queue.aDescTbl[idxDesc].cbBuf         = skip_b;
     528        virtio->Queue.aDescTbl[idxDesc].fFlags        = VIRTIO_Q_DESC_F_WRITE | VIRTIO_Q_DESC_F_NEXT;
     529        virtio->Queue.aDescTbl[idxDesc].idxNext       = idxDesc + 1;
     530        idxDesc++;
     531    }
     532
     533    virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow  = virtio_addr_to_phys(buffer);
     534    virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
     535    virtio->Queue.aDescTbl[idxDesc].cbBuf         = length;
     536    virtio->Queue.aDescTbl[idxDesc].fFlags        = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
     537    virtio->Queue.aDescTbl[idxDesc].idxNext       = skip_a ? idxDesc + 1 : 0;
     538    idxDesc++;
     539
     540    /* Append a sinkhole if data is skipped at the end. */
     541    if (skip_a)
     542    {
     543        virtio->Queue.aDescTbl[idxDesc - 1].fFlags  |= VIRTIO_Q_DESC_F_NEXT;
     544        virtio->Queue.aDescTbl[idxDesc - 1].idxNext = idxDesc;
     545
     546        virtio->Queue.aDescTbl[idxDesc].GCPhysBufLow  = 0; /* See ahci.c:sink_buf_phys */
     547        virtio->Queue.aDescTbl[idxDesc].GCPhysBufHigh = 0;
     548        virtio->Queue.aDescTbl[idxDesc].cbBuf         = skip_a;
     549        virtio->Queue.aDescTbl[idxDesc].fFlags        = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */
     550        virtio->Queue.aDescTbl[idxDesc].idxNext       = 0;
     551    }
    523552
    524553    /* Put it into the queue, the index is supposed to be free-running and clipped to the ring size
     
    581610
    582611    rc = virtio_scsi_cmd_data_in(bios_dsk->virtio_seg :> 0, target_id, (void __far *)&cdb, 16,
    583                                  bios_dsk->drqp.buffer, (count * 512L));
     612                                 bios_dsk->drqp.buffer, (count * 512L), 0, 0);
    584613
    585614    if (!rc)
     
    643672}
    644673
    645 #if 0
    646674#define ATA_DATA_OUT     0x02
    647675
     
    653681 * @param   cmdlen      Length of the CDB.
    654682 * @param   cmdbuf      The CDB buffer.
    655  * @param   before      How much to skip before reading into the provided data buffer.
     683 * @param   skip_b      How much to skip before reading into the provided data buffer.
    656684 * @param   length      How much to transfer.
    657685 * @param   inout       Read/Write direction indicator.
    658686 * @param   buffer      Data buffer to store the data from the device in.
    659687 */
    660 uint16_t scsi_cmd_packet(uint16_t device_id, uint8_t cmdlen, char __far *cmdbuf,
    661                          uint16_t before, uint32_t length, uint8_t inout, char __far *buffer)
     688uint16_t virtio_scsi_cmd_packet(uint16_t device_id, uint8_t cmdlen, char __far *cmdbuf,
     689                                uint16_t skip_b, uint32_t length, uint8_t inout, char __far *buffer)
    662690{
    663691    bio_dsk_t __far *bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
    664     uint32_t        read_len;
    665     uint8_t         status, sizes;
    666     uint16_t        i;
    667     uint16_t        io_base;
     692    uint8_t         rc;
    668693    uint8_t         target_id;
    669694
     
    674699    }
    675700
     701    /* The skip length must be even. */
     702    if (skip_b & 1) {
     703        DBG_VIRTIO("%s: skip must be even (%04x)\n", __func__, skip_b);
     704        return 1;
     705    }
     706
    676707    /* Convert to SCSI specific device number. */
    677708    device_id = VBOX_GET_SCSI_DEVICE(device_id);
     
    683714               bios_dsk->drqp.nsect, bios_dsk->drqp.sect_sz);
    684715
    685     cmdlen -= 2; /* ATAPI uses 12-byte command packets for a READ 10. */
    686 
    687     io_base   = bios_dsk->scsidev[device_id].io_base;
     716    high_bits_save(bios_dsk->virtio_seg :> 0);
    688717    target_id = bios_dsk->scsidev[device_id].target_id;
    689718
    690     /* Wait until the adapter is ready. */
    691     do
    692         status = inb(io_base + VBSCSI_REGISTER_STATUS);
    693     while (status & VBSCSI_BUSY);
    694 
    695     /* On the SCSI level, we have to transfer whole sectors. */
    696     /* NB: With proper residual length support, this should not be necessary; we should
    697      * be able to avoid transferring the 'after' part of the sector.
    698      */
    699     read_len = length + before + bios_dsk->drqp.skip_a;
    700 
    701     sizes = (((read_len) >> 12) & 0xF0) | cmdlen;
    702     outb(io_base + VBSCSI_REGISTER_COMMAND, target_id);                 /* Write the target ID. */
    703     outb(io_base + VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_FROM_DEVICE);    /* Write the transfer direction. */
    704     outb(io_base + VBSCSI_REGISTER_COMMAND, sizes);                     /* Write the CDB size. */
    705     outb(io_base + VBSCSI_REGISTER_COMMAND, read_len);                  /* Write the buffer size. */
    706     outb(io_base + VBSCSI_REGISTER_COMMAND, (read_len) >> 8);
    707     for (i = 0; i < cmdlen; i++)                                        /* Write the CDB. */
    708         outb(io_base + VBSCSI_REGISTER_COMMAND, cmdbuf[i]);
    709 
    710     /* Now wait for the command to complete. */
    711     do
    712         status = inb(io_base + VBSCSI_REGISTER_STATUS);
    713     while (status & VBSCSI_BUSY);
    714 
    715     /* If any error occurred, inform the caller and don't bother reading the data. */
    716     if (status & VBSCSI_ERROR) {
    717         outb(io_base + VBSCSI_REGISTER_RESET, 0);
    718 
    719         status = inb(io_base + VBSCSI_REGISTER_DEVSTAT);
    720         DBG_SCSI("%s: read failed, device status %02X\n", __func__, status);
    721         return 3;
    722     }
    723 
    724     /* Transfer the data read from the device. */
    725 
    726     if (before)     /* If necessary, throw away data which needs to be skipped. */
    727         insb_discard(before, io_base + VBSCSI_REGISTER_DATA_IN);
    728 
    729     bios_dsk->drqp.trsfbytes = length;
    730 
    731     /* The requested length may be exactly 64K or more, which needs
    732      * a bit of care when we're using 16-bit 'rep ins'.
    733      */
    734     while (length > 32768) {
    735         DBG_SCSI("%s: reading 32K to %X:%X\n", __func__, FP_SEG(buffer), FP_OFF(buffer));
    736         rep_insb(buffer, 32768, io_base + VBSCSI_REGISTER_DATA_IN);
    737         length -= 32768;
    738         buffer = (FP_SEG(buffer) + (32768 >> 4)) :> FP_OFF(buffer);
    739     }
    740 
    741     DBG_SCSI("%s: reading %ld bytes to %X:%X\n", __func__, length, FP_SEG(buffer), FP_OFF(buffer));
    742     rep_insb(buffer, length, io_base + VBSCSI_REGISTER_DATA_IN);
    743 
    744     if (bios_dsk->drqp.skip_a)  /* If necessary, throw away more data. */
    745         insb_discard(bios_dsk->drqp.skip_a, io_base + VBSCSI_REGISTER_DATA_IN);
    746 
    747     return 0;
    748 }
    749 #endif
     719    bios_dsk->drqp.lba     = length << 8;     /// @todo xfer length limit
     720    bios_dsk->drqp.buffer  = buffer;
     721    bios_dsk->drqp.nsect   = length / bios_dsk->drqp.sect_sz;
     722
     723    DBG_VIRTIO("%s: reading %u bytes, device %d, target %d\n", __func__,
     724               length, device_id, bios_dsk->scsidev[device_id].target_id);
     725
     726    rc = virtio_scsi_cmd_data_in(bios_dsk->virtio_seg :> 0, target_id, (void __far *)cmdbuf, cmdlen,
     727                                 bios_dsk->drqp.buffer, length, skip_b, bios_dsk->drqp.skip_a);
     728    if (!rc)
     729        bios_dsk->drqp.trsfbytes = length;
     730
     731    DBG_VIRTIO("%s: transferred %u bytes\n", __func__, length);
     732    high_bits_restore(bios_dsk->virtio_seg :> 0);
     733
     734    return rc;
     735}
    750736
    751737static int virtio_scsi_detect_devices(virtio_t __far *virtio)
     
    771757        aCDB[5] = 0;
    772758
    773         rc = virtio_scsi_cmd_data_in(virtio, i, aCDB, 6, buffer, 5);
     759        _fmemset(buffer, 0, sizeof(buffer));
     760
     761        rc = virtio_scsi_cmd_data_in(virtio, i, aCDB, 6, buffer, 5, 0, 0);
    774762        if (rc != 0)
    775763            BX_PANIC("%s: SCSI_INQUIRY failed\n", __func__);
     
    798786                aCDB[13] = 32; /* Allocation length. */
    799787
    800                 rc = virtio_scsi_cmd_data_in(virtio, i, aCDB, 16, buffer, 32);
     788                rc = virtio_scsi_cmd_data_in(virtio, i, aCDB, 16, buffer, 32, 0, 0);
    801789                if (rc != 0)
    802790                    BX_PANIC("%s: SCSI_READ_CAPACITY failed\n", __func__);
     
    922910            }
    923911        }
    924 #if 0
    925912        else if (   ((buffer[0] & 0xe0) == 0)
    926913                 && ((buffer[0] & 0x1f) == 0x05))
     
    951938            devcount_scsi++;
    952939        }
    953 #endif
    954940        else
    955941            DBG_VIRTIO("%s: No supported device detected at %d\n", __func__, i);
Note: See TracChangeset for help on using the changeset viewer.

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