X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fseabios%2Fsrc%2Fblock.c;h=1762e2a33f9160bc633d5528365dd41749643416;hb=a14b48d18a9ed03ec191cf16b162206998a895ce;hp=3f7ecb1d762d0c6d16f5c3cdbc4a6c033fee93e2;hpb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;p=kvmfornfv.git diff --git a/qemu/roms/seabios/src/block.c b/qemu/roms/seabios/src/block.c index 3f7ecb1d7..1762e2a33 100644 --- a/qemu/roms/seabios/src/block.c +++ b/qemu/roms/seabios/src/block.c @@ -10,9 +10,16 @@ #include "hw/ata.h" // process_ata_op #include "hw/ahci.h" // process_ahci_op #include "hw/blockcmd.h" // cdb_* +#include "hw/esp-scsi.h" // esp_scsi_process_op +#include "hw/lsi-scsi.h" // lsi_scsi_process_op +#include "hw/megasas.h" // megasas_process_op #include "hw/pci.h" // pci_bdf_to_bus +#include "hw/pvscsi.h" // pvscsi_process_op #include "hw/rtc.h" // rtc_read +#include "hw/usb-msc.h" // usb_process_op +#include "hw/usb-uas.h" // uas_process_op #include "hw/virtio-blk.h" // process_virtio_blk_op +#include "hw/virtio-scsi.h" // virtio_scsi_process_op #include "malloc.h" // malloc_low #include "output.h" // dprintf #include "stacks.h" // stack_hop @@ -67,10 +74,8 @@ get_translation(struct drive_s *drive) u8 type = drive->type; if (CONFIG_QEMU && type == DTYPE_ATA) { // Emulators pass in the translation info via nvram. - u8 ataid = drive->cntl_id; - u8 channel = ataid / 2; - u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2); - translation >>= 2 * (ataid % 4); + u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4); + translation >>= 2 * (drive->cntl_id % 4); translation &= 0x03; return translation; } @@ -282,11 +287,21 @@ map_floppy_drive(struct drive_s *drive) * Extended Disk Drive (EDD) get drive parameters ****************************************************************/ +// flags for bus_iface field in fill_generic_edd() +#define EDD_ISA 0x01 +#define EDD_PCI 0x02 +#define EDD_BUS_MASK 0x0f +#define EDD_ATA 0x10 +#define EDD_SCSI 0x20 +#define EDD_IFACE_MASK 0xf0 + +// Fill in EDD info static int -fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf - , u32 dpte_so, char *iface_type - , int bdf, u8 channel, u16 iobase, u64 device_path) +fill_generic_edd(struct segoff_s edd, struct drive_s *drive_gf + , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path) { + u16 seg = edd.seg; + struct int13dpt_s *param_far = (void*)(edd.offset+0); u16 size = GET_FARVAR(seg, param_far->size); u16 t13 = size == 74; @@ -335,7 +350,7 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf SET_FARVAR(seg, param_far->size, 30); SET_FARVAR(seg, param_far->dpte.segoff, dpte_so); - if (size < 66 || !iface_type) + if (size < 66 || !bus_iface) return DISK_RET_SUCCESS; // EDD 3.x @@ -344,32 +359,22 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf SET_FARVAR(seg, param_far->reserved1, 0); SET_FARVAR(seg, param_far->reserved2, 0); - int i; - for (i=0; iiface_type); i++) - SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i])); - - if (bdf != -1) { - SET_FARVAR(seg, param_far->host_bus[0], 'P'); - SET_FARVAR(seg, param_far->host_bus[1], 'C'); - SET_FARVAR(seg, param_far->host_bus[2], 'I'); - SET_FARVAR(seg, param_far->host_bus[3], ' '); - - u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) - | (pci_bdf_to_fn(bdf) << 16)); - if (t13) - path |= channel << 24; - - SET_FARVAR(seg, param_far->iface_path, path); - } else { - // ISA - SET_FARVAR(seg, param_far->host_bus[0], 'I'); - SET_FARVAR(seg, param_far->host_bus[1], 'S'); - SET_FARVAR(seg, param_far->host_bus[2], 'A'); - SET_FARVAR(seg, param_far->host_bus[3], ' '); - - SET_FARVAR(seg, param_far->iface_path, iobase); + const char *host_bus = "ISA "; + if ((bus_iface & EDD_BUS_MASK) == EDD_PCI) { + host_bus = "PCI "; + if (!t13) + // Phoenix v3 spec (pre t13) did not define the PCI channel field + iface_path &= 0x00ffffff; } - + memcpy_far(seg, param_far->host_bus, SEG_BIOS, host_bus + , sizeof(param_far->host_bus)); + SET_FARVAR(seg, param_far->iface_path, iface_path); + + const char *iface_type = "ATA "; + if ((bus_iface & EDD_IFACE_MASK) == EDD_SCSI) + iface_type = "SCSI "; + memcpy_far(seg, param_far->iface_type, SEG_BIOS, iface_type + , sizeof(param_far->iface_type)); if (t13) { SET_FARVAR(seg, param_far->t13.device_path[0], device_path); SET_FARVAR(seg, param_far->t13.device_path[1], 0); @@ -386,10 +391,19 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf return DISK_RET_SUCCESS; } +// Build an EDD "iface_path" field for a PCI device +static u32 +edd_pci_path(u16 bdf, u8 channel) +{ + return (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) + | (pci_bdf_to_fn(bdf) << 16) | ((u32)channel << 24)); +} + struct dpte_s DefaultDPTE VARLOW; +// EDD info for ATA and ATAPI drives static int -fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) +fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf) { if (!CONFIG_ATA) return DISK_RET_EPARAM; @@ -440,109 +454,141 @@ fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15); SET_LOW(DefaultDPTE.checksum, -sum); + u32 bustype = EDD_ISA, ifpath = iobase1; + if (bdf >= 0) { + bustype = EDD_PCI; + ifpath = edd_pci_path(bdf, channel); + } return fill_generic_edd( - seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff - , "ATA ", bdf, channel, iobase1, slave); + edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff + , bustype | EDD_ATA, ifpath, slave); } +// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive int noinline -fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) +fill_edd(struct segoff_s edd, struct drive_s *drive_gf) { switch (GET_GLOBALFLAT(drive_gf->type)) { case DTYPE_ATA: case DTYPE_ATA_ATAPI: - return fill_ata_edd(seg, param_far, drive_gf); + return fill_ata_edd(edd, drive_gf); case DTYPE_VIRTIO_BLK: case DTYPE_VIRTIO_SCSI: return fill_generic_edd( - seg, param_far, drive_gf, 0xffffffff - , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0); + edd, drive_gf, 0xffffffff, EDD_PCI | EDD_SCSI + , edd_pci_path(GET_GLOBALFLAT(drive_gf->cntl_id), 0), 0); default: - return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0); + return fill_generic_edd(edd, drive_gf, 0, 0, 0, 0); } } /**************************************************************** - * 16bit calling interface + * Disk driver dispatch ****************************************************************/ -int VISIBLE32FLAT -process_atapi_op(struct disk_op_s *op) +// Fallback handler for command requests not implemented by drivers +int +default_process_op(struct disk_op_s *op) { switch (op->command) { - case CMD_WRITE: case CMD_FORMAT: - return DISK_RET_EWRITEPROTECT; + case CMD_RESET: + case CMD_ISREADY: + case CMD_VERIFY: + case CMD_SEEK: + // Return success if the driver doesn't implement these commands + return DISK_RET_SUCCESS; default: - return scsi_process_op(op); + return DISK_RET_EPARAM; } } -// Execute a disk_op request. -int -process_op(struct disk_op_s *op) +// Command dispatch for disk drivers that run in both 16bit and 32bit mode +static int +process_op_both(struct disk_op_s *op) { - ASSERT16(); - int ret, origcount = op->count; - if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) { - op->count = 0; - return DISK_RET_EBOUNDARY; - } - u8 type = GET_GLOBALFLAT(op->drive_gf->type); - switch (type) { - case DTYPE_FLOPPY: - ret = process_floppy_op(op); - break; - case DTYPE_ATA: - ret = process_ata_op(op); - break; - case DTYPE_RAMDISK: - ret = process_ramdisk_op(op); - break; - case DTYPE_CDEMU: - ret = process_cdemu_op(op); - break; - case DTYPE_VIRTIO_BLK: - ret = process_virtio_blk_op(op); - break; - case DTYPE_AHCI: ; - extern void _cfunc32flat_process_ahci_op(void); - ret = call32(_cfunc32flat_process_ahci_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + switch (GET_GLOBALFLAT(op->drive_gf->type)) { case DTYPE_ATA_ATAPI: - ret = process_atapi_op(op); - break; - case DTYPE_AHCI_ATAPI: ; - extern void _cfunc32flat_process_atapi_op(void); - ret = call32(_cfunc32flat_process_atapi_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; - case DTYPE_SDCARD: ; - extern void _cfunc32flat_process_sdcard_op(void); - ret = call32(_cfunc32flat_process_sdcard_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + return ata_atapi_process_op(op); case DTYPE_USB: + return usb_process_op(op); case DTYPE_UAS: - case DTYPE_VIRTIO_SCSI: + return uas_process_op(op); case DTYPE_LSI_SCSI: + return lsi_scsi_process_op(op); case DTYPE_ESP_SCSI: + return esp_scsi_process_op(op); case DTYPE_MEGASAS: - ret = scsi_process_op(op); - break; + return megasas_process_op(op); + default: + if (!MODESEGMENT) + return DISK_RET_EPARAM; + // In 16bit mode and driver not found - try in 32bit mode + return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op) + , DISK_RET_EPARAM); + } +} + +// Command dispatch for disk drivers that only run in 32bit mode +int VISIBLE32FLAT +process_op_32(struct disk_op_s *op) +{ + ASSERT32FLAT(); + switch (op->drive_gf->type) { + case DTYPE_VIRTIO_BLK: + return virtio_blk_process_op(op); + case DTYPE_AHCI: + return ahci_process_op(op); + case DTYPE_AHCI_ATAPI: + return ahci_atapi_process_op(op); + case DTYPE_SDCARD: + return sdcard_process_op(op); case DTYPE_USB_32: + return usb_process_op(op); case DTYPE_UAS_32: - case DTYPE_PVSCSI: ; - extern void _cfunc32flat_scsi_process_op(void); - ret = call32(_cfunc32flat_scsi_process_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + return uas_process_op(op); + case DTYPE_VIRTIO_SCSI: + return virtio_scsi_process_op(op); + case DTYPE_PVSCSI: + return pvscsi_process_op(op); default: - ret = DISK_RET_EPARAM; - break; + return process_op_both(op); } +} + +// Command dispatch for disk drivers that only run in 16bit mode +static int +process_op_16(struct disk_op_s *op) +{ + ASSERT16(); + switch (GET_GLOBALFLAT(op->drive_gf->type)) { + case DTYPE_FLOPPY: + return floppy_process_op(op); + case DTYPE_ATA: + return ata_process_op(op); + case DTYPE_RAMDISK: + return ramdisk_process_op(op); + case DTYPE_CDEMU: + return cdemu_process_op(op); + default: + return process_op_both(op); + } +} + +// Execute a disk_op_s request. +int +process_op(struct disk_op_s *op) +{ + int ret, origcount = op->count; + if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) { + op->count = 0; + return DISK_RET_EBOUNDARY; + } + if (MODESEGMENT) + ret = process_op_16(op); + else + ret = process_op_32(op); if (ret && op->count == origcount) // If the count hasn't changed on error, assume no data transferred. op->count = 0; @@ -578,5 +624,5 @@ send_disk_op(struct disk_op_s *op) if (! CONFIG_DRIVES) return -1; - return stack_hop((u32)op, GET_SEG(SS), __send_disk_op); + return stack_hop(__send_disk_op, op, GET_SEG(SS)); }