1*8ff6f65dSthorpej /* $NetBSD: flash_ebus.c,v 1.25 2023/12/20 06:36:03 thorpej Exp $ */
25f7e80a8Spooka
35f7e80a8Spooka /*-
45f7e80a8Spooka * Copyright (c) 2010 The NetBSD Foundation, Inc.
55f7e80a8Spooka * All rights reserved.
65f7e80a8Spooka *
75f7e80a8Spooka * This code was written by Alessandro Forin and Neil Pittman
85f7e80a8Spooka * at Microsoft Research and contributed to The NetBSD Foundation
95f7e80a8Spooka * by Microsoft Corporation.
105f7e80a8Spooka *
115f7e80a8Spooka * Redistribution and use in source and binary forms, with or without
125f7e80a8Spooka * modification, are permitted provided that the following conditions
135f7e80a8Spooka * are met:
145f7e80a8Spooka * 1. Redistributions of source code must retain the above copyright
155f7e80a8Spooka * notice, this list of conditions and the following disclaimer.
165f7e80a8Spooka * 2. Redistributions in binary form must reproduce the above copyright
175f7e80a8Spooka * notice, this list of conditions and the following disclaimer in the
185f7e80a8Spooka * documentation and/or other materials provided with the distribution.
195f7e80a8Spooka *
205f7e80a8Spooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
215f7e80a8Spooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225f7e80a8Spooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235f7e80a8Spooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
245f7e80a8Spooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255f7e80a8Spooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265f7e80a8Spooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275f7e80a8Spooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285f7e80a8Spooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295f7e80a8Spooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305f7e80a8Spooka * POSSIBILITY OF SUCH DAMAGE.
315f7e80a8Spooka */
325f7e80a8Spooka
335f7e80a8Spooka #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34*8ff6f65dSthorpej __KERNEL_RCSID(0, "$NetBSD: flash_ebus.c,v 1.25 2023/12/20 06:36:03 thorpej Exp $");
355f7e80a8Spooka
365f7e80a8Spooka /* Driver for the Intel 28F320/640/128 (J3A150) StrataFlash memory device
375f7e80a8Spooka * Extended to include the Intel JS28F256P30T95.
385f7e80a8Spooka */
395f7e80a8Spooka
405f7e80a8Spooka #include <sys/param.h>
415f7e80a8Spooka #include <sys/systm.h>
425f7e80a8Spooka #include <sys/kernel.h>
435f7e80a8Spooka #include <sys/proc.h>
445f7e80a8Spooka #include <sys/errno.h>
455f7e80a8Spooka #include <sys/ioctl.h>
465f7e80a8Spooka #include <sys/device.h>
475f7e80a8Spooka #include <sys/conf.h>
485f7e80a8Spooka #include <sys/file.h>
495f7e80a8Spooka #include <sys/stat.h>
505f7e80a8Spooka #include <sys/ioctl.h>
515f7e80a8Spooka #include <sys/buf.h>
525f7e80a8Spooka #include <sys/bufq.h>
535f7e80a8Spooka #include <sys/uio.h>
545f7e80a8Spooka #include <uvm/uvm_extern.h>
555f7e80a8Spooka #include <sys/disklabel.h>
565f7e80a8Spooka #include <sys/disk.h>
575f7e80a8Spooka #include <sys/syslog.h>
585f7e80a8Spooka #include <sys/vnode.h>
595f7e80a8Spooka #include <sys/kthread.h>
605f7e80a8Spooka #include <sys/lock.h>
615f7e80a8Spooka #include <sys/queue.h>
625f7e80a8Spooka
63445478ceSriastradh #include <sys/rndsource.h>
645f7e80a8Spooka
655f7e80a8Spooka #include "locators.h"
665f7e80a8Spooka #include <prop/proplib.h>
675f7e80a8Spooka
685f7e80a8Spooka #include <emips/ebus/ebusvar.h>
695f7e80a8Spooka #include <emips/emips/machdep.h>
705f7e80a8Spooka #include <machine/emipsreg.h>
715f7e80a8Spooka
725f7e80a8Spooka /* Internal config switches
735f7e80a8Spooka */
745f7e80a8Spooka #define USE_BUFFERED_WRITES 0 /* Faster, but might not work in some (older) cases */
755f7e80a8Spooka #define Verbose 0
765f7e80a8Spooka
775f7e80a8Spooka /* Debug tools
785f7e80a8Spooka */
795f7e80a8Spooka #define DEBUG_INTR 0x01
805f7e80a8Spooka #define DEBUG_XFERS 0x02
815f7e80a8Spooka #define DEBUG_STATUS 0x04
825f7e80a8Spooka #define DEBUG_FUNCS 0x08
835f7e80a8Spooka #define DEBUG_PROBE 0x10
845f7e80a8Spooka #define DEBUG_WRITES 0x20
855f7e80a8Spooka #define DEBUG_READS 0x40
865f7e80a8Spooka #define DEBUG_ERRORS 0x80
875f7e80a8Spooka #ifdef DEBUG
885f7e80a8Spooka int eflash_debug = DEBUG_ERRORS;
895f7e80a8Spooka #define EFLASH_DEBUG(x) (eflash_debug & (x))
905f7e80a8Spooka #define DBGME(_lev_,_x_) if ((_lev_) & eflash_debug) _x_
915f7e80a8Spooka #else
925f7e80a8Spooka #define EFLASH_DEBUG(x) (0)
935f7e80a8Spooka #define DBGME(_lev_,_x_)
945f7e80a8Spooka #endif
955f7e80a8Spooka #define DEBUG_PRINT(_args_,_lev_) DBGME(_lev_,printf _args_)
965f7e80a8Spooka
975f7e80a8Spooka /* Product ID codes
985f7e80a8Spooka */
995f7e80a8Spooka #define MANUF_INTEL 0x89
1005f7e80a8Spooka #define DEVICE_320 0x16
1015f7e80a8Spooka #define DEVICE_640 0x17
1025f7e80a8Spooka #define DEVICE_128 0x18
1035f7e80a8Spooka #define DEVICE_256 0x19
1045f7e80a8Spooka
1055f7e80a8Spooka /* Table of chips we understand.
1065f7e80a8Spooka */
1075f7e80a8Spooka #define nDELTAS 3
1085f7e80a8Spooka struct flash_type {
1095f7e80a8Spooka struct {
1105f7e80a8Spooka uint32_t nSectors;
1115f7e80a8Spooka uint32_t nKB;
1125f7e80a8Spooka } ft_deltas[nDELTAS];
1135f7e80a8Spooka uint8_t ft_manuf_code;
1145f7e80a8Spooka uint8_t ft_device_code;
1155f7e80a8Spooka uint16_t ft_total_sectors;
1165f7e80a8Spooka const char *ft_name;
1175f7e80a8Spooka };
1185f7e80a8Spooka
1195f7e80a8Spooka static const struct flash_type sector_maps[] = {
1205f7e80a8Spooka {
1215f7e80a8Spooka {{32,128},{0,0},},
1225f7e80a8Spooka MANUF_INTEL, DEVICE_320, 32, /* a J3 part */
1235f7e80a8Spooka "StrataFlash 28F320"
1245f7e80a8Spooka },
1255f7e80a8Spooka {
1265f7e80a8Spooka {{64,128},{0,0},},
1275f7e80a8Spooka MANUF_INTEL, DEVICE_640, 64, /* a J3 part */
1285f7e80a8Spooka "StrataFlash 28F640"
1295f7e80a8Spooka },
1305f7e80a8Spooka {
1315f7e80a8Spooka {{128,128},{0,0},},
1325f7e80a8Spooka MANUF_INTEL, DEVICE_128, 128, /* a J3 part */
1335f7e80a8Spooka "StrataFlash 28F128"
1345f7e80a8Spooka },
1355f7e80a8Spooka {
1365f7e80a8Spooka {{255,128},{4,32},{0,0}},
1375f7e80a8Spooka MANUF_INTEL, DEVICE_256, 259, /* a P30 part */
1385f7e80a8Spooka "StrataFlash 28F256"
1395f7e80a8Spooka }
1405f7e80a8Spooka };
1415f7e80a8Spooka #define nMAPS ((sizeof sector_maps) / (sizeof sector_maps[0]))
1425f7e80a8Spooka
1435f7e80a8Spooka /* Instead of dragging in atavar.h.. */
1445f7e80a8Spooka struct eflash_bio {
1455f7e80a8Spooka volatile int flags;/* cmd flags */
1465f7e80a8Spooka #define ATA_POLL 0x0002 /* poll for completion */
1475f7e80a8Spooka #define ATA_SINGLE 0x0008 /* transfer must be done in singlesector mode */
1485f7e80a8Spooka #define ATA_READ 0x0020 /* transfer is a read (otherwise a write) */
1495f7e80a8Spooka #define ATA_CORR 0x0040 /* transfer had a corrected error */
1505f7e80a8Spooka daddr_t blkno; /* block addr */
1515f7e80a8Spooka daddr_t blkdone;/* number of blks transferred */
1525f7e80a8Spooka size_t nblks; /* number of blocks currently transferring */
1535f7e80a8Spooka size_t nbytes; /* number of bytes currently transferring */
1545f7e80a8Spooka char *databuf;/* data buffer address */
1555f7e80a8Spooka volatile int error;
1565f7e80a8Spooka u_int32_t r_error;/* copy of status register */
1575f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
1585f7e80a8Spooka daddr_t badsect[127];/* 126 plus trailing -1 marker */
1595f7e80a8Spooka #endif
1605f7e80a8Spooka };
1615f7e80a8Spooka /* End of atavar.h*/
1625f7e80a8Spooka
1635f7e80a8Spooka /* chip-specific functions
1645f7e80a8Spooka */
1655f7e80a8Spooka struct flash_ops;
1665f7e80a8Spooka
1675f7e80a8Spooka /*
1685f7e80a8Spooka * Device softc
1695f7e80a8Spooka */
1705f7e80a8Spooka struct eflash_softc {
1715f7e80a8Spooka device_t sc_dev;
1725f7e80a8Spooka
1735f7e80a8Spooka /* General disk infos */
1745f7e80a8Spooka struct disk sc_dk;
1755f7e80a8Spooka struct bufq_state *sc_q;
1765f7e80a8Spooka struct callout sc_restart_ch;
1775f7e80a8Spooka
1785f7e80a8Spooka /* IDE disk soft states */
1797991f5a7Sandvar struct buf *sc_bp; /* buf being transferred */
1805f7e80a8Spooka struct buf *active_xfer; /* buf handoff to thread */
1815f7e80a8Spooka struct eflash_bio sc_bio; /* current transfer */
1825f7e80a8Spooka
1835f7e80a8Spooka struct proc *ch_thread;
1845f7e80a8Spooka int ch_flags;
1855f7e80a8Spooka #define ATACH_SHUTDOWN 0x02 /* thread is shutting down */
1865f7e80a8Spooka #define ATACH_IRQ_WAIT 0x10 /* thread is waiting for irq */
1875f7e80a8Spooka #define ATACH_DISABLED 0x80 /* channel is disabled */
1885f7e80a8Spooka #define ATACH_TH_RUN 0x100 /* the kernel thread is working */
1895f7e80a8Spooka #define ATACH_TH_RESET 0x200 /* someone ask the thread to reset */
1905f7e80a8Spooka
1915f7e80a8Spooka int openings;
1925f7e80a8Spooka int sc_flags;
1935f7e80a8Spooka #define EFLASHF_WLABEL 0x004 /* label is writable */
1945f7e80a8Spooka #define EFLASHF_LABELLING 0x008 /* writing label */
1955f7e80a8Spooka #define EFLASHF_LOADED 0x010 /* parameters loaded */
1965f7e80a8Spooka #define EFLASHF_WAIT 0x020 /* waiting for resources */
1975f7e80a8Spooka #define EFLASHF_KLABEL 0x080 /* retain label after 'full' close */
1985f7e80a8Spooka
1995f7e80a8Spooka int retries; /* number of xfer retry */
2005f7e80a8Spooka
2013afd44cfStls krndsource_t rnd_source;
2025f7e80a8Spooka
2035f7e80a8Spooka /* flash-specific state */
2045f7e80a8Spooka struct _Flash *sc_dp;
2055f7e80a8Spooka uint32_t sc_size;
2065f7e80a8Spooka uint32_t sc_capacity;
2075f7e80a8Spooka paddr_t sc_base;
2085f7e80a8Spooka volatile uint8_t *sc_page0;
2095f7e80a8Spooka
2105f7e80a8Spooka /* current read-write sector mapping */
2115f7e80a8Spooka /*volatile*/ uint8_t *sc_sector;
2125f7e80a8Spooka uint32_t sc_sector_size;
2135f7e80a8Spooka uint32_t sc_sector_offset;
2145f7e80a8Spooka #define NOSECTOR ((uint32_t)(~0))
2155f7e80a8Spooka int sc_erased;
2165f7e80a8Spooka
2175f7e80a8Spooka /* device-specificity */
2185f7e80a8Spooka uint32_t sc_buffersize;
2195f7e80a8Spooka vsize_t sc_max_secsize;
2205f7e80a8Spooka unsigned int sc_chips;
2215f7e80a8Spooka const struct flash_ops *sc_ops;
2225f7e80a8Spooka struct flash_type sc_type;
2235f7e80a8Spooka };
2245f7e80a8Spooka
225cbab9cadSchs static int eflash_ebus_match (device_t, cfdata_t, void *);
226cbab9cadSchs static void eflash_ebus_attach (device_t, device_t, void *);
2275f7e80a8Spooka
2285f7e80a8Spooka CFATTACH_DECL_NEW(flash_ebus, sizeof (struct eflash_softc),
2295f7e80a8Spooka eflash_ebus_match, eflash_ebus_attach, NULL, NULL);
2305f7e80a8Spooka
2315f7e80a8Spooka /* implementation decls */
2325f7e80a8Spooka static int flash_identify(struct eflash_softc*);
2335f7e80a8Spooka static int KBinSector(struct flash_type * SecMap, unsigned int SecNo);
2345f7e80a8Spooka static uint32_t SectorStart(struct flash_type * SecMap, int SecNo);
2355f7e80a8Spooka static unsigned int SectorNumber(struct flash_type * SecMap, uint32_t Offset);
2365f7e80a8Spooka static void eflash_thread(void *arg);
2375f7e80a8Spooka static int eflash_read_at (struct eflash_softc *sc, daddr_t start_sector, char *buffer,
2385f7e80a8Spooka size_t nblocks, size_t * pSizeRead);
2395f7e80a8Spooka static int eflash_write_at(struct eflash_softc *sc, daddr_t start_sector, char *buffer,
2405f7e80a8Spooka size_t nblocks, size_t * pSizeWritten);
2415f7e80a8Spooka
2425f7e80a8Spooka /* Config functions
2435f7e80a8Spooka */
2445f7e80a8Spooka static int
eflash_ebus_match(device_t parent,cfdata_t match,void * aux)245cbab9cadSchs eflash_ebus_match(device_t parent, cfdata_t match, void *aux)
2465f7e80a8Spooka {
2475f7e80a8Spooka struct ebus_attach_args *ia = aux;
2485f7e80a8Spooka struct _Flash *f = (struct _Flash *)ia->ia_vaddr;
2495f7e80a8Spooka
2505f7e80a8Spooka if (strcmp("flash", ia->ia_name) != 0)
2515f7e80a8Spooka return (0);
2525f7e80a8Spooka if ((f == NULL) ||
2535f7e80a8Spooka ((f->BaseAddressAndTag & FLASHBT_TAG) != PMTTAG_FLASH))
2545f7e80a8Spooka return (0);
2555f7e80a8Spooka
2565f7e80a8Spooka return (1);
2575f7e80a8Spooka }
2585f7e80a8Spooka
2595f7e80a8Spooka static void
eflash_ebus_attach(device_t parent,device_t self,void * aux)260cbab9cadSchs eflash_ebus_attach(device_t parent, device_t self, void *aux)
2615f7e80a8Spooka {
2625f7e80a8Spooka struct ebus_attach_args *ia =aux;
2635f7e80a8Spooka struct eflash_softc *sc = device_private(self);
2645f7e80a8Spooka uint32_t base, ctrl;
2655f7e80a8Spooka int error;
2665f7e80a8Spooka
2675f7e80a8Spooka /* Plan.
2685f7e80a8Spooka * - mips_map_physmem() (with uncached) first page
2695f7e80a8Spooka * - keep it around since we need status ops
2705f7e80a8Spooka * - find what type it is.
2715f7e80a8Spooka * - then mips_map_physmem() each sector as needed.
2725f7e80a8Spooka */
2735f7e80a8Spooka
2745f7e80a8Spooka sc->sc_dev = self;
2755f7e80a8Spooka sc->sc_dp = (struct _Flash*)ia->ia_vaddr;
2765f7e80a8Spooka base = sc->sc_dp->BaseAddressAndTag & FLASHBT_BASE;
2775f7e80a8Spooka ctrl = sc->sc_dp->Control;
2785f7e80a8Spooka
2795f7e80a8Spooka sc->sc_size = ctrl & FLASHST_SIZE;
2805f7e80a8Spooka sc->sc_capacity = sc->sc_size / DEV_BSIZE;
2815f7e80a8Spooka sc->sc_base = base;
2825f7e80a8Spooka /* The chip is 16bit, so if we get 32bit there are two */
2835f7e80a8Spooka sc->sc_chips = (ctrl & FLASHST_BUS_32) ? 2 : 1;
2845f7e80a8Spooka
2855f7e80a8Spooka /* Map the first page to see what chip we got */
2865f7e80a8Spooka sc->sc_page0 = (volatile uint8_t *) mips_map_physmem(base, PAGE_SIZE);
2875f7e80a8Spooka
2885f7e80a8Spooka if (flash_identify(sc)) {
2895f7e80a8Spooka printf(" base %x: %dMB flash memory (%d x %s)\n", base, sc->sc_size >> 20,
2905f7e80a8Spooka sc->sc_chips, sc->sc_type.ft_name);
2915f7e80a8Spooka } else {
2925f7e80a8Spooka /* BUGBUG If we dont identify it stop the driver! */
2935f7e80a8Spooka printf(": unknown manufacturer id %x, device id %x\n",
2945f7e80a8Spooka sc->sc_type.ft_manuf_code, sc->sc_type.ft_device_code);
2955f7e80a8Spooka }
2965f7e80a8Spooka
2976ec333ebSriz config_pending_incr(self);
2985f7e80a8Spooka
2995f7e80a8Spooka error = kthread_create(PRI_NONE, 0, NULL,
3005f7e80a8Spooka eflash_thread, sc, NULL, "%s", device_xname(sc->sc_dev));
3015f7e80a8Spooka if (error)
3025f7e80a8Spooka aprint_error_dev(sc->sc_dev,
3035f7e80a8Spooka "unable to create kernel thread: error %d\n", error);
3045f7e80a8Spooka }
3055f7e80a8Spooka
3065f7e80a8Spooka /* Implementation functions
3075f7e80a8Spooka */
3085f7e80a8Spooka /* Returns the size in KBytes of a given sector,
3095f7e80a8Spooka * or -1 for bad arguments.
3105f7e80a8Spooka */
KBinSector(struct flash_type * SecMap,unsigned int SecNo)3115f7e80a8Spooka static int KBinSector(struct flash_type * SecMap, unsigned int SecNo)
3125f7e80a8Spooka {
3135f7e80a8Spooka int i;
3145f7e80a8Spooka
3155f7e80a8Spooka for (i = 0; i < nDELTAS; i++) {
3165f7e80a8Spooka if (SecNo < SecMap->ft_deltas[i].nSectors)
3175f7e80a8Spooka return SecMap->ft_deltas[i].nKB;
3185f7e80a8Spooka SecNo -= SecMap->ft_deltas[i].nSectors;
3195f7e80a8Spooka }
3205f7e80a8Spooka
3215f7e80a8Spooka return -1;
3225f7e80a8Spooka }
3235f7e80a8Spooka
3245f7e80a8Spooka #define SectorSize(_map_,_sector_) (1024 * KBinSector(_map_,_sector_))
3255f7e80a8Spooka
3265f7e80a8Spooka /* Whats the starting offset of sector N
3275f7e80a8Spooka */
SectorStart(struct flash_type * SecMap,int SecNo)3285f7e80a8Spooka static uint32_t SectorStart(struct flash_type * SecMap, int SecNo)
3295f7e80a8Spooka {
3305f7e80a8Spooka int i;
3315f7e80a8Spooka uint32_t Offset = 0;
3325f7e80a8Spooka
3335f7e80a8Spooka for (i = 0; i < nDELTAS; i++) {
3345f7e80a8Spooka if ((unsigned int)SecNo < SecMap->ft_deltas[i].nSectors)
3355f7e80a8Spooka return 1024 * (Offset + (SecMap->ft_deltas[i].nKB * SecNo));
3365f7e80a8Spooka SecNo -= SecMap->ft_deltas[i].nSectors;
3375f7e80a8Spooka Offset += SecMap->ft_deltas[i].nSectors * SecMap->ft_deltas[i].nKB;
3385f7e80a8Spooka }
3395f7e80a8Spooka
3405f7e80a8Spooka return ~0;
3415f7e80a8Spooka }
3425f7e80a8Spooka
3435f7e80a8Spooka /* What sector number corresponds to a given offset
3445f7e80a8Spooka */
SectorNumber(struct flash_type * SecMap,uint32_t Offset)3455f7e80a8Spooka static unsigned int SectorNumber(struct flash_type * SecMap, uint32_t Offset)
3465f7e80a8Spooka {
3475f7e80a8Spooka unsigned int i;
3485f7e80a8Spooka unsigned int SecNo = 0;
3495f7e80a8Spooka
3505f7e80a8Spooka Offset /= 1024;
3515f7e80a8Spooka for (i = 0; i < nDELTAS; i++) {
3525f7e80a8Spooka if (Offset < (unsigned int)
3535f7e80a8Spooka ((SecMap->ft_deltas[i].nSectors * SecMap->ft_deltas[i].nKB)))
3545f7e80a8Spooka return SecNo + (Offset / SecMap->ft_deltas[i].nKB);
3555f7e80a8Spooka SecNo += SecMap->ft_deltas[i].nSectors;
3565f7e80a8Spooka Offset -= SecMap->ft_deltas[i].nSectors * SecMap->ft_deltas[i].nKB;
3575f7e80a8Spooka }
3585f7e80a8Spooka
3595f7e80a8Spooka return ~0;
3605f7e80a8Spooka }
3615f7e80a8Spooka
3625f7e80a8Spooka /*
3635f7e80a8Spooka * Semi-generic operations
3645f7e80a8Spooka */
3655f7e80a8Spooka struct flash_ops {
3665f7e80a8Spooka void (*write_uint8) (struct eflash_softc *sc, volatile void *Offset, uint8_t Value);
3675f7e80a8Spooka void (*read_uint8) (struct eflash_softc *sc, volatile void *Offset, uint8_t *Value);
3685f7e80a8Spooka void (*write_uint16) (struct eflash_softc *sc, volatile void *Offset, uint16_t Value);
3695f7e80a8Spooka void (*read_uint16) (struct eflash_softc *sc, volatile void *Offset, uint16_t *Value);
3705f7e80a8Spooka void (*write_uint32) (struct eflash_softc *sc, volatile void *Offset, uint32_t Value);
3715f7e80a8Spooka void (*read_uint32) (struct eflash_softc *sc, volatile void *Offset, uint32_t *Value);
3725f7e80a8Spooka int (*program_word) (struct eflash_softc *sc, volatile void *Offset, uint16_t *pValues,
3735f7e80a8Spooka int Verify, int *nWritten);
3745f7e80a8Spooka int (*program_buffer) (struct eflash_softc *sc, volatile void *Offset, uint16_t *pValues,
3755f7e80a8Spooka int Verify, int *nWritten);
3765f7e80a8Spooka };
3775f7e80a8Spooka
3785f7e80a8Spooka /*
3795f7e80a8Spooka * Hardware access proper, single-chip
3805f7e80a8Spooka */
single_write_uint8(struct eflash_softc * sc,volatile void * Offset,uint8_t Value)3815f7e80a8Spooka static void single_write_uint8 (struct eflash_softc *sc,volatile void *Offset,uint8_t Value)
3825f7e80a8Spooka {
3835f7e80a8Spooka volatile uint8_t * Where = Offset;
3845f7e80a8Spooka *Where = Value;
3855f7e80a8Spooka }
3865f7e80a8Spooka
single_read_uint8(struct eflash_softc * sc,volatile void * Offset,uint8_t * Value)3875f7e80a8Spooka static void single_read_uint8 (struct eflash_softc *sc,volatile void *Offset,uint8_t *Value)
3885f7e80a8Spooka {
3895f7e80a8Spooka volatile uint8_t * Where = Offset;
3905f7e80a8Spooka *Value = *Where;
3915f7e80a8Spooka }
3925f7e80a8Spooka
single_write_uint16(struct eflash_softc * sc,volatile void * Offset,uint16_t Value)3935f7e80a8Spooka static void single_write_uint16 (struct eflash_softc *sc,volatile void *Offset,uint16_t Value)
3945f7e80a8Spooka {
3955f7e80a8Spooka volatile uint16_t * Where = Offset;
3965f7e80a8Spooka *Where = Value;
3975f7e80a8Spooka }
3985f7e80a8Spooka
single_read_uint16(struct eflash_softc * sc,volatile void * Offset,uint16_t * Value)3995f7e80a8Spooka static void single_read_uint16 (struct eflash_softc *sc,volatile void *Offset,uint16_t *Value)
4005f7e80a8Spooka {
4015f7e80a8Spooka volatile uint16_t * Where = Offset;
4025f7e80a8Spooka *Value = *Where;
4035f7e80a8Spooka }
4045f7e80a8Spooka
4055f7e80a8Spooka /* This one should not be used, probably */
single_write_uint32(struct eflash_softc * sc,volatile void * Offset,uint32_t Value)4065f7e80a8Spooka static void single_write_uint32 (struct eflash_softc *sc,volatile void *Offset,uint32_t Value)
4075f7e80a8Spooka {
4085f7e80a8Spooka #if 0
4095f7e80a8Spooka /* The chip cannot take back-to-back writes */
4105f7e80a8Spooka volatile uint32_t * Where = Offset;
4115f7e80a8Spooka *Where = Value;
4125f7e80a8Spooka #else
4135f7e80a8Spooka volatile uint8_t * Where = Offset;
4145f7e80a8Spooka uint16_t v0, v1;
4155f7e80a8Spooka
4165f7e80a8Spooka /* Unfortunately, this is bytesex dependent */
4175f7e80a8Spooka #if (BYTE_ORDER == BIG_ENDIAN)
4185f7e80a8Spooka v1 = (uint16_t) Value;
4195f7e80a8Spooka v0 = (uint16_t) (Value >> 16);
4205f7e80a8Spooka #else
4215f7e80a8Spooka v0 = (uint16_t) Value;
4225f7e80a8Spooka v1 = (uint16_t) (Value >> 16);
4235f7e80a8Spooka #endif
4245f7e80a8Spooka single_write_uint16(sc,Where,v0);
4255f7e80a8Spooka single_write_uint16(sc,Where+2,v1);
4265f7e80a8Spooka #endif
4275f7e80a8Spooka }
4285f7e80a8Spooka
single_read_uint32(struct eflash_softc * sc,volatile void * Offset,uint32_t * Value)4295f7e80a8Spooka static void single_read_uint32 (struct eflash_softc *sc,volatile void *Offset,uint32_t *Value)
4305f7e80a8Spooka {
4315f7e80a8Spooka /* back-to-back reads must be ok */
4325f7e80a8Spooka volatile uint32_t * Where = Offset;
4335f7e80a8Spooka *Value = *Where;
4345f7e80a8Spooka }
4355f7e80a8Spooka
4365f7e80a8Spooka /*
4375f7e80a8Spooka * Hardware access proper, paired-chips
4385f7e80a8Spooka * NB: This set of ops assumes two chips in parallel on a 32bit bus,
4395f7e80a8Spooka * each operation is repeated in parallel to both chips
4405f7e80a8Spooka */
twin_write_uint8(struct eflash_softc * sc,volatile void * Offset,uint8_t Value)4415f7e80a8Spooka static void twin_write_uint8 (struct eflash_softc *sc,volatile void *Offset,uint8_t Value)
4425f7e80a8Spooka {
4435f7e80a8Spooka volatile uint32_t * Where = Offset;
4445f7e80a8Spooka uint32_t v = Value | ((uint32_t)Value << 16);
4455f7e80a8Spooka
4465f7e80a8Spooka v = le32toh(v);
4475f7e80a8Spooka *Where = v;
4485f7e80a8Spooka }
4495f7e80a8Spooka
twin_read_uint8(struct eflash_softc * sc,volatile void * Offset,uint8_t * Value)4505f7e80a8Spooka static void twin_read_uint8 (struct eflash_softc *sc,volatile void *Offset,uint8_t *Value)
4515f7e80a8Spooka {
4525f7e80a8Spooka volatile uint32_t * Where = Offset;
4535f7e80a8Spooka uint32_t v;
4545f7e80a8Spooka v = *Where;
4555f7e80a8Spooka v = le32toh(v);
4565f7e80a8Spooka *Value = (uint8_t) v;
4575f7e80a8Spooka }
4585f7e80a8Spooka
4595f7e80a8Spooka /* This one should *not* be used, error-prone */
twin_write_uint16(struct eflash_softc * sc,volatile void * Offset,uint16_t Value)4605f7e80a8Spooka static void twin_write_uint16 (struct eflash_softc *sc,volatile void *Offset,uint16_t Value)
4615f7e80a8Spooka {
4625f7e80a8Spooka volatile uint16_t * Where = Offset;
4635f7e80a8Spooka *Where = Value;
4645f7e80a8Spooka }
4655f7e80a8Spooka
twin_read_uint16(struct eflash_softc * sc,volatile void * Offset,uint16_t * Value)4665f7e80a8Spooka static void twin_read_uint16 (struct eflash_softc *sc,volatile void *Offset,uint16_t *Value)
4675f7e80a8Spooka {
4685f7e80a8Spooka volatile uint16_t * Where = Offset;
4695f7e80a8Spooka *Value = *Where;
4705f7e80a8Spooka }
4715f7e80a8Spooka
twin_write_uint32(struct eflash_softc * sc,volatile void * Offset,uint32_t Value)4725f7e80a8Spooka static void twin_write_uint32 (struct eflash_softc *sc,volatile void *Offset,uint32_t Value)
4735f7e80a8Spooka {
4745f7e80a8Spooka volatile uint32_t * Where = Offset;
4755f7e80a8Spooka Value = le32toh(Value);
4765f7e80a8Spooka *Where = Value;
4775f7e80a8Spooka }
4785f7e80a8Spooka
twin_read_uint32(struct eflash_softc * sc,volatile void * Offset,uint32_t * Value)4795f7e80a8Spooka static void twin_read_uint32 (struct eflash_softc *sc,volatile void *Offset,uint32_t *Value)
4805f7e80a8Spooka {
4815f7e80a8Spooka volatile uint32_t * Where = Offset;
4825f7e80a8Spooka uint32_t v;
4835f7e80a8Spooka v = *Where;
4845f7e80a8Spooka v = le32toh(v);
4855f7e80a8Spooka *Value = v;
4865f7e80a8Spooka }
4875f7e80a8Spooka
4885f7e80a8Spooka /*
4895f7e80a8Spooka * Command and status definitions
4905f7e80a8Spooka */
4915f7e80a8Spooka
4925f7e80a8Spooka /* Defines for the STATUS register
4935f7e80a8Spooka */
4945f7e80a8Spooka #define ST_reserved 0x01
4955f7e80a8Spooka #define ST_BLOCK_LOCKED 0x02
4965f7e80a8Spooka #define ST_PROGRAM_SUSPENDED 0x04
4975f7e80a8Spooka #define ST_LOW_VOLTAGE 0x08
4985f7e80a8Spooka #define ST_LOCK_BIT_ERROR 0x10
4995f7e80a8Spooka #define ST_ERASE_ERROR 0x20
5005f7e80a8Spooka #define ST_ERASE_SUSPENDED 0x40
5015f7e80a8Spooka #define ST_READY 0x80
5025f7e80a8Spooka #define ST_ERASE_MASK 0xee /* bits to check after erase command */
5035f7e80a8Spooka #define ST_MASK 0xfe /* ignore reserved */
5045f7e80a8Spooka
5055f7e80a8Spooka /* Command set (what we use of it)
5065f7e80a8Spooka */
5075f7e80a8Spooka #define CMD_CONFIRM 0xd0
5085f7e80a8Spooka #define CMD_READ_ARRAY 0xff
5095f7e80a8Spooka #define CMD_READ_ID 0x90
5105f7e80a8Spooka #define CMD_READ_STATUS 0x70
5115f7e80a8Spooka #define CMD_CLEAR_STATUS 0x50
5125f7e80a8Spooka #define CMD_WRITE_WORD 0x40
5135f7e80a8Spooka #define CMD_WRITE_BUFFER 0xe8
5145f7e80a8Spooka #define CMD_ERASE_SETUP 0x20
5155f7e80a8Spooka #define CMD_ERASE_CONFIRM CMD_CONFIRM
5165f7e80a8Spooka #define CMD_SET_PREFIX 0x60 /* set read config, lock bits */
5175f7e80a8Spooka #define CMD_LOCK 0x01
5185f7e80a8Spooka #define CMD_UNLOCK CMD_CONFIRM
5195f7e80a8Spooka /* What we dont use of it
5205f7e80a8Spooka */
5215f7e80a8Spooka #define CMD_READ_QUERY 0x98
5225f7e80a8Spooka # define BUFFER_BYTES 32
5235f7e80a8Spooka #define CMD_ERASE_SUSPEND 0xb0
5245f7e80a8Spooka #define CMD_ERASE_RESUME CMD_CONFIRM
5255f7e80a8Spooka #define CMD_CONFIGURATION 0xb8
5265f7e80a8Spooka #define CMD_PROTECT 0xc0
5275f7e80a8Spooka
5285f7e80a8Spooka /* Enter the Product ID mode (Read Identifier Codes)
5295f7e80a8Spooka */
ProductIdEnter(struct eflash_softc * sc)5305f7e80a8Spooka static void ProductIdEnter(struct eflash_softc *sc)
5315f7e80a8Spooka {
5325f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_READ_ID);
5335f7e80a8Spooka }
5345f7e80a8Spooka
5355f7e80a8Spooka /* Exit the Product ID mode (enter Read Array mode)
5365f7e80a8Spooka */
ProductIdExit(struct eflash_softc * sc)5375f7e80a8Spooka static void ProductIdExit(struct eflash_softc *sc)
5385f7e80a8Spooka {
5395f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_READ_ARRAY);
5405f7e80a8Spooka }
5415f7e80a8Spooka
5425f7e80a8Spooka /* Read the status register
5435f7e80a8Spooka */
ReadStatusRegister(struct eflash_softc * sc)5445f7e80a8Spooka static uint8_t ReadStatusRegister(struct eflash_softc *sc)
5455f7e80a8Spooka {
5465f7e80a8Spooka uint8_t Status;
5475f7e80a8Spooka
5485f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_READ_STATUS);
5495f7e80a8Spooka sc->sc_ops->read_uint8(sc,sc->sc_page0,&Status);
5505f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_READ_ARRAY);
5515f7e80a8Spooka return Status;
5525f7e80a8Spooka }
5535f7e80a8Spooka
5545f7e80a8Spooka /* Clear error bits in status
5555f7e80a8Spooka */
ClearStatusRegister(struct eflash_softc * sc)5565f7e80a8Spooka static void ClearStatusRegister(struct eflash_softc *sc)
5575f7e80a8Spooka {
5585f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_CLEAR_STATUS);
5595f7e80a8Spooka }
5605f7e80a8Spooka
5615f7e80a8Spooka #if DEBUG
5625f7e80a8Spooka /* Decode status bits
5635f7e80a8Spooka */
5645f7e80a8Spooka typedef const char *string;
5655f7e80a8Spooka
PrintStatus(uint8_t Status)5665f7e80a8Spooka static void PrintStatus(uint8_t Status)
5675f7e80a8Spooka {
5685f7e80a8Spooka /* BUGBUG there's a %b format I think? */
5695f7e80a8Spooka string BitNames[8] = {
5705f7e80a8Spooka "reserved", "BLOCK_LOCKED",
5715f7e80a8Spooka "PROGRAM_SUSPENDED", "LOW_VOLTAGE",
5725f7e80a8Spooka "LOCK_BIT_ERROR", "ERASE_ERROR",
5735f7e80a8Spooka "ERASE_SUSPENDED", "READY"
5745f7e80a8Spooka };
5755f7e80a8Spooka int i;
5765f7e80a8Spooka int OneSet = FALSE;
5775f7e80a8Spooka
5785f7e80a8Spooka printf("[status %x =",Status);
5795f7e80a8Spooka for (i = 0; i < 8; i++) {
5805f7e80a8Spooka if (Status & (1<<i)) {
5815f7e80a8Spooka printf("%c%s",
5825f7e80a8Spooka (OneSet) ? '|' : ' ',
5835f7e80a8Spooka BitNames[i]);
5845f7e80a8Spooka OneSet = TRUE;
5855f7e80a8Spooka }
5865f7e80a8Spooka }
5875f7e80a8Spooka printf("]\n");
5885f7e80a8Spooka }
5895f7e80a8Spooka #else
5905f7e80a8Spooka #define PrintStatus(x)
5915f7e80a8Spooka #endif
5925f7e80a8Spooka
5935f7e80a8Spooka /*
5945f7e80a8Spooka * The device can lock up under certain conditions.
5955f7e80a8Spooka * There is no software workaround [must toggle RP# to GND]
5965f7e80a8Spooka * Check if it seems that we are in that state.
5975f7e80a8Spooka */
IsIrresponsive(struct eflash_softc * sc)5985f7e80a8Spooka static int IsIrresponsive(struct eflash_softc *sc)
5995f7e80a8Spooka {
6005f7e80a8Spooka uint8_t Status = ReadStatusRegister(sc);
6015f7e80a8Spooka
6025f7e80a8Spooka if (Status & ST_READY)
6035f7e80a8Spooka return FALSE;
6045f7e80a8Spooka
605ddd60a0fSchristos if ((Status & ST_MASK) ==
6065f7e80a8Spooka (ST_LOCK_BIT_ERROR|ST_ERASE_SUSPENDED|ST_ERASE_ERROR)) {
6075f7e80a8Spooka /* yes, looks that way */
6085f7e80a8Spooka return TRUE;
6095f7e80a8Spooka }
6105f7e80a8Spooka
6115f7e80a8Spooka /* Something is indeed amiss, but we dont really know for sure */
6125f7e80a8Spooka PrintStatus(ReadStatusRegister(sc));
6135f7e80a8Spooka ClearStatusRegister(sc);
6145f7e80a8Spooka PrintStatus(ReadStatusRegister(sc));
6155f7e80a8Spooka
6165f7e80a8Spooka if ((Status & ST_MASK) ==
6175f7e80a8Spooka (ST_LOCK_BIT_ERROR|ST_ERASE_SUSPENDED|ST_ERASE_ERROR)) {
6185f7e80a8Spooka /* yes, looks that way */
6195f7e80a8Spooka return TRUE;
6205f7e80a8Spooka }
6215f7e80a8Spooka
6225f7e80a8Spooka return FALSE;
6235f7e80a8Spooka }
6245f7e80a8Spooka
6255f7e80a8Spooka
6265f7e80a8Spooka /* Write one 16bit word
6275f7e80a8Spooka */
6285f7e80a8Spooka static int
single_program_word(struct eflash_softc * sc,volatile void * Offset,uint16_t * Values,int Verify,int * nWritten)6295f7e80a8Spooka single_program_word(struct eflash_softc *sc, volatile void *Offset, uint16_t *Values,
6305f7e80a8Spooka int Verify, int *nWritten)
6315f7e80a8Spooka {
6325f7e80a8Spooka uint8_t Status;
6335f7e80a8Spooka uint16_t i, Data16, Value;
6345f7e80a8Spooka
6355f7e80a8Spooka *nWritten = 0;
6365f7e80a8Spooka
6375f7e80a8Spooka Value = Values[0];
6385f7e80a8Spooka
6395f7e80a8Spooka if (Verify) {
6405f7e80a8Spooka sc->sc_ops->read_uint16(sc,Offset,&Data16);
6415f7e80a8Spooka #ifdef Verbose
6425f7e80a8Spooka if (Verbose) {
6435f7e80a8Spooka printf("Location %p was x%x\n",
6445f7e80a8Spooka Offset, Data16);
6455f7e80a8Spooka }
6465f7e80a8Spooka #endif
6475f7e80a8Spooka if (Data16 != 0xffff)
6485f7e80a8Spooka printf("Offset %p not ERASED, wont take.\n",Offset);
6495f7e80a8Spooka }
6505f7e80a8Spooka
6515f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_WRITE_WORD);
6525f7e80a8Spooka sc->sc_ops->write_uint16(sc,Offset,Value);
6535f7e80a8Spooka
6545f7e80a8Spooka /* Wait until the operation is completed
6555f7e80a8Spooka * Specs say it takes between 210 and 630 us
6565f7e80a8Spooka * Errata says 360 TYP and Max=TBD (sic)
6575f7e80a8Spooka */
6585f7e80a8Spooka DELAY(800);
6595f7e80a8Spooka
6605f7e80a8Spooka for (i = 0; i < 10; i++) {
6615f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
6625f7e80a8Spooka if ((Status & ST_READY)) break;
6635f7e80a8Spooka DELAY(100);
6645f7e80a8Spooka }
6655f7e80a8Spooka
6665f7e80a8Spooka ProductIdExit(sc);
6675f7e80a8Spooka
6685f7e80a8Spooka if (Verify) {
6695f7e80a8Spooka sc->sc_ops->read_uint16(sc,Offset,&Data16);
6705f7e80a8Spooka #ifdef Verbose
6715f7e80a8Spooka if (Verbose) {
6725f7e80a8Spooka printf("Location %p is now x%x\n",
6735f7e80a8Spooka Offset, Data16);
6745f7e80a8Spooka }
6755f7e80a8Spooka #endif
6765f7e80a8Spooka if ((Data16 != Value)) {
6775f7e80a8Spooka PrintStatus(Status);
6785f7e80a8Spooka printf(". That didnt work, try again.. [%x != %x]\n",
6795f7e80a8Spooka Data16, Value);
6805f7e80a8Spooka ClearStatusRegister(sc);
6815f7e80a8Spooka return FALSE;
6825f7e80a8Spooka }
6835f7e80a8Spooka }
6845f7e80a8Spooka
6855f7e80a8Spooka *nWritten = 2;
6865f7e80a8Spooka return TRUE;
6875f7e80a8Spooka }
6885f7e80a8Spooka
6895f7e80a8Spooka /* Write one buffer, 16bit words at a time
6905f7e80a8Spooka */
6915f7e80a8Spooka static int
single_program_buffer(struct eflash_softc * sc,volatile void * Offset,uint16_t * Values,int Verify,int * nWritten)6925f7e80a8Spooka single_program_buffer(struct eflash_softc *sc, volatile void *Offset, uint16_t *Values,
6935f7e80a8Spooka int Verify, int *nWritten)
6945f7e80a8Spooka {
6955f7e80a8Spooka uint8_t Status;
6965f7e80a8Spooka uint16_t i, Data16, Value = 0;
6975f7e80a8Spooka volatile uint8_t *Where = Offset;
6985f7e80a8Spooka
6995f7e80a8Spooka *nWritten = 0;
7005f7e80a8Spooka if (sc->sc_buffersize == 0)
7015f7e80a8Spooka return FALSE; /* sanity */
7025f7e80a8Spooka
7035f7e80a8Spooka if (Verify) {
7045f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 2) {
7055f7e80a8Spooka sc->sc_ops->read_uint16(sc,Where+i,&Data16);
7065f7e80a8Spooka #ifdef Verbose
7075f7e80a8Spooka if (Verbose) {
7085f7e80a8Spooka printf("Location %p was x%x\n",
7095f7e80a8Spooka Where+i, Data16);
7105f7e80a8Spooka }
7115f7e80a8Spooka #endif
7125f7e80a8Spooka
7135f7e80a8Spooka if (Data16 != 0xffff)
7145f7e80a8Spooka printf("Offset %p not ERASED, wont take.\n",Where+i);
7155f7e80a8Spooka }
7165f7e80a8Spooka }
7175f7e80a8Spooka
7185f7e80a8Spooka /* Specs say to retry if necessary */
7195f7e80a8Spooka for (i = 0; i < 5; i++) {
7205f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_WRITE_BUFFER);
7215f7e80a8Spooka DELAY(10);
7225f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
7235f7e80a8Spooka if ((Status & ST_READY)) break;
7245f7e80a8Spooka }
7255f7e80a8Spooka if (0 == (Status & ST_READY)) {
7265f7e80a8Spooka printf("FAILED program_buffer at Location %p, Status= x%x\n",
7275f7e80a8Spooka Offset, Status);
7285f7e80a8Spooka return FALSE;
7295f7e80a8Spooka }
7305f7e80a8Spooka
7315f7e80a8Spooka /* Say how many words we'll be sending */
7325f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,(uint8_t)(sc->sc_buffersize/2));
7335f7e80a8Spooka
7345f7e80a8Spooka /* Send the data */
7355f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 2) {
7365f7e80a8Spooka Value = Values[i/2];
7375f7e80a8Spooka sc->sc_ops->write_uint16(sc,Where+i,Value);
7385f7e80a8Spooka DELAY(10);/*jic*/
7395f7e80a8Spooka }
7405f7e80a8Spooka
7415f7e80a8Spooka /* Write confirmation */
7425f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_CONFIRM);
7435f7e80a8Spooka
7445f7e80a8Spooka /* Wait until the operation is completed
7455f7e80a8Spooka * Specs say it takes between 800 and 2400 us
7465f7e80a8Spooka * Errata says 1600 TYP and Max=TBD (sic), but fixed in stepping A3 and above.
7475f7e80a8Spooka */
7485f7e80a8Spooka DELAY(800);
7495f7e80a8Spooka
7505f7e80a8Spooka for (i = 0; i < 20; i++) {
7515f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_READ_STATUS);
7525f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
7535f7e80a8Spooka if ((Status & ST_READY)) break;
7545f7e80a8Spooka DELAY(200);
7555f7e80a8Spooka }
7565f7e80a8Spooka
7575f7e80a8Spooka ProductIdExit(sc);
7585f7e80a8Spooka
7595f7e80a8Spooka /* Verify? */
7605f7e80a8Spooka if (Verify) {
7615f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 2) {
7625f7e80a8Spooka sc->sc_ops->read_uint16(sc,Where+i,&Data16);
7635f7e80a8Spooka #ifdef Verbose
7645f7e80a8Spooka if (Verbose) {
7655f7e80a8Spooka printf("Location %p is now x%x\n",
7665f7e80a8Spooka Where+i, Data16);
7675f7e80a8Spooka }
7685f7e80a8Spooka #endif
7695f7e80a8Spooka Value = Values[i/2];
7705f7e80a8Spooka
7715f7e80a8Spooka if ((Data16 != Value)) {
7725f7e80a8Spooka PrintStatus(Status);
7735f7e80a8Spooka printf(". That didnt work, try again.. [%x != %x]\n",
7745f7e80a8Spooka Data16, Value);
7755f7e80a8Spooka ClearStatusRegister(sc);
7765f7e80a8Spooka return FALSE;
7775f7e80a8Spooka }
7785f7e80a8Spooka }
7795f7e80a8Spooka }
7805f7e80a8Spooka
7815f7e80a8Spooka *nWritten = sc->sc_buffersize;
7825f7e80a8Spooka return TRUE;
7835f7e80a8Spooka }
7845f7e80a8Spooka
7855f7e80a8Spooka /* Write one 32bit word
7865f7e80a8Spooka */
7875f7e80a8Spooka static int
twin_program_word(struct eflash_softc * sc,volatile void * Offset,uint16_t * Values,int Verify,int * nWritten)7885f7e80a8Spooka twin_program_word(struct eflash_softc *sc, volatile void *Offset, uint16_t *Values,
7895f7e80a8Spooka int Verify, int *nWritten)
7905f7e80a8Spooka {
7915f7e80a8Spooka uint8_t Status;
7925f7e80a8Spooka uint32_t i, Data32, Value;
7935f7e80a8Spooka uint16_t v0, v1;
7945f7e80a8Spooka
7955f7e80a8Spooka *nWritten = 0;
7965f7e80a8Spooka
7975f7e80a8Spooka v0 = Values[0];
7985f7e80a8Spooka v0 = le16toh(v0);
7995f7e80a8Spooka v1 = Values[1];
8005f7e80a8Spooka v1 = le16toh(v1);
8015f7e80a8Spooka Value = v0 | ((uint32_t)v1 << 16);
8025f7e80a8Spooka if (Verify) {
8035f7e80a8Spooka sc->sc_ops->read_uint32(sc,Offset,&Data32);
8045f7e80a8Spooka #ifdef Verbose
8055f7e80a8Spooka if (Verbose) {
8065f7e80a8Spooka printf("Location %p was x%x\n",
8075f7e80a8Spooka Offset, Data32);
8085f7e80a8Spooka }
8095f7e80a8Spooka #endif
8105f7e80a8Spooka if (Data32 != 0xffffffff)
8115f7e80a8Spooka printf("Offset %p not ERASED, wont take.\n",Offset);
8125f7e80a8Spooka }
8135f7e80a8Spooka
8145f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_WRITE_WORD);
8155f7e80a8Spooka sc->sc_ops->write_uint32(sc,Offset,Value);
8165f7e80a8Spooka
8175f7e80a8Spooka /* Wait until the operation is completed
8185f7e80a8Spooka * Specs say it takes between 210 and 630 us
8195f7e80a8Spooka * Errata says 360 TYP and Max=TBD (sic)
8205f7e80a8Spooka */
8215f7e80a8Spooka DELAY(400);
8225f7e80a8Spooka
8235f7e80a8Spooka for (i = 0; i < 10; i++) {
8245f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
8255f7e80a8Spooka if ((Status & ST_READY)) break;
8265f7e80a8Spooka DELAY(100);
8275f7e80a8Spooka }
8285f7e80a8Spooka
8295f7e80a8Spooka ProductIdExit(sc);
8305f7e80a8Spooka
8315f7e80a8Spooka if (Verify) {
8325f7e80a8Spooka sc->sc_ops->read_uint32(sc,Offset,&Data32);
8335f7e80a8Spooka #ifdef Verbose
8345f7e80a8Spooka if (Verbose) {
8355f7e80a8Spooka printf("Location %p is now x%x\n",
8365f7e80a8Spooka Offset, Data32);
8375f7e80a8Spooka }
8385f7e80a8Spooka #endif
8395f7e80a8Spooka if ((Data32 != Value)) {
8405f7e80a8Spooka PrintStatus(Status);
8415f7e80a8Spooka printf(". That didnt work, try again.. [%x != %x]\n",
8425f7e80a8Spooka Data32, Value);
8435f7e80a8Spooka ClearStatusRegister(sc);
8445f7e80a8Spooka return FALSE;
8455f7e80a8Spooka }
8465f7e80a8Spooka }
8475f7e80a8Spooka
8485f7e80a8Spooka *nWritten = 4;
8495f7e80a8Spooka return TRUE;
8505f7e80a8Spooka }
8515f7e80a8Spooka
8525f7e80a8Spooka /* Write one buffer, 32bit words at a time
8535f7e80a8Spooka */
8545f7e80a8Spooka static int
twin_program_buffer(struct eflash_softc * sc,volatile void * Offset,uint16_t * Values,int Verify,int * nWritten)8555f7e80a8Spooka twin_program_buffer(struct eflash_softc *sc, volatile void *Offset, uint16_t *Values,
8565f7e80a8Spooka int Verify, int *nWritten)
8575f7e80a8Spooka {
8585f7e80a8Spooka uint8_t Status;
8595f7e80a8Spooka uint32_t i, Data32, Value;
8605f7e80a8Spooka uint16_t v0 = 0, v1;
8615f7e80a8Spooka volatile uint8_t *Where = Offset;
8625f7e80a8Spooka
8635f7e80a8Spooka *nWritten = 0;
8645f7e80a8Spooka if (sc->sc_buffersize == 0)
8655f7e80a8Spooka return FALSE; /* sanity */
8665f7e80a8Spooka
8675f7e80a8Spooka if (Verify) {
8685f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 4) {
8695f7e80a8Spooka sc->sc_ops->read_uint32(sc,Where+i,&Data32);
8705f7e80a8Spooka #ifdef Verbose
8715f7e80a8Spooka if (Verbose) {
8725f7e80a8Spooka printf("Location %p was x%x\n",
8735f7e80a8Spooka Where+i, Data32);
8745f7e80a8Spooka }
8755f7e80a8Spooka #endif
8765f7e80a8Spooka if (Data32 != 0xffffffff)
8775f7e80a8Spooka printf("Offset %p not ERASED, wont take.\n",Where+i);
8785f7e80a8Spooka }
8795f7e80a8Spooka }
8805f7e80a8Spooka
8815f7e80a8Spooka /* Specs say to retry if necessary */
8825f7e80a8Spooka for (i = 0; i < 5; i++) {
8835f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_WRITE_BUFFER);
8845f7e80a8Spooka DELAY(10);
8855f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
8865f7e80a8Spooka if ((Status & ST_READY)) break;
8875f7e80a8Spooka }
8885f7e80a8Spooka if (0 == (Status & ST_READY)) {
8895f7e80a8Spooka printf("FAILED program_buffer at Location %p, Status= x%x\n",
8905f7e80a8Spooka Offset, Status);
8915f7e80a8Spooka return FALSE;
8925f7e80a8Spooka }
8935f7e80a8Spooka
8945f7e80a8Spooka /* Say how many words we'll be sending */
8955f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,(uint8_t)(sc->sc_buffersize/4)); /* to each twin! */
8965f7e80a8Spooka
8975f7e80a8Spooka /* Send the data */
8985f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 4) {
8995f7e80a8Spooka v0 = Values[i/2];
9005f7e80a8Spooka v0 = le16toh(v0);
9015f7e80a8Spooka v1 = Values[1+(i/2)];
9025f7e80a8Spooka v1 = le16toh(v1);
9035f7e80a8Spooka Value = v0 | ((uint32_t)v1 << 16);
9045f7e80a8Spooka sc->sc_ops->write_uint32(sc,Where+i,Value);
9055f7e80a8Spooka DELAY(10);/*jic*/
9065f7e80a8Spooka }
9075f7e80a8Spooka
9085f7e80a8Spooka /* Write confirmation */
9095f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_CONFIRM);
9105f7e80a8Spooka
9115f7e80a8Spooka /* Wait until the operation is completed
9125f7e80a8Spooka * Specs say it takes between 800 and 2400 us
9135f7e80a8Spooka * Errata says 1600 TYP and Max=TBD (sic), but fixed in stepping A3 and above.
9145f7e80a8Spooka */
9155f7e80a8Spooka DELAY(800);
9165f7e80a8Spooka
9175f7e80a8Spooka for (i = 0; i < 20; i++) {
9185f7e80a8Spooka sc->sc_ops->write_uint8(sc,Offset,CMD_READ_STATUS);
9195f7e80a8Spooka sc->sc_ops->read_uint8(sc,Offset,&Status);
9205f7e80a8Spooka if ((Status & ST_READY)) break;
9215f7e80a8Spooka DELAY(200);
9225f7e80a8Spooka }
9235f7e80a8Spooka
9245f7e80a8Spooka ProductIdExit(sc);
9255f7e80a8Spooka
9265f7e80a8Spooka /* Verify */
9275f7e80a8Spooka if (Verify) {
9285f7e80a8Spooka for (i = 0; i < sc->sc_buffersize; i+= 4) {
9295f7e80a8Spooka sc->sc_ops->read_uint32(sc,Where+i,&Data32);
9305f7e80a8Spooka #ifdef Verbose
9315f7e80a8Spooka if (Verbose) {
9325f7e80a8Spooka printf("Location %p is now x%x\n",
9335f7e80a8Spooka Where+i, Data32);
9345f7e80a8Spooka }
9355f7e80a8Spooka #endif
9365f7e80a8Spooka v0 = Values[i/2];
9375f7e80a8Spooka v0 = le16toh(v0);
9385f7e80a8Spooka v1 = Values[1+(i/2)];
9395f7e80a8Spooka v1 = le16toh(v1);
9405f7e80a8Spooka Value = v0 | ((uint32_t)v1 << 16);
9415f7e80a8Spooka
9425f7e80a8Spooka if ((Data32 != Value)) {
9435f7e80a8Spooka PrintStatus(Status);
9445f7e80a8Spooka printf(". That didnt work, try again.. [%x != %x]\n",
9455f7e80a8Spooka Data32, Value);
9465f7e80a8Spooka ClearStatusRegister(sc);
9475f7e80a8Spooka return FALSE;
9485f7e80a8Spooka }
9495f7e80a8Spooka }
9505f7e80a8Spooka }
9515f7e80a8Spooka
9525f7e80a8Spooka *nWritten = sc->sc_buffersize;
9535f7e80a8Spooka return TRUE;
9545f7e80a8Spooka }
9555f7e80a8Spooka
9565f7e80a8Spooka /* Is there a lock on a given sector
9575f7e80a8Spooka */
IsSectorLocked(struct eflash_softc * sc,uint8_t * secptr)9585f7e80a8Spooka static int IsSectorLocked(struct eflash_softc *sc, uint8_t *secptr)
9595f7e80a8Spooka {
9605f7e80a8Spooka uint8_t Data, Data1;
9615f7e80a8Spooka
9625f7e80a8Spooka ProductIdEnter(sc);
9635f7e80a8Spooka /* Lockout info is at address 2 of the given sector, meaning A0=0 A1=1.
9645f7e80a8Spooka */
9655f7e80a8Spooka sc->sc_ops->read_uint8(sc,secptr+(0x0002*2*sc->sc_chips),&Data);
9665f7e80a8Spooka sc->sc_ops->read_uint8(sc,secptr+(0x0003*2*sc->sc_chips),&Data1);
9675f7e80a8Spooka
9685f7e80a8Spooka ProductIdExit(sc);
9695f7e80a8Spooka
9705f7e80a8Spooka return (Data & 1);
9715f7e80a8Spooka }
9725f7e80a8Spooka
9735f7e80a8Spooka /* Remove the write-lock to a sector
9745f7e80a8Spooka */
SectorUnLock(struct eflash_softc * sc,uint8_t * secptr)9755f7e80a8Spooka static void SectorUnLock(struct eflash_softc *sc, uint8_t *secptr)
9765f7e80a8Spooka {
9775f7e80a8Spooka uint8_t Status;
9785f7e80a8Spooka int i;
9795f7e80a8Spooka
9805f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: Unlocking sector %d [ptr %p] ...\n",
9815f7e80a8Spooka device_xname(sc->sc_dev), sc->sc_sector_offset, secptr));
9825f7e80a8Spooka
9835f7e80a8Spooka sc->sc_ops->write_uint8(sc,sc->sc_page0,CMD_SET_PREFIX);
9845f7e80a8Spooka sc->sc_ops->write_uint8(sc,secptr,CMD_UNLOCK);
9855f7e80a8Spooka
9865f7e80a8Spooka /* Wait until the unlock is complete.
9875f7e80a8Spooka * Specs say this takes between 64 and 75 usecs.
9885f7e80a8Spooka */
9895f7e80a8Spooka DELAY(100);
9905f7e80a8Spooka
9915f7e80a8Spooka for (i = 0; i < 10; i++) {
9925f7e80a8Spooka sc->sc_ops->read_uint8(sc,secptr,&Status);
9935f7e80a8Spooka if ((Status & ST_READY)) break;
9945f7e80a8Spooka DELAY(100);
9955f7e80a8Spooka }
9965f7e80a8Spooka
9975f7e80a8Spooka ProductIdExit(sc);
9985f7e80a8Spooka
9995f7e80a8Spooka if ((Status & ST_MASK) == ST_READY) {
10005f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: Unlocked ok.\n",
10015f7e80a8Spooka device_xname(sc->sc_dev)));
10025f7e80a8Spooka return;
10035f7e80a8Spooka }
10045f7e80a8Spooka
10055f7e80a8Spooka PrintStatus(Status);
10065f7e80a8Spooka DBGME(DEBUG_ERRORS,printf("%s: Unlock of sector %d NOT completed (status=%x).\n",
10075f7e80a8Spooka device_xname(sc->sc_dev),
10085f7e80a8Spooka sc->sc_sector_offset, Status));
10095f7e80a8Spooka ClearStatusRegister(sc);
10105f7e80a8Spooka }
10115f7e80a8Spooka
10125f7e80a8Spooka
10135f7e80a8Spooka /* Erase one sector
10145f7e80a8Spooka */
SectorErase(struct eflash_softc * sc,void * secptr)10155f7e80a8Spooka static int SectorErase(struct eflash_softc *sc, void *secptr)
10165f7e80a8Spooka {
10175f7e80a8Spooka uint8_t Status = 0;
10185f7e80a8Spooka uint16_t i;
10195f7e80a8Spooka
10205f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: Erasing sector %d [ptr %p] ...\n",
10215f7e80a8Spooka device_xname(sc->sc_dev), sc->sc_sector_offset, secptr));
10225f7e80a8Spooka
10235f7e80a8Spooka /* On some chips we just cannot avoid the locking business.
10245f7e80a8Spooka */
10255f7e80a8Spooka if ((sc->sc_chips == 1) &&
10265f7e80a8Spooka IsSectorLocked(sc,secptr))
10275f7e80a8Spooka SectorUnLock(sc,secptr);
10285f7e80a8Spooka
10295f7e80a8Spooka sc->sc_ops->write_uint8(sc,secptr,CMD_ERASE_SETUP);
10305f7e80a8Spooka sc->sc_ops->write_uint8(sc,secptr,CMD_ERASE_CONFIRM);
10315f7e80a8Spooka
10325f7e80a8Spooka /* Wait until the erase is actually completed
10335f7e80a8Spooka * Specs say it will take between 1 and 5 seconds.
10345f7e80a8Spooka * Errata says it takes 2 sec min and 25 sec max.
10355f7e80a8Spooka * Double that before giving up.
10365f7e80a8Spooka */
10375f7e80a8Spooka for (i = 0; i < 20; i++) {
10385f7e80a8Spooka /* Sleep for at least 2 seconds
10395f7e80a8Spooka */
10405f7e80a8Spooka tsleep(sc,PWAIT,"erase", hz * 2);
10415f7e80a8Spooka
10425f7e80a8Spooka sc->sc_ops->read_uint8(sc,secptr,&Status);
10435f7e80a8Spooka if ((Status & ST_READY)) break;
10445f7e80a8Spooka PrintStatus(Status);
10455f7e80a8Spooka }
10465f7e80a8Spooka
10475f7e80a8Spooka ProductIdExit(sc);
10485f7e80a8Spooka
10495f7e80a8Spooka if ((Status & ST_ERASE_MASK) == ST_READY) {
10505f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: Erased ok.\n", device_xname(sc->sc_dev)));
10515f7e80a8Spooka return 0;
10525f7e80a8Spooka }
10535f7e80a8Spooka
10545f7e80a8Spooka PrintStatus(Status);
10555f7e80a8Spooka DBGME(DEBUG_ERRORS,printf("%s: Erase of sector %d NOT completed (status=%x).\n",
10565f7e80a8Spooka device_xname(sc->sc_dev),
10575f7e80a8Spooka sc->sc_sector_offset, Status));
10585f7e80a8Spooka
10595f7e80a8Spooka ClearStatusRegister(sc);
10605f7e80a8Spooka return EIO;
10615f7e80a8Spooka }
10625f7e80a8Spooka
10635f7e80a8Spooka
10645f7e80a8Spooka
10655f7e80a8Spooka /* Write (a portion of) a sector
10665f7e80a8Spooka */
eflash_write_sector(struct eflash_softc * sc,char * Buffer,size_t n,uint8_t * Offset,int Verify)10675f7e80a8Spooka static size_t eflash_write_sector(struct eflash_softc *sc, char *Buffer, size_t n,
10685f7e80a8Spooka uint8_t *Offset, int Verify)
10695f7e80a8Spooka {
10705f7e80a8Spooka size_t i;
10715f7e80a8Spooka
10725f7e80a8Spooka /* Make sure the device is not screwed up
10735f7e80a8Spooka */
10745f7e80a8Spooka if (IsIrresponsive(sc)) {
10755f7e80a8Spooka printf("FLASH is locked-up (or mapped cacheable?), wont work. ");
10765f7e80a8Spooka }
10775f7e80a8Spooka
10785f7e80a8Spooka for (i = 0; i < n;) {
10795f7e80a8Spooka int nTries;
10805f7e80a8Spooka int nWritten = 0;/*we expect 2 or 4 */
10815f7e80a8Spooka
10825f7e80a8Spooka if (sc->sc_buffersize && ((n-i) >= sc->sc_buffersize)) {
10835f7e80a8Spooka for (nTries = 0; nTries < 5; nTries++)
10845f7e80a8Spooka if (sc->sc_ops->program_buffer(sc,Offset,(uint16_t*)(Buffer+i),Verify,&nWritten))
10855f7e80a8Spooka break;
10865f7e80a8Spooka } else {
10875f7e80a8Spooka for (nTries = 0; nTries < 5; nTries++)
10885f7e80a8Spooka if (sc->sc_ops->program_word(sc,Offset,(uint16_t*)(Buffer+i),Verify,&nWritten))
10895f7e80a8Spooka break;
10905f7e80a8Spooka }
10915f7e80a8Spooka Offset += nWritten;
10925f7e80a8Spooka i += nWritten;
10935f7e80a8Spooka if (nWritten == 0)
10945f7e80a8Spooka break;
10955f7e80a8Spooka }
10965f7e80a8Spooka return i;
10975f7e80a8Spooka }
10985f7e80a8Spooka
10995f7e80a8Spooka /* Identify type and the sector map of the FLASH.
11005f7e80a8Spooka * Argument is the base address of the device and the count of chips on the bus (1/2)
11015f7e80a8Spooka * Returns FALSE if failed
11025f7e80a8Spooka */
11035f7e80a8Spooka static const struct flash_ops single_ops = {
11045f7e80a8Spooka single_write_uint8,
11055f7e80a8Spooka single_read_uint8,
11065f7e80a8Spooka single_write_uint16,
11075f7e80a8Spooka single_read_uint16,
11085f7e80a8Spooka single_write_uint32,
11095f7e80a8Spooka single_read_uint32,
11105f7e80a8Spooka single_program_word,
11115f7e80a8Spooka single_program_buffer
11125f7e80a8Spooka };
11135f7e80a8Spooka
11145f7e80a8Spooka static const struct flash_ops twin_ops = {
11155f7e80a8Spooka twin_write_uint8,
11165f7e80a8Spooka twin_read_uint8,
11175f7e80a8Spooka twin_write_uint16,
11185f7e80a8Spooka twin_read_uint16,
11195f7e80a8Spooka twin_write_uint32,
11205f7e80a8Spooka twin_read_uint32,
11215f7e80a8Spooka twin_program_word,
11225f7e80a8Spooka twin_program_buffer
11235f7e80a8Spooka };
11245f7e80a8Spooka
flash_identify(struct eflash_softc * sc)11255f7e80a8Spooka static int flash_identify(struct eflash_softc *sc)
11265f7e80a8Spooka {
11275f7e80a8Spooka uint8_t Mid, Did;
11285f7e80a8Spooka int i;
11295f7e80a8Spooka
11305f7e80a8Spooka if (sc->sc_chips > 1)
11315f7e80a8Spooka sc->sc_ops = &twin_ops;
11325f7e80a8Spooka else
11335f7e80a8Spooka sc->sc_ops = &single_ops;
11345f7e80a8Spooka
11355f7e80a8Spooka sc->sc_buffersize = 0;
11365f7e80a8Spooka #if USE_BUFFERED_WRITES
11375f7e80a8Spooka sc->sc_buffersize = BUFFER_BYTES * sc->sc_chips;
11385f7e80a8Spooka #endif
11395f7e80a8Spooka sc->sc_sector = NULL;
11405f7e80a8Spooka sc->sc_sector_size = 0;
11415f7e80a8Spooka sc->sc_sector_offset = NOSECTOR;
11425f7e80a8Spooka sc->sc_erased = FALSE;
11435f7e80a8Spooka
11445f7e80a8Spooka ProductIdEnter(sc);
11455f7e80a8Spooka sc->sc_ops->read_uint8(sc,sc->sc_page0+(0x0000*2*sc->sc_chips),&Mid);
11465f7e80a8Spooka sc->sc_ops->read_uint8(sc,sc->sc_page0+(0x0001*2*sc->sc_chips),&Did);
11475f7e80a8Spooka ProductIdExit(sc);
11485f7e80a8Spooka
11495f7e80a8Spooka sc->sc_type.ft_manuf_code = Mid;
11505f7e80a8Spooka sc->sc_type.ft_device_code = Did;
11515f7e80a8Spooka
11525f7e80a8Spooka for (i = 0; i < nMAPS; i++) {
11535f7e80a8Spooka if ((sector_maps[i].ft_manuf_code == Mid) && (sector_maps[i].ft_device_code == Did)) {
11545f7e80a8Spooka int j;
11555f7e80a8Spooka uint32_t ms = 0;
11565f7e80a8Spooka sc->sc_type = sector_maps[i];
11575f7e80a8Spooka /* double the sector sizes if twin-chips */
11585f7e80a8Spooka for (j = 0; j < nDELTAS; j++) {
11595f7e80a8Spooka sc->sc_type.ft_deltas[j].nKB *= sc->sc_chips;
11605f7e80a8Spooka if (ms < sc->sc_type.ft_deltas[j].nKB)
11615f7e80a8Spooka ms = sc->sc_type.ft_deltas[j].nKB;
11625f7e80a8Spooka }
11635f7e80a8Spooka sc->sc_max_secsize = ms * 1024;
11645f7e80a8Spooka return TRUE;
11655f7e80a8Spooka }
11665f7e80a8Spooka }
11675f7e80a8Spooka
11685f7e80a8Spooka return FALSE;
11695f7e80a8Spooka }
11705f7e80a8Spooka
11715f7e80a8Spooka /* Common code for read&write argument validation
11725f7e80a8Spooka */
eflash_validate(struct eflash_softc * sc,daddr_t start,size_t * pSize,void ** pSrc)11735f7e80a8Spooka static int eflash_validate(struct eflash_softc *sc, daddr_t start, size_t *pSize, void **pSrc)
11745f7e80a8Spooka {
11755f7e80a8Spooka daddr_t Size;
11765f7e80a8Spooka uint32_t sec;
11775f7e80a8Spooka size_t secsize, secstart;
11785f7e80a8Spooka
11795f7e80a8Spooka /* Validate args
11805f7e80a8Spooka */
11815f7e80a8Spooka if (start >= sc->sc_capacity) {
11825f7e80a8Spooka *pSize = 0;
11835f7e80a8Spooka DBGME(DEBUG_ERRORS,printf("eflash::ValidateArg(%qx) EOF\n", start));
11845f7e80a8Spooka return E2BIG;
11855f7e80a8Spooka }
11865f7e80a8Spooka
11875f7e80a8Spooka /* Map sector if not already
11885f7e80a8Spooka */
11895f7e80a8Spooka sec = SectorNumber(&sc->sc_type, start << DEV_BSHIFT);
11905f7e80a8Spooka secsize = SectorSize( &sc->sc_type, sec);
11915f7e80a8Spooka secstart = SectorStart(&sc->sc_type,sec);
11925f7e80a8Spooka if (sec != sc->sc_sector_offset) {
11935f7e80a8Spooka int error;
11945f7e80a8Spooka
11955f7e80a8Spooka /* unmap previous first */
11965f7e80a8Spooka if (sc->sc_sector_offset != NOSECTOR) {
11975f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: unmap %p %zx\n",
11985f7e80a8Spooka device_xname(sc->sc_dev), sc->sc_sector, sc->sc_sector_size));
11995f7e80a8Spooka iounaccess((vaddr_t)sc->sc_sector, sc->sc_sector_size);
12005f7e80a8Spooka sc->sc_sector_offset = NOSECTOR;
12015f7e80a8Spooka }
12025f7e80a8Spooka
12035f7e80a8Spooka /* map new */
12045f7e80a8Spooka error = ioaccess((vaddr_t)sc->sc_sector,
12055f7e80a8Spooka secstart + sc->sc_base,
12065f7e80a8Spooka secsize);
1207c69eb063Stsutsui DBGME(DEBUG_FUNCS,printf("%s: mapped %p %zx -> %zx %d\n",
12085f7e80a8Spooka device_xname(sc->sc_dev),
12095f7e80a8Spooka sc->sc_sector, secsize, secstart + sc->sc_base,error));
12105f7e80a8Spooka if (error) return error;
12115f7e80a8Spooka
12125f7e80a8Spooka /* Update state. We have to assume the sector was not erased. Sigh. */
12135f7e80a8Spooka sc->sc_sector_offset = sec;
12145f7e80a8Spooka sc->sc_sector_size = secsize;
12155f7e80a8Spooka sc->sc_erased = FALSE;
12165f7e80a8Spooka }
12175f7e80a8Spooka
12185f7e80a8Spooka /* Adjust size if necessary
12195f7e80a8Spooka */
12205f7e80a8Spooka Size = start + *pSize; /* last sector */
12215f7e80a8Spooka if (Size > sc->sc_capacity) {
12225f7e80a8Spooka /* At most this many sectors
12235f7e80a8Spooka */
12245f7e80a8Spooka Size = sc->sc_capacity - start;
12255f7e80a8Spooka *pSize = (size_t)Size;
12265f7e80a8Spooka }
12275f7e80a8Spooka if (*pSize > (secsize >> DEV_BSHIFT)) {
12285f7e80a8Spooka *pSize = secsize >> DEV_BSHIFT;
12295f7e80a8Spooka }
12305f7e80a8Spooka
12315f7e80a8Spooka *pSrc = sc->sc_sector + (start << DEV_BSHIFT) - secstart;
12325f7e80a8Spooka
12335f7e80a8Spooka DBGME(DEBUG_FUNCS,printf("%s: Validate %qx %zd %p\n",
12345f7e80a8Spooka device_xname(sc->sc_dev), start,*pSize, *pSrc));
12355f7e80a8Spooka return 0;
12365f7e80a8Spooka }
12375f7e80a8Spooka
eflash_read_at(struct eflash_softc * sc,daddr_t start_sector,char * buffer,size_t nblocks,size_t * pSizeRead)12385f7e80a8Spooka static int eflash_read_at (struct eflash_softc *sc,
12395f7e80a8Spooka daddr_t start_sector, char *buffer, size_t nblocks,
12405f7e80a8Spooka size_t * pSizeRead)
12415f7e80a8Spooka {
12425f7e80a8Spooka int error;
12435f7e80a8Spooka uint32_t SizeRead = 0;
12445f7e80a8Spooka void *src;
12455f7e80a8Spooka
12465f7e80a8Spooka DBGME(DEBUG_XFERS|DEBUG_READS,printf("%s: EflashReadAt(%qx %p %zd %p)\n",
12475f7e80a8Spooka device_xname(sc->sc_dev), start_sector, buffer, nblocks, pSizeRead));
12485f7e80a8Spooka
12495f7e80a8Spooka /* Validate & trim arguments
12505f7e80a8Spooka */
12515f7e80a8Spooka error = eflash_validate(sc, start_sector, &nblocks, &src);
12525f7e80a8Spooka
12535f7e80a8Spooka /* Copy data if
12545f7e80a8Spooka */
12555f7e80a8Spooka if (error == 0) {
12565f7e80a8Spooka SizeRead = nblocks;
12575f7e80a8Spooka memcpy(buffer, src, nblocks << DEV_BSHIFT);
12585f7e80a8Spooka }
12595f7e80a8Spooka
12605f7e80a8Spooka if (pSizeRead)
12615f7e80a8Spooka *pSizeRead = SizeRead;
12625f7e80a8Spooka return error;
12635f7e80a8Spooka }
12645f7e80a8Spooka
12655f7e80a8Spooka /* Write SIZE bytes to device.
12665f7e80a8Spooka */
eflash_write_at(struct eflash_softc * sc,daddr_t start_sector,char * buffer,size_t nblocks,size_t * pSizeWritten)12675f7e80a8Spooka static int eflash_write_at (struct eflash_softc *sc,
12685f7e80a8Spooka daddr_t start_sector, char *buffer, size_t nblocks,
12695f7e80a8Spooka size_t * pSizeWritten)
12705f7e80a8Spooka {
12715f7e80a8Spooka int error;
12725f7e80a8Spooka void *src;
12735f7e80a8Spooka size_t SizeWritten = 0;
12745f7e80a8Spooka
12755f7e80a8Spooka DBGME(DEBUG_XFERS|DEBUG_WRITES,printf("%s: EflashWriteAt(%qx %p %zd %p)\n",
12765f7e80a8Spooka device_xname(sc->sc_dev), start_sector, buffer, nblocks, pSizeWritten));
12775f7e80a8Spooka
12785f7e80a8Spooka /* Validate & trim arguments
12795f7e80a8Spooka */
12805f7e80a8Spooka error = eflash_validate(sc, start_sector, &nblocks, &src);
12815f7e80a8Spooka
12825f7e80a8Spooka if (error == 0) {
12835f7e80a8Spooka /* Do we have to erase it */
12845f7e80a8Spooka if (! sc->sc_erased) {
12855f7e80a8Spooka
12865f7e80a8Spooka error = SectorErase(sc,src);
12875f7e80a8Spooka if (error)
12885f7e80a8Spooka goto Out;
12895f7e80a8Spooka sc->sc_erased = TRUE;
12905f7e80a8Spooka }
12915f7e80a8Spooka SizeWritten = eflash_write_sector(sc, buffer, nblocks << DEV_BSHIFT, src, TRUE);
12925f7e80a8Spooka SizeWritten >>= DEV_BSHIFT;
12935f7e80a8Spooka }
12945f7e80a8Spooka
12955f7e80a8Spooka Out:
12965f7e80a8Spooka if (pSizeWritten)
12975f7e80a8Spooka *pSizeWritten = SizeWritten;
12985f7e80a8Spooka return error;
12995f7e80a8Spooka }
13005f7e80a8Spooka
13015f7e80a8Spooka /* Rest of code lifted with mods from the dev\ata\wd.c driver
13025f7e80a8Spooka */
13035f7e80a8Spooka
13045f7e80a8Spooka /*
13055f7e80a8Spooka * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
13065f7e80a8Spooka *
13075f7e80a8Spooka * Redistribution and use in source and binary forms, with or without
13085f7e80a8Spooka * modification, are permitted provided that the following conditions
13095f7e80a8Spooka * are met:
13105f7e80a8Spooka * 1. Redistributions of source code must retain the above copyright
13115f7e80a8Spooka * notice, this list of conditions and the following disclaimer.
13125f7e80a8Spooka * 2. Redistributions in binary form must reproduce the above copyright
13135f7e80a8Spooka * notice, this list of conditions and the following disclaimer in the
13145f7e80a8Spooka * documentation and/or other materials provided with the distribution.
13155f7e80a8Spooka *
13165f7e80a8Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
13175f7e80a8Spooka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13185f7e80a8Spooka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
13195f7e80a8Spooka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
13205f7e80a8Spooka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
13215f7e80a8Spooka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13225f7e80a8Spooka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13235f7e80a8Spooka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13245f7e80a8Spooka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
13255f7e80a8Spooka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13265f7e80a8Spooka */
13275f7e80a8Spooka
13285f7e80a8Spooka /*-
13295f7e80a8Spooka * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
13305f7e80a8Spooka * All rights reserved.
13315f7e80a8Spooka *
13325f7e80a8Spooka * This code is derived from software contributed to The NetBSD Foundation
13335f7e80a8Spooka * by Charles M. Hannum and by Onno van der Linden.
13345f7e80a8Spooka *
13355f7e80a8Spooka * Redistribution and use in source and binary forms, with or without
13365f7e80a8Spooka * modification, are permitted provided that the following conditions
13375f7e80a8Spooka * are met:
13385f7e80a8Spooka * 1. Redistributions of source code must retain the above copyright
13395f7e80a8Spooka * notice, this list of conditions and the following disclaimer.
13405f7e80a8Spooka * 2. Redistributions in binary form must reproduce the above copyright
13415f7e80a8Spooka * notice, this list of conditions and the following disclaimer in the
13425f7e80a8Spooka * documentation and/or other materials provided with the distribution.
13435f7e80a8Spooka *
13445f7e80a8Spooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
13455f7e80a8Spooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13465f7e80a8Spooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13475f7e80a8Spooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
13485f7e80a8Spooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13495f7e80a8Spooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13505f7e80a8Spooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
13515f7e80a8Spooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
13525f7e80a8Spooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
13535f7e80a8Spooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13545f7e80a8Spooka * POSSIBILITY OF SUCH DAMAGE.
13555f7e80a8Spooka */
13565f7e80a8Spooka
13575f7e80a8Spooka static const char ST506[] = "ST506";
13585f7e80a8Spooka
13595f7e80a8Spooka #define EFLASHIORETRIES_SINGLE 4 /* number of retries before single-sector */
13605f7e80a8Spooka #define EFLASHIORETRIES 5 /* number of retries before giving up */
13615f7e80a8Spooka #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */
13625f7e80a8Spooka
13635f7e80a8Spooka #define EFLASHUNIT(dev) DISKUNIT(dev)
13645f7e80a8Spooka #define EFLASHPART(dev) DISKPART(dev)
13655f7e80a8Spooka #define EFLASHMINOR(unit, part) DISKMINOR(unit, part)
13665f7e80a8Spooka #define MAKEEFLASHDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
13675f7e80a8Spooka
13685f7e80a8Spooka #define EFLASHLABELDEV(dev) (MAKEEFLASHDEV(major(dev), EFLASHUNIT(dev), RAW_PART))
13695f7e80a8Spooka
13705f7e80a8Spooka void eflashperror(const struct eflash_softc *);
13715f7e80a8Spooka
13725f7e80a8Spooka extern struct cfdriver eflash_cd;
13735f7e80a8Spooka
13745f7e80a8Spooka dev_type_open(eflashopen);
13755f7e80a8Spooka dev_type_close(eflashclose);
13765f7e80a8Spooka dev_type_read(eflashread);
13775f7e80a8Spooka dev_type_write(eflashwrite);
13785f7e80a8Spooka dev_type_ioctl(eflashioctl);
13795f7e80a8Spooka dev_type_strategy(eflashstrategy);
13805f7e80a8Spooka dev_type_dump(eflashdump);
13815f7e80a8Spooka dev_type_size(eflashsize);
13825f7e80a8Spooka
13835f7e80a8Spooka const struct bdevsw eflash_bdevsw = {
1384a68f9396Sdholland .d_open = eflashopen,
1385a68f9396Sdholland .d_close = eflashclose,
1386a68f9396Sdholland .d_strategy = eflashstrategy,
1387a68f9396Sdholland .d_ioctl = eflashioctl,
1388a68f9396Sdholland .d_dump = eflashdump,
1389a68f9396Sdholland .d_psize = eflashsize,
13908c70ef39Sdholland .d_discard = nodiscard,
1391a68f9396Sdholland .d_flag = D_DISK
13925f7e80a8Spooka };
13935f7e80a8Spooka
13945f7e80a8Spooka const struct cdevsw eflash_cdevsw = {
1395a68f9396Sdholland .d_open = eflashopen,
1396a68f9396Sdholland .d_close = eflashclose,
1397a68f9396Sdholland .d_read = eflashread,
1398a68f9396Sdholland .d_write = eflashwrite,
1399a68f9396Sdholland .d_ioctl = eflashioctl,
1400a68f9396Sdholland .d_stop = nostop,
1401a68f9396Sdholland .d_tty = notty,
1402a68f9396Sdholland .d_poll = nopoll,
1403a68f9396Sdholland .d_mmap = nommap,
1404a68f9396Sdholland .d_kqfilter = nokqfilter,
1405f9228f42Sdholland .d_discard = nodiscard,
1406a68f9396Sdholland .d_flag = D_DISK
14075f7e80a8Spooka };
14085f7e80a8Spooka
14095f7e80a8Spooka void eflashgetdefaultlabel(struct eflash_softc *, struct disklabel *);
14105f7e80a8Spooka void eflashgetdisklabel(struct eflash_softc *);
14115f7e80a8Spooka void eflashstart(void *);
14125f7e80a8Spooka void __eflashstart(struct eflash_softc *, struct buf *);
14135f7e80a8Spooka void eflashrestart(void *);
14145f7e80a8Spooka void eflashattach(struct eflash_softc *);
1415cbab9cadSchs int eflashdetach(device_t, int);
1416cbab9cadSchs int eflashactivate(device_t, enum devact);
14175f7e80a8Spooka
14185f7e80a8Spooka void eflashdone(struct eflash_softc *);
14197b845fa9Schristos static void eflash_set_geometry(struct eflash_softc *sc);
14205f7e80a8Spooka
14216f00c789Smlelstv struct dkdriver eflashdkdriver = {
14226f00c789Smlelstv .d_strategy = eflashstrategy,
14236f00c789Smlelstv .d_minphys = minphys
14246f00c789Smlelstv };
14255f7e80a8Spooka
14265f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
14275f7e80a8Spooka static void bad144intern(struct eflash_softc *);
14285f7e80a8Spooka #endif
14295f7e80a8Spooka
14305f7e80a8Spooka static void eflash_wedges(void *arg);
14315f7e80a8Spooka
14325f7e80a8Spooka void
eflashattach(struct eflash_softc * sc)14335f7e80a8Spooka eflashattach(struct eflash_softc *sc)
14345f7e80a8Spooka {
1435cbab9cadSchs device_t self = sc->sc_dev;
14365f7e80a8Spooka char pbuf[9];
14375f7e80a8Spooka DEBUG_PRINT(("%s: eflashattach\n", device_xname(sc->sc_dev)), DEBUG_FUNCS | DEBUG_PROBE);
14385f7e80a8Spooka
14395f7e80a8Spooka callout_init(&sc->sc_restart_ch, 0);
14405f7e80a8Spooka bufq_alloc(&sc->sc_q, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
14415f7e80a8Spooka
14425f7e80a8Spooka sc->openings = 1; /* wazziz?*/
14435f7e80a8Spooka
14445f7e80a8Spooka aprint_naive("\n");
14455f7e80a8Spooka
14465f7e80a8Spooka /* setup all required fields so that if the attach fails we are ok */
14475f7e80a8Spooka sc->sc_dk.dk_driver = &eflashdkdriver;
14485f7e80a8Spooka sc->sc_dk.dk_name = device_xname(sc->sc_dev);
14495f7e80a8Spooka
14505f7e80a8Spooka format_bytes(pbuf, sizeof(pbuf), sc->sc_capacity * DEV_BSIZE);
14515f7e80a8Spooka aprint_normal("%s: %s, %d cyl, %d head, %d sec, %d bytes/sect x %llu sectors\n",
1452cbab9cadSchs device_xname(self), pbuf, 1, 1, sc->sc_capacity,
14535f7e80a8Spooka DEV_BSIZE, (unsigned long long)sc->sc_capacity);
14545f7e80a8Spooka
14557b845fa9Schristos eflash_set_geometry(sc);
14565f7e80a8Spooka
14575f7e80a8Spooka /*
14585f7e80a8Spooka * Attach the disk structure. We fill in dk_info later.
14595f7e80a8Spooka */
14605f7e80a8Spooka disk_attach(&sc->sc_dk);
14615f7e80a8Spooka
14625f7e80a8Spooka rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
1463ea6af427Stls RND_TYPE_DISK, RND_FLAG_DEFAULT);
14645f7e80a8Spooka
14655f7e80a8Spooka }
14665f7e80a8Spooka
14675f7e80a8Spooka int
eflashactivate(device_t self,enum devact act)1468cbab9cadSchs eflashactivate(device_t self, enum devact act)
14695f7e80a8Spooka {
14705f7e80a8Spooka int rv = 0;
14715f7e80a8Spooka
14725f7e80a8Spooka DEBUG_PRINT(("eflashactivate %x\n", act), DEBUG_FUNCS | DEBUG_PROBE);
14735f7e80a8Spooka
14745f7e80a8Spooka switch (act) {
14755f7e80a8Spooka case DVACT_DEACTIVATE:
14765f7e80a8Spooka /*
14775f7e80a8Spooka * Nothing to do; we key off the device's DVF_ACTIVATE.
14785f7e80a8Spooka */
14795f7e80a8Spooka break;
14805f7e80a8Spooka default:
14815f7e80a8Spooka rv = EOPNOTSUPP;
14825f7e80a8Spooka break;
14835f7e80a8Spooka }
14845f7e80a8Spooka return (rv);
14855f7e80a8Spooka }
14865f7e80a8Spooka
14875f7e80a8Spooka int
eflashdetach(device_t self,int flags)1488cbab9cadSchs eflashdetach(device_t self, int flags)
14895f7e80a8Spooka {
14905f7e80a8Spooka struct eflash_softc *sc = device_private(self);
14915f7e80a8Spooka int s, bmaj, cmaj, i, mn;
14925f7e80a8Spooka
14935f7e80a8Spooka DEBUG_PRINT(("%s: eflashdetach\n", device_xname(sc->sc_dev)), DEBUG_FUNCS | DEBUG_PROBE);
14945f7e80a8Spooka
14955f7e80a8Spooka /* locate the major number */
14965f7e80a8Spooka bmaj = bdevsw_lookup_major(&eflash_bdevsw);
14975f7e80a8Spooka cmaj = cdevsw_lookup_major(&eflash_cdevsw);
14985f7e80a8Spooka
14995f7e80a8Spooka /* Nuke the vnodes for any open instances. */
15005f7e80a8Spooka for (i = 0; i < MAXPARTITIONS; i++) {
15015f7e80a8Spooka mn = EFLASHMINOR(device_unit(self), i);
15025f7e80a8Spooka vdevgone(bmaj, mn, mn, VBLK);
15035f7e80a8Spooka vdevgone(cmaj, mn, mn, VCHR);
15045f7e80a8Spooka }
15055f7e80a8Spooka
15065f7e80a8Spooka /* Delete all of our wedges. */
15075f7e80a8Spooka dkwedge_delall(&sc->sc_dk);
15085f7e80a8Spooka
15095f7e80a8Spooka s = splbio();
15105f7e80a8Spooka
15115f7e80a8Spooka /* Kill off any queued buffers. */
15125f7e80a8Spooka bufq_drain(sc->sc_q);
15135f7e80a8Spooka
15145f7e80a8Spooka /*sc->atabus->ata_killpending(sc->drvp);*/
15155f7e80a8Spooka
15165f7e80a8Spooka splx(s);
1517e38abff0Spgoyette bufq_free(sc->sc_q);
15185f7e80a8Spooka
15195f7e80a8Spooka /* Detach disk. */
15205f7e80a8Spooka disk_detach(&sc->sc_dk);
15215f7e80a8Spooka
15225f7e80a8Spooka /* Unhook the entropy source. */
15235f7e80a8Spooka rnd_detach_source(&sc->rnd_source);
15245f7e80a8Spooka
15255f7e80a8Spooka /*sc->drvp->drive_flags = 0; -- no drive any more here */
15265f7e80a8Spooka
15275f7e80a8Spooka return (0);
15285f7e80a8Spooka }
15295f7e80a8Spooka
15305f7e80a8Spooka extern int dkwedge_autodiscover;
15315f7e80a8Spooka
15325f7e80a8Spooka /* Aux temp thread to avoid deadlock when doing the partitio.. ahem wedges thing.
15335f7e80a8Spooka */
15345f7e80a8Spooka static void
eflash_wedges(void * arg)15355f7e80a8Spooka eflash_wedges(void *arg)
15365f7e80a8Spooka {
15375f7e80a8Spooka struct eflash_softc *sc = (struct eflash_softc*)arg;
15385f7e80a8Spooka
15395f7e80a8Spooka DBGME(DEBUG_STATUS,printf("%s: wedges started for %p\n", sc->sc_dk.dk_name, sc));
15405f7e80a8Spooka
15415f7e80a8Spooka /* Discover wedges on this disk. */
15425f7e80a8Spooka dkwedge_autodiscover = 1;
15435f7e80a8Spooka dkwedge_discover(&sc->sc_dk);
15445f7e80a8Spooka
15456ec333ebSriz config_pending_decr(sc->sc_dev);
15465f7e80a8Spooka
15475f7e80a8Spooka DBGME(DEBUG_STATUS,printf("%s: wedges thread done for %p\n", device_xname(sc->sc_dev), sc));
15485f7e80a8Spooka kthread_exit(0);
15495f7e80a8Spooka }
15505f7e80a8Spooka
15515f7e80a8Spooka static void
eflash_thread(void * arg)15525f7e80a8Spooka eflash_thread(void *arg)
15535f7e80a8Spooka {
15545f7e80a8Spooka struct eflash_softc *sc = (struct eflash_softc*)arg;
15555f7e80a8Spooka struct buf *bp;
15565f7e80a8Spooka vaddr_t addr;
15575f7e80a8Spooka int s, error;
15585f7e80a8Spooka
15595f7e80a8Spooka DBGME(DEBUG_STATUS,printf("%s: thread started for %p\n", device_xname(sc->sc_dev), sc));
15605f7e80a8Spooka
15615f7e80a8Spooka s = splbio();
15625f7e80a8Spooka eflashattach(sc);
15635f7e80a8Spooka splx(s);
15645f7e80a8Spooka
15655f7e80a8Spooka /* Allocate a VM window large enough to map the largest sector
15665f7e80a8Spooka * BUGBUG We could risk it and allocate/free on open/close?
15675f7e80a8Spooka */
15685f7e80a8Spooka addr = uvm_km_alloc(kernel_map, sc->sc_max_secsize, 0, UVM_KMF_VAONLY);
15695f7e80a8Spooka if (addr == 0)
15705f7e80a8Spooka panic("eflash_thread: kernel map full (%lx)", (long unsigned)sc->sc_max_secsize);
15715f7e80a8Spooka sc->sc_sector = (/*volatile*/ uint8_t *) addr;
15725f7e80a8Spooka sc->sc_sector_size = 0;
15735f7e80a8Spooka sc->sc_sector_offset = NOSECTOR;
15745f7e80a8Spooka
15755f7e80a8Spooka error = kthread_create(PRI_NONE, 0, NULL,
15765f7e80a8Spooka eflash_wedges, sc, NULL, "%s.wedges", device_xname(sc->sc_dev));
15775f7e80a8Spooka if (error) {
15785f7e80a8Spooka aprint_error_dev(sc->sc_dev, "wedges: unable to create kernel "
15795f7e80a8Spooka "thread: error %d\n", error);
15805f7e80a8Spooka /* XXX: why continue? */
15815f7e80a8Spooka }
15825f7e80a8Spooka
15835f7e80a8Spooka
15845f7e80a8Spooka DBGME(DEBUG_STATUS,printf("%s: thread service active for %p\n", device_xname(sc->sc_dev), sc));
15855f7e80a8Spooka
15865f7e80a8Spooka s = splbio();
15875f7e80a8Spooka for (;;) {
15885f7e80a8Spooka /* Get next I/O request, wait if necessary
15895f7e80a8Spooka */
15905f7e80a8Spooka if ((sc->ch_flags & (ATACH_TH_RESET | ATACH_SHUTDOWN)) == 0 &&
15915f7e80a8Spooka (sc->active_xfer == NULL)) {
15925f7e80a8Spooka sc->ch_flags &= ~ATACH_TH_RUN;
15935f7e80a8Spooka (void) tsleep(&sc->ch_thread, PRIBIO, "eflashth", 0);
15945f7e80a8Spooka sc->ch_flags |= ATACH_TH_RUN;
15955f7e80a8Spooka }
15965f7e80a8Spooka if (sc->ch_flags & ATACH_SHUTDOWN) {
15975f7e80a8Spooka break;
15985f7e80a8Spooka }
15995f7e80a8Spooka bp = sc->active_xfer;
16005f7e80a8Spooka sc->active_xfer = NULL;
16015f7e80a8Spooka if (bp != NULL) {
16025f7e80a8Spooka
16035f7e80a8Spooka size_t sz = DEV_BSIZE, bnow;
16045f7e80a8Spooka
16055f7e80a8Spooka DBGME(DEBUG_XFERS,printf("%s: task %p %x %p %qx %d (%zd)\n", device_xname(sc->sc_dev), bp,
16065f7e80a8Spooka sc->sc_bio.flags, sc->sc_bio.databuf, sc->sc_bio.blkno,
16075f7e80a8Spooka sc->sc_bio.nbytes, sc->sc_bio.nblks));
16085f7e80a8Spooka
16095f7e80a8Spooka sc->sc_bio.error = 0;
16105f7e80a8Spooka for (; sc->sc_bio.nblks > 0;) {
16115f7e80a8Spooka
16125f7e80a8Spooka bnow = sc->sc_bio.nblks;
16135f7e80a8Spooka if (sc->sc_bio.flags & ATA_SINGLE) bnow = 1;
16145f7e80a8Spooka
16155f7e80a8Spooka if (sc->sc_bio.flags & ATA_READ) {
16165f7e80a8Spooka sc->sc_bio.error =
16175f7e80a8Spooka eflash_read_at(sc, sc->sc_bio.blkno, sc->sc_bio.databuf, bnow, &sz);
16185f7e80a8Spooka } else {
16195f7e80a8Spooka sc->sc_bio.error =
16205f7e80a8Spooka eflash_write_at(sc, sc->sc_bio.blkno, sc->sc_bio.databuf, bnow, &sz);
16215f7e80a8Spooka }
16225f7e80a8Spooka
16235f7e80a8Spooka if (sc->sc_bio.error)
16245f7e80a8Spooka break;
16255f7e80a8Spooka
16265f7e80a8Spooka sc->sc_bio.blkno += sz; /* in blocks */
16275f7e80a8Spooka sc->sc_bio.nblks -= sz;
16285f7e80a8Spooka sc->sc_bio.blkdone += sz;
16295f7e80a8Spooka sz = sz << DEV_BSHIFT; /* in bytes */
16305f7e80a8Spooka sc->sc_bio.databuf += sz;
16315f7e80a8Spooka sc->sc_bio.nbytes -= sz;
16325f7e80a8Spooka }
16335f7e80a8Spooka
16345f7e80a8Spooka eflashdone(sc);
16355f7e80a8Spooka }
16365f7e80a8Spooka }
16375f7e80a8Spooka
16385f7e80a8Spooka splx(s);
16395f7e80a8Spooka sc->ch_thread = NULL;
16405f7e80a8Spooka wakeup(&sc->ch_flags);
16415f7e80a8Spooka
16425f7e80a8Spooka DBGME(DEBUG_STATUS,printf("%s: thread service terminated for %p\n", device_xname(sc->sc_dev), sc));
16435f7e80a8Spooka
16445f7e80a8Spooka kthread_exit(0);
16455f7e80a8Spooka }
16465f7e80a8Spooka
16475f7e80a8Spooka
16485f7e80a8Spooka /*
16495f7e80a8Spooka * Read/write routine for a buffer. Validates the arguments and schedules the
16505f7e80a8Spooka * transfer. Does not wait for the transfer to complete.
16515f7e80a8Spooka */
16525f7e80a8Spooka void
eflashstrategy(struct buf * bp)16535f7e80a8Spooka eflashstrategy(struct buf *bp)
16545f7e80a8Spooka {
16555f7e80a8Spooka struct eflash_softc *sc = device_lookup_private(&eflash_cd, EFLASHUNIT(bp->b_dev));
16565f7e80a8Spooka struct disklabel *lp = sc->sc_dk.dk_label;
16575f7e80a8Spooka daddr_t blkno;
16585f7e80a8Spooka int s;
16595f7e80a8Spooka
16605f7e80a8Spooka DEBUG_PRINT(("%s: eflashstrategy %lld\n", device_xname(sc->sc_dev), bp->b_blkno),
16615f7e80a8Spooka DEBUG_XFERS);
16625f7e80a8Spooka
16635f7e80a8Spooka /* Valid request? */
16645f7e80a8Spooka if (bp->b_blkno < 0 ||
16655f7e80a8Spooka (bp->b_bcount % lp->d_secsize) != 0 ||
16665f7e80a8Spooka (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) {
16675f7e80a8Spooka bp->b_error = EINVAL;
16685f7e80a8Spooka goto done;
16695f7e80a8Spooka }
16705f7e80a8Spooka
16715f7e80a8Spooka /* If device invalidated (e.g. media change, door open), error. */
16725f7e80a8Spooka if ((sc->sc_flags & EFLASHF_LOADED) == 0) {
16735f7e80a8Spooka bp->b_error = EIO;
16745f7e80a8Spooka goto done;
16755f7e80a8Spooka }
16765f7e80a8Spooka
16775f7e80a8Spooka /* If it's a null transfer, return immediately. */
16785f7e80a8Spooka if (bp->b_bcount == 0)
16795f7e80a8Spooka goto done;
16805f7e80a8Spooka
16815f7e80a8Spooka /*
16825f7e80a8Spooka * Do bounds checking, adjust transfer. if error, process.
16835f7e80a8Spooka * If end of partition, just return.
16845f7e80a8Spooka */
16855f7e80a8Spooka if (EFLASHPART(bp->b_dev) == RAW_PART) {
16865f7e80a8Spooka if (bounds_check_with_mediasize(bp, DEV_BSIZE,
16875f7e80a8Spooka sc->sc_capacity) <= 0)
16885f7e80a8Spooka goto done;
16895f7e80a8Spooka } else {
16905f7e80a8Spooka if (bounds_check_with_label(&sc->sc_dk, bp,
16915f7e80a8Spooka (sc->sc_flags & (EFLASHF_WLABEL|EFLASHF_LABELLING)) != 0) <= 0)
16925f7e80a8Spooka goto done;
16935f7e80a8Spooka }
16945f7e80a8Spooka
16955f7e80a8Spooka /*
16965f7e80a8Spooka * Now convert the block number to absolute and put it in
16975f7e80a8Spooka * terms of the device's logical block size.
16985f7e80a8Spooka */
16995f7e80a8Spooka if (lp->d_secsize >= DEV_BSIZE)
17005f7e80a8Spooka blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
17015f7e80a8Spooka else
17025f7e80a8Spooka blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
17035f7e80a8Spooka
17045f7e80a8Spooka if (EFLASHPART(bp->b_dev) != RAW_PART)
17055f7e80a8Spooka blkno += lp->d_partitions[EFLASHPART(bp->b_dev)].p_offset;
17065f7e80a8Spooka
17075f7e80a8Spooka bp->b_rawblkno = blkno;
17085f7e80a8Spooka
17095f7e80a8Spooka /* Queue transfer on drive, activate drive and controller if idle. */
17105f7e80a8Spooka s = splbio();
17115f7e80a8Spooka bufq_put(sc->sc_q, bp);
17125f7e80a8Spooka eflashstart(sc);
17135f7e80a8Spooka splx(s);
17145f7e80a8Spooka return;
17155f7e80a8Spooka done:
17165f7e80a8Spooka /* Toss transfer; we're done early. */
17175f7e80a8Spooka bp->b_resid = bp->b_bcount;
17185f7e80a8Spooka biodone(bp);
17195f7e80a8Spooka }
17205f7e80a8Spooka
17215f7e80a8Spooka /*
17225f7e80a8Spooka * Queue a drive for I/O.
17235f7e80a8Spooka */
17245f7e80a8Spooka void
eflashstart(void * arg)17255f7e80a8Spooka eflashstart(void *arg)
17265f7e80a8Spooka {
17275f7e80a8Spooka struct eflash_softc *sc = arg;
17285f7e80a8Spooka struct buf *bp = NULL;
17295f7e80a8Spooka
17305f7e80a8Spooka DEBUG_PRINT(("%s: eflashstart\n", device_xname(sc->sc_dev)),
17315f7e80a8Spooka DEBUG_XFERS);
17325f7e80a8Spooka while (sc->openings > 0) {
17335f7e80a8Spooka
17345f7e80a8Spooka /* Is there a buf for us ? */
17355f7e80a8Spooka if ((bp = bufq_get(sc->sc_q)) == NULL)
17365f7e80a8Spooka return;
17375f7e80a8Spooka
17385f7e80a8Spooka /*
17395f7e80a8Spooka * Make the command. First lock the device
17405f7e80a8Spooka */
17415f7e80a8Spooka sc->openings--;
17425f7e80a8Spooka
17435f7e80a8Spooka sc->retries = 0;
17445f7e80a8Spooka __eflashstart(sc, bp);
17455f7e80a8Spooka }
17465f7e80a8Spooka }
17475f7e80a8Spooka
17485f7e80a8Spooka void
__eflashstart(struct eflash_softc * sc,struct buf * bp)17495f7e80a8Spooka __eflashstart(struct eflash_softc *sc, struct buf *bp)
17505f7e80a8Spooka {
17515f7e80a8Spooka DEBUG_PRINT(("%s: __eflashstart %p\n", device_xname(sc->sc_dev), bp),
17525f7e80a8Spooka DEBUG_XFERS);
17535f7e80a8Spooka
17545f7e80a8Spooka sc->sc_bp = bp;
17555f7e80a8Spooka /*
17565f7e80a8Spooka * If we're retrying, retry in single-sector mode. This will give us
17575f7e80a8Spooka * the sector number of the problem, and will eventually allow the
17585f7e80a8Spooka * transfer to succeed.
17595f7e80a8Spooka */
17605f7e80a8Spooka if (sc->retries >= EFLASHIORETRIES_SINGLE)
17615f7e80a8Spooka sc->sc_bio.flags = ATA_SINGLE;
17625f7e80a8Spooka else
17635f7e80a8Spooka sc->sc_bio.flags = 0;
17645f7e80a8Spooka if (bp->b_flags & B_READ)
17655f7e80a8Spooka sc->sc_bio.flags |= ATA_READ;
17665f7e80a8Spooka sc->sc_bio.blkno = bp->b_rawblkno;
17675f7e80a8Spooka sc->sc_bio.blkdone = 0;
17685f7e80a8Spooka sc->sc_bio.nbytes = bp->b_bcount;
17695f7e80a8Spooka sc->sc_bio.nblks = bp->b_bcount >> DEV_BSHIFT;
17705f7e80a8Spooka sc->sc_bio.databuf = bp->b_data;
17715f7e80a8Spooka /* Instrumentation. */
17725f7e80a8Spooka disk_busy(&sc->sc_dk);
17735f7e80a8Spooka sc->active_xfer = bp;
17745f7e80a8Spooka wakeup(&sc->ch_thread);
17755f7e80a8Spooka }
17765f7e80a8Spooka
17775f7e80a8Spooka void
eflashdone(struct eflash_softc * sc)17785f7e80a8Spooka eflashdone(struct eflash_softc *sc)
17795f7e80a8Spooka {
17805f7e80a8Spooka struct buf *bp = sc->sc_bp;
17815f7e80a8Spooka const char *errmsg;
17825f7e80a8Spooka int do_perror = 0;
17835f7e80a8Spooka
17845f7e80a8Spooka DEBUG_PRINT(("%s: eflashdone %p\n", device_xname(sc->sc_dev), bp),
17855f7e80a8Spooka DEBUG_XFERS);
17865f7e80a8Spooka
17875f7e80a8Spooka if (bp == NULL)
17885f7e80a8Spooka return;
17895f7e80a8Spooka
17905f7e80a8Spooka bp->b_resid = sc->sc_bio.nbytes;
17915f7e80a8Spooka switch (sc->sc_bio.error) {
17925f7e80a8Spooka case ETIMEDOUT:
17935f7e80a8Spooka errmsg = "device timeout";
17945f7e80a8Spooka do_perror = 1;
17955f7e80a8Spooka goto retry;
17965f7e80a8Spooka case EBUSY:
17975f7e80a8Spooka errmsg = "device stuck";
17985f7e80a8Spooka retry: /* Just reset and retry. Can we do more ? */
17995f7e80a8Spooka /*eflash_reset(sc);*/
18005f7e80a8Spooka diskerr(bp, "flash", errmsg, LOG_PRINTF,
18015f7e80a8Spooka sc->sc_bio.blkdone, sc->sc_dk.dk_label);
18025f7e80a8Spooka if (sc->retries < EFLASHIORETRIES)
18035f7e80a8Spooka printf(", retrying");
18045f7e80a8Spooka printf("\n");
18055f7e80a8Spooka if (do_perror)
18065f7e80a8Spooka eflashperror(sc);
18075f7e80a8Spooka if (sc->retries < EFLASHIORETRIES) {
18085f7e80a8Spooka sc->retries++;
18095f7e80a8Spooka callout_reset(&sc->sc_restart_ch, RECOVERYTIME,
18105f7e80a8Spooka eflashrestart, sc);
18115f7e80a8Spooka return;
18125f7e80a8Spooka }
18135f7e80a8Spooka
18145f7e80a8Spooka bp->b_error = EIO;
18155f7e80a8Spooka break;
18165f7e80a8Spooka case 0:
18175f7e80a8Spooka if ((sc->sc_bio.flags & ATA_CORR) || sc->retries > 0)
18185f7e80a8Spooka printf("%s: soft error (corrected)\n",
18195f7e80a8Spooka device_xname(sc->sc_dev));
18205f7e80a8Spooka break;
18215f7e80a8Spooka case ENODEV:
18225f7e80a8Spooka case E2BIG:
18235f7e80a8Spooka bp->b_error = EIO;
18245f7e80a8Spooka break;
18255f7e80a8Spooka }
18265f7e80a8Spooka disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
18275f7e80a8Spooka (bp->b_flags & B_READ));
18285f7e80a8Spooka rnd_add_uint32(&sc->rnd_source, bp->b_blkno);
18295f7e80a8Spooka biodone(bp);
18305f7e80a8Spooka sc->openings++;
18315f7e80a8Spooka eflashstart(sc);
18325f7e80a8Spooka }
18335f7e80a8Spooka
18345f7e80a8Spooka void
eflashrestart(void * v)18355f7e80a8Spooka eflashrestart(void *v)
18365f7e80a8Spooka {
18375f7e80a8Spooka struct eflash_softc *sc = v;
18385f7e80a8Spooka struct buf *bp = sc->sc_bp;
18395f7e80a8Spooka int s;
18405f7e80a8Spooka DEBUG_PRINT(("%s: eflashrestart\n", device_xname(sc->sc_dev)),
18415f7e80a8Spooka DEBUG_XFERS);
18425f7e80a8Spooka
18435f7e80a8Spooka s = splbio();
18445f7e80a8Spooka __eflashstart(v, bp);
18455f7e80a8Spooka splx(s);
18465f7e80a8Spooka }
18475f7e80a8Spooka
18485f7e80a8Spooka int
eflashread(dev_t dev,struct uio * uio,int flags)18495f7e80a8Spooka eflashread(dev_t dev, struct uio *uio, int flags)
18505f7e80a8Spooka {
18515f7e80a8Spooka DEBUG_PRINT(("eflashread\n"), DEBUG_XFERS);
18525f7e80a8Spooka return (physio(eflashstrategy, NULL, dev, B_READ, minphys, uio));
18535f7e80a8Spooka }
18545f7e80a8Spooka
18555f7e80a8Spooka int
eflashwrite(dev_t dev,struct uio * uio,int flags)18565f7e80a8Spooka eflashwrite(dev_t dev, struct uio *uio, int flags)
18575f7e80a8Spooka {
18585f7e80a8Spooka DEBUG_PRINT(("eflashwrite\n"), DEBUG_XFERS);
18595f7e80a8Spooka return (physio(eflashstrategy, NULL, dev, B_WRITE, minphys, uio));
18605f7e80a8Spooka }
18615f7e80a8Spooka
18625f7e80a8Spooka int
eflashopen(dev_t dev,int flag,int fmt,struct lwp * l)18635f7e80a8Spooka eflashopen(dev_t dev, int flag, int fmt, struct lwp *l)
18645f7e80a8Spooka {
18655f7e80a8Spooka struct eflash_softc *sc;
18665f7e80a8Spooka int part, error;
18675f7e80a8Spooka
1868c69eb063Stsutsui DEBUG_PRINT(("eflashopen %" PRIx64 "\n", dev), DEBUG_FUNCS);
18695f7e80a8Spooka sc = device_lookup_private(&eflash_cd, EFLASHUNIT(dev));
18705f7e80a8Spooka if (sc == NULL)
18715f7e80a8Spooka return (ENXIO);
18725f7e80a8Spooka
18735f7e80a8Spooka if (! device_is_active(sc->sc_dev))
18745f7e80a8Spooka return (ENODEV);
18755f7e80a8Spooka
18765f7e80a8Spooka part = EFLASHPART(dev);
18775f7e80a8Spooka
18785f7e80a8Spooka mutex_enter(&sc->sc_dk.dk_openlock);
18795f7e80a8Spooka
18805f7e80a8Spooka /*
18815f7e80a8Spooka * If there are wedges, and this is not RAW_PART, then we
18825f7e80a8Spooka * need to fail.
18835f7e80a8Spooka */
18845f7e80a8Spooka if (sc->sc_dk.dk_nwedges != 0 && part != RAW_PART) {
18855f7e80a8Spooka error = EBUSY;
18865f7e80a8Spooka goto bad;
18875f7e80a8Spooka }
18885f7e80a8Spooka
18895f7e80a8Spooka if (sc->sc_dk.dk_openmask != 0) {
18905f7e80a8Spooka /*
18915f7e80a8Spooka * If any partition is open, but the disk has been invalidated,
18925f7e80a8Spooka * disallow further opens.
18935f7e80a8Spooka */
18945f7e80a8Spooka if ((sc->sc_flags & EFLASHF_LOADED) == 0) {
18955f7e80a8Spooka error = EIO;
18965f7e80a8Spooka goto bad;
18975f7e80a8Spooka }
18985f7e80a8Spooka } else {
18995f7e80a8Spooka if ((sc->sc_flags & EFLASHF_LOADED) == 0) {
19005f7e80a8Spooka sc->sc_flags |= EFLASHF_LOADED;
19015f7e80a8Spooka
19025f7e80a8Spooka /* Load the partition info if not already loaded. */
19035f7e80a8Spooka eflashgetdisklabel(sc);
19045f7e80a8Spooka }
19055f7e80a8Spooka }
19065f7e80a8Spooka
19075f7e80a8Spooka /* Check that the partition exists. */
19085f7e80a8Spooka if (part != RAW_PART &&
19095f7e80a8Spooka (part >= sc->sc_dk.dk_label->d_npartitions ||
19105f7e80a8Spooka sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
19115f7e80a8Spooka error = ENXIO;
19125f7e80a8Spooka goto bad;
19135f7e80a8Spooka }
19145f7e80a8Spooka
19155f7e80a8Spooka /* Insure only one open at a time. */
19165f7e80a8Spooka switch (fmt) {
19175f7e80a8Spooka case S_IFCHR:
19185f7e80a8Spooka sc->sc_dk.dk_copenmask |= (1 << part);
19195f7e80a8Spooka break;
19205f7e80a8Spooka case S_IFBLK:
19215f7e80a8Spooka sc->sc_dk.dk_bopenmask |= (1 << part);
19225f7e80a8Spooka break;
19235f7e80a8Spooka }
19245f7e80a8Spooka sc->sc_dk.dk_openmask =
19255f7e80a8Spooka sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
19265f7e80a8Spooka
19275f7e80a8Spooka mutex_exit(&sc->sc_dk.dk_openlock);
19285f7e80a8Spooka return 0;
19295f7e80a8Spooka
19305f7e80a8Spooka bad:
19315f7e80a8Spooka mutex_exit(&sc->sc_dk.dk_openlock);
19325f7e80a8Spooka DEBUG_PRINT(("%s: eflashopen -> %d\n", device_xname(sc->sc_dev), error),
19335f7e80a8Spooka DEBUG_XFERS);
19345f7e80a8Spooka return error;
19355f7e80a8Spooka }
19365f7e80a8Spooka
19375f7e80a8Spooka int
eflashclose(dev_t dev,int flag,int fmt,struct lwp * l)19385f7e80a8Spooka eflashclose(dev_t dev, int flag, int fmt, struct lwp *l)
19395f7e80a8Spooka {
19405f7e80a8Spooka struct eflash_softc *sc = device_lookup_private(&eflash_cd, EFLASHUNIT(dev));
19415f7e80a8Spooka int part = EFLASHPART(dev);
19425f7e80a8Spooka
1943c69eb063Stsutsui DEBUG_PRINT(("eflashclose %" PRIx64 "\n", dev), DEBUG_FUNCS);
19445f7e80a8Spooka
19455f7e80a8Spooka mutex_enter(&sc->sc_dk.dk_openlock);
19465f7e80a8Spooka
19475f7e80a8Spooka switch (fmt) {
19485f7e80a8Spooka case S_IFCHR:
19495f7e80a8Spooka sc->sc_dk.dk_copenmask &= ~(1 << part);
19505f7e80a8Spooka break;
19515f7e80a8Spooka case S_IFBLK:
19525f7e80a8Spooka sc->sc_dk.dk_bopenmask &= ~(1 << part);
19535f7e80a8Spooka break;
19545f7e80a8Spooka }
19555f7e80a8Spooka sc->sc_dk.dk_openmask =
19565f7e80a8Spooka sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
19575f7e80a8Spooka
19585f7e80a8Spooka if (sc->sc_dk.dk_openmask == 0) {
19595f7e80a8Spooka
19605f7e80a8Spooka if (! (sc->sc_flags & EFLASHF_KLABEL))
19615f7e80a8Spooka sc->sc_flags &= ~EFLASHF_LOADED;
19625f7e80a8Spooka
19635f7e80a8Spooka DEBUG_PRINT(("%s: eflashclose flg %x\n", device_xname(sc->sc_dev), sc->sc_flags),
19645f7e80a8Spooka DEBUG_XFERS);
19655f7e80a8Spooka
19665f7e80a8Spooka }
19675f7e80a8Spooka
19685f7e80a8Spooka mutex_exit(&sc->sc_dk.dk_openlock);
19695f7e80a8Spooka return 0;
19705f7e80a8Spooka }
19715f7e80a8Spooka
19725f7e80a8Spooka void
eflashgetdefaultlabel(struct eflash_softc * sc,struct disklabel * lp)19735f7e80a8Spooka eflashgetdefaultlabel(struct eflash_softc *sc, struct disklabel *lp)
19745f7e80a8Spooka {
19755f7e80a8Spooka
19765f7e80a8Spooka DEBUG_PRINT(("%s: eflashgetdefaultlabel\n", device_xname(sc->sc_dev)), DEBUG_FUNCS);
19775f7e80a8Spooka memset(lp, 0, sizeof(struct disklabel));
19785f7e80a8Spooka
19795f7e80a8Spooka lp->d_secsize = DEV_BSIZE;
19805f7e80a8Spooka lp->d_ntracks = 1;
19815f7e80a8Spooka lp->d_nsectors = sc->sc_capacity;
19825f7e80a8Spooka lp->d_ncylinders = 1;
19835f7e80a8Spooka lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
19845f7e80a8Spooka
1985c182898bSchristos lp->d_type = DKTYPE_ST506; /* ?!? */
19865f7e80a8Spooka
19875f7e80a8Spooka strncpy(lp->d_typename, ST506, 16);
19885f7e80a8Spooka strncpy(lp->d_packname, "fictitious", 16);
19895f7e80a8Spooka if (sc->sc_capacity > UINT32_MAX)
19905f7e80a8Spooka lp->d_secperunit = UINT32_MAX;
19915f7e80a8Spooka else
19925f7e80a8Spooka lp->d_secperunit = sc->sc_capacity;
19935f7e80a8Spooka lp->d_rpm = 3600;
19945f7e80a8Spooka lp->d_interleave = 1;
19955f7e80a8Spooka lp->d_flags = 0;
19965f7e80a8Spooka
19975f7e80a8Spooka lp->d_partitions[RAW_PART].p_offset = 0;
19985f7e80a8Spooka lp->d_partitions[RAW_PART].p_size =
19995f7e80a8Spooka lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
20005f7e80a8Spooka lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
20015f7e80a8Spooka lp->d_npartitions = RAW_PART + 1;
20025f7e80a8Spooka
20035f7e80a8Spooka lp->d_magic = DISKMAGIC;
20045f7e80a8Spooka lp->d_magic2 = DISKMAGIC;
20055f7e80a8Spooka lp->d_checksum = dkcksum(lp);
20065f7e80a8Spooka }
20075f7e80a8Spooka
20085f7e80a8Spooka /*
20095f7e80a8Spooka * Fabricate a default disk label, and try to read the correct one.
20105f7e80a8Spooka */
20115f7e80a8Spooka void
eflashgetdisklabel(struct eflash_softc * sc)20125f7e80a8Spooka eflashgetdisklabel(struct eflash_softc *sc)
20135f7e80a8Spooka {
20145f7e80a8Spooka struct disklabel *lp = sc->sc_dk.dk_label;
20155f7e80a8Spooka const char *errstring;
20165f7e80a8Spooka
20175f7e80a8Spooka DEBUG_PRINT(("%s: eflashgetdisklabel\n", device_xname(sc->sc_dev)), DEBUG_FUNCS);
20185f7e80a8Spooka
20195f7e80a8Spooka memset(sc->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
20205f7e80a8Spooka
20215f7e80a8Spooka eflashgetdefaultlabel(sc, lp);
20225f7e80a8Spooka
20235f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
20245f7e80a8Spooka sc->sc_bio.badsect[0] = -1;
20255f7e80a8Spooka #endif
20265f7e80a8Spooka
20275f7e80a8Spooka /* BUGBUG: maj==0?? why is this not EFLASHLABELDEV(??sc->sc_dev) */
20285f7e80a8Spooka errstring = readdisklabel(MAKEEFLASHDEV(0, device_unit(sc->sc_dev),
20295f7e80a8Spooka RAW_PART), eflashstrategy, lp,
20305f7e80a8Spooka sc->sc_dk.dk_cpulabel);
20315f7e80a8Spooka if (errstring) {
20325f7e80a8Spooka printf("%s: %s\n", device_xname(sc->sc_dev), errstring);
20335f7e80a8Spooka return;
20345f7e80a8Spooka }
20355f7e80a8Spooka
20365f7e80a8Spooka #if DEBUG
20375f7e80a8Spooka if (EFLASH_DEBUG(DEBUG_WRITES)) {
20385f7e80a8Spooka int i, n = sc->sc_dk.dk_label->d_npartitions;
20395f7e80a8Spooka printf("%s: %d parts\n", device_xname(sc->sc_dev), n);
20405f7e80a8Spooka for (i = 0; i < n; i++) {
20415f7e80a8Spooka printf("\t[%d]: t=%x s=%d o=%d\n", i,
20425f7e80a8Spooka sc->sc_dk.dk_label->d_partitions[i].p_fstype,
20435f7e80a8Spooka sc->sc_dk.dk_label->d_partitions[i].p_size,
20445f7e80a8Spooka sc->sc_dk.dk_label->d_partitions[i].p_offset);
20455f7e80a8Spooka }
20465f7e80a8Spooka }
20475f7e80a8Spooka #endif
20485f7e80a8Spooka
20495f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
20505f7e80a8Spooka if ((lp->d_flags & D_BADSECT) != 0)
20515f7e80a8Spooka bad144intern(sc);
20525f7e80a8Spooka #endif
20535f7e80a8Spooka }
20545f7e80a8Spooka
20555f7e80a8Spooka void
eflashperror(const struct eflash_softc * sc)20565f7e80a8Spooka eflashperror(const struct eflash_softc *sc)
20575f7e80a8Spooka {
20585f7e80a8Spooka const char *devname = device_xname(sc->sc_dev);
20595f7e80a8Spooka u_int32_t Status = sc->sc_bio.r_error;
20605f7e80a8Spooka
20615f7e80a8Spooka printf("%s: (", devname);
20625f7e80a8Spooka
20635f7e80a8Spooka if (Status == 0)
20645f7e80a8Spooka printf("error not notified");
20655f7e80a8Spooka else
20665f7e80a8Spooka printf("status=x%x", Status);
20675f7e80a8Spooka
20685f7e80a8Spooka printf(")\n");
20695f7e80a8Spooka }
20705f7e80a8Spooka
20715f7e80a8Spooka int
eflashioctl(dev_t dev,u_long xfer,void * addr,int flag,struct lwp * l)20725f7e80a8Spooka eflashioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l)
20735f7e80a8Spooka {
20745f7e80a8Spooka struct eflash_softc *sc = device_lookup_private(&eflash_cd, EFLASHUNIT(dev));
20755f7e80a8Spooka int error = 0, s;
20765f7e80a8Spooka
20775f7e80a8Spooka DEBUG_PRINT(("eflashioctl(%lx)\n",xfer), DEBUG_FUNCS);
20785f7e80a8Spooka
20795f7e80a8Spooka if ((sc->sc_flags & EFLASHF_LOADED) == 0)
20805f7e80a8Spooka return EIO;
20815f7e80a8Spooka
2082c60db2e9Schristos error = disk_ioctl(&sc->sc_dk, dev, xfer, addr, flag, l);
20835f7e80a8Spooka if (error != EPASSTHROUGH)
20845f7e80a8Spooka return (error);
20855f7e80a8Spooka
20865f7e80a8Spooka switch (xfer) {
20875f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
20885f7e80a8Spooka case DIOCSBAD:
20895f7e80a8Spooka if ((flag & FWRITE) == 0)
20905f7e80a8Spooka return EBADF;
20915f7e80a8Spooka sc->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
20925f7e80a8Spooka sc->sc_dk.dk_label->d_flags |= D_BADSECT;
20935f7e80a8Spooka bad144intern(sc);
20945f7e80a8Spooka return 0;
20955f7e80a8Spooka #endif
20965f7e80a8Spooka
20975f7e80a8Spooka case DIOCWDINFO:
20985f7e80a8Spooka case DIOCSDINFO:
20995f7e80a8Spooka {
21005f7e80a8Spooka struct disklabel *lp;
21015f7e80a8Spooka
21025f7e80a8Spooka if ((flag & FWRITE) == 0)
21035f7e80a8Spooka return EBADF;
21045f7e80a8Spooka
21055f7e80a8Spooka lp = (struct disklabel *)addr;
21065f7e80a8Spooka
21075f7e80a8Spooka mutex_enter(&sc->sc_dk.dk_openlock);
21085f7e80a8Spooka sc->sc_flags |= EFLASHF_LABELLING;
21095f7e80a8Spooka
21105f7e80a8Spooka error = setdisklabel(sc->sc_dk.dk_label,
21115f7e80a8Spooka lp, /*sc->sc_dk.dk_openmask : */0,
21125f7e80a8Spooka sc->sc_dk.dk_cpulabel);
21135f7e80a8Spooka if (error == 0) {
21145f7e80a8Spooka if (xfer == DIOCWDINFO)
21155f7e80a8Spooka error = writedisklabel(EFLASHLABELDEV(dev),
21165f7e80a8Spooka eflashstrategy, sc->sc_dk.dk_label,
21175f7e80a8Spooka sc->sc_dk.dk_cpulabel);
21185f7e80a8Spooka }
21195f7e80a8Spooka
21205f7e80a8Spooka sc->sc_flags &= ~EFLASHF_LABELLING;
21215f7e80a8Spooka mutex_exit(&sc->sc_dk.dk_openlock);
21225f7e80a8Spooka return error;
21235f7e80a8Spooka }
21245f7e80a8Spooka
21255f7e80a8Spooka case DIOCKLABEL:
21265f7e80a8Spooka if (*(int *)addr)
21275f7e80a8Spooka sc->sc_flags |= EFLASHF_KLABEL;
21285f7e80a8Spooka else
21295f7e80a8Spooka sc->sc_flags &= ~EFLASHF_KLABEL;
21305f7e80a8Spooka return 0;
21315f7e80a8Spooka
21325f7e80a8Spooka case DIOCWLABEL:
21335f7e80a8Spooka if ((flag & FWRITE) == 0)
21345f7e80a8Spooka return EBADF;
21355f7e80a8Spooka if (*(int *)addr)
21365f7e80a8Spooka sc->sc_flags |= EFLASHF_WLABEL;
21375f7e80a8Spooka else
21385f7e80a8Spooka sc->sc_flags &= ~EFLASHF_WLABEL;
21395f7e80a8Spooka return 0;
21405f7e80a8Spooka
21415f7e80a8Spooka case DIOCGDEFLABEL:
21425f7e80a8Spooka eflashgetdefaultlabel(sc, (struct disklabel *)addr);
21435f7e80a8Spooka return 0;
21445f7e80a8Spooka
21455f7e80a8Spooka case DIOCCACHESYNC:
21465f7e80a8Spooka return 0;
21475f7e80a8Spooka
21485f7e80a8Spooka case DIOCGSTRATEGY:
21495f7e80a8Spooka {
21505f7e80a8Spooka struct disk_strategy *dks = (void *)addr;
21515f7e80a8Spooka
21525f7e80a8Spooka s = splbio();
21535f7e80a8Spooka strlcpy(dks->dks_name, bufq_getstrategyname(sc->sc_q),
21545f7e80a8Spooka sizeof(dks->dks_name));
21555f7e80a8Spooka splx(s);
21565f7e80a8Spooka dks->dks_paramlen = 0;
21575f7e80a8Spooka
21585f7e80a8Spooka return 0;
21595f7e80a8Spooka }
21605f7e80a8Spooka
21615f7e80a8Spooka case DIOCSSTRATEGY:
21625f7e80a8Spooka {
21635f7e80a8Spooka struct disk_strategy *dks = (void *)addr;
21645f7e80a8Spooka struct bufq_state *new;
21655f7e80a8Spooka struct bufq_state *old;
21665f7e80a8Spooka
21675f7e80a8Spooka if ((flag & FWRITE) == 0) {
21685f7e80a8Spooka return EBADF;
21695f7e80a8Spooka }
21705f7e80a8Spooka if (dks->dks_param != NULL) {
21715f7e80a8Spooka return EINVAL;
21725f7e80a8Spooka }
21735f7e80a8Spooka dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
21745f7e80a8Spooka error = bufq_alloc(&new, dks->dks_name,
21755f7e80a8Spooka BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
21765f7e80a8Spooka if (error) {
21775f7e80a8Spooka return error;
21785f7e80a8Spooka }
21795f7e80a8Spooka s = splbio();
21805f7e80a8Spooka old = sc->sc_q;
21815f7e80a8Spooka bufq_move(new, old);
21825f7e80a8Spooka sc->sc_q = new;
21835f7e80a8Spooka splx(s);
21845f7e80a8Spooka bufq_free(old);
21855f7e80a8Spooka
21865f7e80a8Spooka return 0;
21875f7e80a8Spooka }
21885f7e80a8Spooka
21895f7e80a8Spooka default:
21905f7e80a8Spooka /* NB: we get a DIOCGWEDGEINFO, but nobody else handles it either */
21915f7e80a8Spooka DEBUG_PRINT(("eflashioctl: unsup x%lx\n", xfer), DEBUG_FUNCS);
21925f7e80a8Spooka return ENOTTY;
21935f7e80a8Spooka }
21945f7e80a8Spooka }
21955f7e80a8Spooka
21965f7e80a8Spooka int
eflashsize(dev_t dev)21975f7e80a8Spooka eflashsize(dev_t dev)
21985f7e80a8Spooka {
21995f7e80a8Spooka struct eflash_softc *sc;
22005f7e80a8Spooka int part, omask;
22015f7e80a8Spooka int size;
22025f7e80a8Spooka
22035f7e80a8Spooka DEBUG_PRINT(("eflashsize\n"), DEBUG_FUNCS);
22045f7e80a8Spooka
22055f7e80a8Spooka sc = device_lookup_private(&eflash_cd, EFLASHUNIT(dev));
22065f7e80a8Spooka if (sc == NULL)
22075f7e80a8Spooka return (-1);
22085f7e80a8Spooka
22095f7e80a8Spooka part = EFLASHPART(dev);
22105f7e80a8Spooka omask = sc->sc_dk.dk_openmask & (1 << part);
22115f7e80a8Spooka
22125f7e80a8Spooka if (omask == 0 && eflashopen(dev, 0, S_IFBLK, NULL) != 0)
22135f7e80a8Spooka return (-1);
22145f7e80a8Spooka if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
22155f7e80a8Spooka size = -1;
22165f7e80a8Spooka else
22175f7e80a8Spooka size = sc->sc_dk.dk_label->d_partitions[part].p_size *
22185f7e80a8Spooka (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
22195f7e80a8Spooka if (omask == 0 && eflashclose(dev, 0, S_IFBLK, NULL) != 0)
22205f7e80a8Spooka return (-1);
22215f7e80a8Spooka return (size);
22225f7e80a8Spooka }
22235f7e80a8Spooka
22245f7e80a8Spooka /*
22255f7e80a8Spooka * Dump core after a system crash.
22265f7e80a8Spooka */
22275f7e80a8Spooka int
eflashdump(dev_t dev,daddr_t blkno,void * va,size_t size)22285f7e80a8Spooka eflashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
22295f7e80a8Spooka {
22305f7e80a8Spooka /* no we dont */
22315f7e80a8Spooka return (ENXIO);
22325f7e80a8Spooka }
22335f7e80a8Spooka
22345f7e80a8Spooka #ifdef HAS_BAD144_HANDLING
22355f7e80a8Spooka /*
22365f7e80a8Spooka * Internalize the bad sector table.
22375f7e80a8Spooka */
22385f7e80a8Spooka void
bad144intern(struct eflash_softc * sc)22395f7e80a8Spooka bad144intern(struct eflash_softc *sc)
22405f7e80a8Spooka {
22415f7e80a8Spooka struct dkbad *bt = &sc->sc_dk.dk_cpulabel->bad;
22425f7e80a8Spooka struct disklabel *lp = sc->sc_dk.dk_label;
22435f7e80a8Spooka int i = 0;
22445f7e80a8Spooka
22455f7e80a8Spooka DEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS);
22465f7e80a8Spooka
22475f7e80a8Spooka for (; i < NBT_BAD; i++) {
22485f7e80a8Spooka if (bt->bt_bad[i].bt_cyl == 0xffff)
22495f7e80a8Spooka break;
22505f7e80a8Spooka sc->sc_bio.badsect[i] =
22515f7e80a8Spooka bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
22525f7e80a8Spooka (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
22535f7e80a8Spooka (bt->bt_bad[i].bt_trksec & 0xff);
22545f7e80a8Spooka }
22555f7e80a8Spooka for (; i < NBT_BAD+1; i++)
22565f7e80a8Spooka sc->sc_bio.badsect[i] = -1;
22575f7e80a8Spooka }
22585f7e80a8Spooka #endif
22595f7e80a8Spooka
22605f7e80a8Spooka static void
eflash_set_geometry(struct eflash_softc * sc)22617b845fa9Schristos eflash_set_geometry(struct eflash_softc *sc)
22625f7e80a8Spooka {
22637b845fa9Schristos struct disk_geom *dg = &sc->sc_dk.dk_geom;
22645f7e80a8Spooka
22657b845fa9Schristos memset(dg, 0, sizeof(*dg));
22665f7e80a8Spooka
22677b845fa9Schristos dg->dg_secperunit = sc->sc_capacity;
22687b845fa9Schristos dg->dg_secsize = DEV_BSIZE /* XXX 512? */;
22697b845fa9Schristos dg->dg_nsectors = sc->sc_capacity;
22707b845fa9Schristos dg->dg_ntracks = 1;
22717b845fa9Schristos dg->dg_ncylinders = sc->sc_capacity;
22725f7e80a8Spooka
22737b845fa9Schristos disk_set_info(sc->sc_dev, &sc->sc_dk, ST506);
22745f7e80a8Spooka }
2275