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
