aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Pulz <Joerg.Pulz@frm2.tum.de>2023-07-07 21:43:34 +0000
committerWarner Losh <imp@FreeBSD.org>2023-07-07 21:45:30 +0000
commit27b4a1b7e5b871c248dc501aa359c93f7263b074 (patch)
tree9068bfad2a597c0db97b5754786e1db7654f290d
parent233ab94cfd78db16ca431b09f36cebb8ee4674e9 (diff)
downloadsrc-27b4a1b7e5b871c248dc501aa359c93f7263b074.tar.gz
src-27b4a1b7e5b871c248dc501aa359c93f7263b074.zip
isp(4): Add support to read contents of the FLT (flash layout table)
The FLT is like a TOC for the flash area and contains entries for every flash region with start/end address, size and flags. Start using NVRAM addresses from FLT instead of hardcoded ones for ISP28xx based HBAs. The FLT should be available on earlier HBAs too, probably since ISP24xx based. This needs further investigation and testing. PR: 271062 Reviewed by: imp, mav Sponsored by: Technical University of Munich Pull Request: https://github.com/freebsd/freebsd-src/pull/726
-rw-r--r--sys/dev/isp/isp.c296
-rw-r--r--sys/dev/isp/ispreg.h81
-rw-r--r--sys/dev/isp/ispvar.h22
3 files changed, 397 insertions, 2 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index 46bb40c0fe07..14795198a850 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -123,6 +123,14 @@ static int isp_read_nvram_2400(ispsoftc_t *);
static void isp_rd_2400_nvram(ispsoftc_t *, uint32_t, uint32_t *);
static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *);
+static int isp_read_flthdr_28xx(ispsoftc_t *);
+static void isp_rd_28xx_flthdr(ispsoftc_t *, uint32_t, uint32_t *);
+static void isp_parse_flthdr_28xx(ispsoftc_t *, uint8_t *);
+
+static int isp_read_flt_28xx(ispsoftc_t *);
+static void isp_rd_28xx_flt(ispsoftc_t *, uint32_t, uint32_t *);
+static int isp_parse_flt_28xx(ispsoftc_t *, uint8_t *);
+
static void
isp_change_fw_state(ispsoftc_t *isp, int chan, int state)
{
@@ -4334,18 +4342,36 @@ cleanup:
static int
isp_read_nvram(ispsoftc_t *isp, int bus)
{
+ if (IS_28XX(isp)) {
+ fcparam *fcp = FCPARAM(isp, 0);
+ int r = 0;
+ fcp->flash_data_addr = ISP28XX_BASE_ADDR;
+ fcp->flt_length = 0;
+ r = isp_read_flthdr_28xx(isp);
+ if (r == 0) {
+ isp_read_flt_28xx(isp);
+ } else {
+ fcp->flt_region_nvram =
+ (0x300000 + ISP2400_NVRAM_PORT_ADDR(isp->isp_port));
+ }
+ }
return (isp_read_nvram_2400(isp));
}
static int
isp_read_nvram_2400(ispsoftc_t *isp)
{
+ fcparam *fcp = FCPARAM(isp, 0);
int retval = 0;
uint32_t addr, csum, lwrds, *dptr;
uint8_t nvram_data[ISP2400_NVRAM_SIZE];
- addr = ISP2400_NVRAM_PORT_ADDR(isp->isp_port);
+ if (IS_28XX(isp)) {
+ addr = fcp->flt_region_nvram;
+ } else {
+ addr = ISP2400_NVRAM_PORT_ADDR(isp->isp_port);
+ }
dptr = (uint32_t *) nvram_data;
for (lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) {
isp_rd_2400_nvram(isp, addr++, dptr++);
@@ -4381,7 +4407,9 @@ isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp)
uint32_t tmp = 0;
if (IS_28XX(isp)) {
- base = 0x7fad0000; /* 0x7f7d0000 + 0x300000 */
+ fcparam *fcp = FCPARAM(isp, 0);
+ base = fcp->flash_data_addr + addr;
+ addr = 0;
} else if (IS_26XX(isp)) {
base = 0x7fe7c000; /* XXX: Observation, may be wrong. */
} else if (IS_25XX(isp)) {
@@ -4449,3 +4477,267 @@ isp_parse_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data)
fcp->isp_xfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data);
fcp->isp_zfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data);
}
+
+static int
+isp_read_flthdr_28xx(ispsoftc_t *isp)
+{
+ int retval = 0;
+ uint32_t addr, lwrds, *dptr;
+ uint16_t csum;
+ uint8_t flthdr_data[FLT_HEADER_SIZE];
+
+ addr = ISP28XX_FLT_ADDR;
+ dptr = (uint32_t *) flthdr_data;
+
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "FLTL[DEF]: 0x%x", ISP28XX_FLT_ADDR);
+ for (lwrds = 0; lwrds < FLT_HEADER_SIZE >> 2; lwrds++) {
+ isp_rd_28xx_flthdr(isp, addr++, dptr++);
+ }
+ dptr = (uint32_t *) flthdr_data;
+ for (csum = 0, lwrds = 0; lwrds < FLT_HEADER_SIZE >> 4; lwrds++) {
+ uint16_t tmp;
+ ISP_IOXGET_16(isp, &dptr[lwrds], tmp);
+ csum += tmp;
+ }
+ if (csum != 0) {
+ retval = -1;
+ goto out;
+ }
+ isp_parse_flthdr_28xx(isp, flthdr_data);
+out:
+ return (retval);
+}
+
+static void
+isp_rd_28xx_flthdr(ispsoftc_t *isp, uint32_t addr, uint32_t *rp)
+{
+ fcparam *fcp = FCPARAM(isp, 0);
+ int loops = 0;
+ uint32_t base = fcp->flash_data_addr;
+ uint32_t tmp = 0;
+
+ ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr);
+ for (loops = 0; loops < 5000; loops++) {
+ ISP_DELAY(10);
+ tmp = ISP_READ(isp, BIU2400_FLASH_ADDR);
+ if ((tmp & (1U << 31)) != 0) {
+ break;
+ }
+ }
+ if (tmp & (1U << 31)) {
+ *rp = ISP_READ(isp, BIU2400_FLASH_DATA);
+ ISP_SWIZZLE_NVRAM_LONG(isp, rp);
+ } else {
+ *rp = 0xffffffff;
+ }
+}
+
+static void
+isp_parse_flthdr_28xx(ispsoftc_t *isp, uint8_t *flthdr_data)
+{
+ fcparam *fcp = FCPARAM(isp, 0);
+ uint16_t ver, csum;
+
+ ver = le16toh((uint16_t) (ISP28XX_FLT_VERSION(flthdr_data)));
+ fcp->flt_length = le16toh((uint16_t) (ISP28XX_FLT_LENGTH(flthdr_data)));
+ csum = le16toh((uint16_t) (ISP28XX_FLT_CSUM(flthdr_data)));
+
+ if ((fcp->flt_length == 0 ) ||
+ (fcp->flt_length > (FLT_HEADER_SIZE + FLT_REGIONS_SIZE))) {
+ isp_prt(isp, ISP_LOGWARN,
+ "FLT[DEF]: Invalid length=0x%x(%d)",
+ fcp->flt_length, fcp->flt_length);
+ }
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "FLT[DEF]: version=0x%x length=0x%x(%d) checksum=0x%x",
+ ver, fcp->flt_length, fcp->flt_length, csum);
+}
+
+static int
+isp_read_flt_28xx(ispsoftc_t *isp)
+{
+ fcparam *fcp = FCPARAM(isp, 0);
+ int retval = 0;
+ int len = fcp->flt_length - FLT_HEADER_SIZE;
+ uint32_t addr, lwrds, *dptr;
+ uint8_t flt_data[len];
+ fcp->flt_region_entries = len / FLT_REGION_SIZE;
+
+ addr = ISP28XX_FLT_ADDR + (FLT_HEADER_SIZE >> 2);
+ dptr = (uint32_t *) flt_data;
+ isp_prt(isp, ISP_LOGDEBUG0, "FLT[DEF]: regions=%d",
+ fcp->flt_region_entries);
+ for (lwrds = 0; lwrds < len >> 2; lwrds++) {
+ isp_rd_28xx_flt(isp, addr++, dptr++);
+ }
+ retval = isp_parse_flt_28xx(isp, flt_data);
+ return (retval);
+}
+
+static void
+isp_rd_28xx_flt(ispsoftc_t *isp, uint32_t addr, uint32_t *rp)
+{
+ fcparam *fcp = FCPARAM(isp, 0);
+ int loops = 0;
+ uint32_t base = fcp->flash_data_addr;
+ uint32_t tmp = 0;
+
+ ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr);
+ for (loops = 0; loops < 5000; loops++) {
+ ISP_DELAY(10);
+ tmp = ISP_READ(isp, BIU2400_FLASH_ADDR);
+ if ((tmp & (1U << 31)) != 0) {
+ break;
+ }
+ }
+ if (tmp & (1U << 31)) {
+ *rp = ISP_READ(isp, BIU2400_FLASH_DATA);
+ ISP_SWIZZLE_NVRAM_LONG(isp, rp);
+ } else {
+ *rp = 0xffffffff;
+ }
+}
+
+static int
+isp_parse_flt_28xx(ispsoftc_t *isp, uint8_t *flt_data)
+{
+ fcparam *fcp = FCPARAM(isp, 0);
+ int count;
+ struct flt_region region[fcp->flt_region_entries];
+
+ for (count = 0; count < fcp->flt_region_entries; count++) {
+ region[count].code =
+ le16toh((uint16_t) (ISP28XX_FLT_REG_CODE(flt_data, count)));
+ region[count].attribute =
+ (uint8_t) (ISP28XX_FLT_REG_ATTR(flt_data, count));
+ region[count].reserved =
+ (uint8_t) (ISP28XX_FLT_REG_RES(flt_data, count));
+ region[count].size =
+ le32toh((uint32_t) (ISP28XX_FLT_REG_SIZE(flt_data, count)) >> 2);
+ region[count].start =
+ le32toh((uint32_t) (ISP28XX_FLT_REG_START(flt_data, count)) >> 2);
+ region[count].end =
+ le32toh((uint32_t) (ISP28XX_FLT_REG_END(flt_data, count)) >> 2);
+
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "FLT[0x%x]: start=0x%x end=0x%x size=0x%x attribute=0x%x",
+ region[count].code, region[count].start, region[count].end,
+ region[count].size, region[count].attribute);
+
+ switch(region[count].code) {
+ case FLT_REG_FW:
+ fcp->flt_region_fw = region[count].start;
+ break;
+ case FLT_REG_BOOT_CODE:
+ fcp->flt_region_boot = region[count].start;
+ break;
+ case FLT_REG_VPD_0:
+ fcp->flt_region_vpd_nvram = region[count].start;
+ if (isp->isp_port == 0)
+ fcp->flt_region_vpd = region[count].start;
+ break;
+ case FLT_REG_VPD_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_vpd = region[count].start;
+ break;
+ case FLT_REG_VPD_2:
+ if (isp->isp_port == 2)
+ fcp->flt_region_vpd = region[count].start;
+ break;
+ case FLT_REG_VPD_3:
+ if (isp->isp_port == 3)
+ fcp->flt_region_vpd = region[count].start;
+ break;
+ case FLT_REG_NVRAM_0:
+ if (isp->isp_port == 0)
+ fcp->flt_region_nvram = region[count].start;
+ break;
+ case FLT_REG_NVRAM_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_nvram = region[count].start;
+ break;
+ case FLT_REG_NVRAM_2:
+ if (isp->isp_port == 2)
+ fcp->flt_region_nvram = region[count].start;
+ break;
+ case FLT_REG_NVRAM_3:
+ if (isp->isp_port == 3)
+ fcp->flt_region_nvram = region[count].start;
+ break;
+ case FLT_REG_FDT:
+ fcp->flt_region_fdt = region[count].start;
+ break;
+ case FLT_REG_FLT:
+ fcp->flt_region_flt = region[count].start;
+ break;
+ case FLT_REG_NPIV_CONF_0:
+ if (isp->isp_port == 0)
+ fcp->flt_region_npiv_conf = region[count].start;
+ break;
+ case FLT_REG_NPIV_CONF_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_npiv_conf = region[count].start;
+ break;
+ case FLT_REG_GOLD_FW:
+ fcp->flt_region_gold_fw = region[count].start;
+ break;
+ case FLT_REG_FCP_PRIO_0:
+ if (isp->isp_port == 0)
+ fcp->flt_region_fcp_prio = region[count].start;
+ break;
+ case FLT_REG_FCP_PRIO_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_fcp_prio = region[count].start;
+ break;
+ case FLT_REG_AUX_IMG_PRI_28XX:
+ fcp->flt_region_aux_img_status_pri = region[count].start;
+ break;
+ case FLT_REG_AUX_IMG_SEC_28XX:
+ fcp->flt_region_aux_img_status_sec = region[count].start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_0:
+ if (isp->isp_port == 0)
+ fcp->flt_region_nvram_sec = region[count].start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_nvram_sec = region[count].start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_2:
+ if (isp->isp_port == 2)
+ fcp->flt_region_nvram_sec = region[count].start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_3:
+ if (isp->isp_port == 3)
+ fcp->flt_region_nvram_sec = region[count].start;
+ break;
+ case FLT_REG_VPD_SEC_28XX_0:
+ fcp->flt_region_vpd_nvram_sec = region[count].start;
+ if (isp->isp_port == 0)
+ fcp->flt_region_vpd_sec = region[count].start;
+ break;
+ case FLT_REG_VPD_SEC_28XX_1:
+ if (isp->isp_port == 1)
+ fcp->flt_region_vpd_sec = region[count].start;
+ break;
+ case FLT_REG_VPD_SEC_28XX_2:
+ if (isp->isp_port == 2)
+ fcp->flt_region_vpd_sec = region[count].start;
+ break;
+ case FLT_REG_VPD_SEC_28XX_3:
+ if (isp->isp_port == 3)
+ fcp->flt_region_vpd_sec = region[count].start;
+ break;
+ }
+ }
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "FLT[FLT]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram 0x%x "
+ "fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x",
+ fcp->flt_region_boot, fcp->flt_region_fw, fcp->flt_region_vpd_nvram,
+ fcp->flt_region_vpd, fcp->flt_region_nvram, fcp->flt_region_fdt,
+ fcp->flt_region_flt, fcp->flt_region_npiv_conf,
+ fcp->flt_region_fcp_prio);
+
+ return (0);
+}
diff --git a/sys/dev/isp/ispreg.h b/sys/dev/isp/ispreg.h
index 4f7bc9cb37ce..9d2594a97a99 100644
--- a/sys/dev/isp/ispreg.h
+++ b/sys/dev/isp/ispreg.h
@@ -252,4 +252,85 @@ typedef struct {
#define ISP2400_NVRAM_FIRMWARE_OPTIONS3(c) \
((c)[52] | ((c)[53] << 8) | ((c)[54] << 16) | ((c)[55] << 24))
+/*
+ * Qlogic FLT
+ */
+#define ISP24XX_BASE_ADDR 0x7ff00000
+#define ISP24XX_FLT_ADDR 0x11400
+
+#define ISP25XX_BASE_ADDR ISP24XX_BASE_ADDR
+#define ISP25XX_FLT_ADDR 0x50400
+
+#define ISP27XX_BASE_ADDR 0x7f800000
+#define ISP27XX_FLT_ADDR (0x3F1000/4)
+
+#define ISP28XX_BASE_ADDR 0x7f7d0000
+#define ISP28XX_FLT_ADDR (0x11000/4)
+
+#define FLT_HEADER_SIZE 8
+#define FLT_REGION_SIZE 16
+#define FLT_MAX_REGIONS 0xFF
+#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS)
+
+#define ISP28XX_FLT_VERSION(c) ((c)[0] | ((c)[1] << 8))
+#define ISP28XX_FLT_LENGTH(c) ((c)[2] | ((c)[3] << 8))
+#define ISP28XX_FLT_CSUM(c) ((c)[4] | ((c)[5] << 8))
+#define ISP28XX_FLT_REG_CODE(c, o) \
+ ((c)[0 + FLT_REGION_SIZE * o] | ((c)[1 + FLT_REGION_SIZE * o] << 8))
+#define ISP28XX_FLT_REG_ATTR(c, o) ((c)[2 + FLT_REGION_SIZE * o])
+#define ISP28XX_FLT_REG_RES(c, o) ((c)[3 + FLT_REGION_SIZE * o])
+#define ISP28XX_FLT_REG_SIZE(c, o) (\
+ ((uint32_t)(c)[4 + FLT_REGION_SIZE * o] << 0) | \
+ ((uint32_t)(c)[5 + FLT_REGION_SIZE * o] << 8) | \
+ ((uint32_t)(c)[6 + FLT_REGION_SIZE * o] << 16) | \
+ ((uint32_t)(c)[7 + FLT_REGION_SIZE * o] << 24))
+#define ISP28XX_FLT_REG_START(c, o) (\
+ ((uint32_t)(c)[8 + FLT_REGION_SIZE * o] << 0) | \
+ ((uint32_t)(c)[9 + FLT_REGION_SIZE * o] << 8) | \
+ ((uint32_t)(c)[10 + FLT_REGION_SIZE * o] << 16) | \
+ ((uint32_t)(c)[11 + FLT_REGION_SIZE * o] << 24))
+#define ISP28XX_FLT_REG_END(c, o) (\
+ ((uint32_t)(c)[12 + FLT_REGION_SIZE * o] << 0) | \
+ ((uint32_t)(c)[13 + FLT_REGION_SIZE * o] << 8) | \
+ ((uint32_t)(c)[14 + FLT_REGION_SIZE * o] << 16) | \
+ ((uint32_t)(c)[15 + FLT_REGION_SIZE * o] << 24))
+
+struct flt_region {
+ uint16_t code;
+ uint8_t attribute;
+ uint8_t reserved;
+ uint32_t size;
+ uint32_t start;
+ uint32_t end;
+};
+
+#define FLT_REG_FW 0x01
+#define FLT_REG_BOOT_CODE 0x07
+#define FLT_REG_VPD_0 0x14
+#define FLT_REG_NVRAM_0 0x15
+#define FLT_REG_VPD_1 0x16
+#define FLT_REG_NVRAM_1 0x17
+#define FLT_REG_VPD_2 0xd4
+#define FLT_REG_NVRAM_2 0xd5
+#define FLT_REG_VPD_3 0xd6
+#define FLT_REG_NVRAM_3 0xd7
+#define FLT_REG_FDT 0x1a
+#define FLT_REG_FLT 0x1c
+#define FLT_REG_NPIV_CONF_0 0x29
+#define FLT_REG_NPIV_CONF_1 0x2a
+#define FLT_REG_GOLD_FW 0x2f
+#define FLT_REG_FCP_PRIO_0 0x87
+#define FLT_REG_FCP_PRIO_1 0x88
+
+#define FLT_REG_AUX_IMG_PRI_28XX 0x125
+#define FLT_REG_AUX_IMG_SEC_28XX 0x126
+#define FLT_REG_NVRAM_SEC_28XX_0 0x10d
+#define FLT_REG_NVRAM_SEC_28XX_1 0x10f
+#define FLT_REG_NVRAM_SEC_28XX_2 0x111
+#define FLT_REG_NVRAM_SEC_28XX_3 0x113
+#define FLT_REG_VPD_SEC_28XX_0 0x10c
+#define FLT_REG_VPD_SEC_28XX_1 0x10e
+#define FLT_REG_VPD_SEC_28XX_2 0x110
+#define FLT_REG_VPD_SEC_28XX_3 0x112
+
#endif /* _ISPREG_H */
diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h
index c597e715fa14..ae693c5c15e8 100644
--- a/sys/dev/isp/ispvar.h
+++ b/sys/dev/isp/ispvar.h
@@ -369,6 +369,28 @@ typedef struct {
int isp_use_gft_id; /* Use GFT_ID */
int isp_use_gff_id; /* Use GFF_ID */
+ uint32_t flash_data_addr;
+ /*
+ * FLT
+ */
+ uint16_t flt_length;
+ uint32_t flt_region_entries;
+ uint32_t flt_region_aux_img_status_pri;
+ uint32_t flt_region_aux_img_status_sec;
+ uint32_t flt_region_boot;
+ uint32_t flt_region_fcp_prio;
+ uint32_t flt_region_fdt;
+ uint32_t flt_region_flt;
+ uint32_t flt_region_fw;
+ uint32_t flt_region_gold_fw;
+ uint32_t flt_region_npiv_conf;
+ uint32_t flt_region_nvram;
+ uint32_t flt_region_nvram_sec;
+ uint32_t flt_region_vpd;
+ uint32_t flt_region_vpd_nvram;
+ uint32_t flt_region_vpd_nvram_sec;
+ uint32_t flt_region_vpd_sec;
+
/*
* Current active WWNN/WWPN
*/