Changeset 82164 in vbox
- Timestamp:
- Nov 25, 2019 10:32:37 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 134974
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/BIOS/virtio.c
r81407 r82164 25 25 #include "scsi.h" 26 26 27 #define DEBUG_VIRTIO 127 //#define DEBUG_VIRTIO 1 28 28 #if DEBUG_VIRTIO 29 29 # define DBG_VIRTIO(...) BX_INFO(__VA_ARGS__) … … 278 278 #define VIRTIO_SCSI_Q_REQUEST 0x02 279 279 280 #define VIRTIO_SCSI_STS_RESPONSE_OK 0x00 281 280 282 /* Machinery to save/restore high bits of EAX. 32-bit port I/O needs to use 281 283 * EAX, but saving/restoring EAX around each port access would be inefficient. … … 338 340 } 339 341 342 static void virtio_reg_isr_prepare(virtio_t __far *virtio, uint32_t cbAcc) 343 { 344 virtio_reg_set_bar_offset_length(virtio, 345 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u8Bar, 346 virtio->aBarCfgs[VIRTIO_PCI_CAP_ISR_CFG - 1].u32Offset, 347 cbAcc); 348 } 349 340 350 static uint8_t virtio_reg_common_read_u8(virtio_t __far *virtio, uint16_t offReg) 341 351 { … … 362 372 } 363 373 364 static uint32_t virtio_reg_common_read_u32(virtio_t __far *virtio, uint16_t offReg)365 {366 virtio_reg_common_access_prepare(virtio, offReg, sizeof(uint32_t));367 return pci_read_config_dword(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));368 }369 370 374 static void virtio_reg_common_write_u32(virtio_t __far *virtio, uint16_t offReg, uint32_t u32Val) 371 375 { … … 374 378 } 375 379 376 static uint16_t virtio_reg_dev_cfg_read_u16(virtio_t __far *virtio, uint16_t offReg)377 {378 virtio_reg_dev_access_prepare(virtio, offReg, sizeof(uint16_t));379 return pci_read_config_word(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t));380 }381 382 380 static uint32_t virtio_reg_dev_cfg_read_u32(virtio_t __far *virtio, uint16_t offReg) 383 381 { … … 398 396 } 399 397 398 static uint8_t virtio_reg_isr_read_u8(virtio_t __far *virtio) 399 { 400 virtio_reg_isr_prepare(virtio, sizeof(uint8_t)); 401 return pci_read_config_byte(virtio->u8Bus, virtio->u8DevFn, virtio->u8PciCfgOff + sizeof(virtio_pci_cap_t)); 402 } 403 400 404 /** 401 405 * Allocates 1K of conventional memory. … … 429 433 } 430 434 431 int virtio_scsi_cmd_data_ in(virtio_t __far *virtio, uint8_t idTgt, uint8_t __far *aCDB,435 int virtio_scsi_cmd_data_out(virtio_t __far *virtio, uint8_t idTgt, uint8_t __far *aCDB, 432 436 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length) 433 437 { … … 451 455 virtio->Queue.aDescTbl[0].idxNext = 1; 452 456 457 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(buffer); 458 virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0; 459 virtio->Queue.aDescTbl[1].cbBuf = length; 460 virtio->Queue.aDescTbl[1].fFlags = VIRTIO_Q_DESC_F_NEXT; 461 virtio->Queue.aDescTbl[1].idxNext = 1; 462 463 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts); 464 virtio->Queue.aDescTbl[1].GCPhysBufHigh = 0; 465 virtio->Queue.aDescTbl[1].cbBuf = sizeof(virtio->ScsiReqSts); 466 virtio->Queue.aDescTbl[1].fFlags = VIRTIO_Q_DESC_F_WRITE; /* End of chain. */ 467 virtio->Queue.aDescTbl[1].idxNext = 0; 468 469 /* Put it into the queue. */ 470 virtio->Queue.AvailRing.au16Ring[virtio->Queue.AvailRing.idxNextFree] = 0; 471 virtio->Queue.AvailRing.idxNextFree++; 472 virtio->Queue.AvailRing.idxNextFree %= VIRTIO_SCSI_RING_ELEM; 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, idxNext); 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 out. */ 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 int virtio_scsi_cmd_data_in(virtio_t __far *virtio, uint8_t idTgt, uint8_t __far *aCDB, 493 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length) 494 { 495 uint16_t idxUsedOld = virtio->Queue.UsedRing.idxNextUsed; 496 uint64_t idxNext = virtio->Queue.AvailRing.idxNextFree; 497 498 _fmemset(&virtio->ScsiReqHdr, 0, sizeof(virtio->ScsiReqHdr)); 499 _fmemset(&virtio->ScsiReqSts, 0, sizeof(virtio->ScsiReqSts)); 500 501 virtio->ScsiReqHdr.au8Lun[0] = 0x1; 502 virtio->ScsiReqHdr.au8Lun[1] = idTgt; 503 virtio->ScsiReqHdr.au8Lun[2] = 0; 504 virtio->ScsiReqHdr.au8Lun[3] = 0; 505 _fmemcpy(&virtio->ScsiReqHdr.abCdb[0], aCDB, cbCDB); 506 507 /* Fill in the descriptors. */ 508 virtio->Queue.aDescTbl[0].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqHdr); 509 virtio->Queue.aDescTbl[0].GCPhysBufHigh = 0; 510 virtio->Queue.aDescTbl[0].cbBuf = sizeof(virtio->ScsiReqHdr); 511 virtio->Queue.aDescTbl[0].fFlags = VIRTIO_Q_DESC_F_NEXT; 512 virtio->Queue.aDescTbl[0].idxNext = 1; 513 453 514 /* No data out buffer, the status comes right after this in the next descriptor. */ 454 515 virtio->Queue.aDescTbl[1].GCPhysBufLow = virtio_addr_to_phys(&virtio->ScsiReqSts); … … 476 537 while (idxUsedOld == virtio->Queue.UsedRing.idxNextUsed); 477 538 478 DBG_VIRTIO("VirtIO: Request complete\n"); 539 DBG_VIRTIO("VirtIO: Request complete u8Response=%u\n", virtio->ScsiReqSts.u8Response); 540 541 /* Read ISR register to de-assert the interrupt, don't need to do anything with out. */ 542 virtio_reg_isr_read_u8(virtio); 543 544 if (virtio->ScsiReqSts.u8Response != VIRTIO_SCSI_STS_RESPONSE_OK) 545 return 4; 479 546 480 547 return 0; 481 548 } 549 550 /** 551 * Read sectors from an attached VirtIO SCSI device. 552 * 553 * @returns status code. 554 * @param bios_dsk Pointer to disk request packet (in the 555 * EBDA). 556 */ 557 int virtio_scsi_read_sectors(bio_dsk_t __far *bios_dsk) 558 { 559 uint8_t rc; 560 cdb_rw16 cdb; 561 uint32_t count; 562 uint8_t target_id; 563 uint8_t device_id; 564 565 device_id = VBOX_GET_SCSI_DEVICE(bios_dsk->drqp.dev_id); 566 if (device_id > BX_MAX_SCSI_DEVICES) 567 BX_PANIC("%s: device_id out of range %d\n", __func__, device_id); 568 569 count = bios_dsk->drqp.nsect; 570 571 high_bits_save(bios_dsk->virtio_seg :> 0); 572 /* Prepare a CDB. */ 573 cdb.command = SCSI_READ_16; 574 cdb.lba = swap_64(bios_dsk->drqp.lba); 575 cdb.pad1 = 0; 576 cdb.nsect32 = swap_32(count); 577 cdb.pad2 = 0; 578 579 580 target_id = bios_dsk->scsidev[device_id].target_id; 581 582 DBG_VIRTIO("%s: reading %u sectors, device %d, target %d\n", __func__, 583 count, device_id, bios_dsk->scsidev[device_id].target_id); 584 585 rc = virtio_scsi_cmd_data_in(bios_dsk->virtio_seg :> 0, target_id, (void __far *)&cdb, 16, 586 bios_dsk->drqp.buffer, (count * 512L)); 587 588 if (!rc) 589 { 590 bios_dsk->drqp.trsfsectors = count; 591 bios_dsk->drqp.trsfbytes = count * 512L; 592 } 593 DBG_VIRTIO("%s: transferred %u sectors\n", __func__, bios_dsk->drqp.nsect); 594 high_bits_restore(bios_dsk->virtio_seg :> 0); 595 596 return rc; 597 } 598 599 /** 600 * Write sectors to an attached VirtIO SCSI device. 601 * 602 * @returns status code. 603 * @param bios_dsk Pointer to disk request packet (in the 604 * EBDA). 605 */ 606 int virtio_scsi_write_sectors(bio_dsk_t __far *bios_dsk) 607 { 608 uint8_t rc; 609 cdb_rw16 cdb; 610 uint32_t count; 611 uint8_t target_id; 612 uint8_t device_id; 613 614 device_id = VBOX_GET_SCSI_DEVICE(bios_dsk->drqp.dev_id); 615 if (device_id > BX_MAX_SCSI_DEVICES) 616 BX_PANIC("%s: device_id out of range %d\n", __func__, device_id); 617 618 count = bios_dsk->drqp.nsect; 619 620 high_bits_save(bios_dsk->virtio_seg :> 0); 621 622 /* Prepare a CDB. */ 623 cdb.command = SCSI_WRITE_16; 624 cdb.lba = swap_64(bios_dsk->drqp.lba); 625 cdb.pad1 = 0; 626 cdb.nsect32 = swap_32(count); 627 cdb.pad2 = 0; 628 629 target_id = bios_dsk->scsidev[device_id].target_id; 630 631 DBG_VIRTIO("%s: writing %u sectors, device %d, target %d\n", __func__, 632 count, device_id, bios_dsk->scsidev[device_id].target_id); 633 634 rc = virtio_scsi_cmd_data_out(bios_dsk->virtio_seg :> 0, target_id, (void __far *)&cdb, 16, 635 bios_dsk->drqp.buffer, (count * 512L)); 636 637 if (!rc) 638 { 639 bios_dsk->drqp.trsfsectors = count; 640 bios_dsk->drqp.trsfbytes = (count * 512L); 641 } 642 DBG_VIRTIO("%s: transferred %u sectors\n", __func__, bios_dsk->drqp.nsect); 643 high_bits_restore(bios_dsk->virtio_seg :> 0); 644 645 return rc; 646 } 647 648 #if 0 649 #define ATA_DATA_OUT 0x02 650 651 /** 652 * Perform a "packet style" read with supplied CDB. 653 * 654 * @returns status code. 655 * @param device_id ID of the device to access. 656 * @param cmdlen Length of the CDB. 657 * @param cmdbuf The CDB buffer. 658 * @param before How much to skip before reading into the provided data buffer. 659 * @param length How much to transfer. 660 * @param inout Read/Write direction indicator. 661 * @param buffer Data buffer to store the data from the device in. 662 */ 663 uint16_t scsi_cmd_packet(uint16_t device_id, uint8_t cmdlen, char __far *cmdbuf, 664 uint16_t before, uint32_t length, uint8_t inout, char __far *buffer) 665 { 666 bio_dsk_t __far *bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk; 667 uint32_t read_len; 668 uint8_t status, sizes; 669 uint16_t i; 670 uint16_t io_base; 671 uint8_t target_id; 672 673 /* Data out is currently not supported. */ 674 if (inout == ATA_DATA_OUT) { 675 BX_INFO("%s: DATA_OUT not supported yet\n", __func__); 676 return 1; 677 } 678 679 /* Convert to SCSI specific device number. */ 680 device_id = VBOX_GET_SCSI_DEVICE(device_id); 681 682 DBG_VIRTIO("%s: reading %lu bytes, skip %u/%u, device %d, target %d\n", __func__, 683 length, bios_dsk->drqp.skip_b, bios_dsk->drqp.skip_a, 684 device_id, bios_dsk->scsidev[device_id].target_id); 685 DBG_VIRTIO("%s: reading %u %u-byte sectors\n", __func__, 686 bios_dsk->drqp.nsect, bios_dsk->drqp.sect_sz); 687 688 cmdlen -= 2; /* ATAPI uses 12-byte command packets for a READ 10. */ 689 690 io_base = bios_dsk->scsidev[device_id].io_base; 691 target_id = bios_dsk->scsidev[device_id].target_id; 692 693 /* Wait until the adapter is ready. */ 694 do 695 status = inb(io_base + VBSCSI_REGISTER_STATUS); 696 while (status & VBSCSI_BUSY); 697 698 /* On the SCSI level, we have to transfer whole sectors. */ 699 /* NB: With proper residual length support, this should not be necessary; we should 700 * be able to avoid transferring the 'after' part of the sector. 701 */ 702 read_len = length + before + bios_dsk->drqp.skip_a; 703 704 sizes = (((read_len) >> 12) & 0xF0) | cmdlen; 705 outb(io_base + VBSCSI_REGISTER_COMMAND, target_id); /* Write the target ID. */ 706 outb(io_base + VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_FROM_DEVICE); /* Write the transfer direction. */ 707 outb(io_base + VBSCSI_REGISTER_COMMAND, sizes); /* Write the CDB size. */ 708 outb(io_base + VBSCSI_REGISTER_COMMAND, read_len); /* Write the buffer size. */ 709 outb(io_base + VBSCSI_REGISTER_COMMAND, (read_len) >> 8); 710 for (i = 0; i < cmdlen; i++) /* Write the CDB. */ 711 outb(io_base + VBSCSI_REGISTER_COMMAND, cmdbuf[i]); 712 713 /* Now wait for the command to complete. */ 714 do 715 status = inb(io_base + VBSCSI_REGISTER_STATUS); 716 while (status & VBSCSI_BUSY); 717 718 /* If any error occurred, inform the caller and don't bother reading the data. */ 719 if (status & VBSCSI_ERROR) { 720 outb(io_base + VBSCSI_REGISTER_RESET, 0); 721 722 status = inb(io_base + VBSCSI_REGISTER_DEVSTAT); 723 DBG_SCSI("%s: read failed, device status %02X\n", __func__, status); 724 return 3; 725 } 726 727 /* Transfer the data read from the device. */ 728 729 if (before) /* If necessary, throw away data which needs to be skipped. */ 730 insb_discard(before, io_base + VBSCSI_REGISTER_DATA_IN); 731 732 bios_dsk->drqp.trsfbytes = length; 733 734 /* The requested length may be exactly 64K or more, which needs 735 * a bit of care when we're using 16-bit 'rep ins'. 736 */ 737 while (length > 32768) { 738 DBG_SCSI("%s: reading 32K to %X:%X\n", __func__, FP_SEG(buffer), FP_OFF(buffer)); 739 rep_insb(buffer, 32768, io_base + VBSCSI_REGISTER_DATA_IN); 740 length -= 32768; 741 buffer = (FP_SEG(buffer) + (32768 >> 4)) :> FP_OFF(buffer); 742 } 743 744 DBG_SCSI("%s: reading %ld bytes to %X:%X\n", __func__, length, FP_SEG(buffer), FP_OFF(buffer)); 745 rep_insb(buffer, length, io_base + VBSCSI_REGISTER_DATA_IN); 746 747 if (bios_dsk->drqp.skip_a) /* If necessary, throw away more data. */ 748 insb_discard(bios_dsk->drqp.skip_a, io_base + VBSCSI_REGISTER_DATA_IN); 749 750 return 0; 751 } 752 #endif 482 753 483 754 static int virtio_scsi_detect_devices(virtio_t __far *virtio) … … 608 879 hd_index = devcount_scsi + BX_MAX_ATA_DEVICES; 609 880 610 //bios_dsk->scsidev[devcount_scsi].io_base = io_base;611 881 bios_dsk->scsidev[devcount_scsi].target_id = i; 612 bios_dsk->devices[hd_index].type = DSK_TYPE_ SCSI;882 bios_dsk->devices[hd_index].type = DSK_TYPE_VIRTIO_SCSI; 613 883 bios_dsk->devices[hd_index].device = DSK_DEVICE_HD; 614 884 bios_dsk->devices[hd_index].removable = 0; … … 655 925 } 656 926 } 927 #if 0 657 928 else if ( ((buffer[0] & 0xe0) == 0) 658 929 && ((buffer[0] & 0x1f) == 0x05)) … … 668 939 removable = buffer[1] & 0x80 ? 1 : 0; 669 940 670 //bios_dsk->scsidev[devcount_scsi].io_base = io_base;671 941 bios_dsk->scsidev[devcount_scsi].target_id = i; 672 bios_dsk->devices[hd_index].type = DSK_TYPE_ SCSI;942 bios_dsk->devices[hd_index].type = DSK_TYPE_VIRTIO_SCSI; 673 943 bios_dsk->devices[hd_index].device = DSK_DEVICE_CDROM; 674 944 bios_dsk->devices[hd_index].removable = removable; … … 684 954 devcount_scsi++; 685 955 } 956 #endif 686 957 else 687 958 DBG_VIRTIO("%s: No supported device detected at %d\n", __func__, i); … … 689 960 bios_dsk->scsi_devcount = devcount_scsi; 690 961 } 962 963 return 0; 691 964 } 692 965 … … 699 972 uint16_t ebda_seg; 700 973 uint16_t virtio_seg; 701 uint32_t fFeatures;702 974 uint8_t u8DevStat; 703 975 bio_dsk_t __far *bios_dsk; … … 718 990 719 991 bios_dsk->virtio_seg = virtio_seg; 720 bios_dsk->virtio_devcnt = 0;721 992 722 993 virtio = virtio_seg :> 0;
Note:
See TracChangeset
for help on using the changeset viewer.