Beispiel #1
0
/**
 * Init the SCSI driver and detect attached disks.
 */
void BIOSCALL scsi_init(void)
{
    uint8_t             identifier;
    bio_dsk_t __far     *bios_dsk;

    bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;

    bios_dsk->scsi_hdcount = 0;

    identifier = 0;

    /* Detect BusLogic adapter. */
    outb(BUSLOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
    identifier = inb(BUSLOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY);

    if (identifier == 0x55)
    {
        /* Detected - Enumerate attached devices. */
        VBSCSI_DEBUG("scsi_init: BusLogic SCSI adapter detected\n");
        outb(BUSLOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_RESET, 0);
        scsi_enumerate_attached_devices(BUSLOGIC_BIOS_IO_PORT);
    }
    else
    {
        VBSCSI_DEBUG("scsi_init: BusLogic SCSI adapter not detected\n");
    }

    /* Detect LsiLogic adapter. */
    outb(LSILOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
    identifier = inb(LSILOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY);

    if (identifier == 0x55)
    {
        /* Detected - Enumerate attached devices. */
        VBSCSI_DEBUG("scsi_init: LSI Logic SCSI adapter detected\n");
        outb(LSILOGIC_BIOS_IO_PORT+VBSCSI_REGISTER_RESET, 0);
        scsi_enumerate_attached_devices(LSILOGIC_BIOS_IO_PORT);
    }
    else
    {
        VBSCSI_DEBUG("scsi_init: LSI Logic SCSI adapter not detected\n");
    }

    /* Detect LsiLogic SAS adapter. */
    outb(LSILOGIC_SAS_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY, 0x55);
    identifier = inb(LSILOGIC_SAS_BIOS_IO_PORT+VBSCSI_REGISTER_IDENTIFY);

    if (identifier == 0x55)
    {
        /* Detected - Enumerate attached devices. */
        VBSCSI_DEBUG("scsi_init: LSI Logic SAS adapter detected\n");
        outb(LSILOGIC_SAS_BIOS_IO_PORT+VBSCSI_REGISTER_RESET, 0);
        scsi_enumerate_attached_devices(LSILOGIC_SAS_BIOS_IO_PORT);
    }
    else
    {
        VBSCSI_DEBUG("scsi_init: LSI Logic SAS adapter not detected\n");
    }
}
Beispiel #2
0
/**
 * Enumerate attached devices.
 *
 * @returns nothing.
 * @param   io_base    The I/O base port of the controller.
 */
void scsi_enumerate_attached_devices(uint16_t io_base)
{
    int                 i;
    uint8_t             buffer[0x0200];
    bio_dsk_t __far     *bios_dsk;

    bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;

        /* Go through target devices. */
        for (i = 0; i < VBSCSI_MAX_DEVICES; i++)
    {
        uint8_t     rc;
        uint8_t     aCDB[10];

        aCDB[0] = SCSI_INQUIRY;
        aCDB[1] = 0;
        aCDB[2] = 0;
        aCDB[3] = 0;
        aCDB[4] = 5; /* Allocation length. */
        aCDB[5] = 0;

        rc = scsi_cmd_data_in(io_base, i, aCDB, 6, buffer, 5);
        if (rc != 0)
            BX_PANIC("scsi_enumerate_attached_devices: SCSI_INQUIRY failed\n");

        /* Check if there is a disk attached. */
        if (   ((buffer[0] & 0xe0) == 0)
                && ((buffer[0] & 0x1f) == 0x00))
        {
            VBSCSI_DEBUG("scsi_enumerate_attached_devices: Disk detected at %d\n", i);

            /* We add the disk only if the maximum is not reached yet. */
            if (bios_dsk->scsi_hdcount < BX_MAX_SCSI_DEVICES)
            {
                uint32_t    sectors, sector_size, cylinders;
                uint16_t    heads, sectors_per_track;
                uint8_t     hdcount, hdcount_scsi, hd_index;

                /* Issue a read capacity command now. */
                _fmemset(aCDB, 0, sizeof(aCDB));
                aCDB[0] = SCSI_READ_CAPACITY;

                rc = scsi_cmd_data_in(io_base, i, aCDB, 10, buffer, 8);
                if (rc != 0)
                    BX_PANIC("scsi_enumerate_attached_devices: SCSI_READ_CAPACITY failed\n");

                /* Build sector number and size from the buffer. */
                //@todo: byte swapping for dword sized items should be farmed out...
                sectors =   ((uint32_t)buffer[0] << 24)
                            | ((uint32_t)buffer[1] << 16)
                            | ((uint32_t)buffer[2] << 8)
                            | ((uint32_t)buffer[3]);

                sector_size =   ((uint32_t)buffer[4] << 24)
                                | ((uint32_t)buffer[5] << 16)
                                | ((uint32_t)buffer[6] << 8)
                                | ((uint32_t)buffer[7]);

                /* We only support the disk if sector size is 512 bytes. */
                if (sector_size != 512)
                {
                    /* Leave a log entry. */
                    BX_INFO("Disk %d has an unsupported sector size of %u\n", i, sector_size);
                    continue;
                }

                /* We need to calculate the geometry for the disk. From
                 * the BusLogic driver in the Linux kernel.
                 */
                if (sectors >= (uint32_t)4 * 1024 * 1024)
                {
                    heads = 255;
                    sectors_per_track = 63;
                }
                else if (sectors >= (uint32_t)2 * 1024 * 1024)
                {
                    heads = 128;
                    sectors_per_track = 32;
                }
                else
                {
                    heads = 64;
                    sectors_per_track = 32;
                }
                cylinders = (uint32_t)(sectors / (heads * sectors_per_track));
                hdcount_scsi = bios_dsk->scsi_hdcount;

                /* Calculate index into the generic disk table. */
                hd_index = hdcount_scsi + BX_MAX_ATA_DEVICES;

                bios_dsk->scsidev[hdcount_scsi].io_base   = io_base;
                bios_dsk->scsidev[hdcount_scsi].target_id = i;
                bios_dsk->devices[hd_index].type        = DSK_TYPE_SCSI;
                bios_dsk->devices[hd_index].device      = DSK_DEVICE_HD;
                bios_dsk->devices[hd_index].removable   = 0;
                bios_dsk->devices[hd_index].lock        = 0;
                bios_dsk->devices[hd_index].blksize     = sector_size;
                bios_dsk->devices[hd_index].translation = GEO_TRANSLATION_LBA;

                /* Write LCHS values. */
                bios_dsk->devices[hd_index].lchs.heads = heads;
                bios_dsk->devices[hd_index].lchs.spt   = sectors_per_track;
                if (cylinders > 1024)
                    bios_dsk->devices[hd_index].lchs.cylinders = 1024;
                else
                    bios_dsk->devices[hd_index].lchs.cylinders = (uint16_t)cylinders;

                /* Write PCHS values. */
                bios_dsk->devices[hd_index].pchs.heads = heads;
                bios_dsk->devices[hd_index].pchs.spt   = sectors_per_track;
                if (cylinders > 1024)
                    bios_dsk->devices[hd_index].pchs.cylinders = 1024;
                else
                    bios_dsk->devices[hd_index].pchs.cylinders = (uint16_t)cylinders;

                bios_dsk->devices[hd_index].sectors = sectors;

                /* Store the id of the disk in the ata hdidmap. */
                hdcount = bios_dsk->hdcount;
                bios_dsk->hdidmap[hdcount] = hdcount_scsi + BX_MAX_ATA_DEVICES;
                hdcount++;
                bios_dsk->hdcount = hdcount;

                /* Update hdcount in the BDA. */
                hdcount = read_byte(0x40, 0x75);
                hdcount++;
                write_byte(0x40, 0x75, hdcount);

                hdcount_scsi++;
                bios_dsk->scsi_hdcount = hdcount_scsi;
            }
            else
            {
                /* We reached the maximum of SCSI disks we can boot from. We can quit detecting. */
                break;
            }
        }
        else
            VBSCSI_DEBUG("scsi_enumerate_attached_devices: No disk detected at %d\n", i);
    }
}