These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / src / block.c
index 3f7ecb1..1762e2a 100644 (file)
 #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));
 }