aboutsummaryrefslogtreecommitdiff
path: root/src/block.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-05-10 11:42:22 -0400
committerKevin O'Connor <kevin@koconnor.net>2014-06-04 11:06:58 -0400
commit39ca4988f88feb317015fbe79dc6f5e456876ad9 (patch)
tree14cf8726bac012b905d545ba254f68101f4de5cf /src/block.c
parentf9645c78faaf8cc4d4c6d46c023ccb22158f7f2c (diff)
downloadseabios-hppa-39ca4988f88feb317015fbe79dc6f5e456876ad9.zip
seabios-hppa-39ca4988f88feb317015fbe79dc6f5e456876ad9.tar.gz
seabios-hppa-39ca4988f88feb317015fbe79dc6f5e456876ad9.tar.bz2
edd: Move EDD get drive parameters (int 1348) logic from disk.c to block.c.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/block.c')
-rw-r--r--src/block.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/block.c b/src/block.c
index 264f376..c8cdf57 100644
--- a/src/block.c
+++ b/src/block.c
@@ -11,6 +11,7 @@
#include "hw/ata.h" // process_ata_op
#include "hw/ahci.h" // process_ahci_op
#include "hw/blockcmd.h" // cdb_*
+#include "hw/pci.h" // pci_bdf_to_bus
#include "hw/rtc.h" // rtc_read
#include "hw/virtio-blk.h" // process_virtio_blk_op
#include "malloc.h" // malloc_low
@@ -310,6 +311,184 @@ __disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
/****************************************************************
+ * Extended Disk Drive (EDD) get drive parameters
+ ****************************************************************/
+
+int noinline
+fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf)
+{
+ u16 size = GET_FARVAR(seg, param_far->size);
+ u16 t13 = size == 74;
+
+ // Buffer is too small
+ if (size < 26)
+ return DISK_RET_EPARAM;
+
+ // EDD 1.x
+
+ u8 type = GET_GLOBALFLAT(drive_gf->type);
+ u16 npc = GET_GLOBALFLAT(drive_gf->pchs.cylinder);
+ u16 nph = GET_GLOBALFLAT(drive_gf->pchs.head);
+ u16 nps = GET_GLOBALFLAT(drive_gf->pchs.sector);
+ u64 lba = GET_GLOBALFLAT(drive_gf->sectors);
+ u16 blksize = GET_GLOBALFLAT(drive_gf->blksize);
+
+ dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
+ , size, type, npc, nph, nps, (u32)lba, blksize);
+
+ SET_FARVAR(seg, param_far->size, 26);
+ if (type == DTYPE_ATA_ATAPI) {
+ // 0x74 = removable, media change, lockable, max values
+ SET_FARVAR(seg, param_far->infos, 0x74);
+ SET_FARVAR(seg, param_far->cylinders, 0xffffffff);
+ SET_FARVAR(seg, param_far->heads, 0xffffffff);
+ SET_FARVAR(seg, param_far->spt, 0xffffffff);
+ SET_FARVAR(seg, param_far->sector_count, (u64)-1);
+ } else {
+ if (lba > (u64)nps*nph*0x3fff) {
+ SET_FARVAR(seg, param_far->infos, 0x00); // geometry is invalid
+ SET_FARVAR(seg, param_far->cylinders, 0x3fff);
+ } else {
+ SET_FARVAR(seg, param_far->infos, 0x02); // geometry is valid
+ SET_FARVAR(seg, param_far->cylinders, (u32)npc);
+ }
+ SET_FARVAR(seg, param_far->heads, (u32)nph);
+ SET_FARVAR(seg, param_far->spt, (u32)nps);
+ SET_FARVAR(seg, param_far->sector_count, lba);
+ }
+ SET_FARVAR(seg, param_far->blksize, blksize);
+
+ if (size < 30 ||
+ (type != DTYPE_ATA && type != DTYPE_ATA_ATAPI &&
+ type != DTYPE_VIRTIO_BLK && type != DTYPE_VIRTIO_SCSI))
+ return DISK_RET_SUCCESS;
+
+ // EDD 2.x
+
+ int bdf;
+ u16 iobase1 = 0;
+ u64 device_path = 0;
+ u8 channel = 0;
+ SET_FARVAR(seg, param_far->size, 30);
+ if (type == DTYPE_ATA || type == DTYPE_ATA_ATAPI) {
+ SET_FARVAR(seg, param_far->dpte, SEGOFF(SEG_LOW, (u32)&DefaultDPTE));
+
+ // Fill in dpte
+ struct atadrive_s *adrive_gf = container_of(
+ drive_gf, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf);
+ u8 slave = GET_GLOBALFLAT(adrive_gf->slave);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ u8 irq = GET_GLOBALFLAT(chan_gf->irq);
+ iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
+ device_path = slave;
+ channel = GET_GLOBALFLAT(chan_gf->chanid);
+
+ u16 options = 0;
+ if (type == DTYPE_ATA) {
+ u8 translation = GET_GLOBALFLAT(drive_gf->translation);
+ if (translation != TRANSLATION_NONE) {
+ options |= 1<<3; // CHS translation
+ if (translation == TRANSLATION_LBA)
+ options |= 1<<9;
+ if (translation == TRANSLATION_RECHS)
+ options |= 3<<9;
+ }
+ } else {
+ // ATAPI
+ options |= 1<<5; // removable device
+ options |= 1<<6; // atapi device
+ }
+ options |= 1<<4; // lba translation
+ if (CONFIG_ATA_PIO32)
+ options |= 1<<7;
+
+ SET_LOW(DefaultDPTE.iobase1, iobase1);
+ SET_LOW(DefaultDPTE.iobase2, iobase2 + ATA_CB_DC);
+ SET_LOW(DefaultDPTE.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+ | ATA_CB_DH_LBA));
+ SET_LOW(DefaultDPTE.unused, 0xcb);
+ SET_LOW(DefaultDPTE.irq, irq);
+ SET_LOW(DefaultDPTE.blkcount, 1);
+ SET_LOW(DefaultDPTE.dma, 0);
+ SET_LOW(DefaultDPTE.pio, 0);
+ SET_LOW(DefaultDPTE.options, options);
+ SET_LOW(DefaultDPTE.reserved, 0);
+ SET_LOW(DefaultDPTE.revision, 0x11);
+
+ u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15);
+ SET_LOW(DefaultDPTE.checksum, -sum);
+ } else {
+ SET_FARVAR(seg, param_far->dpte.segoff, 0xffffffff);
+ bdf = GET_GLOBALFLAT(drive_gf->cntl_id);
+ }
+
+ if (size < 66)
+ return DISK_RET_SUCCESS;
+
+ // EDD 3.x
+ SET_FARVAR(seg, param_far->key, 0xbedd);
+ SET_FARVAR(seg, param_far->dpi_length, t13 ? 44 : 36);
+ SET_FARVAR(seg, param_far->reserved1, 0);
+ SET_FARVAR(seg, param_far->reserved2, 0);
+
+ 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, iobase1);
+ }
+
+ if (type != DTYPE_VIRTIO_BLK) {
+ SET_FARVAR(seg, param_far->iface_type[0], 'A');
+ SET_FARVAR(seg, param_far->iface_type[1], 'T');
+ SET_FARVAR(seg, param_far->iface_type[2], 'A');
+ SET_FARVAR(seg, param_far->iface_type[3], ' ');
+ } else {
+ SET_FARVAR(seg, param_far->iface_type[0], 'S');
+ SET_FARVAR(seg, param_far->iface_type[1], 'C');
+ SET_FARVAR(seg, param_far->iface_type[2], 'S');
+ SET_FARVAR(seg, param_far->iface_type[3], 'I');
+ }
+ SET_FARVAR(seg, param_far->iface_type[4], ' ');
+ SET_FARVAR(seg, param_far->iface_type[5], ' ');
+ SET_FARVAR(seg, param_far->iface_type[6], ' ');
+ SET_FARVAR(seg, param_far->iface_type[7], ' ');
+
+ if (t13) {
+ SET_FARVAR(seg, param_far->t13.device_path[0], device_path);
+ SET_FARVAR(seg, param_far->t13.device_path[1], 0);
+
+ SET_FARVAR(seg, param_far->t13.checksum
+ , -checksum_far(seg, (void*)param_far+30, 43));
+ } else {
+ SET_FARVAR(seg, param_far->phoenix.device_path, device_path);
+
+ SET_FARVAR(seg, param_far->phoenix.checksum
+ , -checksum_far(seg, (void*)param_far+30, 35));
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
* 16bit calling interface
****************************************************************/