+ ASSERT16();
+ u8 type = GET_GLOBAL(op->drive_g->type);
+ switch (type) {
+ case DTYPE_FLOPPY:
+ return process_floppy_op(op);
+ case DTYPE_ATA:
+ return process_ata_op(op);
+ case DTYPE_ATAPI:
+ return process_atapi_op(op);
+ case DTYPE_RAMDISK:
+ return process_ramdisk_op(op);
+ case DTYPE_CDEMU:
+ return process_cdemu_op(op);
+ case DTYPE_USB:
+ return process_usb_op(op);
+ case DTYPE_VIRTIO:
+ return process_virtio_op(op);
+ case DTYPE_AHCI:
+ return process_ahci_op(op);
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+// Execute a "disk_op_s" request - this runs on a stack in the ebda.
+static int
+__send_disk_op(struct disk_op_s *op_far, u16 op_seg)
+{
+ struct disk_op_s dop;
+ memcpy_far(GET_SEG(SS), &dop
+ , op_seg, op_far
+ , sizeof(dop));
+
+ dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
+ , dop.drive_g, (u32)dop.lba, dop.buf_fl
+ , dop.count, dop.command);
+
+ int status = process_op(&dop);
+
+ // Update count with total sectors transferred.
+ SET_FARVAR(op_seg, op_far->count, dop.count);
+
+ return status;
+}
+
+// Execute a "disk_op_s" request by jumping to a stack in the ebda.
+int
+send_disk_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ if (! CONFIG_DRIVES)
+ return -1;
+
+ return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);