Changeset 65964 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Mar 7, 2017 10:44:12 AM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 113790
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/ATAPIPassthrough.cpp
r65108 r65964 19 19 #include <iprt/assert.h> 20 20 #include <iprt/mem.h> 21 #include <iprt/string.h> 21 22 22 23 #include <VBox/log.h> … … 628 629 } 629 630 631 632 static uint8_t atapiPassthroughCmdErrorSimple(uint8_t *pbSense, size_t cbSense, uint8_t uATAPISenseKey, uint8_t uATAPIASC) 633 { 634 memset(pbSense, '\0', cbSense); 635 if (RT_LIKELY(cbSense >= 13)) 636 { 637 pbSense[0] = 0x70 | (1 << 7); 638 pbSense[2] = uATAPISenseKey & 0x0f; 639 pbSense[7] = 10; 640 pbSense[12] = uATAPIASC; 641 } 642 return SCSI_STATUS_CHECK_CONDITION; 643 } 644 645 646 DECLHIDDEN(bool) ATAPIPassthroughParseCdb(const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf, 647 PTRACKLIST pTrackList, uint8_t *pbSense, size_t cbSense, 648 PDMMEDIATXDIR *penmTxDir, size_t *pcbXfer, 649 size_t *pcbSector, uint8_t *pu8ScsiSts) 650 { 651 uint32_t uLba = 0; 652 uint32_t cSectors = 0; 653 size_t cbSector = 0; 654 size_t cbXfer = 0; 655 bool fPassthrough = false; 656 PDMMEDIATXDIR enmTxDir = PDMMEDIATXDIR_NONE; 657 658 RT_NOREF(cbCdb); 659 660 switch (pbCdb[0]) 661 { 662 /* First the commands we can pass through without further processing. */ 663 case SCSI_BLANK: 664 case SCSI_CLOSE_TRACK_SESSION: 665 case SCSI_LOAD_UNLOAD_MEDIUM: 666 case SCSI_PAUSE_RESUME: 667 case SCSI_PLAY_AUDIO_10: 668 case SCSI_PLAY_AUDIO_12: 669 case SCSI_PLAY_AUDIO_MSF: 670 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: 671 case SCSI_REPAIR_TRACK: 672 case SCSI_RESERVE_TRACK: 673 case SCSI_SCAN: 674 case SCSI_SEEK_10: 675 case SCSI_SET_CD_SPEED: 676 case SCSI_SET_READ_AHEAD: 677 case SCSI_START_STOP_UNIT: 678 case SCSI_STOP_PLAY_SCAN: 679 case SCSI_SYNCHRONIZE_CACHE: 680 case SCSI_TEST_UNIT_READY: 681 case SCSI_VERIFY_10: 682 fPassthrough = true; 683 break; 684 case SCSI_ERASE_10: 685 uLba = scsiBE2H_U32(pbCdb + 2); 686 cbXfer = scsiBE2H_U16(pbCdb + 7); 687 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 688 fPassthrough = true; 689 break; 690 case SCSI_FORMAT_UNIT: 691 cbXfer = cbBuf; 692 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 693 fPassthrough = true; 694 break; 695 case SCSI_GET_CONFIGURATION: 696 cbXfer = scsiBE2H_U16(pbCdb + 7); 697 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 698 fPassthrough = true; 699 break; 700 case SCSI_GET_EVENT_STATUS_NOTIFICATION: 701 cbXfer = scsiBE2H_U16(pbCdb + 7); 702 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 703 fPassthrough = true; 704 break; 705 case SCSI_GET_PERFORMANCE: 706 cbXfer = cbBuf; 707 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 708 fPassthrough = true; 709 break; 710 case SCSI_INQUIRY: 711 cbXfer = scsiBE2H_U16(pbCdb + 3); 712 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 713 fPassthrough = true; 714 break; 715 case SCSI_MECHANISM_STATUS: 716 cbXfer = scsiBE2H_U16(pbCdb + 8); 717 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 718 fPassthrough = true; 719 break; 720 case SCSI_MODE_SELECT_10: 721 cbXfer = scsiBE2H_U16(pbCdb + 7); 722 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 723 fPassthrough = true; 724 break; 725 case SCSI_MODE_SENSE_10: 726 cbXfer = scsiBE2H_U16(pbCdb + 7); 727 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 728 fPassthrough = true; 729 break; 730 case SCSI_READ_10: 731 uLba = scsiBE2H_U32(pbCdb + 2); 732 cSectors = scsiBE2H_U16(pbCdb + 7); 733 cbSector = 2048; 734 cbXfer = cSectors * cbSector; 735 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 736 fPassthrough = true; 737 break; 738 case SCSI_READ_12: 739 uLba = scsiBE2H_U32(pbCdb + 2); 740 cSectors = scsiBE2H_U32(pbCdb + 6); 741 cbSector = 2048; 742 cbXfer = cSectors * cbSector; 743 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 744 fPassthrough = true; 745 break; 746 case SCSI_READ_BUFFER: 747 cbXfer = scsiBE2H_U24(pbCdb + 6); 748 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 749 fPassthrough = true; 750 break; 751 case SCSI_READ_BUFFER_CAPACITY: 752 cbXfer = scsiBE2H_U16(pbCdb + 7); 753 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 754 fPassthrough = true; 755 break; 756 case SCSI_READ_CAPACITY: 757 cbXfer = 8; 758 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 759 fPassthrough = true; 760 break; 761 case SCSI_READ_CD: 762 case SCSI_READ_CD_MSF: 763 { 764 /* Get sector size based on the expected sector type field. */ 765 switch ((pbCdb[1] >> 2) & 0x7) 766 { 767 case 0x0: /* All types. */ 768 { 769 uint32_t iLbaStart; 770 771 if (pbCdb[0] == SCSI_READ_CD) 772 iLbaStart = scsiBE2H_U32(&pbCdb[2]); 773 else 774 iLbaStart = scsiMSF2LBA(&pbCdb[3]); 775 776 if (pTrackList) 777 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pTrackList, iLbaStart); 778 else 779 cbSector = 2048; /* Might be incorrect if we couldn't determine the type. */ 780 break; 781 } 782 case 0x1: /* CD-DA */ 783 cbSector = 2352; 784 break; 785 case 0x2: /* Mode 1 */ 786 cbSector = 2048; 787 break; 788 case 0x3: /* Mode 2 formless */ 789 cbSector = 2336; 790 break; 791 case 0x4: /* Mode 2 form 1 */ 792 cbSector = 2048; 793 break; 794 case 0x5: /* Mode 2 form 2 */ 795 cbSector = 2324; 796 break; 797 default: /* Reserved */ 798 AssertMsgFailed(("Unknown sector type\n")); 799 cbSector = 0; /** @todo we should probably fail the command here already. */ 800 } 801 802 if (pbCdb[0] == SCSI_READ_CD) 803 cbXfer = scsiBE2H_U24(pbCdb + 6) * cbSector; 804 else /* SCSI_READ_MSF */ 805 { 806 cSectors = scsiMSF2LBA(pbCdb + 6) - scsiMSF2LBA(pbCdb + 3); 807 if (cSectors > 32) 808 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */ 809 cbXfer = cSectors * cbSector; 810 } 811 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 812 fPassthrough = true; 813 break; 814 } 815 case SCSI_READ_DISC_INFORMATION: 816 cbXfer = scsiBE2H_U16(pbCdb + 7); 817 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 818 fPassthrough = true; 819 break; 820 case SCSI_READ_DVD_STRUCTURE: 821 cbXfer = scsiBE2H_U16(pbCdb + 8); 822 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 823 fPassthrough = true; 824 break; 825 case SCSI_READ_FORMAT_CAPACITIES: 826 cbXfer = scsiBE2H_U16(pbCdb + 7); 827 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 828 fPassthrough = true; 829 break; 830 case SCSI_READ_SUBCHANNEL: 831 cbXfer = scsiBE2H_U16(pbCdb + 7); 832 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 833 fPassthrough = true; 834 break; 835 case SCSI_READ_TOC_PMA_ATIP: 836 cbXfer = scsiBE2H_U16(pbCdb + 7); 837 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 838 fPassthrough = true; 839 break; 840 case SCSI_READ_TRACK_INFORMATION: 841 cbXfer = scsiBE2H_U16(pbCdb + 7); 842 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 843 fPassthrough = true; 844 break; 845 case SCSI_REPORT_KEY: 846 cbXfer = scsiBE2H_U16(pbCdb + 8); 847 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 848 fPassthrough = true; 849 break; 850 case SCSI_REQUEST_SENSE: 851 cbXfer = pbCdb[4]; 852 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 853 fPassthrough = true; 854 break; 855 case SCSI_SEND_CUE_SHEET: 856 cbXfer = scsiBE2H_U24(pbCdb + 6); 857 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 858 fPassthrough = true; 859 break; 860 case SCSI_SEND_DVD_STRUCTURE: 861 cbXfer = scsiBE2H_U16(pbCdb + 8); 862 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 863 fPassthrough = true; 864 break; 865 case SCSI_SEND_EVENT: 866 cbXfer = scsiBE2H_U16(pbCdb + 8); 867 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 868 fPassthrough = true; 869 break; 870 case SCSI_SEND_KEY: 871 cbXfer = scsiBE2H_U16(pbCdb + 8); 872 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 873 fPassthrough = true; 874 break; 875 case SCSI_SEND_OPC_INFORMATION: 876 cbXfer = scsiBE2H_U16(pbCdb + 7); 877 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 878 fPassthrough = true; 879 break; 880 case SCSI_SET_STREAMING: 881 cbXfer = scsiBE2H_U16(pbCdb + 9); 882 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 883 fPassthrough = true; 884 break; 885 case SCSI_WRITE_10: 886 case SCSI_WRITE_AND_VERIFY_10: 887 uLba = scsiBE2H_U32(pbCdb + 2); 888 cSectors = scsiBE2H_U16(pbCdb + 7); 889 if (pTrackList) 890 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pTrackList, uLba); 891 else 892 cbSector = 2048; 893 cbXfer = cSectors * cbSector; 894 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 895 fPassthrough = true; 896 break; 897 case SCSI_WRITE_12: 898 uLba = scsiBE2H_U32(pbCdb + 2); 899 cSectors = scsiBE2H_U32(pbCdb + 6); 900 if (pTrackList) 901 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pTrackList, uLba); 902 else 903 cbSector = 2048; 904 cbXfer = cSectors * cbSector; 905 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 906 fPassthrough = true; 907 break; 908 case SCSI_WRITE_BUFFER: 909 switch (pbCdb[1] & 0x1f) 910 { 911 case 0x04: /* download microcode */ 912 case 0x05: /* download microcode and save */ 913 case 0x06: /* download microcode with offsets */ 914 case 0x07: /* download microcode with offsets and save */ 915 case 0x0e: /* download microcode with offsets and defer activation */ 916 case 0x0f: /* activate deferred microcode */ 917 LogRel(("ATAPI: CD-ROM passthrough command attempted to update firmware, blocked\n")); 918 *pu8ScsiSts = atapiPassthroughCmdErrorSimple(pbSense, cbSense, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); 919 break; 920 default: 921 cbXfer = scsiBE2H_U16(pbCdb + 6); 922 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 923 fPassthrough = true; 924 break; 925 } 926 break; 927 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */ 928 cbXfer = scsiBE2H_U32(pbCdb + 6); 929 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 930 fPassthrough = true; 931 break; 932 case SCSI_REZERO_UNIT: 933 /* Obsolete command used by cdrecord. What else would one expect? 934 * This command is not sent to the drive, it is handled internally, 935 * as the Linux kernel doesn't like it (message "scsi: unknown 936 * opcode 0x01" in syslog) and replies with a sense code of 0, 937 * which sends cdrecord to an endless loop. */ 938 *pu8ScsiSts = atapiPassthroughCmdErrorSimple(pbSense, cbSense, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 939 break; 940 default: 941 LogRel(("ATAPI: Passthrough unimplemented for command %#x\n", pbCdb[0])); 942 *pu8ScsiSts = atapiPassthroughCmdErrorSimple(pbSense, cbSense, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 943 break; 944 } 945 946 if (fPassthrough) 947 { 948 *penmTxDir = enmTxDir; 949 *pcbXfer = cbXfer; 950 *pcbSector = cbSector; 951 } 952 953 return fPassthrough; 954 } 955 -
trunk/src/VBox/Devices/Storage/ATAPIPassthrough.h
r62506 r65964 19 19 20 20 #include <VBox/cdefs.h> 21 #include <VBox/vmm/pdmifs.h> 22 #include <VBox/vmm/pdmstorageifs.h> 21 23 22 24 RT_C_DECLS_BEGIN … … 70 72 DECLHIDDEN(uint32_t) ATAPIPassthroughTrackListGetSectorSizeFromLba(PTRACKLIST pTrackList, uint32_t iAtapiLba); 71 73 74 /** 75 * Parses the given CDB and returns whether it is safe to pass it through to the host drive. 76 * 77 * @returns Flag whether passing the CDB through to the host drive is safe. 78 * @param pbCdb The CDB to parse. 79 * @param cbCdb Size of the CDB in bytes. 80 * @param cbBuf Size of the guest buffer. 81 * @param pTrackList The track list for the current medium if available (optional). 82 * @param pbSense Pointer to the sense buffer. 83 * @param cbSense Size of the sense buffer. 84 * @param penmTxDir Where to store the transfer direction (guest to host or vice versa). 85 * @param pcbXfer Where to store the transfer size encoded in the CDB. 86 * @param pcbSector Where to store the sector size used for the transfer. 87 * @param pu8ScsiSts Where to store the SCSI status code. 88 */ 89 DECLHIDDEN(bool) ATAPIPassthroughParseCdb(const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf, 90 PTRACKLIST pTrackList, uint8_t *pbSense, size_t cbSense, 91 PDMMEDIATXDIR *penmTxDir, size_t *pcbXfer, 92 size_t *pcbSector, uint8_t *pu8ScsiSts); 93 72 94 RT_C_DECLS_END 73 95
Note:
See TracChangeset
for help on using the changeset viewer.