summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2014-02-23 08:59:10 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2014-02-23 08:59:10 +0000
commit89a7bea5c9a1ead5f9f854a1c2d30060ee3f45c6 (patch)
tree2073fb6a30ea05539197a9c4f3b74ac785d04520
parentd15e75e88d6d5e951cb4607fa2e3a1c422fb8e28 (diff)
rework firmware handling a bit. when built without firmware, check that
the chip already has firmware before trying to boot it, so we can explain why it's not working rather than printing cryptic errors.
-rw-r--r--sys/dev/pci/qle.c101
-rw-r--r--sys/dev/pci/qlereg.h3
2 files changed, 73 insertions, 31 deletions
diff --git a/sys/dev/pci/qle.c b/sys/dev/pci/qle.c
index c99176be51f..34836731a72 100644
--- a/sys/dev/pci/qle.c
+++ b/sys/dev/pci/qle.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: qle.c,v 1.12 2014/02/20 20:20:28 kettenis Exp $ */
+/* $OpenBSD: qle.c,v 1.13 2014/02/23 08:59:09 jmatthew Exp $ */
/*
* Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
@@ -43,7 +43,7 @@
#include <dev/pci/qlereg.h>
-#ifndef ISP_NOFIRMWARE
+#ifndef QLE_NOFIRMWARE
#include <dev/microcode/isp/asm_2400.h>
#include <dev/microcode/isp/asm_2500.h>
#endif
@@ -294,6 +294,8 @@ int qle_async(struct qle_softc *, u_int16_t);
int qle_load_fwchunk(struct qle_softc *,
struct qle_dmamem *, const u_int32_t *);
+u_int32_t qle_read_ram_word(struct qle_softc *, u_int32_t);
+int qle_verify_firmware(struct qle_softc *, u_int32_t);
int qle_load_firmware_chunks(struct qle_softc *, const u_int32_t *);
int qle_read_nvram(struct qle_softc *);
@@ -334,6 +336,10 @@ qle_attach(struct device *parent, struct device *self, void *aux)
struct scsibus_attach_args saa;
struct qle_init_cb *icb;
bus_size_t mbox_base;
+ u_int32_t firmware_addr;
+#ifndef QLE_NOFIRMWARE
+ const u_int32_t *firmware = NULL;
+#endif
pcireg_t bars[] = { QLE_PCI_MEM_BAR, QLE_PCI_IO_BAR };
pcireg_t memtype;
@@ -391,27 +397,22 @@ qle_attach(struct device *parent, struct device *self, void *aux)
case PCI_PRODUCT_QLOGIC_ISP2422:
sc->sc_isp_type = QLE_ISP2422;
sc->sc_isp_gen = QLE_GEN_ISP24XX;
- mbox_base = QLE_MBOX_BASE_24XX;
break;
case PCI_PRODUCT_QLOGIC_ISP2432:
sc->sc_isp_type = QLE_ISP2432;
sc->sc_isp_gen = QLE_GEN_ISP24XX;
- mbox_base = QLE_MBOX_BASE_24XX;
break;
case PCI_PRODUCT_QLOGIC_ISP2512:
sc->sc_isp_type = QLE_ISP2512;
sc->sc_isp_gen = QLE_GEN_ISP25XX;
- mbox_base = QLE_MBOX_BASE_24XX;
break;
case PCI_PRODUCT_QLOGIC_ISP2522:
sc->sc_isp_type = QLE_ISP2522;
sc->sc_isp_gen = QLE_GEN_ISP25XX;
- mbox_base = QLE_MBOX_BASE_24XX;
break;
case PCI_PRODUCT_QLOGIC_ISP2532:
sc->sc_isp_type = QLE_ISP2532;
sc->sc_isp_gen = QLE_GEN_ISP25XX;
- mbox_base = QLE_MBOX_BASE_24XX;
break;
default:
@@ -419,6 +420,10 @@ qle_attach(struct device *parent, struct device *self, void *aux)
goto deintr;
}
+ /* these are the same for 24xx and 25xx but may vary later */
+ mbox_base = QLE_MBOX_BASE_24XX;
+ firmware_addr = QLE_2400_CODE_ORG;
+
if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, mbox_base,
sizeof(sc->sc_mbox), &sc->sc_mbox_ioh) != 0) {
printf("%s: unable to map mbox registers\n", DEVNAME(sc));
@@ -450,28 +455,34 @@ qle_attach(struct device *parent, struct device *self, void *aux)
if (qle_read_nvram(sc) == 0)
sc->sc_nvram_valid = 1;
-#ifndef ISP_NOFIRMWARE
+#ifdef QLE_NOFIRMWARE
+ if (qle_verify_firmware(sc, firmware_addr)) {
+ printf("%s: no firmware loaded\n", DEVNAME(sc));
+ goto deintr;
+ }
+#else
switch (sc->sc_isp_gen) {
case QLE_GEN_ISP24XX:
- if (qle_load_firmware_chunks(sc, isp_2400_risc_code)) {
- printf("firmware load failed\n");
- goto deintr;
- }
+ firmware = isp_2400_risc_code;
break;
case QLE_GEN_ISP25XX:
- if (qle_load_firmware_chunks(sc, isp_2500_risc_code)) {
- printf("firmware load failed\n");
- goto deintr;
- }
+ firmware = isp_2500_risc_code;
break;
+ default:
+ printf("%s: no firmware to load?\n", DEVNAME(sc));
+ goto deintr;
+ }
+ if (qle_load_firmware_chunks(sc, firmware)) {
+ printf("%s: firmware load failed\n", DEVNAME(sc));
+ goto deintr;
}
#endif
/* execute firmware */
sc->sc_mbox[0] = QLE_MBOX_EXEC_FIRMWARE;
- sc->sc_mbox[1] = QLE_2400_CODE_ORG >> 16;
- sc->sc_mbox[2] = QLE_2400_CODE_ORG & 0xffff;
-#ifdef ISP_NOFIRMWARE
+ sc->sc_mbox[1] = firmware_addr >> 16;
+ sc->sc_mbox[2] = firmware_addr & 0xffff;
+#ifdef QLE_NOFIRMWARE
sc->sc_mbox[3] = 1;
#else
sc->sc_mbox[3] = 0;
@@ -2381,32 +2392,62 @@ qle_load_fwchunk(struct qle_softc *sc, struct qle_dmamem *mem,
dest += words;
}
- sc->sc_mbox[0] = QLE_MBOX_VERIFY_CSUM;
- sc->sc_mbox[1] = src[2] >> 16;
- sc->sc_mbox[2] = src[2];
- if (qle_mbox(sc, 0x0007, 0x0007)) {
- printf("verification of chunk at %x failed: %x %x\n", src[2],
- sc->sc_mbox[1], sc->sc_mbox[2]);
- return (1);
- }
-
- return (0);
+ return (qle_verify_firmware(sc, src[2]));
}
int
qle_load_firmware_chunks(struct qle_softc *sc, const u_int32_t *fw)
{
struct qle_dmamem *mem;
+ int res = 0;
mem = qle_dmamem_alloc(sc, 65536);
for (;;) {
- qle_load_fwchunk(sc, mem, fw);
+ if (qle_load_fwchunk(sc, mem, fw)) {
+ res = 1;
+ break;
+ }
if (fw[1] == 0)
break;
fw += fw[3];
}
qle_dmamem_free(sc, mem);
+ return (res);
+}
+
+u_int32_t
+qle_read_ram_word(struct qle_softc *sc, u_int32_t addr)
+{
+ sc->sc_mbox[0] = QLE_MBOX_READ_RISC_RAM;
+ sc->sc_mbox[1] = addr & 0xffff;
+ sc->sc_mbox[8] = addr >> 16;
+ if (qle_mbox(sc, 0x0103, 0x000e)) {
+ return (0);
+ }
+ return ((sc->sc_mbox[3] << 16) | sc->sc_mbox[2]);
+}
+
+int
+qle_verify_firmware(struct qle_softc *sc, u_int32_t addr)
+{
+ /*
+ * QLE_MBOX_VERIFY_CSUM requires at least the firmware header
+ * to be correct, otherwise it wanders all over ISP memory and
+ * gets lost. Check that chunk address (addr+2) is right and
+ * size (addr+3) is plausible first.
+ */
+ if ((qle_read_ram_word(sc, addr+2) != addr) ||
+ (qle_read_ram_word(sc, addr+3) > 0xffff)) {
+ return (1);
+ }
+
+ sc->sc_mbox[0] = QLE_MBOX_VERIFY_CSUM;
+ sc->sc_mbox[1] = addr >> 16;
+ sc->sc_mbox[2] = addr;
+ if (qle_mbox(sc, 0x0007, 0x0007)) {
+ return (1);
+ }
return (0);
}
diff --git a/sys/dev/pci/qlereg.h b/sys/dev/pci/qlereg.h
index a1fda46cfb0..56260fcdd97 100644
--- a/sys/dev/pci/qlereg.h
+++ b/sys/dev/pci/qlereg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: qlereg.h,v 1.1 2014/02/12 23:04:26 jmatthew Exp $ */
+/* $OpenBSD: qlereg.h,v 1.2 2014/02/23 08:59:09 jmatthew Exp $ */
/*
* Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
@@ -127,6 +127,7 @@
#define QLE_MBOX_ABOUT_FIRMWARE 0x0008
#define QLE_MBOX_LOAD_RISC_RAM 0x000B
#define QLE_MBOX_INIT_RISC_RAM 0x000E
+#define QLE_MBOX_READ_RISC_RAM 0x000F
#define QLE_MBOX_GET_IO_STATUS 0x0012
#define QLE_MBOX_STOP_FIRMWARE 0x0014
#define QLE_MBOX_GET_ID 0x0020