summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2015-01-05 23:18:37 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2015-01-05 23:18:37 +0000
commitaa2fef782dd26415df1f36bb0818a10082e4bc40 (patch)
tree492c5b2447aae563a00571d86df962dc9c264691 /sys
parent81734bec0f7469af826699b8ce44d91fb2fdd3f7 (diff)
there's already three different types of chips in this family of
controllers. the flags used in sgls on the first gen (thunderbolt) are different to the ones used on the second and third gens (fury and invader). this creates an mfii_iop struct to store differences between these chips, and uses them to set the flags on the sgls we generate for the chip. this solves lockups caused by stuck io on the following chips: mfii0 at pci1 dev 0 function 0 "Symbios Logic MegaRAID SAS3108" rev 0x02: msi mfii0: "PERC H730 Mini", firmware 25.2.1.0037, 1024MB cache and mfii0 at pci1 dev 0 function 0 "Symbios Logic MegaRAID SAS3008" rev 0x02: msi mfii0: "PERC H330 Mini", firmware 25.2.1.0037 ive also tested this diff on: mfii0 at pci10 dev 0 function 0 "Symbios Logic MegaRAID SAS2208" rev 0x05: msi mfii0: "PERC H810 Adapter", firmware 21.2.0-0007, 1024MB cache and mfii0 at pci1 dev 0 function 0 "Symbios Logic MegaRAID SAS2208" rev 0x05: msi mfii0: "PERC H710 Mini", firmware 21.3.0-0009, 512MB cache Hrvoje Popovski reported the bug and verified the fix on his hardware.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/mfii.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/sys/dev/pci/mfii.c b/sys/dev/pci/mfii.c
index d0977308f4a..c2319f23019 100644
--- a/sys/dev/pci/mfii.c
+++ b/sys/dev/pci/mfii.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfii.c,v 1.19 2014/10/08 14:44:39 dlg Exp $ */
+/* $OpenBSD: mfii.c,v 1.20 2015/01/05 23:18:36 dlg Exp $ */
/*
* Copyright (c) 2012 David Gwynne <dlg@openbsd.org>
@@ -200,8 +200,14 @@ struct mfii_pd_softc {
uint8_t pd_timeout;
};
+struct mfii_iop {
+ u_int8_t sge_flag_chain;
+ u_int8_t sge_flag_eol;
+};
+
struct mfii_softc {
struct device sc_dev;
+ const struct mfii_iop *sc_iop;
pci_chipset_tag_t sc_pc;
pcitag_t sc_tag;
@@ -325,16 +331,54 @@ int mfii_pd_scsi_cmd_cdb(struct mfii_softc *,
#define mfii_fw_state(_sc) mfii_read((_sc), MFI_OSP)
-static const struct pci_matchid mfii_devices[] = {
- { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_2208 },
- { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3008 },
- { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3108 }
+const struct mfii_iop mfii_iop_thunderbolt = {
+ MFII_SGE_CHAIN_ELEMENT | MFII_SGE_ADDR_IOCPLBNTA,
+ 0
};
+const struct mfii_iop mfii_iop_25 = {
+ MFII_SGE_CHAIN_ELEMENT,
+ MFII_SGE_END_OF_LIST
+};
+
+struct mfii_device {
+ pcireg_t mpd_vendor;
+ pcireg_t mpd_product;
+ const struct mfii_iop *mpd_iop;
+};
+
+const struct mfii_device mfii_devices[] = {
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_2208,
+ &mfii_iop_thunderbolt },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3008,
+ &mfii_iop_25 },
+ { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_MEGARAID_3108,
+ &mfii_iop_25 }
+};
+
+const struct mfii_iop *mfii_find_iop(struct pci_attach_args *);
+
+const struct mfii_iop *
+mfii_find_iop(struct pci_attach_args *pa)
+{
+ const struct mfii_device *mpd;
+ int i;
+
+ for (i = 0; i < nitems(mfii_devices); i++) {
+ mpd = &mfii_devices[i];
+
+ if (mpd->mpd_vendor == PCI_VENDOR(pa->pa_id) &&
+ mpd->mpd_product == PCI_PRODUCT(pa->pa_id))
+ return (mpd->mpd_iop);
+ }
+
+ return (NULL);
+}
+
int
mfii_match(struct device *parent, void *match, void *aux)
{
- return (pci_matchbyid(aux, mfii_devices, nitems(mfii_devices)));
+ return ((mfii_find_iop(aux) != NULL) ? 1 : 0);
}
void
@@ -348,6 +392,7 @@ mfii_attach(struct device *parent, struct device *self, void *aux)
u_int32_t status;
/* init sc */
+ sc->sc_iop = mfii_find_iop(aux);
sc->sc_dmat = pa->pa_dmat;
SIMPLEQ_INIT(&sc->sc_ccb_freeq);
mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
@@ -1560,8 +1605,7 @@ mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
ce = nsge + space;
ce->sg_addr = htole64(ccb->ccb_sgl_dva);
ce->sg_len = htole32(ccb->ccb_sgl_len);
- ce->sg_flags = MFII_SGE_CHAIN_ELEMENT |
- MFII_SGE_ADDR_IOCPLBNTA;
+ ce->sg_flags = sc->sc_iop->sge_flag_chain;
req->chain_offset = ((u_int8_t *)ce - (u_int8_t *)req) / 16;
}
@@ -1578,6 +1622,7 @@ mfii_load_ccb(struct mfii_softc *sc, struct mfii_ccb *ccb, void *sglp,
nsge = sge + 1;
}
+ sge->sg_flags |= sc->sc_iop->sge_flag_eol;
bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
ccb->ccb_direction == MFII_DATA_OUT ?