[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers/sbus/char/jsflash.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1991, 1992  Linus Torvalds	(drivers/char/mem.c)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1997  Eddie C. Dost		(drivers/sbus/char/flash.c)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1997-2000 Pavel Machek <pavel@ucw.cz>   (drivers/block/nbd.c)
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1999-2000 Pete Zaitcev
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is used to program OS into a Flash SIMM on
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Krups and Espresso platforms.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: do not allow erase/programming if file systems are mounted.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: Erase/program both banks of a 8MB SIMM.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is anticipated that programming an OS Flash will be a routine
1625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * procedure. In the same time it is exceedingly dangerous because
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a user can program its OBP flash with OS image and effectively
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kill the machine.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver uses an interface different from Eddie's flash.c
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as a silly safeguard.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX The flash.c manipulates page caching characteristics in a certain
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dubious way; also it assumes that remap_pfn_range() can remap
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI bus locations, which may be false. ioremap() must be used
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead. We should discuss this.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
30613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann#include <linux/mutex.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/genhd.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pcic.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/oplib.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/jsflash.h>		/* ioctl arguments. <linux/> ?? */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSFIDSZ		(sizeof(struct jsflash_ident_arg))
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSFPRGSZ	(sizeof(struct jsflash_program_arg))
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our device numbers have no business in system headers.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The only thing a user knows is the device name /dev/jsflash.
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Block devices are laid out like this:
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   minor+0	- Bootstrap, for 8MB SIMM 0x20400000[0x800000]
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   minor+1	- Filesystem to mount, normally 0x20400400[0x7ffc00]
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   minor+2	- Whole flash area for any case... 0x20000000[0x01000000]
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Total 3 minors per flash device.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is easier to have static size vectors, so we define
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a total minor range JSF_MAX, which must cover all minors.
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* character device */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_MINOR	178	/* 178 is registered with hpa */
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* block device */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_MAX		 3	/* 3 minors wasted total so far. */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_NPART	 3	/* 3 minors per flash device */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_PART_BITS	 2	/* 2 bits of minors to cover JSF_NPART */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_PART_MASK	 0x3	/* 2 bits mask */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmannstatic DEFINE_MUTEX(jsf_mutex);
72613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Access functions.
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We could ioremap(), but it's easier this way.
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int jsf_inl(unsigned long addr)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long retval;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"=r" (retval) :
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"r" (addr), "i" (ASI_M_BYPASS));
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return retval;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void jsf_outl(unsigned long addr, __u32 data)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"r" (data), "r" (addr), "i" (ASI_M_BYPASS) :
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"memory");
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * soft carrier
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct jsfd_part {
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long dbase;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long dsize;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct jsflash {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long base;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long size;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long busy;		/* In use? */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsflash_ident_arg id;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* int mbase; */		/* Minor base, typically zero */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsfd_part dv[JSF_NPART];
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We do not map normal memory or obio as a safety precaution.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But offsets are real, for ease of userland programming.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_BASE_TOP	0x30000000
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_BASE_ALL	0x20000000
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define JSF_BASE_JK	0x20400000
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct gendisk *jsfd_disk[JSF_MAX];
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let's pretend we may have several of these...
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct jsflash jsf0;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for AMD to finish its embedded algorithm.
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We use the Toggle bit DQ6 (0x40) because it does not
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * depend on the data value as /DATA bit DQ7 does.
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Do we need any timeout here? So far it never hanged, beware broken hw.
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void jsf_wait(unsigned long p) {
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int x1, x2;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;) {
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x1 = jsf_inl(p);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x2 = jsf_inl(p);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((x1 & 0x40404040) == (x2 & 0x40404040)) return;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Programming will only work if Flash is clean,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we leave it to the programmer application.
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AMD must be programmed one byte at a time;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thus, Simple Tech SIMM must be written 4 bytes at a time.
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write waits for the chip to become ready after the write
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * was finished. This is done so that application would read
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * consistent data after the write is done.
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void jsf_write4(unsigned long fa, u32 data) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(fa, 0xAAAAAAAA);		/* Unlock 1 Write 1 */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(fa, 0x55555555);		/* Unlock 1 Write 2 */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(fa, 0xA0A0A0A0);		/* Byte Program */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(fa, data);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_wait(fa);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void jsfd_read(char *buf, unsigned long p, size_t togo) {
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union byte4 {
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char s[4];
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int n;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} b;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (togo >= 4) {
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		togo -= 4;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b.n = jsf_inl(p);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(buf, b.s, 4);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += 4;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += 4;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
186165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboestatic void jsfd_do_request(struct request_queue *q)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct request *req;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1909934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo	req = blk_fetch_request(q);
1916b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo	while (req) {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct jsfd_part *jdp = req->rq_disk->private_data;
19383096ebf1263b2c1ee5e653ba37d993d02e3eb7bTejun Heo		unsigned long offset = blk_rq_pos(req) << 9;
1941011c1b9f2e45ce7c6e38888d2b83936aec38771Tejun Heo		size_t len = blk_rq_cur_bytes(req);
1956b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo		int err = -EIO;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1976b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo		if ((offset + len) > jdp->dsize)
1986b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo			goto end;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rq_data_dir(req) != READ) {
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "jsfd: write\n");
2026b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo			goto end;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((jdp->dbase & 0xff000000) != 0x20000000) {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "jsfd: bad base %x\n", (int)jdp->dbase);
2076b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo			goto end;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210fb1be43301ce045b5e563416e701573464a2ed96Jens Axboe		jsfd_read(bio_data(req->bio), jdp->dbase + offset, len);
2116b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo		err = 0;
2126b0bf407b586b6ba8e060ad9979cb2bc3370b7ebTejun Heo	end:
2139934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo		if (!__blk_end_request_cur(req, err))
2149934c8c04561413609d2bc38c6b9f268cba774a4Tejun Heo			req = blk_fetch_request(q);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The memory devices use the full 32/64 bits of the offset, and so we cannot
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check against negative addresses: they are ok. The return value is weird,
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * though, in that case (0).
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also note that seeking relative to the "end of file" isn't supported:
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it has no meaning, so it returns -EINVAL.
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic loff_t jsf_lseek(struct file * file, loff_t offset, int orig)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	loff_t ret;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_lock(&jsf_mutex);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (orig) {
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0:
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			file->f_pos = offset;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = file->f_pos;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 1:
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			file->f_pos += offset;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = file->f_pos;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EINVAL;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
243613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_unlock(&jsf_mutex);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OS SIMM Cannot be read in other size but a 32bits word.
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
250bc05d83bbf20a32eb24624726d1027aa960a573cAl Virostatic ssize_t jsf_read(struct file * file, char __user * buf,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    size_t togo, loff_t *ppos)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long p = *ppos;
254bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro	char __user *tmp = buf;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union byte4 {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char s[4];
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int n;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} b;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p < JSF_BASE_ALL || p >= JSF_BASE_TOP) {
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((p + togo) < p	/* wrap */
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   || (p + togo) >= JSF_BASE_TOP) {
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		togo = JSF_BASE_TOP - p;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (p < JSF_BASE_ALL && togo != 0) {
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* __bzero XXX */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t x = JSF_BASE_ALL - p;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (x > togo) x = togo;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		clear_user(tmp, x);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp += x;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += x;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		togo -= x;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Implementation of clear_user() calls __bzero
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * without regard to modversions,
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * so we cannot build a module.
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (togo >= 4) {
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		togo -= 4;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		b.n = jsf_inl(p);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(tmp, b.s, 4))
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp += 4;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += 4;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * XXX Small togo may remain if 1 byte is ordered.
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * It would be nice if we did a word size read and unpacked it.
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ppos = p;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tmp-buf;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
306bc05d83bbf20a32eb24624726d1027aa960a573cAl Virostatic ssize_t jsf_write(struct file * file, const char __user * buf,
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    size_t count, loff_t *ppos)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSPC;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsf_ioctl_erase(unsigned long arg)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long p;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* p = jsf0.base;	hits wrong bank */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = 0x20400000;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0xAAAAAAAA);		/* Unlock 1 Write 1 */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0x55555555);		/* Unlock 1 Write 2 */
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0x80808080);		/* Erase setup */
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0xAAAAAAAA);		/* Unlock 2 Write 1 */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0x55555555);		/* Unlock 2 Write 2 */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_outl(p, 0x10101010);		/* Chip erase */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This code is ok, except that counter based timeout
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * has no place in this world. Let's just drop timeouts...
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__u32 x;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 1000000; i++) {
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			x = jsf_inl(p);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((x & 0x80808080) == 0x80808080) break;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((x & 0x80808080) != 0x80808080) {
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsf0: erase timeout with 0x%08x\n", x);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsf0: erase done with 0x%08x\n", x);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_wait(p);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Program a block of flash.
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Very simple because we can do it byte by byte anyway.
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
357bc05d83bbf20a32eb24624726d1027aa960a573cAl Virostatic int jsf_ioctl_program(void __user *arg)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsflash_program_arg abuf;
360bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro	char __user *uptr;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long p;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int togo;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	union {
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int n;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char s[4];
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} b;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
368bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro	if (copy_from_user(&abuf, arg, JSFPRGSZ))
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = abuf.off;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	togo = abuf.size;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((togo & 3) || (p & 3)) return -EINVAL;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
374bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro	uptr = (char __user *) (unsigned long) abuf.data;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (togo != 0) {
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		togo -= 4;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(&b.s[0], uptr, 4))
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf_write4(p, b.n);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p += 4;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uptr += 4;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3876c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarovstatic long jsf_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
389613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_lock(&jsf_mutex);
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error = -ENOTTY;
391bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro	void __user *argp = (void __user *)arg;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3936c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarov	if (!capable(CAP_SYS_ADMIN)) {
394613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann		mutex_unlock(&jsf_mutex);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EPERM;
3966c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarov	}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case JSFLASH_IDENT:
3996c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarov		if (copy_to_user(argp, &jsf0.id, JSFIDSZ)) {
400613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann			mutex_unlock(&jsf_mutex);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
4026c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarov		}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case JSFLASH_ERASE:
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = jsf_ioctl_erase(arg);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case JSFLASH_PROGRAM:
408bc05d83bbf20a32eb24624726d1027aa960a573cAl Viro		error = jsf_ioctl_program(argp);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
412613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_unlock(&jsf_mutex);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsf_mmap(struct file * file, struct vm_area_struct * vma)
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENXIO;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsf_open(struct inode * inode, struct file * filp)
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
423613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_lock(&jsf_mutex);
42428fbbf491368c9491461ca492e13862da1b49180Arnd Bergmann	if (jsf0.base == 0) {
425613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann		mutex_unlock(&jsf_mutex);
42628fbbf491368c9491461ca492e13862da1b49180Arnd Bergmann		return -ENXIO;
42728fbbf491368c9491461ca492e13862da1b49180Arnd Bergmann	}
42828fbbf491368c9491461ca492e13862da1b49180Arnd Bergmann	if (test_and_set_bit(0, (void *)&jsf0.busy) != 0) {
429613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann		mutex_unlock(&jsf_mutex);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
43128fbbf491368c9491461ca492e13862da1b49180Arnd Bergmann	}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
433613655fa39ff6957754fa8ceb8559980920eb8eeArnd Bergmann	mutex_unlock(&jsf_mutex);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;	/* XXX What security? */
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsf_release(struct inode *inode, struct file *file)
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf0.busy = 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44300977a59b951207d38380c75f03a36829950265cArjan van de Venstatic const struct file_operations jsf_fops = {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek =	jsf_lseek,
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read =		jsf_read,
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write =	jsf_write,
4486c0f8bc77233d000a34a01989c42e650c8c32180Stoyan Gaydarov	.unlocked_ioctl =	jsf_ioctl,
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mmap =		jsf_mmap,
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =		jsf_open,
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release =	jsf_release,
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops };
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45683d5cde47dedf01b6a4a4331882cbc0a7eea3c2eAlexey Dobriyanstatic const struct block_device_operations jsfd_fops = {
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsflash_init(void)
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsflash *jsf;
4648d1255627d4ce9cb4b9d0a1c44b6c18d92e84a99Andres Salomon	phandle node;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char banner[128];
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct linux_prom_registers reg0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = prom_getchild(prom_root_node);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	node = prom_searchsiblings(node, "flash-memory");
4704a3a255289e7e322b8044286cce85031990f888aAndres Salomon	if (node != 0 && (s32)node != -1) {
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (prom_getproperty(node, "reg",
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (char *)&reg0, sizeof(reg0)) == -1) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsflash: no \"reg\" property\n");
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENXIO;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (reg0.which_io != 0) {
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsflash: bus number nonzero: 0x%x:%x\n",
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    reg0.which_io, reg0.phys_addr);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENXIO;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Flash may be somewhere else, for instance on Ebus.
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * So, don't do the following check for IIep flash space.
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((reg0.phys_addr >> 24) != 0x20) {
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsflash: suspicious address: 0x%x:%x\n",
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    reg0.which_io, reg0.phys_addr);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENXIO;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((int)reg0.reg_size <= 0) {
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("jsflash: bad size 0x%x\n", (int)reg0.reg_size);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENXIO;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* XXX Remove this code once PROLL ID12 got widespread */
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("jsflash: no /flash-memory node, use PROLL >= 12\n");
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prom_getproperty(prom_root_node, "banner-name", banner, 128);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strcmp (banner, "JavaStation-NC") != 0 &&
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    strcmp (banner, "JavaStation-E") != 0) {
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENXIO;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg0.which_io = 0;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg0.phys_addr = 0x20400000;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reg0.reg_size  = 0x00800000;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Let us be really paranoid for modifications to probing code. */
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sparc_cpu_model != sun4m) {
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* We must be on sun4m because we use MMU Bypass ASI. */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (jsf0.base == 0) {
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf = &jsf0;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->base = reg0.phys_addr;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->size = reg0.reg_size;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* XXX Redo the userland interface. */
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->id.off = JSF_BASE_ALL;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->id.size = 0x01000000;	/* 16M - all segments */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(jsf->id.name, "Krups_all");
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[0].dbase = jsf->base;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[0].dsize = jsf->size;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[1].dbase = jsf->base + 1024;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[1].dsize = jsf->size - 1024;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[2].dbase = JSF_BASE_ALL;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf->dv[2].dsize = 0x01000000;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("Espresso Flash @0x%lx [%d MB]\n", jsf->base,
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (int) (jsf->size / (1024*1024)));
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc = misc_register(&jsf_dev)) != 0) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "jsf: unable to get misc minor %d\n",
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    JSF_MINOR);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf0.base = 0;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct request_queue *jsf_queue;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int jsfd_init(void)
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static DEFINE_SPINLOCK(lock);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsflash *jsf;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct jsfd_part *jdp;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (jsf0.base == 0)
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < JSF_MAX; i++) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct gendisk *disk = alloc_disk(1);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!disk)
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsfd_disk[i] = disk;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_blkdev(JSFD_MAJOR, "jsfd")) {
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EIO;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf_queue = blk_init_queue(jsfd_do_request, &lock);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!jsf_queue) {
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unregister_blkdev(JSFD_MAJOR, "jsfd");
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < JSF_MAX; i++) {
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct gendisk *disk = jsfd_disk[i];
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((i & JSF_PART_MASK) >= JSF_NPART) continue;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsf = &jsf0;	/* actually, &jsfv[i >> JSF_PART_BITS] */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jdp = &jsf->dv[i&JSF_PART_MASK];
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->major = JSFD_MAJOR;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->first_minor = i;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(disk->disk_name, "jsfd%d", i);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->fops = &jsfd_fops;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_capacity(disk, jdp->dsize >> 9);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->private_data = jdp;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disk->queue = jsf_queue;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_disk(disk);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_disk_ro(disk, 1);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i--)
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_disk(jsfd_disk[i]);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init jsflash_init_module(void) {
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((rc = jsflash_init()) == 0) {
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jsfd_init();
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit jsflash_cleanup_module(void)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < JSF_MAX; i++) {
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((i & JSF_PART_MASK) >= JSF_NPART) continue;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_gendisk(jsfd_disk[i]);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		put_disk(jsfd_disk[i]);
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (jsf0.busy)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("jsf0: cleaning busy unit\n");
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf0.base = 0;
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jsf0.busy = 0;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	misc_deregister(&jsf_dev);
63000d59405cf6d7ef8932394ab5a12da1a50ce581eAkinobu Mita	unregister_blkdev(JSFD_MAJOR, "jsfd");
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	blk_cleanup_queue(jsf_queue);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(jsflash_init_module);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(jsflash_cleanup_module);
636