Date: Fri, 19 Jan 2024 16:53:30 GMT From: Alexander Motin <mav@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: a922b89834ef - stable/13 - isp(4): Add support to read contents of the FLT (flash layout table) Message-ID: <202401191653.40JGrUHR060007@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=a922b89834ef611395cb440a5b4098d2c741c5fd commit a922b89834ef611395cb440a5b4098d2c741c5fd Author: Joerg Pulz <Joerg.Pulz@frm2.tum.de> AuthorDate: 2023-07-07 21:43:34 +0000 Commit: Alexander Motin <mav@FreeBSD.org> CommitDate: 2024-01-19 16:51:45 +0000 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 (cherry picked from commit 27b4a1b7e5b871c248dc501aa359c93f7263b074) --- sys/dev/isp/isp.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++- sys/dev/isp/ispreg.h | 81 ++++++++++++++ sys/dev/isp/ispvar.h | 22 ++++ 3 files changed, 397 insertions(+), 2 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index eddf175e669b..8eeeef33ca11 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -122,6 +122,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) { @@ -4333,18 +4341,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++); @@ -4380,7 +4406,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)) { @@ -4448,3 +4476,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 c4e379e881b6..953c86f72f69 100644 --- a/sys/dev/isp/ispreg.h +++ b/sys/dev/isp/ispreg.h @@ -251,4 +251,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 faf26bc7b055..4af309b51932 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -368,6 +368,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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202401191653.40JGrUHR060007>