summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/src/block.c')
-rw-r--r--qemu/roms/seabios/src/block.c248
1 files changed, 147 insertions, 101 deletions
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; i<sizeof(param_far->iface_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));
}