VirtualBox

Ignore:
Timestamp:
Nov 17, 2015 3:32:43 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
104155
Message:

BIOS: Support 64-bit LBA operation. Contributed by Maksym Sobolyev. Thank you!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/BIOS/scsi.c

    r56292 r58724  
    4949
    5050/* Command opcodes. */
     51#define SCSI_SERVICE_ACT   0x9e
    5152#define SCSI_INQUIRY       0x12
    52 #define SCSI_READ_CAPACITY 0x25
     53#define SCSI_READ_CAP_10  0x25
    5354#define SCSI_READ_10       0x28
    5455#define SCSI_WRITE_10      0x2a
     56#define SCSI_READ_CAP_16   0x10    /* Not an opcode by itself, sub-action for the "Service Action" */
     57#define SCSI_READ_16       0x88
     58#define SCSI_WRITE_16      0x8a
    5559
    5660/* Data transfer direction. */
     
    6973} cdb_rw10;
    7074
     75/* READ_16/WRITE_16 CDB layout. */
     76typedef struct {
     77    uint16_t    command;    /* Command. */
     78    uint64_t    lba;        /* LBA, MSB first! */
     79    uint32_t    nsect32;    /* Sector count, MSB first! */
     80    uint8_t     pad1;       /* Unused. */
     81    uint8_t     pad2;       /* Unused. */
     82} cdb_rw16;
     83
    7184#pragma pack()
    7285
    7386ct_assert(sizeof(cdb_rw10) == 10);
    74 
     87ct_assert(sizeof(cdb_rw16) == 16);
    7588
    7689void insb_discard(unsigned nbytes, unsigned port);
     
    94107    while (status & VBSCSI_BUSY);
    95108
    96 
    97     sizes = ((length >> 12) & 0xF0) | cbCDB;
     109    sizes = ((length >> 12) & 0xF0) | (cbCDB == 16) ? 0 : cbCDB;
    98110    outb(io_base + VBSCSI_REGISTER_COMMAND, target_id);                 /* Write the target ID. */
    99111    outb(io_base + VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_FROM_DEVICE);    /* Write the transfer direction. */
     
    146158
    147159
    148     sizes = ((length >> 12) & 0xF0) | cbCDB;
     160    sizes = ((length >> 12) & 0xF0) | (cbCDB == 16) ? 0 : cbCDB;
    149161    outb(io_base + VBSCSI_REGISTER_COMMAND, target_id);                 /* Write the target ID. */
    150162    outb(io_base + VBSCSI_REGISTER_COMMAND, SCSI_TXDIR_TO_DEVICE);      /* Write the transfer direction. */
     
    185197}
    186198
     199static uint64_t swap_64(uint64_t val)
     200{
     201    uint64_t rval;
     202
     203    rval = swap_32(val & 0xffffffff);
     204    rval <<= 32;
     205    rval |= swap_32(val >> 32);
     206
     207    return rval;
     208}
     209
    187210/**
    188211 * Read sectors from an attached SCSI device.
     
    195218{
    196219    uint8_t             rc;
    197     cdb_rw10            cdb;
    198     uint16_t            count;
     220    cdb_rw16            cdb;
     221    uint32_t            count;
    199222    uint16_t            io_base;
    200223    uint8_t             target_id;
     
    208231
    209232    /* Prepare a CDB. */
    210     cdb.command = SCSI_READ_10;
    211     cdb.lba     = swap_32(bios_dsk->drqp.lba);
     233    cdb.command = SCSI_READ_16;
     234    cdb.lba     = swap_64(bios_dsk->drqp.lba);
    212235    cdb.pad1    = 0;
    213     cdb.nsect   = swap_16(count);
     236    cdb.nsect32 = swap_32(count);
    214237    cdb.pad2    = 0;
    215238
     
    221244             count, device_id, bios_dsk->scsidev[device_id].target_id);
    222245
    223     rc = scsi_cmd_data_in(io_base, target_id, (void __far *)&cdb, 10,
     246    rc = scsi_cmd_data_in(io_base, target_id, (void __far *)&cdb, 16,
    224247                          bios_dsk->drqp.buffer, (count * 512L));
    225248
     
    244267{
    245268    uint8_t             rc;
    246     cdb_rw10            cdb;
    247     uint16_t            count;
     269    cdb_rw16            cdb;
     270    uint32_t            count;
    248271    uint16_t            io_base;
    249272    uint8_t             target_id;
     
    257280
    258281    /* Prepare a CDB. */
    259     cdb.command = SCSI_WRITE_10;
    260     cdb.lba     = swap_32(bios_dsk->drqp.lba);
     282    cdb.command = SCSI_WRITE_16;
     283    cdb.lba     = swap_64(bios_dsk->drqp.lba);
    261284    cdb.pad1    = 0;
    262     cdb.nsect   = swap_16(count);
     285    cdb.nsect32 = swap_32(count);
    263286    cdb.pad2    = 0;
    264287
     
    269292             count, device_id, bios_dsk->scsidev[device_id].target_id);
    270293
    271     rc = scsi_cmd_data_out(io_base, target_id, (void __far *)&cdb, 10,
     294    rc = scsi_cmd_data_out(io_base, target_id, (void __far *)&cdb, 16,
    272295                           bios_dsk->drqp.buffer, (count * 512L));
    273296
     
    403426    {
    404427        uint8_t     rc;
    405         uint8_t     aCDB[10];
     428        uint8_t     aCDB[16];
    406429        uint8_t     hd_index, devcount_scsi;
    407430
     
    428451            if (devcount_scsi < BX_MAX_SCSI_DEVICES)
    429452            {
    430                 uint32_t    sectors, sector_size, cylinders;
     453                uint64_t    sectors, t;
     454                uint32_t    sector_size, cylinders;
    431455                uint16_t    heads, sectors_per_track;
    432456                uint8_t     hdcount;
     
    435459                /* Issue a read capacity command now. */
    436460                _fmemset(aCDB, 0, sizeof(aCDB));
    437                 aCDB[0] = SCSI_READ_CAPACITY;
    438 
    439                 rc = scsi_cmd_data_in(io_base, i, aCDB, 10, buffer, 8);
     461                aCDB[0] = SCSI_SERVICE_ACT;
     462                aCDB[1] = SCSI_READ_CAP_16;
     463                aCDB[13] = 32; /* Allocation length. */
     464
     465                rc = scsi_cmd_data_in(io_base, i, aCDB, 16, buffer, 32);
    440466                if (rc != 0)
    441467                    BX_PANIC("%s: SCSI_READ_CAPACITY failed\n", __func__);
    442468
    443                 /* Build sector number and size from the buffer. */
    444                 //@todo: byte swapping for dword sized items should be farmed out...
    445                 sectors =   ((uint32_t)buffer[0] << 24)
    446                           | ((uint32_t)buffer[1] << 16)
    447                           | ((uint32_t)buffer[2] << 8)
    448                           | ((uint32_t)buffer[3]);
    449                 ++sectors;  /* Returned value is the last LBA, zero-based. */
    450 
    451                 sector_size =   ((uint32_t)buffer[4] << 24)
    452                               | ((uint32_t)buffer[5] << 16)
    453                               | ((uint32_t)buffer[6] << 8)
    454                               | ((uint32_t)buffer[7]);
     469                /* The value returned is the last addressable LBA, not
     470                 * the size, which what "+ 1" is for.
     471                 */
     472                sectors = swap_64(*(uint64_t *)buffer) + 1;
     473
     474                sector_size =   ((uint32_t)buffer[8] << 24)
     475                              | ((uint32_t)buffer[9] << 16)
     476                              | ((uint32_t)buffer[10] << 8)
     477                              | ((uint32_t)buffer[11]);
    455478
    456479                /* We only support the disk if sector size is 512 bytes. */
     
    497520                        heads = 255;
    498521                        sectors_per_track = 63;
     522                        /* Approximate x / (255 * 63) using shifts */
     523                        t = (sectors >> 6) + (sectors >> 12);
     524                        cylinders = (t >> 8) + (t >> 16);
    499525                    }
    500526                    else if (sectors >= (uint32_t)2 * 1024 * 1024)
     
    502528                        heads = 128;
    503529                        sectors_per_track = 32;
     530                        cylinders = sectors >> 12;
    504531                    }
    505532                    else
     
    507534                        heads = 64;
    508535                        sectors_per_track = 32;
     536                        cylinders = sectors >> 11;
    509537                    }
    510                     cylinders = (uint32_t)(sectors / (heads * sectors_per_track));
    511538                }
    512539
     
    523550                bios_dsk->devices[hd_index].translation = GEO_TRANSLATION_LBA;
    524551
    525                 /* Write LCHS values. */
     552                /* Write LCHS/PCHS values. */
    526553                bios_dsk->devices[hd_index].lchs.heads = heads;
    527554                bios_dsk->devices[hd_index].lchs.spt   = sectors_per_track;
    528                 if (cylinders > 1024)
    529                     bios_dsk->devices[hd_index].lchs.cylinders = 1024;
    530                 else
    531                     bios_dsk->devices[hd_index].lchs.cylinders = (uint16_t)cylinders;
    532 
    533                 BX_INFO("SCSI %d-ID#%d: LCHS=%u/%u/%u %lu sectors\n", devcount_scsi,
    534                         i, (uint16_t)cylinders, heads, sectors_per_track, sectors);
    535 
    536                 /* Write PCHS values. */
    537555                bios_dsk->devices[hd_index].pchs.heads = heads;
    538556                bios_dsk->devices[hd_index].pchs.spt   = sectors_per_track;
    539                 if (cylinders > 1024)
     557
     558                if (cylinders > 1024) {
     559                    bios_dsk->devices[hd_index].lchs.cylinders = 1024;
    540560                    bios_dsk->devices[hd_index].pchs.cylinders = 1024;
    541                 else
     561                } else {
     562                    bios_dsk->devices[hd_index].lchs.cylinders = (uint16_t)cylinders;
    542563                    bios_dsk->devices[hd_index].pchs.cylinders = (uint16_t)cylinders;
     564                }
     565
     566                BX_INFO("SCSI %d-ID#%d: LCHS=%lu/%u/%u 0x%llx sectors\n", devcount_scsi,
     567                        i, (uint32_t)cylinders, heads, sectors_per_track, sectors);
    543568
    544569                bios_dsk->devices[hd_index].sectors = sectors;
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