[OpenBIOS] [PATCH 06/11] pci: add driver for LSI 53C810 SCSI controller

Mark Cave-Ayland mark.cave-ayland at ilande.co.uk
Sat May 26 21:29:51 CEST 2018


This is to enable booting PReP machines in OpenBIOS.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
---
 config/examples/ppc_config.xml |   1 +
 drivers/build.xml              |   1 +
 drivers/lsi.c                  | 770 +++++++++++++++++++++++++++++++++++++++++
 drivers/pci.c                  |  19 +
 drivers/pci_database.c         |   8 +
 drivers/pci_database.h         |   1 +
 include/drivers/drivers.h      |   4 +
 include/drivers/pci.h          |   3 +
 8 files changed, 807 insertions(+)
 create mode 100644 drivers/lsi.c

diff --git a/config/examples/ppc_config.xml b/config/examples/ppc_config.xml
index 4c14eb6..0ac3817 100644
--- a/config/examples/ppc_config.xml
+++ b/config/examples/ppc_config.xml
@@ -83,3 +83,4 @@
   <option name="CONFIG_DRIVER_USB" type="boolean" value="true"/>
   <option name="CONFIG_DEBUG_USB" type="boolean" value="false"/>
   <option name="CONFIG_USB_HID" type="boolean" value="true"/>
+  <option name="CONFIG_DRIVER_LSI_53C810" type="boolean" value="true"/>
diff --git a/drivers/build.xml b/drivers/build.xml
index bd1abd3..de84e38 100644
--- a/drivers/build.xml
+++ b/drivers/build.xml
@@ -26,6 +26,7 @@
   <object source="usbhid.c" condition="USB_HID"/>
   <object source="usbohci.c" condition="DRIVER_USB"/>
   <object source="usbohci_rh.c" condition="DRIVER_USB"/>
+  <object source="lsi.c" condition="DRIVER_LSI_53C810"/>
  </library>
 
  <dictionary name="openbios" target="forth">
diff --git a/drivers/lsi.c b/drivers/lsi.c
new file mode 100644
index 0000000..1f3f038
--- /dev/null
+++ b/drivers/lsi.c
@@ -0,0 +1,770 @@
+/*
+ *   OpenBIOS LSI driver
+ *
+ *   Copyright (C) 2018 Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
+ *
+ *   Based upon drivers/esp.c
+ *
+ *   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 "libc/byteorder.h"
+#include "libc/vsprintf.h"
+#include "libopenbios/bindings.h"
+#include "drivers/drivers.h"
+#include "scsi.h"
+
+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;
+
+typedef struct lsi_table {
+    uint32_t id;
+    uint32_t id_addr;
+    uint32_t msg_out_len;
+    uint32_t msg_out_ptr;
+    uint32_t cmd_len;
+    uint32_t cmd_ptr;
+    uint32_t data_in_len;
+    uint32_t data_in_ptr;
+    uint32_t status_len;
+    uint32_t status_ptr;
+    uint32_t msg_in_len;
+    uint32_t msg_in_ptr;
+} lsi_table_t;
+
+typedef struct lsi_private {
+    volatile uint8_t *mmio;
+    uint32_t *scripts;
+    uint32_t *scripts_iova;
+    lsi_table_t *table;
+    lsi_table_t *table_iova;
+    volatile uint8_t *buffer;
+    volatile uint8_t *buffer_iova;
+    sd_private_t sd[8];
+} lsi_private_t;
+
+static lsi_private_t *global_lsi;
+
+#ifdef CONFIG_DEBUG_LSI
+#define DPRINTF(fmt, args...)                   \
+    do { printk(fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+/* DECLARE data structures for the nodes.  */
+DECLARE_UNNAMED_NODE(ob_sd, INSTALL_OPEN, sizeof(sd_private_t *));
+DECLARE_UNNAMED_NODE(ob_lsi, INSTALL_OPEN, sizeof(lsi_private_t **));
+
+#ifdef CONFIG_DEBUG_LSI
+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
+
+#define PHASE_DO          0
+#define PHASE_DI          1
+#define PHASE_CMD         2
+#define PHASE_ST          3
+#define PHASE_MO          6
+#define PHASE_MI          7
+
+#define LSI_DSTAT         0x0c
+#define LSI_DSA           0x10
+#define LSI_ISTAT0        0x14
+#define LSI_DSP           0x2c
+#define LSI_SIST0         0x42
+#define LSI_SIST1         0x43
+
+#define LSI_ISTAT0_DIP    0x01
+#define LSI_ISTAT0_SIP    0x02
+
+/* Indirection table */
+#define LSI_TABLE_OFFSET(x)  (((uintptr_t)&(x)) - ((uintptr_t)lsi->table))
+
+#define LSI_TABLE_MSG_OUT_OFFSET   0x0
+#define LSI_TABLE_CMD_OFFSET       0x2
+#define LSI_TABLE_DATA_OFFSET      0x20
+#define LSI_TABLE_STATUS_OFFSET    0x10
+#define LSI_TABLE_MSG_IN_OFFSET    0x12
+
+static void
+init_scripts(lsi_private_t *lsi)
+{
+    /* Initialise SCRIPTS for the commands we are interested in */
+
+    /* 1 - INQUIRY / READ CAPACITY */
+    
+    /* 1.0 Select with ATN */
+    lsi->scripts[0x0] = __cpu_to_le32(0x47000000);
+    lsi->scripts[0x1] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 1.1 Select LUN */    
+    lsi->scripts[0x2] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24));
+    lsi->scripts[0x3] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len));
+
+    /* 1.2 Send command */
+    lsi->scripts[0x4] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24));
+    lsi->scripts[0x5] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len));
+
+    /* 1.3 Data in */
+    lsi->scripts[0x6] = __cpu_to_le32(0x10000000 | (PHASE_DI << 24));
+    lsi->scripts[0x7] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->data_in_len));
+
+    /* 1.4 Status */
+    lsi->scripts[0x8] = __cpu_to_le32(0x10000000 | (PHASE_ST << 24));
+    lsi->scripts[0x9] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->status_len));
+
+    /* 1.5 Message in */
+    lsi->scripts[0xa] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24));
+    lsi->scripts[0xb] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len));
+    
+    /* 1.6 Wait disconnect */
+    lsi->scripts[0xc] = __cpu_to_le32(0x48000000);
+    lsi->scripts[0xd] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 1.7 Interrupt */
+    lsi->scripts[0xe] = __cpu_to_le32(0x98080000);
+    lsi->scripts[0xf] = 0x0;
+    
+    
+    /* 2 - TEST UNIT READY */
+    
+    /* 2.0 Select with ATN */
+    lsi->scripts[0x10] = __cpu_to_le32(0x47000000);
+    lsi->scripts[0x11] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 2.1 Select LUN */    
+    lsi->scripts[0x12] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24));
+    lsi->scripts[0x13] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len));
+
+    /* 2.2 Send command */
+    lsi->scripts[0x14] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24));
+    lsi->scripts[0x15] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len));
+
+    /* 2.3 Status */
+    lsi->scripts[0x16] = __cpu_to_le32(0x10000000 | (PHASE_ST << 24));
+    lsi->scripts[0x17] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->status_len));
+
+    /* 2.4 Message in */
+    lsi->scripts[0x18] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24));
+    lsi->scripts[0x19] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len));
+    
+    /* 2.5 Wait disconnect */
+    lsi->scripts[0x1a] = __cpu_to_le32(0x48000000);
+    lsi->scripts[0x1b] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+    
+    /* 2.6 Interrupt */
+    lsi->scripts[0x1c] = __cpu_to_le32(0x98080000);
+    lsi->scripts[0x1d] = 0x0;
+    
+    
+    /* 3 - READ 10 */
+    
+    /* 3.0 Select with ATN */
+    lsi->scripts[0x20] = __cpu_to_le32(0x47000000);
+    lsi->scripts[0x21] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 3.1 Select LUN */    
+    lsi->scripts[0x22] = __cpu_to_le32(0x10000000 | (PHASE_MO << 24));
+    lsi->scripts[0x23] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_out_len));
+
+    /* 3.2 Send command */
+    lsi->scripts[0x24] = __cpu_to_le32(0x10000000 | (PHASE_CMD << 24));
+    lsi->scripts[0x25] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->cmd_len));
+
+    /* 3.3 Message in */
+    lsi->scripts[0x26] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24));
+    lsi->scripts[0x27] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len));
+        
+    /* 3.6 Interrupt */
+    lsi->scripts[0x28] = __cpu_to_le32(0x98080000);
+    lsi->scripts[0x29] = 0x0;
+
+    /* 3.7 Wait reselect */    
+    lsi->scripts[0x2a] = __cpu_to_le32(0x50000000);
+    lsi->scripts[0x2b] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 3.8 Message in */
+    lsi->scripts[0x2c] = __cpu_to_le32(0x10000000 | (PHASE_MI << 24));
+    lsi->scripts[0x2d] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->msg_in_len));
+        
+    /* 3.9 Data in */
+    lsi->scripts[0x2e] = __cpu_to_le32(0x10000000 | (PHASE_DI << 24));
+    lsi->scripts[0x2f] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->data_in_len));
+    
+    /* 3.10 Wait disconnect */
+    lsi->scripts[0x30] = __cpu_to_le32(0x48000000);
+    lsi->scripts[0x31] = __cpu_to_le32(LSI_TABLE_OFFSET(lsi->table->id));
+
+    /* 3.11 Interrupt */
+    lsi->scripts[0x32] = __cpu_to_le32(0x98080000);
+    lsi->scripts[0x33] = 0x0;
+}
+
+static void
+init_table(lsi_private_t *lsi)
+{
+    uint32_t dsa;
+
+    /* Initialise indirect table */
+    lsi->table->msg_out_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_MSG_OUT_OFFSET]);
+    lsi->table->cmd_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_CMD_OFFSET]);
+    lsi->table->data_in_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_DATA_OFFSET]);
+    lsi->table->status_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_STATUS_OFFSET]);
+    lsi->table->msg_in_ptr = __cpu_to_le32((uintptr_t)&lsi->buffer_iova[LSI_TABLE_MSG_IN_OFFSET]);
+    
+    /* Set the DSA to point to the base of our data table */
+    dsa = (uintptr_t)lsi->table_iova;
+    lsi->mmio[LSI_DSA] = dsa & 0xff;
+    lsi->mmio[LSI_DSA + 1] = (dsa >> 8) & 0xff;
+    lsi->mmio[LSI_DSA + 2] = (dsa >> 16) & 0xff;
+    lsi->mmio[LSI_DSA + 3] = (dsa >> 24) & 0xff;
+}
+
+static unsigned int
+lsi_interrupt_status(lsi_private_t *lsi)
+{
+    uint32_t istat, sist0, sist1, dstat;
+    
+    /* Wait for interrupt status */
+    while ((istat = lsi->mmio[LSI_ISTAT0]) == 0);
+
+    if (istat & LSI_ISTAT0_SIP) {
+        /* If SCSI interrupt, clear SCSI interrupt registers */
+        sist0 = lsi->mmio[LSI_SIST0];
+        sist1 = lsi->mmio[LSI_SIST1];
+        
+        if (sist0 != 0 || sist1 != 0) {
+            return 1;
+        }
+    }
+    
+    if (istat & LSI_ISTAT0_DIP) {
+        /* If DMA interrupt, clear DMA interrupt register */
+        dstat = lsi->mmio[LSI_DSTAT];
+        
+        if ((dstat & 0x7f) != 0x4) {
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+static unsigned int
+inquiry(lsi_private_t *lsi, sd_private_t *sd)
+{
+    const char *media[2] = { "UNKNOWN", "UNKNOWN"};
+    uint8_t *buffer;
+
+    // Setup command = Inquiry
+    memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 7);
+    lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80;
+    lsi->table->msg_out_len = __cpu_to_le32(0x1);
+    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET] = INQUIRY;
+    lsi->table->cmd_len = __cpu_to_le32(0x6);
+    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 4] = 36;
+    lsi->table->data_in_len = __cpu_to_le32(36);
+
+    lsi->table->status_len = __cpu_to_le32(0x1);
+    lsi->table->msg_in_len = __cpu_to_le32(0x1);
+    
+    lsi->table->id = __cpu_to_le32((sd->id << 16));
+    lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x2]);
+    
+    /* Write DSP to start DMA engine */    
+    uint32_t dsp = (uintptr_t)lsi->scripts_iova;
+    lsi->mmio[LSI_DSP] = dsp & 0xff;
+    lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff;
+    lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff;
+    lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff;
+    
+    if (lsi_interrupt_status(lsi)) {
+        sd->present = 0;
+        sd->media = -1;
+        return 0;
+    }
+
+    buffer = (uint8_t *)&lsi->buffer[LSI_TABLE_DATA_OFFSET];
+    sd->present = 1;
+    sd->media = 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, &buffer[16], 16);
+    sd->model[17] = '\0';
+
+    return 1;
+}
+
+static unsigned int
+read_capacity(lsi_private_t *lsi, sd_private_t *sd)
+{
+    uint8_t *buffer;
+    
+    // Setup command = Read Capacity    
+    memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 11);
+    lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80;
+    lsi->table->msg_out_len = __cpu_to_le32(0x1);
+    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET] = READ_CAPACITY;
+    lsi->table->cmd_len = __cpu_to_le32(0x11);
+    
+    lsi->table->data_in_len = __cpu_to_le32(0x8);
+
+    lsi->table->status_len = __cpu_to_le32(0x1);
+    lsi->table->msg_in_len = __cpu_to_le32(0x1);
+    
+    lsi->table->id = __cpu_to_le32((sd->id << 16));
+    lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x2]);
+    
+    /* Write DSP to start DMA engine */    
+    uint32_t dsp = (uintptr_t)lsi->scripts_iova;
+    lsi->mmio[LSI_DSP] = dsp & 0xff;
+    lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff;
+    lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff;
+    lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff;
+
+    if (lsi_interrupt_status(lsi)) {
+        sd->sectors = 0;
+        sd->bs = 0;
+        DPRINTF("read_capacity id %d failed\n", sd->id);
+        return 0;
+    }
+    
+    buffer = (uint8_t *)&lsi->buffer[LSI_TABLE_DATA_OFFSET];
+    sd->bs = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+    sd->sectors = ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | 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(lsi_private_t *lsi, sd_private_t *sd)
+{
+    /* Setup command = Test Unit Ready */
+    memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 7);
+    lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80;
+    lsi->table->msg_out_len = __cpu_to_le32(0x1);
+    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET] = TEST_UNIT_READY;
+    lsi->table->cmd_len = __cpu_to_le32(0x6);
+
+    lsi->table->status_len = __cpu_to_le32(0x1);
+    lsi->table->msg_in_len = __cpu_to_le32(0x1);
+
+    lsi->table->id = __cpu_to_le32((sd->id << 16));
+    lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x12]);
+
+    /* Write DSP to start DMA engine */    
+    uint32_t dsp = (uintptr_t)&lsi->scripts_iova[0x10];
+    lsi->mmio[LSI_DSP] = dsp & 0xff;
+    lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff;
+    lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff;
+    lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff;
+
+    if (lsi_interrupt_status(lsi)) {
+        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 void
+ob_lsi_dma_alloc(__attribute__((unused)) lsi_private_t **lsi)
+{
+    call_parent_method("dma-alloc");
+}
+
+static void
+ob_lsi_dma_free(__attribute__((unused)) lsi_private_t **lsi)
+{
+    call_parent_method("dma-free");
+}
+
+static void
+ob_lsi_dma_map_in(__attribute__((unused)) lsi_private_t **lsi)
+{
+    call_parent_method("dma-map-in");
+}
+
+static void
+ob_lsi_dma_map_out(__attribute__((unused)) lsi_private_t **lsi)
+{
+    call_parent_method("dma-map-out");
+}
+
+static void
+ob_lsi_dma_sync(__attribute__((unused)) lsi_private_t **lsi)
+{
+    call_parent_method("dma-sync");
+}
+
+// offset is in sectors
+static int
+ob_sd_read_sector(lsi_private_t *lsi, sd_private_t *sd, int offset)
+{
+    uint32_t dsp;
+
+    DPRINTF("ob_sd_read_sector id %d sector=%d\n",
+            sd->id, offset);
+
+    // Setup command = Read(10)
+    memset((uint8_t *)&lsi->buffer[LSI_TABLE_CMD_OFFSET], 0, 10);
+    lsi->buffer[LSI_TABLE_MSG_OUT_OFFSET] = 0x80;
+    lsi->table->msg_out_len = __cpu_to_le32(0x1);
+    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET] = READ_10;    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 2] = (offset >> 24) & 0xff;
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 3] = (offset >> 16) & 0xff;;    
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 4] = (offset >> 8) & 0xff;
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 5] = offset & 0xff;
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 7] = 0;
+    lsi->buffer[LSI_TABLE_CMD_OFFSET + 8] = 1;
+    lsi->table->cmd_len = __cpu_to_le32(0xa);
+
+    lsi->table->data_in_len = __cpu_to_le32(sd->bs);
+
+    lsi->table->status_len = __cpu_to_le32(0x1);
+    lsi->table->msg_in_len = __cpu_to_le32(0x2);
+    
+    lsi->table->id = __cpu_to_le32((sd->id << 16));
+    lsi->table->id_addr = __cpu_to_le32(&lsi->scripts_iova[0x22]);
+    
+    /* Write DSP to start DMA engine */    
+    dsp = (uintptr_t)&lsi->scripts_iova[0x20];
+    lsi->mmio[LSI_DSP] = dsp & 0xff;
+    lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff;
+    lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff;
+    lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff;
+    
+    if (lsi_interrupt_status(lsi)) {
+        return 1;
+    }
+
+    // Reslect and data transfer
+    lsi->table->msg_in_len = __cpu_to_le32(0x1);
+
+    lsi->table->data_in_len = __cpu_to_le32(sd->bs);
+    
+    /* Write DSP to start DMA engine */    
+    dsp = (uintptr_t)&lsi->scripts_iova[0x2a];
+    lsi->mmio[LSI_DSP] = dsp & 0xff;
+    lsi->mmio[LSI_DSP + 1] = (dsp >> 8) & 0xff;
+    lsi->mmio[LSI_DSP + 2] = (dsp >> 16) & 0xff;
+    lsi->mmio[LSI_DSP + 3] = (dsp >> 24) & 0xff;
+
+    if (lsi_interrupt_status(lsi)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+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_lsi, *sd, sect_offset)) {
+            DPRINTF("ob_sd_read_blocks: error\n");
+            RET(0);
+        }
+        while (n && pos < spb * 512) {
+            memcpy(dest, (uint8_t *)&global_lsi->buffer[LSI_TABLE_DATA_OFFSET] + 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();
+    *sd = &global_lsi->sd[id];
+
+#ifdef CONFIG_DEBUG_LSI
+    {
+        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 void
+ob_lsi_decodeunit(__attribute__((unused)) lsi_private_t **lsi_p)
+{
+    /* ( str len -- id ) */
+    fword("parse-hex");
+}
+
+static void
+ob_lsi_encodeunit(__attribute__((unused)) lsi_private_t **lsi_p)
+{
+    /* ( id -- str len ) */
+    fword("pocket");
+    fword("tohexstr");
+}
+
+static void
+ob_lsi_open(__attribute__((unused)) lsi_private_t **lsi_p)
+{
+    PUSH(-1);
+}
+
+static void
+ob_lsi_close(__attribute__((unused)) lsi_private_t **lsi_p)
+{
+    return;
+}
+
+NODE_METHODS(ob_lsi) = {
+    { "open"       ,    ob_lsi_open },
+    { "close"      ,    ob_lsi_close },
+    { "decode-unit",    ob_lsi_decodeunit },
+    { "encode-unit",    ob_lsi_encodeunit },
+    { "dma-alloc",      ob_lsi_dma_alloc   },
+    { "dma-free",       ob_lsi_dma_free    },
+    { "dma-map-in",     ob_lsi_dma_map_in  },
+    { "dma-map-out",    ob_lsi_dma_map_out },
+    { "dma-sync",       ob_lsi_dma_sync    },
+};
+
+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_lsi_init(const char *path, uint64_t mmio, uint64_t ram)
+{
+    int id, diskcount = 0, cdcount = 0, *counter_ptr;
+    char nodebuff[256], aliasbuff[256];
+    phandle_t ph = get_cur_dev();
+    lsi_private_t *lsi;
+    int i;
+    ucell addr;
+
+    REGISTER_NODE_METHODS(ob_lsi, path);
+
+    lsi = malloc(sizeof(lsi_private_t));
+    if (!lsi) {
+        DPRINTF("Can't allocate LSI private structure\n");
+        return -1;
+    }
+
+    global_lsi = lsi;
+
+    /* Buffer for commands */
+    fword("my-self");
+    push_str(path);
+    feval("open-dev to my-self");
+
+    PUSH(0x1000);
+    feval("dma-alloc");
+    addr = POP();
+    lsi->buffer = cell2pointer(addr);
+
+    PUSH(addr);
+    PUSH(0x1000);
+    PUSH(0);
+    feval("dma-map-in");
+    addr = POP();
+    lsi->buffer_iova = cell2pointer(addr);
+
+    PUSH(0x40 * sizeof(uint32_t));
+    feval("dma-alloc");
+    addr = POP();
+    lsi->scripts = cell2pointer(addr);
+
+    PUSH(addr);
+    PUSH(0x40 * sizeof(uint32_t));
+    PUSH(0);
+    feval("dma-map-in");
+    addr = POP();
+    lsi->scripts_iova = cell2pointer(addr);
+
+    PUSH(sizeof(lsi_table_t));
+    feval("dma-alloc");
+    addr = POP();
+    lsi->table = cell2pointer(addr);
+
+    PUSH(addr);
+    PUSH(sizeof(lsi_table_t));
+    PUSH(0);
+    feval("dma-map-in");
+    addr = POP();
+    lsi->table_iova = cell2pointer(addr);
+
+    set_int_property(ph, "#address-cells", 1);
+    set_int_property(ph, "#size-cells", 0);
+    feval("to my-self");
+
+    /* Initialise SCRIPTS */
+    lsi->mmio = (uint8_t *)(uint32_t)mmio;
+    init_scripts(lsi);
+    init_table(lsi);
+
+    /* Scan the SCSI bus */
+    for (id = 0; id < 8; id++) {
+        lsi->sd[id].id = id;
+        if (!inquiry(lsi, &lsi->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(lsi, &lsi->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(lsi, &lsi->sd[id]);
+
+#ifdef CONFIG_DEBUG_LSI
+        dump_drive(&lsi->sd[id]);
+#endif
+    }
+
+    for (id = 0; id < 8; id++) {
+        if (!lsi->sd[id].present)
+            continue;
+        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), "%s/sd@%d",
+                 get_path_from_ph(ph), id);
+        REGISTER_NODE_METHODS(ob_sd, nodebuff);
+        if (lsi->sd[id].media == TYPE_ROM) {
+            counter_ptr = &cdcount;
+        } else {
+            counter_ptr = &diskcount;
+        }
+        if (*counter_ptr == 0) {
+            add_alias(nodebuff, lsi->sd[id].media_str[0]);
+            add_alias(nodebuff, lsi->sd[id].media_str[1]);
+        }
+        snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
+                 lsi->sd[id].media_str[0], *counter_ptr);
+        add_alias(nodebuff, aliasbuff);
+        snprintf(aliasbuff, sizeof(aliasbuff), "%s%d",
+                 lsi->sd[id].media_str[1], *counter_ptr);
+        add_alias(nodebuff, aliasbuff);
+    }
+
+    return 0;
+}
diff --git a/drivers/pci.c b/drivers/pci.c
index e48a791..f16aeb9 100644
--- a/drivers/pci.c
+++ b/drivers/pci.c
@@ -1159,6 +1159,25 @@ int usb_ohci_config_cb(const pci_config_t *config)
     return 0;
 }
 
+int lsi53c810_config_cb(const pci_config_t *config)
+{    
+#ifdef CONFIG_DRIVER_LSI_53C810
+    uint64_t mmio, ram;
+
+    /* Enable PCI bus mastering */
+    ob_pci_enable_bus_master(config);
+    
+    /* Map PCI memory BAR 1: LSI MMIO */
+    mmio = ob_pci_map(config->assigned[1], 0x400);
+
+    /* Map PCI memory BAR 2: LSI RAM */
+    ram = ob_pci_map(config->assigned[2], 0x400);    
+    
+    ob_lsi_init(config->path, mmio, ram);
+#endif
+    return 0;
+}
+
 void ob_pci_enable_bus_master(const pci_config_t *config)
 {
 	/* Enable bus mastering for the PCI device */
diff --git a/drivers/pci_database.c b/drivers/pci_database.c
index 43e59e0..8288acd 100644
--- a/drivers/pci_database.c
+++ b/drivers/pci_database.c
@@ -55,6 +55,14 @@ static const pci_dev_t scsi_devices[] = {
         NULL, NULL,
     },
     {
+        /* lsi53c810 controller */
+        PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810,
+        NULL, "lsi53c810", NULL,
+        "pci1000,1\0",
+        0, 0, 0,
+        lsi53c810_config_cb, NULL,
+    },
+    {
         0xFFFF, 0xFFFF,
         NULL, NULL, NULL, NULL,
         -1, -1, -1,
diff --git a/drivers/pci_database.h b/drivers/pci_database.h
index ac72284..6f5eb39 100644
--- a/drivers/pci_database.h
+++ b/drivers/pci_database.h
@@ -43,6 +43,7 @@ extern int usb_ohci_config_cb(const pci_config_t *config);
 extern int rtl8139_config_cb(const pci_config_t *config);
 extern int sungem_config_cb (const pci_config_t *config);
 extern int sunhme_config_cb(const pci_config_t *config);
+extern int lsi53c810_config_cb(const pci_config_t *config);
 
 static inline int pci_compat_len(const pci_dev_t *dev)
 {
diff --git a/include/drivers/drivers.h b/include/drivers/drivers.h
index 64824e4..38efcc8 100644
--- a/include/drivers/drivers.h
+++ b/include/drivers/drivers.h
@@ -60,6 +60,10 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels);
 int ob_esp_init(unsigned int slot, uint64_t base, unsigned long espoffset,
                 unsigned long dmaoffset);
 #endif
+#ifdef CONFIG_DRIVER_LSI_53C810
+/* drivers/lsi.c */
+int ob_lsi_init(const char *path, uint64_t mmio, uint64_t ram);
+#endif
 #ifdef CONFIG_DRIVER_OBIO
 /* drivers/obio.c */
 int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset,
diff --git a/include/drivers/pci.h b/include/drivers/pci.h
index b70eb3a..fc7573a 100644
--- a/include/drivers/pci.h
+++ b/include/drivers/pci.h
@@ -182,6 +182,9 @@ extern const pci_arch_t *arch;
 
 /* Vendors and devices. */
 
+#define PCI_VENDOR_ID_LSI_LOGIC          0x1000
+#define PCI_DEVICE_ID_LSI_53C810         0x0001
+
 #define PCI_VENDOR_ID_ATI                0x1002
 #define PCI_DEVICE_ID_ATI_RAGE128_PF     0x5046
 
-- 
2.11.0




More information about the OpenBIOS mailing list