2 * arch/xtensa/platforms/iss/simdisk.c
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
8 * Copyright (C) 2001-2013 Tensilica Inc.
9 * Authors Victor Prupis
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/string.h>
17 #include <linux/blkdev.h>
18 #include <linux/bio.h>
19 #include <linux/proc_fs.h>
20 #include <asm/uaccess.h>
21 #include <platform/simcall.h>
23 #define SIMDISK_MAJOR 240
24 #define SECTOR_SHIFT 9
25 #define SIMDISK_MINORS 1
26 #define MAX_SIMDISK_COUNT 10
31 struct request_queue
*queue
;
33 struct proc_dir_entry
*procfile
;
40 static int simdisk_count
= CONFIG_BLK_DEV_SIMDISK_COUNT
;
41 module_param(simdisk_count
, int, S_IRUGO
);
42 MODULE_PARM_DESC(simdisk_count
, "Number of simdisk units.");
45 static const char *filename
[MAX_SIMDISK_COUNT
] = {
46 #ifdef CONFIG_SIMDISK0_FILENAME
47 CONFIG_SIMDISK0_FILENAME
,
48 #ifdef CONFIG_SIMDISK1_FILENAME
49 CONFIG_SIMDISK1_FILENAME
,
54 static int simdisk_param_set_filename(const char *val
,
55 const struct kernel_param
*kp
)
57 if (n_files
< ARRAY_SIZE(filename
))
58 filename
[n_files
++] = val
;
64 static const struct kernel_param_ops simdisk_param_ops_filename
= {
65 .set
= simdisk_param_set_filename
,
67 module_param_cb(filename
, &simdisk_param_ops_filename
, &n_files
, 0);
68 MODULE_PARM_DESC(filename
, "Backing storage filename.");
70 static int simdisk_major
= SIMDISK_MAJOR
;
72 static void simdisk_transfer(struct simdisk
*dev
, unsigned long sector
,
73 unsigned long nsect
, char *buffer
, int write
)
75 unsigned long offset
= sector
<< SECTOR_SHIFT
;
76 unsigned long nbytes
= nsect
<< SECTOR_SHIFT
;
78 if (offset
> dev
->size
|| dev
->size
- offset
< nbytes
) {
79 pr_notice("Beyond-end %s (%ld %ld)\n",
80 write
? "write" : "read", offset
, nbytes
);
84 spin_lock(&dev
->lock
);
88 __simc(SYS_lseek
, dev
->fd
, offset
, SEEK_SET
, 0, 0);
90 io
= simc_write(dev
->fd
, buffer
, nbytes
);
92 io
= simc_read(dev
->fd
, buffer
, nbytes
);
94 pr_err("SIMDISK: IO error %d\n", errno
);
101 spin_unlock(&dev
->lock
);
104 static int simdisk_xfer_bio(struct simdisk
*dev
, struct bio
*bio
)
107 struct bio_vec
*bvec
;
108 sector_t sector
= bio
->bi_sector
;
110 bio_for_each_segment(bvec
, bio
, i
) {
111 char *buffer
= __bio_kmap_atomic(bio
, i
, KM_USER0
);
112 unsigned len
= bvec
->bv_len
>> SECTOR_SHIFT
;
114 simdisk_transfer(dev
, sector
, len
, buffer
,
115 bio_data_dir(bio
) == WRITE
);
117 __bio_kunmap_atomic(bio
, KM_USER0
);
122 static void simdisk_make_request(struct request_queue
*q
, struct bio
*bio
)
124 struct simdisk
*dev
= q
->queuedata
;
125 int status
= simdisk_xfer_bio(dev
, bio
);
126 bio_endio(bio
, status
);
130 static int simdisk_open(struct block_device
*bdev
, fmode_t mode
)
132 struct simdisk
*dev
= bdev
->bd_disk
->private_data
;
134 spin_lock(&dev
->lock
);
136 check_disk_change(bdev
);
138 spin_unlock(&dev
->lock
);
142 static int simdisk_release(struct gendisk
*disk
, fmode_t mode
)
144 struct simdisk
*dev
= disk
->private_data
;
145 spin_lock(&dev
->lock
);
147 spin_unlock(&dev
->lock
);
151 static const struct block_device_operations simdisk_ops
= {
152 .owner
= THIS_MODULE
,
153 .open
= simdisk_open
,
154 .release
= simdisk_release
,
157 static struct simdisk
*sddev
;
158 static struct proc_dir_entry
*simdisk_procdir
;
160 static int simdisk_attach(struct simdisk
*dev
, const char *filename
)
164 filename
= kstrdup(filename
, GFP_KERNEL
);
165 if (filename
== NULL
)
168 spin_lock(&dev
->lock
);
174 dev
->fd
= simc_open(filename
, O_RDWR
, 0);
176 pr_err("SIMDISK: Can't open %s: %d\n", filename
, errno
);
180 dev
->size
= __simc(SYS_lseek
, dev
->fd
, 0, SEEK_END
, 0, 0);
181 set_capacity(dev
->gd
, dev
->size
>> SECTOR_SHIFT
);
182 dev
->filename
= filename
;
183 pr_info("SIMDISK: %s=%s\n", dev
->gd
->disk_name
, dev
->filename
);
187 spin_unlock(&dev
->lock
);
192 static int simdisk_detach(struct simdisk
*dev
)
196 spin_lock(&dev
->lock
);
198 if (dev
->users
!= 0) {
200 } else if (dev
->fd
!= -1) {
201 if (simc_close(dev
->fd
)) {
202 pr_err("SIMDISK: error closing %s: %d\n",
203 dev
->filename
, errno
);
206 pr_info("SIMDISK: %s detached from %s\n",
207 dev
->gd
->disk_name
, dev
->filename
);
209 kfree(dev
->filename
);
210 dev
->filename
= NULL
;
213 spin_unlock(&dev
->lock
);
217 static int proc_read_simdisk(char *page
, char **start
, off_t off
,
218 int count
, int *eof
, void *data
)
221 struct simdisk
*dev
= (struct simdisk
*) data
;
222 len
= sprintf(page
, "%s\n", dev
->filename
? dev
->filename
: "");
226 static int proc_write_simdisk(struct file
*file
, const char *buffer
,
227 unsigned long count
, void *data
)
229 char *tmp
= kmalloc(count
+ 1, GFP_KERNEL
);
230 struct simdisk
*dev
= (struct simdisk
*) data
;
235 if (copy_from_user(tmp
, buffer
, count
)) {
240 err
= simdisk_detach(dev
);
244 if (count
> 0 && tmp
[count
- 1] == '\n')
250 err
= simdisk_attach(dev
, tmp
);
259 static int __init
simdisk_setup(struct simdisk
*dev
, int which
,
260 struct proc_dir_entry
*procdir
)
262 char tmp
[2] = { '0' + which
, 0 };
265 dev
->filename
= NULL
;
266 spin_lock_init(&dev
->lock
);
269 dev
->queue
= blk_alloc_queue(GFP_KERNEL
);
270 if (dev
->queue
== NULL
) {
271 pr_err("blk_alloc_queue failed\n");
272 goto out_alloc_queue
;
275 blk_queue_make_request(dev
->queue
, simdisk_make_request
);
276 dev
->queue
->queuedata
= dev
;
278 dev
->gd
= alloc_disk(SIMDISK_MINORS
);
279 if (dev
->gd
== NULL
) {
280 pr_err("alloc_disk failed\n");
283 dev
->gd
->major
= simdisk_major
;
284 dev
->gd
->first_minor
= which
;
285 dev
->gd
->fops
= &simdisk_ops
;
286 dev
->gd
->queue
= dev
->queue
;
287 dev
->gd
->private_data
= dev
;
288 snprintf(dev
->gd
->disk_name
, 32, "simdisk%d", which
);
289 set_capacity(dev
->gd
, 0);
292 dev
->procfile
= create_proc_entry(tmp
, 0644, procdir
);
293 dev
->procfile
->data
= dev
;
294 dev
->procfile
->read_proc
= proc_read_simdisk
;
295 dev
->procfile
->write_proc
= proc_write_simdisk
;
299 blk_cleanup_queue(dev
->queue
);
306 static int __init
simdisk_init(void)
310 if (register_blkdev(simdisk_major
, "simdisk") < 0) {
311 pr_err("SIMDISK: register_blkdev: %d\n", simdisk_major
);
314 pr_info("SIMDISK: major: %d\n", simdisk_major
);
316 if (n_files
> simdisk_count
)
317 simdisk_count
= n_files
;
318 if (simdisk_count
> MAX_SIMDISK_COUNT
)
319 simdisk_count
= MAX_SIMDISK_COUNT
;
321 sddev
= kmalloc(simdisk_count
* sizeof(struct simdisk
),
326 simdisk_procdir
= proc_mkdir("simdisk", 0);
327 if (simdisk_procdir
== NULL
)
328 goto out_free_unregister
;
330 for (i
= 0; i
< simdisk_count
; ++i
) {
331 if (simdisk_setup(sddev
+ i
, i
, simdisk_procdir
) == 0) {
332 if (filename
[i
] != NULL
&& filename
[i
][0] != 0 &&
333 (n_files
== 0 || i
< n_files
))
334 simdisk_attach(sddev
+ i
, filename
[i
]);
343 unregister_blkdev(simdisk_major
, "simdisk");
346 module_init(simdisk_init
);
348 static void simdisk_teardown(struct simdisk
*dev
, int which
,
349 struct proc_dir_entry
*procdir
)
351 char tmp
[2] = { '0' + which
, 0 };
355 del_gendisk(dev
->gd
);
357 blk_cleanup_queue(dev
->queue
);
358 remove_proc_entry(tmp
, procdir
);
361 static void __exit
simdisk_exit(void)
365 for (i
= 0; i
< simdisk_count
; ++i
)
366 simdisk_teardown(sddev
+ i
, i
, simdisk_procdir
);
367 remove_proc_entry("simdisk", 0);
369 unregister_blkdev(simdisk_major
, "simdisk");
371 module_exit(simdisk_exit
);
373 MODULE_ALIAS_BLOCKDEV_MAJOR(SIMDISK_MAJOR
);
375 MODULE_LICENSE("GPL");