summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/drivers/esp.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/drivers/esp.c')
-rw-r--r--qemu/roms/openbios/drivers/esp.c598
1 files changed, 0 insertions, 598 deletions
diff --git a/qemu/roms/openbios/drivers/esp.c b/qemu/roms/openbios/drivers/esp.c
deleted file mode 100644
index ad3db280d..000000000
--- a/qemu/roms/openbios/drivers/esp.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * OpenBIOS ESP driver
- *
- * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
- * Copyright (C) 2005 Stefan Reinauer <stepan@openbios.org>
- *
- * Credit goes to Hale Landis for his excellent ata demo software
- * OF node handling and some fixes by Stefan Reinauer
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2
- *
- */
-
-#include "config.h"
-#include "libopenbios/bindings.h"
-#include "kernel/kernel.h"
-#include "libc/byteorder.h"
-#include "libc/vsprintf.h"
-
-#include "drivers/drivers.h"
-#include "asm/io.h"
-#include "scsi.h"
-#include "asm/dma.h"
-#include "esp.h"
-#include "libopenbios/ofmem.h"
-
-#define BUFSIZE 4096
-
-#ifdef CONFIG_DEBUG_ESP
-#define DPRINTF(fmt, args...) \
- do { printk(fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-struct esp_dma {
- volatile struct sparc_dma_registers *regs;
- enum dvma_rev revision;
-};
-
-typedef struct sd_private {
- unsigned int bs;
- const char *media_str[2];
- uint32_t sectors;
- uint8_t media;
- uint8_t id;
- uint8_t present;
- char model[40];
-} sd_private_t;
-
-struct esp_regs {
- unsigned char regs[ESP_REG_SIZE];
-};
-
-typedef struct esp_private {
- volatile struct esp_regs *ll;
- uint32_t buffer_dvma;
- unsigned int irq; /* device IRQ number */
- struct esp_dma espdma;
- unsigned char *buffer;
- sd_private_t sd[8];
-} esp_private_t;
-
-static esp_private_t *global_esp;
-
-/* DECLARE data structures for the nodes. */
-DECLARE_UNNAMED_NODE(ob_sd, INSTALL_OPEN, sizeof(sd_private_t *));
-DECLARE_UNNAMED_NODE(ob_esp, INSTALL_OPEN, sizeof(esp_private_t *));
-
-#ifdef CONFIG_DEBUG_ESP
-static void dump_drive(sd_private_t *drive)
-{
- printk("SCSI DRIVE @%lx:\n", (unsigned long)drive);
- printk("id: %d\n", drive->id);
- printk("media: %s\n", drive->media_str[0]);
- printk("media: %s\n", drive->media_str[1]);
- printk("model: %s\n", drive->model);
- printk("sectors: %d\n", drive->sectors);
- printk("present: %d\n", drive->present);
- printk("bs: %d\n", drive->bs);
-}
-#endif
-
-static int
-do_command(esp_private_t *esp, sd_private_t *sd, int cmdlen, int replylen)
-{
- int status;
-
- // Set SCSI target
- esp->ll->regs[ESP_BUSID] = sd->id & 7;
- // Set DMA address
- esp->espdma.regs->st_addr = esp->buffer_dvma;
- // Set DMA length
- esp->ll->regs[ESP_TCLOW] = cmdlen & 0xff;
- esp->ll->regs[ESP_TCMED] = (cmdlen >> 8) & 0xff;
- // Set DMA direction and enable DMA
- esp->espdma.regs->cond_reg = DMA_ENABLE;
- // Set ATN, issue command
- esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA;
- // Wait for DMA to complete. Can this fail?
- while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */;
- // Check status
- status = esp->ll->regs[ESP_STATUS];
- // Clear interrupts to avoid guests seeing spurious interrupts
- (void)esp->ll->regs[ESP_INTRPT];
-
- DPRINTF("do_command: id %d, cmd[0] 0x%x, status 0x%x\n", sd->id, esp->buffer[1], status);
-
- /* Target didn't want all command data? */
- if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT) {
- return status;
- }
- if (replylen == 0) {
- return 0;
- }
- /* Target went to status phase instead of data phase? */
- if ((status & ESP_STAT_PMASK) == ESP_STATP) {
- return status;
- }
-
- // Get reply
- // Set DMA address
- esp->espdma.regs->st_addr = esp->buffer_dvma;
- // Set DMA length
- esp->ll->regs[ESP_TCLOW] = replylen & 0xff;
- esp->ll->regs[ESP_TCMED] = (replylen >> 8) & 0xff;
- // Set DMA direction
- esp->espdma.regs->cond_reg = DMA_ST_WRITE | DMA_ENABLE;
- // Transfer
- esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA;
- // Wait for DMA to complete
- while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */;
- // Check status
- status = esp->ll->regs[ESP_STATUS];
- // Clear interrupts to avoid guests seeing spurious interrupts
- (void)esp->ll->regs[ESP_INTRPT];
-
- DPRINTF("do_command_reply: status 0x%x\n", status);
-
- if ((status & ESP_STAT_TCNT) != ESP_STAT_TCNT)
- return status;
- else
- return 0; // OK
-}
-
-// offset is in sectors
-static int
-ob_sd_read_sector(esp_private_t *esp, sd_private_t *sd, int offset)
-{
- DPRINTF("ob_sd_read_sector id %d sector=%d\n",
- sd->id, offset);
-
- // Setup command = Read(10)
- memset(esp->buffer, 0, 11);
- esp->buffer[0] = 0x80;
- esp->buffer[1] = READ_10;
-
- esp->buffer[3] = (offset >> 24) & 0xff;
- esp->buffer[4] = (offset >> 16) & 0xff;
- esp->buffer[5] = (offset >> 8) & 0xff;
- esp->buffer[6] = offset & 0xff;
-
- esp->buffer[8] = 0;
- esp->buffer[9] = 1;
-
- if (do_command(esp, sd, 11, sd->bs))
- return 0;
-
- return 0;
-}
-
-static unsigned int
-read_capacity(esp_private_t *esp, sd_private_t *sd)
-{
- // Setup command = Read Capacity
- memset(esp->buffer, 0, 11);
- esp->buffer[0] = 0x80;
- esp->buffer[1] = READ_CAPACITY;
-
- if (do_command(esp, sd, 11, 8)) {
- sd->sectors = 0;
- sd->bs = 0;
- DPRINTF("read_capacity id %d failed\n", sd->id);
- return 0;
- }
- sd->bs = (esp->buffer[4] << 24) | (esp->buffer[5] << 16) | (esp->buffer[6] << 8) | esp->buffer[7];
- sd->sectors = ((esp->buffer[0] << 24) | (esp->buffer[1] << 16) | (esp->buffer[2] << 8) | esp->buffer[3]) * (sd->bs / 512);
-
- DPRINTF("read_capacity id %d bs %d sectors %d\n", sd->id, sd->bs,
- sd->sectors);
- return 1;
-}
-
-static unsigned int
-test_unit_ready(esp_private_t *esp, sd_private_t *sd)
-{
- /* Setup command = Test Unit Ready */
- memset(esp->buffer, 0, 7);
- esp->buffer[0] = 0x80;
- esp->buffer[1] = TEST_UNIT_READY;
-
- if (do_command(esp, sd, 7, 0)) {
- DPRINTF("test_unit_ready id %d failed\n", sd->id);
- return 0;
- }
-
- DPRINTF("test_unit_ready id %d success\n", sd->id);
- return 1;
-}
-
-static unsigned int
-inquiry(esp_private_t *esp, sd_private_t *sd)
-{
- const char *media[2] = { "UNKNOWN", "UNKNOWN"};
-
- // Setup command = Inquiry
- memset(esp->buffer, 0, 7);
- esp->buffer[0] = 0x80;
- esp->buffer[1] = INQUIRY;
-
- esp->buffer[5] = 36;
-
- if (do_command(esp, sd, 7, 36)) {
- sd->present = 0;
- sd->media = -1;
- return 0;
- }
- sd->present = 1;
- sd->media = esp->buffer[0];
-
- switch (sd->media) {
- case TYPE_DISK:
- media[0] = "disk";
- media[1] = "hd";
- break;
- case TYPE_ROM:
- media[0] = "cdrom";
- media[1] = "cd";
- break;
- }
- sd->media_str[0] = media[0];
- sd->media_str[1] = media[1];
- memcpy(sd->model, &esp->buffer[16], 16);
- sd->model[17] = '\0';
-
- return 1;
-}
-
-
-static void
-ob_sd_read_blocks(sd_private_t **sd)
-{
- cell n = POP(), cnt = n;
- ucell blk = POP();
- char *dest = (char*)POP();
- int pos, spb, sect_offset;
-
- DPRINTF("ob_sd_read_blocks id %d %lx block=%d n=%d\n", (*sd)->id, (unsigned long)dest, blk, n );
-
- if ((*sd)->bs == 0) {
- PUSH(0);
- return;
- }
- spb = (*sd)->bs / 512;
- while (n) {
- sect_offset = blk / spb;
- pos = (blk - sect_offset * spb) * 512;
-
- if (ob_sd_read_sector(global_esp, *sd, sect_offset)) {
- DPRINTF("ob_sd_read_blocks: error\n");
- RET(0);
- }
- while (n && pos < spb * 512) {
- memcpy(dest, global_esp->buffer + pos, 512);
- pos += 512;
- dest += 512;
- n--;
- blk++;
- }
- }
- PUSH(cnt);
-}
-
-static void
-ob_sd_block_size(__attribute__((unused))sd_private_t **sd)
-{
- PUSH(512);
-}
-
-static void
-ob_sd_open(__attribute__((unused))sd_private_t **sd)
-{
- int ret = 1, id;
- phandle_t ph;
-
- fword("my-unit");
- id = POP();
- POP(); // unit id is 2 ints but we only need one.
- *sd = &global_esp->sd[id];
-
-#ifdef CONFIG_DEBUG_ESP
- {
- char *args;
-
- fword("my-args");
- args = pop_fstr_copy();
- DPRINTF("opening drive %d args %s\n", id, args);
- free(args);
- }
-#endif
-
- selfword("open-deblocker");
-
- /* interpose disk-label */
- ph = find_dev("/packages/disk-label");
- fword("my-args");
- PUSH_ph( ph );
- fword("interpose");
-
- RET ( -ret );
-}
-
-static void
-ob_sd_close(__attribute__((unused)) sd_private_t **sd)
-{
- selfword("close-deblocker");
-}
-
-NODE_METHODS(ob_sd) = {
- { "open", ob_sd_open },
- { "close", ob_sd_close },
- { "read-blocks", ob_sd_read_blocks },
- { "block-size", ob_sd_block_size },
-};
-
-
-static int
-espdma_init(unsigned int slot, uint64_t base, unsigned long offset,
- struct esp_dma *espdma)
-{
- espdma->regs = (void *)ofmem_map_io(base + (uint64_t)offset, 0x10);
-
- if (espdma->regs == NULL) {
- DPRINTF("espdma_init: cannot map registers\n");
- return -1;
- }
-
- DPRINTF("dma1: ");
-
- switch ((espdma->regs->cond_reg) & DMA_DEVICE_ID) {
- case DMA_VERS0:
- espdma->revision = dvmarev0;
- DPRINTF("Revision 0 ");
- break;
- case DMA_ESCV1:
- espdma->revision = dvmaesc1;
- DPRINTF("ESC Revision 1 ");
- break;
- case DMA_VERS1:
- espdma->revision = dvmarev1;
- DPRINTF("Revision 1 ");
- break;
- case DMA_VERS2:
- espdma->revision = dvmarev2;
- DPRINTF("Revision 2 ");
- break;
- case DMA_VERHME:
- espdma->revision = dvmahme;
- DPRINTF("HME DVMA gate array ");
- break;
- case DMA_VERSPLUS:
- espdma->revision = dvmarevplus;
- DPRINTF("Revision 1 PLUS ");
- break;
- default:
- DPRINTF("unknown dma version %x",
- (espdma->regs->cond_reg) & DMA_DEVICE_ID);
- /* espdma->allocated = 1; */
- break;
- }
- DPRINTF("\n");
-
- push_str("/iommu/sbus/espdma");
- fword("find-device");
-
- /* set reg */
- PUSH(slot);
- fword("encode-int");
- PUSH(offset);
- fword("encode-int");
- fword("encode+");
- PUSH(0x00000010);
- fword("encode-int");
- fword("encode+");
- push_str("reg");
- fword("property");
-
- return 0;
-}
-
-static void
-ob_esp_initialize(__attribute__((unused)) esp_private_t **esp)
-{
- phandle_t ph = get_cur_dev();
-
- set_int_property(ph, "#address-cells", 2);
- set_int_property(ph, "#size-cells", 0);
-
- /* set device type */
- push_str("scsi");
- fword("device-type");
-
- /* QEMU's ESP emulation does not support mixing DMA and FIFO messages. By
- setting this attribute, we prevent the Solaris ESP kernel driver from
- trying to use this feature when booting a disk image (and failing) */
- PUSH(0x58);
- fword("encode-int");
- push_str("scsi-options");
- fword("property");
-
- PUSH(0x24);
- fword("encode-int");
- PUSH(0);
- fword("encode-int");
- fword("encode+");
- push_str("intr");
- fword("property");
-}
-
-static void
-ob_esp_decodeunit(__attribute__((unused)) esp_private_t **esp)
-{
- fword("decode-unit-scsi");
-}
-
-
-static void
-ob_esp_encodeunit(__attribute__((unused)) esp_private_t **esp)
-{
- fword("encode-unit-scsi");
-}
-
-NODE_METHODS(ob_esp) = {
- { NULL, ob_esp_initialize },
- { "decode-unit", ob_esp_decodeunit },
- { "encode-unit", ob_esp_encodeunit },
-};
-
-static void
-add_alias(const char *device, const char *alias)
-{
- DPRINTF("add_alias dev \"%s\" = alias \"%s\"\n", device, alias);
- push_str("/aliases");
- fword("find-device");
- push_str(device);
- fword("encode-string");
- push_str(alias);
- fword("property");
-}
-
-int
-ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset,
- unsigned long dmaoffset)
-{
- int id, diskcount = 0, cdcount = 0, *counter_ptr;
- char nodebuff[256], aliasbuff[256];
- esp_private_t *esp;
- unsigned int i;
-
- DPRINTF("Initializing SCSI...");
-
- esp = malloc(sizeof(esp_private_t));
- if (!esp) {
- DPRINTF("Can't allocate ESP private structure\n");
- return -1;
- }
-
- global_esp = esp;
-
- if (espdma_init(slot, base, dmaoffset, &esp->espdma) != 0) {
- return -1;
- }
- /* Get the IO region */
- esp->ll = (void *)ofmem_map_io(base + (uint64_t)espoffset,
- sizeof(struct esp_regs));
- if (esp->ll == NULL) {
- DPRINTF("Can't map ESP registers\n");
- return -1;
- }
-
- esp->buffer = (void *)dvma_alloc(BUFSIZE, &esp->buffer_dvma);
- if (!esp->buffer || !esp->buffer_dvma) {
- DPRINTF("Can't get a DVMA buffer\n");
- return -1;
- }
-
- // Chip reset
- esp->ll->regs[ESP_CMD] = ESP_CMD_RC;
-
- DPRINTF("ESP at 0x%lx, buffer va 0x%lx dva 0x%lx\n", (unsigned long)esp,
- (unsigned long)esp->buffer, (unsigned long)esp->buffer_dvma);
- DPRINTF("done\n");
- DPRINTF("Initializing SCSI devices...");
-
- for (id = 0; id < 8; id++) {
- esp->sd[id].id = id;
- if (!inquiry(esp, &esp->sd[id])) {
- DPRINTF("Unit %d not present\n", id);
- continue;
- }
- /* Clear Unit Attention condition from reset */
- for (i = 0; i < 5; i++) {
- if (test_unit_ready(esp, &esp->sd[id])) {
- break;
- }
- }
- if (i == 5) {
- DPRINTF("Unit %d present but won't become ready\n", id);
- continue;
- }
- DPRINTF("Unit %d present\n", id);
- read_capacity(esp, &esp->sd[id]);
-
-#ifdef CONFIG_DEBUG_ESP
- dump_drive(&esp->sd[id]);
-#endif
- }
-
- REGISTER_NAMED_NODE(ob_esp, "/iommu/sbus/espdma/esp");
- device_end();
- /* set reg */
- push_str("/iommu/sbus/espdma/esp");
- fword("find-device");
- PUSH(slot);
- fword("encode-int");
- PUSH(espoffset);
- fword("encode-int");
- fword("encode+");
- PUSH(0x00000010);
- fword("encode-int");
- fword("encode+");
- push_str("reg");
- fword("property");
-
- PUSH(0x02625a00);
- fword("encode-int");
- push_str("clock-frequency");
- fword("property");
-
- for (id = 0; id < 8; id++) {
- if (!esp->sd[id].present)
- continue;
- push_str("/iommu/sbus/espdma/esp");
- fword("find-device");
- fword("new-device");
- push_str("sd");
- fword("device-name");
- push_str("block");
- fword("device-type");
- fword("is-deblocker");
- PUSH(id);
- fword("encode-int");
- PUSH(0);
- fword("encode-int");
- fword("encode+");
- push_str("reg");
- fword("property");
- fword("finish-device");
- snprintf(nodebuff, sizeof(nodebuff), "/iommu/sbus/espdma/esp/sd@%d,0",
- id);
- REGISTER_NODE_METHODS(ob_sd, nodebuff);
- if (esp->sd[id].media == TYPE_ROM) {
- counter_ptr = &cdcount;
- } else {
- counter_ptr = &diskcount;
- }
- if (*counter_ptr == 0) {
- add_alias(nodebuff, esp->sd[id].media_str[0]);
- add_alias(nodebuff, esp->sd[id].media_str[1]);
- }
- snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
- esp->sd[id].media_str[0], *counter_ptr);
- add_alias(nodebuff, aliasbuff);
- snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
- esp->sd[id].media_str[1], *counter_ptr);
- add_alias(nodebuff, aliasbuff);
- snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)", id);
- add_alias(nodebuff, aliasbuff);
- snprintf(aliasbuff, sizeof(aliasbuff), "sd(0,%d,0)@0,0", id);
- add_alias(nodebuff, aliasbuff);
- (*counter_ptr)++;
- }
- DPRINTF("done\n");
-
- return 0;
-}