diff options
author | brooks <brooks@FreeBSD.org> | 2012-08-25 18:08:20 +0000 |
---|---|---|
committer | brooks <brooks@FreeBSD.org> | 2012-08-25 18:08:20 +0000 |
commit | b4eee9541e5d371d4fbbda29db51fdc8f54620c7 (patch) | |
tree | de1757a58d5aeb15579c0707c60afd8287b24d0f | |
parent | e384ca8b42c7be835c0d338f6038966641c9b9c9 (diff) | |
download | FreeBSD-src-b4eee9541e5d371d4fbbda29db51fdc8f54620c7.zip FreeBSD-src-b4eee9541e5d371d4fbbda29db51fdc8f54620c7.tar.gz |
Add isf(4), a driver for the Intel StrataFlash family of NOR flash parts.
The driver attempts to support all documented parts, but has only been
tested with the 512Mbit part on the Terasic DE4 FPGA board. It should be
trivial to adapt the driver's attach routine to other embedded boards
using with any parts in the family.
Also import isfctl(8) which can be used to erase sections of the flash.
Sponsored by: DARPA, AFRL
-rw-r--r-- | share/man/man4/Makefile | 1 | ||||
-rw-r--r-- | share/man/man4/isf.4 | 135 | ||||
-rw-r--r-- | sys/conf/files | 2 | ||||
-rw-r--r-- | sys/dev/isf/isf.c | 740 | ||||
-rw-r--r-- | sys/dev/isf/isf.h | 94 | ||||
-rw-r--r-- | sys/dev/isf/isf_nexus.c | 120 | ||||
-rw-r--r-- | sys/mips/conf/BERI_DE4.hints | 10 | ||||
-rw-r--r-- | sys/mips/conf/BERI_DE4_MDROOT | 1 | ||||
-rw-r--r-- | sys/mips/conf/BERI_DE4_SDROOT | 1 | ||||
-rw-r--r-- | usr.sbin/Makefile | 1 | ||||
-rw-r--r-- | usr.sbin/isfctl/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/isfctl/isfctl.8 | 89 | ||||
-rw-r--r-- | usr.sbin/isfctl/isfctl.c | 115 |
13 files changed, 1316 insertions, 0 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index e0124fa..1863c55 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -192,6 +192,7 @@ MAN= aac.4 \ ipwfw.4 \ isci.4 \ iscsi_initiator.4 \ + isf.4 \ isp.4 \ ispfw.4 \ iwi.4 \ diff --git a/share/man/man4/isf.4 b/share/man/man4/isf.4 new file mode 100644 index 0000000..f863720 --- /dev/null +++ b/share/man/man4/isf.4 @@ -0,0 +1,135 @@ +.\"- +.\" Copyright (c) 2012 SRI International +.\" All rights reserved. +.\" +.\" This software was developed by SRI International and the University of +.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) +.\" ("CTSRD"), as part of the DARPA CRASH research programme. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 3, 2012 +.Dt ISF 4 +.Os +.Sh NAME +.Nm isf +.Nd driver for Intel StrataFlash NOR flash devices +.Sh SYNOPSIS +.Cd "device isf" +.Pp +In +.Pa /boot/device.hints : +.Cd hint.isf.0.at="nexus0" +.Cd hint.isf.0.maddr=0x74000000 +.Cd hint.isf.0.msize=0x2000000 +.Sh DESCRIPTION +The +.Nm +device driver provides support for Intel StrataFlash NOR flash devices. +Devices are presented as +.Xr disk 9 +devices and read access is supported along with limited write support. +Erasing blocks is supported the +.Dv ISF_ERASE +ioctl. +.Pp +The erase block size of +.Nm +devices is 128K. +NOR flash blocks contains all 1's after an erase cycle. +Writes to +.Nm +devices are allowed to succeed if and only if they all bits in the write +block (512-bytes) remain the same or transition from 1 to 0. +.Sh HARDWARE +The current version of the +.Nm +driver is known to support the 64MB part found on the Altera DE4 board. +It attempts to support other StrataFlash parts documented in the +datasheet, but those are untested. +.Sh IOCTLS +The +.Nm device +supports the +.Xr ioctl 2 +command codes: +.Bl -tag -width ISF_ERASE +.It Dv ISF_ERASE +Erase one or more blocks. +.Dv ISF_ERASE is defined as follows: +.Bd -literal + struct isf_range { + off_t ir_off; + size_t ir_size; + }; + + #define ISF_ERASE _IOW('I', 1, struct isf_range) +.Ed +.Pp +The +.Li ir_off +member marks the beginning of the area to be erased and must fall on at 128K +boundary. +The +.Li ir_size +member indicates the size of the area to be erased and must a multiple +of 128K. +.El +.Sh SEE ALSO +.Xr isfctl 4 , +.Xr disk 9 +.Rs +.%T Intel StrataFlash Embedded Memory (P30) +.%D November 1, 2005 +.%I Intel Corporation +.%U http://www.xilinx.com/products/boards/ml505/datasheets/30666604.pdf +.Re +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 10.0 . +.Sh AUTHORS +The +.Nm +device driver and this manual page were +developed by SRI International and the University of Cambridge Computer +Laboratory under DARPA/AFRL contract +.Pq FA8750-10-C-0237 +.Pq Do CTSRD Dc , +as part of the DARPA CRASH research programme. +.Sh BUGS +While an erase is in progress, all read and write operations return +.Er EBUSY . +In principle, reads could be allowed outside the programming region the +blocked currently being erased resides in and writes could be allowed by +suspending the erase, but neither of these is currently implemented. +.Pp +Depending on the flash part ether the top or bottom 128K of the flash +address space is divided into 4 32K erase blocks. +The +.Nm +driver hides this from the user requiring that all erase requests be +multiples of 128K in size and erasing the individual blocks as needed at +the top or bottom. diff --git a/sys/conf/files b/sys/conf/files index 54100da..a95e045 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1380,6 +1380,8 @@ dev/iscsi/initiator/isc_cam.c optional iscsi_initiator scbus dev/iscsi/initiator/isc_soc.c optional iscsi_initiator scbus dev/iscsi/initiator/isc_sm.c optional iscsi_initiator scbus dev/iscsi/initiator/isc_subr.c optional iscsi_initiator scbus +dev/isf/isf.c optional isf +dev/isf/isf_nexus.c optional isf dev/isp/isp.c optional isp dev/isp/isp_freebsd.c optional isp dev/isp/isp_library.c optional isp diff --git a/sys/dev/isf/isf.c b/sys/dev/isf/isf.c new file mode 100644 index 0000000..b3ac080 --- /dev/null +++ b/sys/dev/isf/isf.c @@ -0,0 +1,740 @@ +/*- + * Copyright (c) 2012 Robert N. M. Watson + * Copyright (c) 2012 SRI International + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/module.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/endian.h> +#include <sys/bio.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/rman.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <geom/geom_disk.h> + +#include <dev/isf/isf.h> + +/* Read Mode */ +#define ISF_CMD_RA 0xFF /* Read Array mode */ +#define ISF_CMD_RSR 0x70 /* Read Status Register mode */ +#define ISF_CMD_RDI 0x90 /* Read Device ID/Config Reg mode */ +#define ISF_CMD_RQ 0x98 /* Read Query mode */ +#define ISF_CMD_CSR 0x50 /* Clear Status Register */ + +/* Write Mode */ +#define ISF_CMD_WPS 0x40 /* Word Program Setup */ +#define ISF_CMD_BPS 0xE8 /* Buffered Program Setup */ +#define ISF_CMD_BPC 0xD0 /* Buffered Program Confirm */ + +/* Erase Mode */ +#define ISF_CMD_BES 0x20 /* Block Erase Setup */ +#define ISF_CMD_BEC 0xD0 /* Block Erase Confirm */ + +/* Block Locking/Unlocking */ +#define ISF_CMD_LBS 0x60 /* Lock Block Setup */ +#define ISF_CMD_LB 0x01 /* Lock Block */ +#define ISF_CMD_UB 0xD0 /* Unlock Block */ + +/* + * Read Device Identifier registers. + * + * NOTE: ISF_RDIR_BLC is relative to the block base address. + */ +#define ISF_REG_MC 0x00 /* Manufacture Code */ +#define ISF_REG_ID 0x01 /* Device ID Code */ +#define ISF_REG_BLC 0x02 /* Block Lock Configuration */ +#define ISF_REG_RCR 0x05 /* Read Configuration Register */ + +/* + * Protection Registers + */ +#define ISF_REG_L0 0x80 /* Lock Register 0 */ +#define ISF_REG_FPP 0x81 /* 64-bit Factory Protection Register */ +#define ISF_REG_UPP 0x85 /* 64-bit User Protection Register */ +#define ISF_REG_L1 0x89 /* Lock Register 1 */ +#define ISF_REG_PP1 0x8A /* 128-bit Protection Register 1 */ +#define ISF_REG_PP2 0x92 /* 128-bit Protection Register 2 */ +#define ISF_REG_PP3 0x9A /* 128-bit Protection Register 3 */ +#define ISF_REG_PP4 0xA2 /* 128-bit Protection Register 4 */ +#define ISF_REG_PP5 0xAA /* 128-bit Protection Register 5 */ +#define ISF_REG_PP6 0xB2 /* 128-bit Protection Register 6 */ +#define ISF_REG_PP7 0xBA /* 128-bit Protection Register 7 */ +#define ISF_REG_PP8 0xC2 /* 128-bit Protection Register 8 */ +#define ISF_REG_PP9 0xCA /* 128-bit Protection Register 9 */ +#define ISF_REG_PP10 0xD2 /* 128-bit Protection Register 10 */ +#define ISF_REG_PP11 0xDA /* 128-bit Protection Register 11 */ +#define ISF_REG_PP12 0xE2 /* 128-bit Protection Register 12 */ +#define ISF_REG_PP13 0xEA /* 128-bit Protection Register 13 */ +#define ISF_REG_PP14 0xF2 /* 128-bit Protection Register 14 */ +#define ISF_REG_PP15 0xFA /* 128-bit Protection Register 15 */ +#define ISF_REG_PP16 0x102 /* 128-bit Protection Register 16 */ + +#define ISF_SR_BWS (1 << 0) /* BEFP Status */ +#define ISF_SR_BLS (1 << 1) /* Block-Locked Status */ +#define ISF_SR_PSS (1 << 2) /* Program Suspend Status */ +#define ISF_SR_VPPS (1 << 3) /* Vpp Status */ +#define ISF_SR_PS (1 << 4) /* Program Status */ +#define ISF_SR_ES (1 << 5) /* Erase Status */ +#define ISF_SR_ESS (1 << 6) /* Erase Suspend Status */ +#define ISF_SR_DWS (1 << 7) /* Device Write Status */ +#define ISF_SR_FSC_MASK (ISF_SR_VPPS | ISF_SR_PS | ISF_SR_BLS) + +#define ISF_BUFFER_PROGRAM + +MALLOC_DEFINE(M_ISF, "isf_data", "Intel StrateFlash driver"); +static int isf_debug = 0; + +static struct isf_chips { + uint16_t chip_id; + size_t chip_size; + const char *chip_desc; +} chip_ids[] = { + { 0x8817, 0x0800000, "64-Mbit Top Parameter" }, + { 0x881A, 0x0800000, "64-Mbit Bottom Parameter" }, + { 0x8818, 0x1000000, "128-Mbit Top Parameter" }, + { 0x881B, 0x1000000, "128-Mbit Bottom Parameter" }, + { 0x8919, 0x2000000, "256-Mbit Top Parameter" }, + { 0x891C, 0x2000000, "256-Mbit Bottom Parameter" }, + { 0x8961, 0x2000000, "512-Mbit package (half)" }, + { 0x0000, 0x0000000, NULL } +}; + +static void isf_task(void *arg); + +/* + * Device driver for the Intel StrataFlash NOR flash device. This + * implementation is known to work with 256Mb instances of the device, but may + * also work with other 64/128/512Mb parts without much work. Multiple + * device instances should be used when multiple parts are in the same + * physical package, due to variable block size support in the StrataFlash + * part. + */ + +static uint16_t +isf_read_reg(struct isf_softc *sc, uint16_t reg) +{ + + if (isf_debug) + device_printf(sc->isf_dev, "isf_read_reg(0x%02x)\n", reg); + return (le16toh(bus_read_2(sc->isf_res, reg * 2))); +} + +static uint64_t +isf_read_reg64(struct isf_softc *sc, uint16_t reg) +{ + uint64_t val; + uint16_t *val16 = (uint16_t *)&val; + + if (isf_debug) + device_printf(sc->isf_dev, "isf_read_reg64(0x%02x)\n", reg); + val16[0] = bus_read_2(sc->isf_res, reg * 2); + val16[1] = bus_read_2(sc->isf_res, (reg+1) * 2); + val16[2] = bus_read_2(sc->isf_res, (reg+2) * 2); + val16[3] = bus_read_2(sc->isf_res, (reg+3) * 2); + + return(le64toh(val)); +} + +static uint16_t +isf_read_off(struct isf_softc *sc, off_t off) +{ + + KASSERT(off >= 0, ("%s: negative offset\n", __func__)); + KASSERT(off < sc->isf_disk->d_mediasize, + ("%s: offset out side address space 0x%08jx \n", __func__, + (intmax_t)off)); + + if (isf_debug) + device_printf(sc->isf_dev, "isf_read_off(0x%08jx)\n", + (intmax_t)off); + return (le16toh(bus_read_2(sc->isf_res, off))); +} + +static void +isf_write_cmd(struct isf_softc *sc, off_t off, uint16_t cmd) +{ + + if (isf_debug) + device_printf(sc->isf_dev, "isf_write_cmd(0x%08jx, 0x%02x)\n", + off, cmd); + bus_write_2(sc->isf_res, off, htole16(cmd)); +} + +static uint16_t +isf_read_status(struct isf_softc *sc, off_t off) +{ + + isf_write_cmd(sc, off/2, ISF_CMD_RSR); + return isf_read_off(sc, off); +} + +static void +isf_clear_status(struct isf_softc *sc) +{ + + isf_write_cmd(sc, 0, ISF_CMD_CSR); +} + +static int +isf_full_status_check(struct isf_softc *sc, off_t off) +{ + int error = 0; + uint16_t status; + + status = isf_read_status(sc, off); + if (status & ISF_SR_VPPS) { + device_printf(sc->isf_dev, "Vpp Range Error\n"); + error = EIO; + } else if (status & ISF_SR_PS) { + device_printf(sc->isf_dev, "Program Error\n"); + error = EIO; + } else if (status & ISF_SR_BLS) { + device_printf(sc->isf_dev, "Device Protect Error\n"); + error = EIO; + } + isf_clear_status(sc); + + return(error); +} + +static int +isf_full_erase_status_check(struct isf_softc *sc, off_t off) +{ + int error = 0; + uint16_t status; + + status = isf_read_status(sc, off); + if (status & ISF_SR_VPPS) { + device_printf(sc->isf_dev, "Vpp Range Error\n"); + error = EIO; + } else if (status & (ISF_SR_PS|ISF_SR_ES)) { + device_printf(sc->isf_dev, "Command Sequence Error\n"); + error = EIO; + } else if (status & ISF_SR_ES) { + device_printf(sc->isf_dev, "Block Erase Error\n"); + error = EIO; + } else if (status & ISF_SR_BLS) { + device_printf(sc->isf_dev, "Block Locked Error\n"); + error = EIO; + } + isf_clear_status(sc); + + return(error); +} + +static void +isf_unlock_block(struct isf_softc *sc, off_t off) +{ + + isf_write_cmd(sc, off, ISF_CMD_LBS); + isf_write_cmd(sc, off, ISF_CMD_UB); + isf_write_cmd(sc, off, ISF_CMD_RA); +} + +static void +isf_lock_block(struct isf_softc *sc, off_t off) +{ + + isf_write_cmd(sc, off, ISF_CMD_LBS); + isf_write_cmd(sc, off, ISF_CMD_LB); + isf_write_cmd(sc, off, ISF_CMD_RA); +} + +static void +isf_read(struct isf_softc *sc, off_t off, void *data, size_t len) +{ + + KASSERT((uintptr_t)data % 2 == 0, + ("%s: unaligned data %p", __func__, data)); + KASSERT((len <= ISF_SECTORSIZE) && (len % 2 == 0), + ("%s: invalid length %ju", __func__, len)); + KASSERT(off % ISF_SECTORSIZE == 0, + ("%s: invalid offset %ju\n", __func__, off)); + + /* + * It is not permitted to read blocks that are in the process of + * being erased, but we know they will be all 1's after the + * erase so just report that value if asked about a block that + * is being erased. + */ + if (sc->isf_bstate[off / ISF_ERASE_BLOCK] == BS_ERASING) + memset(data, 0xFF, len); + else + bus_read_region_2(sc->isf_res, off, (uint16_t *)data, len / 2); +} + +static int +isf_write(struct isf_softc *sc, off_t off, void *data, size_t len) +{ + int cycles, error = 0; + uint16_t *dp; + uint16_t status; + off_t coff; + + KASSERT((uintptr_t)data % 2 == 0, + ("%s: unaligned data %p", __func__, data)); + KASSERT((len <= ISF_SECTORSIZE) && (len % 2 == 0), + ("%s: invalid length %ju", __func__, len)); + KASSERT(off % ISF_SECTORSIZE == 0, + ("%s: invalid offset %ju\n", __func__, off)); + KASSERT(!sc->isf_erasing, + ("%s: trying to write while erasing\n", __func__)); + KASSERT(sc->isf_bstate[off / ISF_ERASE_BLOCK] != BS_ERASING, + ("%s: block being erased at %ju\n", __func__, off)); + + isf_unlock_block(sc, off); + +#ifdef ISF_BUFFER_PROGRAM + for (dp = data, coff = off; dp - (uint16_t *)data < len / 2; + dp += 32, coff += 64) { + isf_clear_status(sc); + isf_write_cmd(sc, coff, ISF_CMD_BPS); + cycles = 0xFFFF; + while ( !(isf_read_off(sc, coff) & ISF_SR_DWS) ) { + if (cycles-- == 0) { + device_printf(sc->isf_dev, "timeout waiting" + " for write to start at 0x08%jx\n", + (intmax_t)coff); + return (EIO); + } + isf_write_cmd(sc, coff, ISF_CMD_BPS); + } + + /* When writing N blocks, send N-1 as the count */ + isf_write_cmd(sc, coff, 31); + bus_write_region_2(sc->isf_res, coff, dp, 32); + + isf_write_cmd(sc, coff, ISF_CMD_BPC); + + status = isf_read_off(sc, coff); + cycles = 0xFFFFF; + while ( !(status & ISF_SR_DWS) ) { + if (cycles-- == 0) { + device_printf(sc->isf_dev, "timeout waiting" + " for write to complete at 0x08%jx\n", + (intmax_t)coff); + error = EIO; + break; + } + status = isf_read_off(sc, coff); + } + isf_full_status_check(sc, off); + + isf_write_cmd(sc, coff, ISF_CMD_RA); + } +#else + for (dp = data, coff = off; dp - (uint16_t *)data < len / 2; + dp++, coff += 2) { + isf_write_cmd(sc, coff, ISF_CMD_WPS); + bus_write_2(sc->isf_res, coff, *dp); + status = isf_read_off(sc, coff); + cycles=0xFFFFF; + while ( !(status & ISF_SR_DWS) ) { + if (cycles-- == 0) { + device_printf(sc->isf_dev, "timeout waiting" + " for write to complete at 0x08%jx\n", + (intmax_t)coff); + error = EIO; + break; + } + status = isf_read_off(sc, coff); + } + + } + isf_full_status_check(sc, off); + isf_write_cmd(sc, coff, ISF_CMD_RA); +#endif + + isf_lock_block(sc, off); + + return error; +} + +static void +isf_erase_at(struct isf_softc *sc, off_t off) +{ + int cycles; + uint16_t status; + + isf_unlock_block(sc, off); + isf_clear_status(sc); + + isf_write_cmd(sc, off, ISF_CMD_BES); + isf_write_cmd(sc, off, ISF_CMD_BEC); + + cycles=0xFFFFFF; + status = isf_read_off(sc, off); + while ( !(status & ISF_SR_DWS) ) { +#ifdef NOTYET + ISF_SLEEP(sc, sc, hz); +#endif + if (cycles-- == 0) { + device_printf(sc->isf_dev, + "Giving up on erase\n"); + break; + } + status = isf_read_off(sc, off); + } + + isf_full_erase_status_check(sc, off); + + isf_lock_block(sc, off); + + isf_write_cmd(sc, off, ISF_CMD_RA); +} + +static void +isf_erase_range(struct isf_softc *sc, off_t blk_off, size_t size) +{ + off_t off; + off_t ms = sc->isf_disk->d_mediasize; + + KASSERT(blk_off % ISF_ERASE_BLOCK == 0, + ("%s: invalid offset %ju\n", __func__, blk_off)); + + ISF_LOCK_ASSERT(sc); + + for (off = blk_off; off < blk_off + size; off += ISF_ERASE_BLOCK) { + sc->isf_bstate[off / ISF_ERASE_BLOCK] = BS_ERASING; + + /* + * The first or last 128K is four blocks depending which + * part this is. For now, just assume both are and + * erase four times. + */ + if (off == 0 || ms - off == ISF_ERASE_BLOCK) { + isf_erase_at(sc, off); + isf_erase_at(sc, off + 0x08000); + isf_erase_at(sc, off + 0x10000); + isf_erase_at(sc, off + 0x18000); + } else + isf_erase_at(sc, off); + + sc->isf_bstate[off / ISF_ERASE_BLOCK] = BS_STEADY; + } +} + +/* + * disk(9) methods. + */ +static int +isf_disk_ioctl(struct disk *disk, u_long cmd, void *data, int fflag, + struct thread *td) +{ + int error = 0; + struct isf_softc *sc = disk->d_drv1; + struct isf_range *ir; + + switch (cmd) { + case ISF_ERASE: + ir = data; + if (ir->ir_off % ISF_ERASE_BLOCK != 0 || + ir->ir_off >= disk->d_mediasize || + ir->ir_size == 0 || + ir->ir_size % ISF_ERASE_BLOCK != 0 || + ir->ir_off + ir->ir_size > disk->d_mediasize) { + error = EINVAL; + break; + } + ISF_LOCK(sc); + if (sc->isf_erasing) { + ISF_UNLOCK(sc); + error = EBUSY; + break; + } + sc->isf_erasing = 1; + isf_erase_range(sc, ir->ir_off, ir->ir_size); + sc->isf_erasing = 0; + ISF_UNLOCK(sc); + break; + default: + error = EINVAL; + } + + return (error); +} + +static void +isf_disk_strategy(struct bio *bp) +{ + struct isf_softc *sc = bp->bio_disk->d_drv1;; + + /* + * We advertise a block size and maximum I/O size up the stack; catch + * any attempts to not follow the rules. + */ + KASSERT(bp->bio_bcount == ISF_SECTORSIZE, + ("%s: I/O size not %d", __func__, ISF_SECTORSIZE)); + + ISF_LOCK(sc); + bioq_disksort(&sc->isf_bioq, bp); + ISF_WAKEUP(sc); + ISF_UNLOCK(sc); +} + +static void +isf_task(void *arg) +{ + struct isf_softc *sc = arg; + struct bio *bp; + int ss = sc->isf_disk->d_sectorsize; + int error, i; + + for (;;) { + ISF_LOCK(sc); + do { + bp = bioq_first(&sc->isf_bioq); + if (bp == NULL) { + if (sc->isf_doomed) + kproc_exit(0); + else + ISF_SLEEP(sc, sc, 0); + } + } while (bp == NULL); + bioq_remove(&sc->isf_bioq, bp); + + error = 0; + switch (bp->bio_cmd) { + case BIO_READ: + isf_read(sc, bp->bio_pblkno * ss, bp->bio_data, + bp->bio_bcount); + break; + + case BIO_WRITE: + /* + * In principle one could suspend the in-progress + * erase, process any pending writes to other + * blocks and then proceed, but that seems + * overly complex for the likely usage modes. + */ + if (sc->isf_erasing) { + error = EBUSY; + break; + } + + /* + * Read in the block we want to write and check that + * we're only setting bits to 0. If an erase would + * be required return an I/O error. + */ + isf_read(sc, bp->bio_pblkno * ss, sc->isf_rbuf, + bp->bio_bcount); + for (i = 0; i < bp->bio_bcount / 2; i++) + if ((sc->isf_rbuf[i] & + ((uint16_t *)bp->bio_data)[i]) != + ((uint16_t *)bp->bio_data)[i]) { + device_printf(sc->isf_dev, "write" + " requires erase at 0x%08jx\n", + bp->bio_pblkno * ss); + error = EIO; + break; + } + if (error != 0) + break; + + error = isf_write(sc, bp->bio_pblkno * ss, + bp->bio_data, bp->bio_bcount); + break; + + default: + panic("%s: unsupported I/O operation %d", __func__, + bp->bio_cmd); + } + if (error == 0) + biodone(bp); + else + biofinish(bp, NULL, error); + ISF_UNLOCK(sc); + } +} + +static void +isf_dump_info(struct isf_softc *sc) +{ + int i; + int32_t reg; + + isf_write_cmd(sc, 0, ISF_CMD_RDI); + device_printf(sc->isf_dev, "manufacturer code: 0x%04x\n", + isf_read_reg(sc, ISF_REG_MC)); + device_printf(sc->isf_dev, "device id code: 0x%04x\n", + isf_read_reg(sc, ISF_REG_ID)); + device_printf(sc->isf_dev, "read config register: 0x%04x\n", + isf_read_reg(sc, ISF_REG_RCR)); + + device_printf(sc->isf_dev, "lock register 0: 0x%04x\n", + isf_read_reg(sc, ISF_REG_L0)); + device_printf(sc->isf_dev, "lock register 1: 0x%04x\n", + isf_read_reg(sc, ISF_REG_L1)); + + device_printf(sc->isf_dev, "factory PPR: 0x%016jx\n", + (uintmax_t)isf_read_reg64(sc, ISF_REG_FPP)); + device_printf(sc->isf_dev, "user PPR (64-bit): 0x%016jx\n", + (uintmax_t)isf_read_reg64(sc, ISF_REG_UPP)); + + for (reg = ISF_REG_PP1, i = 1; reg <= ISF_REG_PP16; reg += 8, i++) { + /* XXX: big-endian ordering of uint64_t's */ + device_printf(sc->isf_dev, + "user PPR [%02d]: 0x%016jx%016jx\n", i, + (uintmax_t)isf_read_reg64(sc, reg+4), + (uintmax_t)isf_read_reg64(sc, reg)); + } + + isf_write_cmd(sc, 0, ISF_CMD_RA); +} + +static void +isf_disk_insert(struct isf_softc *sc, off_t mediasize) +{ + struct disk *disk; + + sc->isf_doomed = 0; + sc->isf_erasing = 0; + sc->isf_bstate = malloc(sizeof(*sc->isf_bstate) * + (mediasize / ISF_ERASE_BLOCK), M_ISF, M_ZERO | M_WAITOK); + kproc_create(&isf_task, sc, &sc->isf_proc, 0, 0, "isf"); + + disk = disk_alloc(); + disk->d_drv1 = sc; + disk->d_name = "isf"; + disk->d_unit = sc->isf_unit; + disk->d_strategy = isf_disk_strategy; + disk->d_ioctl = isf_disk_ioctl; + disk->d_sectorsize = ISF_SECTORSIZE; + disk->d_mediasize = mediasize; + disk->d_maxsize = ISF_SECTORSIZE; + sc->isf_disk = disk; + + if (bootverbose) + isf_dump_info(sc); + + disk_create(disk, DISK_VERSION); + device_printf(sc->isf_dev, "%juM flash device\n", + (uintmax_t)disk->d_mediasize / (1024 * 1024)); + +} + +static void +isf_disk_remove(struct isf_softc *sc) +{ + struct disk *disk; + + ISF_LOCK_ASSERT(sc); + KASSERT(sc->isf_disk != NULL, ("%s: isf_disk NULL", __func__)); + + sc->isf_doomed = 1; + ISF_WAKEUP(sc); + ISF_SLEEP(sc, sc->isf_proc, 0); + + /* + * XXXRW: Is it OK to call disk_destroy() under the mutex, or should + * we be deferring that to the calling context once it is released? + */ + disk = sc->isf_disk; + disk_gone(disk); + disk_destroy(disk); + sc->isf_disk = NULL; + free(sc->isf_bstate, M_ISF); + device_printf(sc->isf_dev, "flash device removed\n"); +} + +int +isf_attach(struct isf_softc *sc) +{ + uint16_t id; + u_long start, size; + struct isf_chips *cp = chip_ids; + + start = rman_get_start(sc->isf_res); + if (start % 2 != 0) { + device_printf(sc->isf_dev, + "Unsupported flash start alignment %lu\n", + start); + return (ENXIO); + } + + isf_write_cmd(sc, 0, ISF_CMD_RDI); + id = isf_read_reg(sc, ISF_REG_ID); + while (cp->chip_id != id) + cp++; + if (cp->chip_desc == NULL) { + device_printf(sc->isf_dev, + "Unsupported device ID 0x%04x\n", id); + return (ENXIO); + } + isf_write_cmd(sc, 0, ISF_CMD_RA); + + size = rman_get_size(sc->isf_res); + if (size != cp->chip_size) { + device_printf(sc->isf_dev, + "Unsupported flash size %lu\n", size); + return (ENXIO); + } + + bioq_init(&sc->isf_bioq); + ISF_LOCK_INIT(sc); + sc->isf_disk = NULL; + isf_disk_insert(sc, size); + return(0); +} + +void +isf_detach(struct isf_softc *sc) +{ + + /* + * Simulate a disk removal if one is present to deal with any pending + * or queued I/O. This will occur as a result of a device driver + * detach -- the Intel StrataFlash has no notion of removal itself. + * + * XXXRW: Is the locking here right? + */ + ISF_LOCK(sc); + isf_disk_remove(sc); + bioq_flush(&sc->isf_bioq, NULL, ENXIO); + KASSERT(bioq_first(&sc->isf_bioq) == NULL, + ("%s: non-empty bioq", __func__)); + ISF_UNLOCK(sc); + ISF_LOCK_DESTROY(sc); +} diff --git a/sys/dev/isf/isf.h b/sys/dev/isf/isf.h new file mode 100644 index 0000000..f5cdc08 --- /dev/null +++ b/sys/dev/isf/isf.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2012 Robert N. M. Watson + * Copyright (c) 2012 SRI International + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_ISF_H_ +#define _DEV_ISF_H_ + +struct isf_range { + off_t ir_off; /* Offset of range to delete (set to 0xFF) */ + size_t ir_size; /* Size of range */ +}; + +#define ISF_ERASE _IOW('I', 1, struct isf_range) + +/* + * Ordinary read and write operations are limited to 512 bytes. + * We support erasing 128K blocks and ignore the fact that portions of the + * flash are in fact divided into 32K blocks. + */ +#define ISF_SECTORSIZE (512) +#define ISF_ERASE_BLOCK (128 * 1024) + +#ifdef _KERNEL +MALLOC_DECLARE(M_ISF); + +enum bstate { + BS_STEADY = 0, + BS_ERASING +}; + +struct isf_softc { + device_t isf_dev; + int isf_unit; + struct resource *isf_res; + int isf_rid; + struct mtx isf_lock; + struct disk *isf_disk; + struct proc *isf_proc; + int isf_doomed; + + /* + * Fields relating to in-progress and pending I/O, if any. + */ + struct bio_queue_head isf_bioq; + uint16_t isf_rbuf[ISF_SECTORSIZE / 2]; + int isf_erasing; + enum bstate *isf_bstate; +}; + +#define ISF_LOCK(sc) mtx_lock(&(sc)->isf_lock) +#define ISF_LOCK_ASSERT(sc) mtx_assert(&(sc)->isf_lock, MA_OWNED) +#define ISF_LOCK_DESTROY(sc) mtx_destroy(&(sc)->isf_lock) +#define ISF_LOCK_INIT(sc) mtx_init(&(sc)->isf_lock, "isf", NULL, \ + MTX_DEF) +#define ISF_SLEEP(sc, wait, timo) mtx_sleep((wait), \ + &(sc)->isf_lock, PRIBIO, \ + "isf", (timo)) +#define ISF_UNLOCK(sc) mtx_unlock(&(sc)->isf_lock) +#define ISF_WAKEUP(sc) wakeup((sc)) + +int isf_attach(struct isf_softc *sc); +void isf_detach(struct isf_softc *sc); +#endif /* _KERNEL */ + +#endif /* _DEV_ISF_H_ */ diff --git a/sys/dev/isf/isf_nexus.c b/sys/dev/isf/isf_nexus.c new file mode 100644 index 0000000..af2f874 --- /dev/null +++ b/sys/dev/isf/isf_nexus.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2012 Robert N. M. Watson + * Copyright (c) 2012 SRI International + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/condvar.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/rman.h> +#include <sys/systm.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <geom/geom_disk.h> + +#include <dev/isf/isf.h> + +/* + * Nexus bus attachment for the Intel Strata Flash devices. Appropriate for + * most Altera FPGA SoC-style configurations in which the part will be exposed + * to the processor via a memory-mapped Avalon bus. + */ +static int +isf_nexus_probe(device_t dev) +{ + + device_set_desc(dev, "Intel StrataFlash NOR flash device"); + return (BUS_PROBE_DEFAULT); +} + +static int +isf_nexus_attach(device_t dev) +{ + int error; + struct isf_softc *sc; + + sc = device_get_softc(dev); + sc->isf_dev = dev; + sc->isf_unit = device_get_unit(dev); + sc->isf_rid = 0; + sc->isf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->isf_rid, RF_ACTIVE); + if (sc->isf_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + return (ENXIO); + } + error = isf_attach(sc); + if (error) + bus_release_resource(dev, SYS_RES_MEMORY, sc->isf_rid, + sc->isf_res); + return (error); +} + +static int +isf_nexus_detach(device_t dev) +{ + struct isf_softc *sc; + + sc = device_get_softc(dev); + KASSERT(sc->isf_res != NULL, ("%s: resources not allocated", + __func__)); + isf_detach(sc); + bus_release_resource(dev, SYS_RES_MEMORY, sc->isf_rid, sc->isf_res); + return (0); +} + +static device_method_t isf_nexus_methods[] = { + DEVMETHOD(device_probe, isf_nexus_probe), + DEVMETHOD(device_attach, isf_nexus_attach), + DEVMETHOD(device_detach, isf_nexus_detach), + { 0, 0 } +}; + +static driver_t isf_nexus_driver = { + "isf", + isf_nexus_methods, + sizeof(struct isf_softc), +}; + +static devclass_t isf_devclass; + +DRIVER_MODULE(isf, nexus, isf_nexus_driver, isf_devclass, 0, 0); diff --git a/sys/mips/conf/BERI_DE4.hints b/sys/mips/conf/BERI_DE4.hints index 319d0c2..4ffe6c2 100644 --- a/sys/mips/conf/BERI_DE4.hints +++ b/sys/mips/conf/BERI_DE4.hints @@ -46,6 +46,16 @@ hint.altera_avgen.0.devname="berirom" #hint.altera_avgen.0.mmapio="rwx" #hint.altera_avgen.0.devname="de4flash" +# +# General Intel StrataFlash driver +# +hint.isf.0.at="nexus0" +hint.isf.0.maddr=0x74000000 +hint.isf.0.msize=0x2000000 +hint.isf.1.at="nexus0" +hint.isf.1.maddr=0x76000000 +hint.isf.1.msize=0x2000000 + # Reserved configuration blocks. Don't touch. hint.map.0.at="isf0" hint.map.0.start=0x00000000 diff --git a/sys/mips/conf/BERI_DE4_MDROOT b/sys/mips/conf/BERI_DE4_MDROOT index 8903179..658c925 100644 --- a/sys/mips/conf/BERI_DE4_MDROOT +++ b/sys/mips/conf/BERI_DE4_MDROOT @@ -25,4 +25,5 @@ device altera_avgen device altera_jtag_uart device altera_sdcard +device isf #device sc diff --git a/sys/mips/conf/BERI_DE4_SDROOT b/sys/mips/conf/BERI_DE4_SDROOT index dcd177b..b41e6ff 100644 --- a/sys/mips/conf/BERI_DE4_SDROOT +++ b/sys/mips/conf/BERI_DE4_SDROOT @@ -18,4 +18,5 @@ device altera_avgen device altera_jtag_uart device altera_sdcard +device isf #device sc diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 95eb7b8..19c19c96 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -35,6 +35,7 @@ SUBDIR= adduser \ ifmcstat \ inetd \ iostat \ + isfctl \ kldxref \ mailwrapper \ makefs \ diff --git a/usr.sbin/isfctl/Makefile b/usr.sbin/isfctl/Makefile new file mode 100644 index 0000000..30f8e5b --- /dev/null +++ b/usr.sbin/isfctl/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= isfctl + +MAN= isfctl.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/isfctl/isfctl.8 b/usr.sbin/isfctl/isfctl.8 new file mode 100644 index 0000000..06b2f3a --- /dev/null +++ b/usr.sbin/isfctl/isfctl.8 @@ -0,0 +1,89 @@ +.\"- +.\" Copyright (c) 2012 SRI International +.\" All rights reserved. +.\" +.\" This software was developed by SRI International and the University of +.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) +.\" ("CTSRD"), as part of the DARPA CRASH research programme. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 3, 2012 +.Dt ISFCTL 8 +.Os +.Sh NAME +.Nm isfctl +.Nd Intel StrataFlash device control program +.Sh SYNOPSIS +.Nm +.Ar device +.Ic erase +.Ar offset +.Ar size +.Sh DESCRIPTION +The +.Nm +utility provides a way for administrators to control aspects of +.Xr isf 4 +devices that can not be managed though the +.Xr disk 9 +interface. +.Pp +The +.Nm +utility takes a device name as its first argument followed by a command. +Currently supported commands are: +.Bl -tag -width erase +.It Ic erase +Erase blocks beginning at +.Ar offset +covering a total of +.Ar size +bytes. +The +.Ar offset +argument must be a multiple of 128K. +The +.Ar size +argument must either be a multiple of 128K or a number less than 32K in +which case it is treated as a number of 128K blocks to erase. +.El +.Sh EXAMPLES +.Dl isfctl isf0 erase 0 0x20000 +.Pp +Erase the first block of the isf0 device. +.Sh SEE ALSO +.Xr isf 4 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 10.0 . +.Sh AUTHORS +This software and this manual page were +developed by SRI International and the University of Cambridge Computer +Laboratory under DARPA/AFRL contract +.Pq FA8750-10-C-0237 +.Pq Do CTSRD Dc , +as part of the DARPA CRASH research programme. diff --git a/usr.sbin/isfctl/isfctl.c b/usr.sbin/isfctl/isfctl.c new file mode 100644 index 0000000..af99093 --- /dev/null +++ b/usr.sbin/isfctl/isfctl.c @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2012 SRI International + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <err.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* XXXBED: should install and include sys/dev/isf.h */ +struct isf_range { + off_t ir_off; /* Offset of range to delete (set to 0xFF) */ + size_t ir_size; /* Size of range */ +}; + +#define ISF_ERASE _IOW('I', 1, struct isf_range) + +#define ISF_ERASE_BLOCK (128 * 1024) + +static enum {UNSET, ERASE} action = UNSET; + +static void +usage(void) +{ + fprintf(stderr, "usage: isfctl <device> erase <offset> <size>\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + struct isf_range ir; + int fd, i; + char *p, *dev; + + if (argc < 2) + usage(); + argc--; argv++; + + if (*argv[0] == '/') + dev = argv[0]; + else + asprintf(&dev, "/dev/%s", argv[0]); + argc--; argv++; + fd = open(dev, O_RDWR); + if (fd < 0) + err(1, "unable to open device -- %s", dev); + + if (strcmp(argv[0], "erase") == 0) { + if (argc != 3) + usage(); + action = ERASE; + ir.ir_off = strtol(argv[1], &p, 0); + if (*p) + errx(1, "invalid offset -- %s", argv[2]); + ir.ir_size = strtol(argv[2], &p, 0); + if (*p) + errx(1, "invalid size -- %s", argv[3]); + /* + * If the user requests to delete less than 32K of space + * then assume that they want to delete a number of 128K + * blocks. + */ + if (ir.ir_size < 32 * 1024) + ir.ir_size *= 128 * 1024; + } + + switch (action) { + case ERASE: + i = ioctl(fd, ISF_ERASE, &ir); + if (i < 0) + err(1, "ioctl(%s, %jx, %zx)", dev, + (intmax_t)ir.ir_off, ir.ir_size); + break; + default: + usage(); + } + + close(fd); + return (0); +} |