I had a spare hour this afternoon, so I decided to try adding support
for the new generation of LSI MegaRAID SAS and Dell PERC controllers.
Unfortunately I haven't got a machine set up to test this on either
the new gen (SAS1078/PERC6) or previous gen (SAS1064R/PERC5) hardware.
I know it is unconventional to post code here rather than endless
discussion, but I'm posting the diff anway in the hope that someone
with such hardware can test it for me.

The code to apply this to can be found in the SVN repo up at
https://svn.itee.uq.edu.au/repo/mfi, and to use it you'll have to add
the resulting module it to the kernel manually using something like
this:

# add_drv -i '"pci1000,60"' -c scsi mfi

I'd like to know if existing PERC5 support still works as well as if
the new gen PERC6 gear works.

Cheers,
dlg

Index: mfi.c
===================================================================
--- mfi.c       (revision 94)
+++ mfi.c       (working copy)
@@ -137,10 +137,20 @@
        int                     mpd_senselen;
 };
 
+struct mfi_iop_ops {
+       uint32_t                (*mio_fw_state)(struct mfi_softc *);
+       void                    (*mio_intr_ena)(struct mfi_softc *);
+       int                     (*mio_intr)(struct mfi_softc *);
+       void                    (*mio_post)(struct mfi_softc *,
+                                   struct mfi_ccb *);
+};
+
 struct mfi_softc {
        dev_info_t              *sc_dev;
        scsi_hba_tran_t         *sc_tran;
 
+       struct mfi_iop_ops      *sc_iop;
+
        int                     sc_ncmds;
 
        ddi_acc_handle_t        sc_reg_space;
@@ -174,7 +184,7 @@
 static int             mfi_wait_ne(struct mfi_softc *, off_t,
                            uint32_t, uint32_t, int);
 
-static int             mfi_pci_work(dev_info_t *);
+static int             mfi_pci_work(struct mfi_softc *);
 static int             mfi_transition_firmware(struct mfi_softc *);
 static int             mfi_init_firmware(struct mfi_softc *);
 
@@ -227,6 +237,35 @@
 static void            mfi_tran_sync_pkt(struct scsi_address *,
                            struct scsi_pkt *);
 
+static uint32_t                mfi_xscale_fw_state(struct mfi_softc *);
+static void            mfi_xscale_intr_ena(struct mfi_softc *);
+static int             mfi_xscale_intr(struct mfi_softc *);
+static void            mfi_xscale_post(struct mfi_softc *,
+                           struct mfi_ccb *);
+
+static struct mfi_iop_ops mfi_iop_xscale = {
+       mfi_xscale_fw_state,
+       mfi_xscale_intr_ena,
+       mfi_xscale_intr,
+       mfi_xscale_post
+};
+
+static uint32_t        mfi_ppc_fw_state(struct mfi_softc *);
+static void            mfi_ppc_intr_ena(struct mfi_softc *);
+static int             mfi_ppc_intr(struct mfi_softc *);
+static void            mfi_ppc_post(struct mfi_softc *, struct mfi_ccb *);
+
+static struct mfi_iop_ops mfi_iop_ppc = {
+       mfi_ppc_fw_state,
+       mfi_ppc_intr_ena,
+       mfi_ppc_intr,
+       mfi_ppc_post
+};
+
+#define mfi_fw_state(_s)       ((_s)->sc_iop->mio_fw_state(_s))
+#define mfi_intr_enable(_s)    ((_s)->sc_iop->mio_intr_ena(_s))
+#define mfi_my_intr(_s)                ((_s)->sc_iop->mio_intr(_s))
+
 static ddi_dma_attr_t pcq_dma_attr = {
        DMA_ATTR_V0,            /* version of this structure */
        0,                      /* lowest usable address */
@@ -354,7 +393,7 @@
        sc->sc_dev = dip;
        sc->sc_io_dma_attr = io_dma_attr;
 
-       if (mfi_pci_work(dip) != DDI_SUCCESS) {
+       if (mfi_pci_work(sc) != DDI_SUCCESS) {
                /* error printed by mfi_pci_work */
                goto free_sc;
        }
@@ -389,7 +428,7 @@
                goto unmutex;
        }
 
-       status = mfi_read(sc, MFI_OMSG0);
+       status = mfi_fw_state(sc);
        sc->sc_ncmds = MFI_OMSG0_MAXCMD(status);
 
        /* the hardware may support more or less than we can fit */
@@ -416,7 +455,7 @@
                cmn_err(CE_NOTE, "unable to establish interrupt");
                goto free_ccbs;
        }
-       mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
+       mfi_intr_enable(sc);
 
        if (mfi_hba_attach(sc) != DDI_SUCCESS) {
                cmn_err(CE_NOTE, "unable to attach scsi");
@@ -481,14 +520,12 @@
 {
        struct mfi_softc        *sc = (struct mfi_softc *)arg;
        struct mfi_ccb          *ccb;
-       uint32_t                status, producer, consumer, context;
+       uint32_t                producer, consumer, context;
        uint_t                  rv = DDI_INTR_UNCLAIMED;
 
        mutex_enter(&sc->sc_replyq_mutex);
 
-       status = mfi_read(sc, MFI_OSTS);
-       if (status & MFI_OSTS_INTR_VALID) {
-               mfi_write(sc, MFI_OSTS, status);
+       if (mfi_my_intr(sc)) {
                rv = DDI_INTR_CLAIMED;
 
                ddi_dma_sync(sc->sc_pcq_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
@@ -520,17 +557,23 @@
 }
 
 static int
-mfi_pci_work(dev_info_t *dip)
+mfi_pci_work(struct mfi_softc *sc)
 {
        ddi_acc_handle_t        pci_conf;
        uint16_t                command;
        int                     rv = DDI_SUCCESS;
 
-       if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS) {
+       if (pci_config_setup(sc->sc_dev, &pci_conf) != DDI_SUCCESS) {
                cmn_err(CE_NOTE, "unable to map pci config space");
                return (DDI_FAILURE);
        }
 
+       if (pci_config_get16(pci_conf, PCI_CONF_VENID) == 0x1000 &&
+           pci_config_get16(pci_conf, PCI_CONF_DEVID) == 0x0060)
+               sc->sc_iop = &mfi_iop_ppc;
+       else
+               sc->sc_iop = &mfi_iop_xscale;
+
        /* force the busmaster enable bit on */
        command = pci_config_get16(pci_conf, PCI_CONF_COMM);
        if ((command & PCI_COMM_ME) == 0) {
@@ -556,7 +599,7 @@
        int                     wait;
 
        for (;;) {
-               state = mfi_read(sc, MFI_OMSG0) & MFI_OMSG0_FWSTATE;
+               state = mfi_fw_state(sc) & MFI_OMSG0_FWSTATE;
 
                switch (state) {
                case MFI_FWSTATE_READY:
@@ -570,18 +613,18 @@
                        mfi_write(sc, MFI_IDB, MFI_IDB_CLEAR_HANDSHAKE);
                case MFI_FWSTATE_UNDEFINED:
                case MFI_FWSTATE_BB_INIT:
-                       wait = 2;
+                       wait = 20;
                        break;
 
                case MFI_FWSTATE_OPERATIONAL:
                        mfi_write(sc, MFI_IDB, MFI_IDB_INIT_READY);
-                       wait = 10;
+                       wait = 100;
                        break;
 
                case MFI_FWSTATE_FW_INIT:
                case MFI_FWSTATE_DEVICE_SCAN:
                case MFI_FWSTATE_FLUSH_CACHE:
-                       wait = 20;
+                       wait = 200;
                        break;
 
                default:
@@ -589,10 +632,13 @@
                        return (DDI_FAILURE);
                }
 
-               if (mfi_wait_ne(sc, MFI_OMSG0, MFI_OMSG0_FWSTATE,
-                   state, wait) != 0) {
-                       cmn_err(CE_NOTE, "firmware wont transition");
-                       return (DDI_FAILURE);
+               while ((mfi_fw_state(sc) & MFI_OMSG0_FWSTATE) != 0) {
+                       if (wait-- == 0) {
+                               cmn_err(CE_NOTE, "firmware wont transition");
+                               return (DDI_FAILURE);
+                       }
+
+                       delay(drv_usectohz(100000));
                }
        }
 }
@@ -1245,7 +1291,7 @@
        ddi_dma_sync(ccb->ccb_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
 
        mutex_enter(&sc->sc_post_mutex);
-       mfi_write(sc, MFI_IQP, (ccb->ccb_cmd_dva >> 3) | 0x7);
+       sc->sc_iop->mio_post(sc, ccb);
        mutex_exit(&sc->sc_post_mutex);
 }
 
@@ -1492,3 +1538,71 @@
 
        return (1);
 }
+
+static uint32_t
+mfi_xscale_fw_state(struct mfi_softc *sc)
+{
+       return (mfi_read(sc, MFI_OMSG0));
+}
+
+static void
+mfi_xscale_intr_ena(struct mfi_softc *sc)
+{
+       mfi_write(sc, MFI_OMSK, MFI_ENABLE_INTR);
+}
+
+static int
+mfi_xscale_intr(struct mfi_softc *sc)
+{
+       uint32_t status;
+
+       status = mfi_read(sc, MFI_OSTS);
+       if ((status & MFI_OSTS_INTR_VALID) == 0)
+               return (0);
+
+       /* write status back to acknowledge interrupt */
+       mfi_write(sc, MFI_OSTS, status);
+
+       return (1);
+}
+
+static void
+mfi_xscale_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
+{
+       mfi_write(sc, MFI_IQP, (ccb->ccb_cmd_dva >> 3) |
+           ccb->ccb_extra_frames);
+}
+
+static uint32_t
+mfi_ppc_fw_state(struct mfi_softc *sc)
+{
+       return (mfi_read(sc, MFI_OSP));
+}
+
+static void
+mfi_ppc_intr_ena(struct mfi_softc *sc)
+{
+       mfi_write(sc, MFI_ODC, 0xffffffff);
+       mfi_write(sc, MFI_OMSK, ~0x8000004);
+}
+
+static int
+mfi_ppc_intr(struct mfi_softc *sc)
+{
+       uint32_t status;
+
+       status = mfi_read(sc, MFI_OSTS);
+       if ((status, MFI_OSTS_PPC_INTR_VALID) == 0)
+               return (0);
+
+       /* write status back to acknowledge interrupt */
+       mfi_write(sc, MFI_ODC, status);
+
+       return (1);
+}
+
+static void
+mfi_ppc_post(struct mfi_softc *sc, struct mfi_ccb *ccb)
+{
+       mfi_write(sc, MFI_IQP, 0x1 | ccb->ccb_cmd_dva | (0x7 << 1));
+}
Index: mfireg.h
===================================================================
--- mfireg.h    (revision 94)
+++ mfireg.h    (working copy)
@@ -35,6 +35,8 @@
 #define MFI_OMSK               0x34 /* outbound intr mask */
 #define MFI_IQP                        0x40 /* inbound queue port */
 #define MFI_OQP                        0x44 /* outbound queue port */
+#define MFI_ODC                        0xa0 /* outbound doorbell clr */
+#define MFI_OSP                        0xb0 /* outbound scratch pad */
 
 /* bits for the OMSG0 register */
 #define MFI_OMSG0_FWSTATE              0xf0000000
@@ -63,6 +65,7 @@
 #define MFI_IDB_RESET_FLAGS            (MFI_INIT_READY|MFI_INIT_MFIMODE)
 
 #define MFI_OSTS_INTR_VALID            0x00000002
+#define MFI_OSTS_PPC_INTR_VALID                0x80000000
 
 #define MFI_ENABLE_INTR                        0x00000001
 
_______________________________________________
driver-discuss mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/driver-discuss

Reply via email to