diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-20 03:54:17 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2004-03-20 03:54:17 +0000 |
commit | 1b1d62eac8378ffe9933e2937e55e990078cd4d6 (patch) | |
tree | 4d798a3422c6d9b83f18d6fd46f388d1c91e4012 /sys | |
parent | f56163e66caaae31b77570a65b994446117ad454 (diff) |
Implement firmware download.
From Milos Urbanek via Marco Peereboom, with suggestions from LSI.
ok deraadt@.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/mpt.c | 185 | ||||
-rw-r--r-- | sys/dev/ic/mpt.h | 5 | ||||
-rw-r--r-- | sys/dev/ic/mpt_openbsd.h | 3 |
3 files changed, 177 insertions, 16 deletions
diff --git a/sys/dev/ic/mpt.c b/sys/dev/ic/mpt.c index f10a2b91c24..d5efe1cb2d8 100644 --- a/sys/dev/ic/mpt.c +++ b/sys/dev/ic/mpt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt.c,v 1.3 2004/03/19 02:47:36 krw Exp $ */ +/* $OpenBSD: mpt.c,v 1.4 2004/03/20 03:54:16 krw Exp $ */ /* $NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $ */ /* @@ -181,6 +181,9 @@ mpt_soft_reset(mpt_softc_t *mpt) void mpt_hard_reset(mpt_softc_t *mpt) { + u_int32_t diag0; + int count; + /* This extra read comes for the Linux source * released by LSI. It's function is undocumented! */ @@ -214,9 +217,25 @@ mpt_hard_reset(mpt_softc_t *mpt) /* Note that if there is no valid firmware to run, the doorbell will remain in the reset state (0x00000000) */ - if (mpt->download_fw) { - /* FIXME do download boot we panic for now */ - panic("FWDownloadBoot not implemented yet."); + + /* try to download firmware, if available */ + if (mpt->fw) { + /* wait for the adapter to finish the reset */ + for (count = 0; count < 30; count++) { + diag0 = mpt_read(mpt, MPI_DIAGNOSTIC_OFFSET); + mpt_prt(mpt, "diag0=%08x\n", diag0); + if (!(diag0 & MPI_DIAG_RESET_ADAPTER)) { + break; + } + + /* wait 1 second */ + DELAY(1000); + } + count = mpt_downloadboot(mpt); + if (count < 0) { + panic("firmware downloadboot failure (%d)!\n", + count); + } } } @@ -1149,14 +1168,6 @@ mpt_init(mpt_softc_t *mpt, u_int32_t who) mpt->fw_download_boot = facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT; - /* if download boot set download flag */ - if (mpt->fw_download_boot) { - mpt->download_fw = 1; - } - else { - mpt->download_fw = 0; - } - mpt->fw_image_size = facts.FWImageSize; if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { @@ -1327,7 +1338,7 @@ mpt_do_upload(mpt_softc_t *mpt) prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; prequest->Function = MPI_FUNCTION_FW_UPLOAD; - prequest->MsgContext = 0; /* XXX MU ok? */ + prequest->MsgContext = 0; ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; ptcsge->Reserved = 0; @@ -1407,3 +1418,151 @@ mpt_do_upload(mpt_softc_t *mpt) return error; } +/* + * mpt_downloadboot - DownloadBoot code + * Returns 0 for success, <0 for failure + */ +int +mpt_downloadboot(mpt_softc_t *mpt) +{ + MpiFwHeader_t *fwhdr = NULL; + MpiExtImageHeader_t *exthdr = NULL; + int fw_size; + u_int32_t diag0; +#if MPT_DEBUG + u_int32_t diag1; +#endif + int count = 0; + u_int32_t *ptr = NULL; + u_int32_t nextimg; + u_int32_t load_addr; + u_int32_t diagrw_data; + +#ifdef MPT_DEBUG + diag0 = mpt_read(mpt, MPT_OFFSET_DIAGNOSTIC); + if (mpt->mpt2) + diag1 = mpt_read(mpt->mpt2, MPT_OFFSET_DIAGNOSTIC); + mpt_prt(mpt, "diag0=%08x, diag1=%08x\n", diag0, diag1); +#endif + mpt_prt(mpt, "fw size 0x%x, ioc FW ptr %p\n", + mpt->fw_image_size, mpt->fw); + if (mpt->mpt2) + mpt_prt(mpt->mpt2, "ioc FW ptr %p\n", mpt->mpt2->fw); + + fw_size = mpt->fw_image_size; + + if (fw_size == 0) + return -1; + + mpt_prt(mpt, "FW Image @ %p\n", mpt->fw); + + if (!mpt->fw) + return -2; + + /* + * Write magic sequence to WriteSequence register + * until enter diagnostic mode + */ + diag0 = mpt_read(mpt, MPT_OFFSET_DIAGNOSTIC); + while ((diag0 & MPI_DIAG_DRWE) == 0) { + mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); + mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); + mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); + mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); + mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); + mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); + + /* wait 100msec */ + DELAY(100); + + count++; + if (count > 20) { + mpt_prt(mpt, "enable diagnostic mode FAILED! (%02xh)\n", + diag0); + return -EFAULT; + } + + diag0 = mpt_read(mpt, MPT_OFFSET_DIAGNOSTIC); +#ifdef MPT_DEBUG + if (mpt->mpt2) + diag1 = mpt_read(mpt->mpt2, MPT_OFFSET_DIAGNOSTIC); + mpt_prt(mpt, "diag0=%08x, diag1=%08x\n", diag0, diag1); +#endif + mpt_prt(mpt, "wrote magic DiagWriteEn sequence (%x)\n", diag0); + } + + /* Set the DiagRwEn and Disable ARM bits */ + diag0 |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM); + mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, diag0); + +#ifdef MPT_DEBUG + if (mpt->mpt2) + diag1 = mpt_read(mpt->mpt2, MPT_OFFSET_DIAGNOSTIC); + mpt_prt(mpt, "diag0=%08x, diag1=%08x\n", diag0, diag1); +#endif + + fwhdr = (MpiFwHeader_t *) mpt->fw; + ptr = (u_int32_t *) fwhdr; + count = (fwhdr->ImageSize + 3)/4; + nextimg = fwhdr->NextImageHeaderOffset; + + /* + * write the LoadStartAddress to the DiagRw Address Register + * XXX linux is using programmed IO for the RWADDR and RWDATA + */ + mpt_write(mpt, MPT_OFFSET_RWADDR, fwhdr->LoadStartAddress); + + mpt_prt(mpt, "LoadStart addr written 0x%x \n", fwhdr->LoadStartAddress); + mpt_prt(mpt, "writing file image: 0x%x u32's @ %p\n", count, ptr); + + while (count--) { + mpt_write(mpt, MPT_OFFSET_RWDATA, *ptr); + ptr++; + } + + while (nextimg) { + ptr = (u_int32_t *) (mpt->fw + nextimg); + exthdr = (MpiExtImageHeader_t *) ptr; + count = (exthdr->ImageSize +3)/4; + nextimg = exthdr->NextImageHeaderOffset; + load_addr = exthdr->LoadStartAddress; + + mpt_prt(mpt, "write ext image: 0x%x u32's @ %p\n", count, ptr); + + mpt_write(mpt, MPT_OFFSET_RWADDR, load_addr); + + while (count--) { + mpt_write(mpt, MPT_OFFSET_RWDATA, *ptr); + ptr++; + } + } + + /* write the IopResetVectorRegAddr */ + mpt_prt(mpt, "write IopResetVector addr!\n"); + mpt_write(mpt, MPT_OFFSET_RWADDR, fwhdr->IopResetRegAddr); + + /* write the IopResetVectorValue */ + mpt_prt(mpt, "write IopResetVector value!\n"); + mpt_write(mpt, MPT_OFFSET_RWDATA, fwhdr->IopResetVectorValue); + + /* + * clear the internal flash bad bit - autoincrementing register, + * so must do two writes. + */ + mpt_write(mpt, MPT_OFFSET_RWADDR, 0x3F000000); + diagrw_data = mpt_read(mpt, MPT_OFFSET_RWDATA); + diagrw_data |= 0x4000000; + mpt_write(mpt, MPT_OFFSET_RWADDR, 0x3F000000); + mpt_write(mpt, MPT_OFFSET_RWDATA, diagrw_data); + + /* clear the RW enable and DISARM bits */ + diag0 = mpt_read(mpt, MPT_OFFSET_DIAGNOSTIC); + diag0 &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE + | MPI_DIAG_FLASH_BAD_SIG); + mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, diag0); + + /* write 0xFF to reset the sequencer */ + mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); + + return 0; +} diff --git a/sys/dev/ic/mpt.h b/sys/dev/ic/mpt.h index b79f32cf802..73a6aa5bf03 100644 --- a/sys/dev/ic/mpt.h +++ b/sys/dev/ic/mpt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt.h,v 1.2 2004/03/17 00:47:06 krw Exp $ */ +/* $OpenBSD: mpt.h,v 1.3 2004/03/20 03:54:16 krw Exp $ */ /* $NetBSD: mpt.h,v 1.2 2003/07/08 10:06:31 itojun Exp $ */ /* @@ -51,6 +51,8 @@ #define MPT_OFFSET_SEQUENCE 0x04 #define MPT_OFFSET_DIAGNOSTIC 0x08 #define MPT_OFFSET_TEST 0x0C +#define MPT_OFFSET_RWDATA 0x10 +#define MPT_OFFSET_RWADDR 0x14 #define MPT_OFFSET_INTR_STATUS 0x30 #define MPT_OFFSET_INTR_MASK 0x34 #define MPT_OFFSET_REQUEST_Q 0x40 @@ -178,6 +180,7 @@ int mpt_read_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); int mpt_write_cfg_page(mpt_softc_t *, int, fCONFIG_PAGE_HEADER *); /* FW Download Boot */ +int mpt_downloadboot(mpt_softc_t *); int mpt_do_upload(mpt_softc_t *); int mpt_alloc_fw_mem(mpt_softc_t *, uint32_t , int); void mpt_free_fw_mem(mpt_softc_t *); diff --git a/sys/dev/ic/mpt_openbsd.h b/sys/dev/ic/mpt_openbsd.h index c1586c7b9a9..0cdc9ad9338 100644 --- a/sys/dev/ic/mpt_openbsd.h +++ b/sys/dev/ic/mpt_openbsd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mpt_openbsd.h,v 1.5 2004/03/19 02:47:36 krw Exp $ */ +/* $OpenBSD: mpt_openbsd.h,v 1.6 2004/03/20 03:54:16 krw Exp $ */ /* $NetBSD: mpt_netbsd.h,v 1.2 2003/04/16 23:02:14 thorpej Exp $ */ /* @@ -266,7 +266,6 @@ typedef struct mpt_softc { uint32_t success; /* success after timeout */ uint8_t upload_fw; /* If set, do a fw upload */ - uint8_t download_fw; /* If set, do a fw download */ /* Firmware memory */ bus_dmamap_t fw_dmap; int fw_rseg; |