qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] LSI53C895A, IDE HDD detection under SCO OpenServer 5.0.


From: Craig Ringer
Subject: Re: [Qemu-devel] LSI53C895A, IDE HDD detection under SCO OpenServer 5.0.5
Date: Thu, 30 Oct 2008 00:38:14 +0900
User-agent: Thunderbird 2.0.0.17 (X11/20080925)

Hi all

Sorry to reply to myself, but thanks to an incredibly useful tip on the IRC channel that the controller has public documentation, I've got it detecting under OpenServer 5.0.5. The OpenServer kernel panics shortly afterwards, so there's clearly still something not right, but it's at least finding the controller and talking to it to a reasonable degree.

I've attached a diff showing the changes I ended up making. It's not intended as a patch to be applied to qemu, at least not at this point, but I thought it might be informative and useful. I haven't removed the uncommenting of the LSI_DEBUG and LSI_DEBUG_REG flags, nor the wrapping of lsi_reg_readb with a function that prints the return values, so it's really raw.

The initial problem, by the way, was that the driver didn't like the controller reporting a PCI latency setting of 0. It seemed happy enough with 255, which is what most BIOSes seem to set according to various lspci results from real hardware that I found on the 'net.

After that was changed the driver started accessing the device registers via the memory mapping. It pokes all sorts of registers that the virtual hardware doesn't currently implement, so there was a long and repetitive compile/build/test cycle to identfy and implement each one that was missing. I'm far from sure I'm doing the right thing with all of them, especially as the driver does things it probably shouldn't, such as:

- Writing to several read-only registers
- Writing to a register where only bit 3 may be set with the value 0x51
- Writing to the reserved register 0xff; and
- Running a script that writes to registers 0x100 - 0x105, though they
  don't appear to exist. This last one looks like it might well be a
  bug in the virtual hardware.

At this point it seems to be doing quite a bit of communication with the controller before infinitely looping on a SCRIPTS invocation.

lsi_scsi: SCRIPTS dsp=f0010003 opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
lsi_scsi: SCRIPTS dsp=f001000b opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
lsi_scsi: SCRIPTS dsp=f0010013 opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
lsi_scsi: SCRIPTS dsp=f001001b opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
lsi_scsi: SCRIPTS dsp=f0010023 opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
lsi_scsi: SCRIPTS dsp=f001002b opcode ffffffff arg ffffffff
lsi_scsi: Load reg 0xff size 7 addr 0xffffffff = 00ff5397
... and so on ...

so it's presumably scanning for something or otherwise expecting one of these calls to produce a different result than it does.

Any tips would be appreciated. I just thought I'd put this out in public view in case I don't manage to get it all sorted out and someone else is in this delightful position later.

No idea about the IDE detection yet, I haven't had a chance to look at what it's doing there.

--
Craig Ringer
--- lsi53c895a.c        2008-01-07 04:38:42.000000000 +0900
+++ /home/craig/tmp/qemu-0.9.1/hw/lsi53c895a.c  2008-10-30 00:10:40.000000000 
+0900
@@ -14,8 +14,8 @@
 #include "pci.h"
 #include "scsi-disk.h"
 
-//#define DEBUG_LSI
-//#define DEBUG_LSI_REG
+#define DEBUG_LSI
+#define DEBUG_LSI_REG
 
 #ifdef DEBUG_LSI
 #define DPRINTF(fmt, args...) \
@@ -209,6 +209,7 @@
     uint8_t mbox0;
     uint8_t mbox1;
     uint8_t dfifo;
+    uint8_t ctest2; /* Only bit 3 used for PCICIE flag */
     uint8_t ctest3;
     uint8_t ctest4;
     uint8_t ctest5;
@@ -280,6 +281,7 @@
     s->mbox0 = 0;
     s->mbox1 = 0;
     s->dfifo = 0;
+    s->ctest2 = 0; /* See comment on declaration */
     s->ctest3 = 0;
     s->ctest4 = 0;
     s->ctest5 = 0;
@@ -1207,7 +1209,7 @@
     DPRINTF("SCRIPTS execution stopped\n");
 }
 
-static uint8_t lsi_reg_readb(LSIState *s, int offset)
+static uint8_t lsi_reg_readb_wrap(LSIState *s, int offset)
 {
     uint8_t tmp;
 #define CASE_GET_REG32(name, addr) \
@@ -1268,7 +1270,7 @@
     case 0x19: /* CTEST1 */
         return 0;
     case 0x1a: /* CTEST2 */
-        tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM;
+        tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
         if (s->istat0 & LSI_ISTAT0_SIGP) {
             s->istat0 &= ~LSI_ISTAT0_SIGP;
             tmp |= LSI_CTEST2_SIGP;
@@ -1316,8 +1318,12 @@
         s->sist1 = 0;
         lsi_update_irq(s);
         return tmp;
-    case 0x47: /* GPCNTL0 */
-        return 0x0f;
+    case 0x46: /* MACNTL */
+       return 0xf0;
+    case 0x47: /* GPIO */
+        /* GPIO doesn't make a great deal of sense on a virtual device.
+         * Drivers that access this seem happy with 0x0f. */
+         return 0x0f;
     case 0x48: /* STIME0 */
         return s->stime0;
     case 0x4a: /* RESPID0 */
@@ -1374,6 +1380,16 @@
 #undef CASE_GET_REG32
 }
 
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+       /* Register map: page 128 */
+       /* Registers 5c-5f: scratch */
+       uint8_t tmp;
+       tmp = lsi_reg_readb_wrap(s,offset);
+       DPRINTF("  Value: %02hhx\n", tmp);
+       return tmp;
+}
+
 static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
 {
 #define CASE_SET_REG32(name, addr) \
@@ -1385,6 +1401,7 @@
 #ifdef DEBUG_LSI_REG
     DPRINTF("Write reg %x = %02x\n", offset, val);
 #endif
+
     switch (offset) {
     case 0x00: /* SCNTL0 */
         s->scntl0 = val;
@@ -1429,6 +1446,20 @@
            SCRIPTS register move instructions are.  */
         s->sfbr = val;
         break;
+    case 0x09: /* SOCL */
+        /* OpenServer's slha driver sets this register, but it's not really 
meant
+         * to and we just ignore the effect. */
+       DPRINTF("SOCL set to %02hhx, ignoring\n", val);
+        break;
+    case 0x0a: /* SSID */
+        /* This register is read only, but OpenServer's slha driver writes 0 
to it
+         * anyway so clearly the real hardware permits that. */
+        if (val != 0x00)
+            BADF("Write to read-only register SSID (0x0a)");
+        break;
+    case 0x0b: /* SBCL */
+        /* OpenServer's slha driver likes to write to this register, though 
it's read only. */
+        break;
     case 0x0c: case 0x0d: case 0x0e: case 0x0f:
         /* Linux writes to these readonly registers on startup.  */
         return;
@@ -1458,6 +1489,13 @@
     case 0x17: /* MBOX1 */
         s->mbox1 = val;
         break;
+    case 0x1a: /* CTEST2 */
+        /* Read only, except bit 3 (PCICIE) which may be written */
+        /* The docs say writing to this all other bits must be 0, 
+         * but the OpenServer driver doesn't follow that rule so we'll
+         * just mask the other bits' values. */
+        s->ctest2 = val & LSI_CTEST2_PCICIE;
+       break;
     case 0x1b: /* CTEST3 */
         s->ctest3 = val & 0x0f;
         break;
@@ -1572,6 +1610,11 @@
     CASE_SET_REG32(ia, 0xd4)
     CASE_SET_REG32(sbc, 0xd8)
     CASE_SET_REG32(csbc, 0xdc)
+    case 0xff:
+        /* SCO Openserver's slha driver writes to this for no apparent reason.
+         * The register is reserved. We ignore the write. */
+       DPRINTF("WARNING: Write to reserved register 0xff\n");
+        break;
     default:
         if (offset >= 0x5c && offset < 0xa0) {
             int n;
@@ -1580,6 +1623,10 @@
             shift = (offset & 3) * 8;
             s->scratch[n] &= ~(0xff << shift);
             s->scratch[n] |= (val & 0xff) << shift;
+        } else if (offset >= 0x100) {
+            /* This is outside the register mapping, but OpenServer's slha 
driver
+             * still writes to it... */
+            DPRINTF("WARNING: Write %hx = %02hhx outside existing register 
space; ignoring.\n", offset, val);
         } else {
             BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
         }
@@ -1858,12 +1905,21 @@
         return NULL;
     }
 
+    /* PCI Vendor ID (word) */
     s->pci_dev.config[0x00] = 0x00;
     s->pci_dev.config[0x01] = 0x10;
+    /* PCI device ID (word) */
     s->pci_dev.config[0x02] = 0x12;
     s->pci_dev.config[0x03] = 0x00;
+    /* PCI base class code */
     s->pci_dev.config[0x0b] = 0x01;
-    s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
+    /* PCI subsystem ID */
+    s->pci_dev.config[0x2e] = 0x00;
+    s->pci_dev.config[0x2f] = 0x10;
+    /* PCI latency timer = 255 */
+    s->pci_dev.config[0x0d] = 0xff;
+    /* Interrupt pin 1 */
+    s->pci_dev.config[0x3d] = 0x01;
 
     s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn,
                                              lsi_mmio_writefn, s);

reply via email to

[Prev in Thread] Current Thread [Next in Thread]