/** * 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"); } }
/** * 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); } }