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 <linux/uaccess.h>
21 #include <platform/simcall.h>
23 #define SIMDISK_MAJOR 240
24 #define SIMDISK_MINORS 1
25 #define MAX_SIMDISK_COUNT 10
31 struct proc_dir_entry
*procfile
;
38 static int simdisk_count
= CONFIG_BLK_DEV_SIMDISK_COUNT
;
39 module_param(simdisk_count
, int, S_IRUGO
);
40 MODULE_PARM_DESC(simdisk_count
, "Number of simdisk units.");
43 static const char *filename
[MAX_SIMDISK_COUNT
] = {
44 #ifdef CONFIG_SIMDISK0_FILENAME
45 CONFIG_SIMDISK0_FILENAME
,
46 #ifdef CONFIG_SIMDISK1_FILENAME
47 CONFIG_SIMDISK1_FILENAME
,
52 static int simdisk_param_set_filename(const char *val
,
53 const struct kernel_param
*kp
)
55 if (n_files
< ARRAY_SIZE(filename
))
56 filename
[n_files
++] = val
;
62 static const struct kernel_param_ops simdisk_param_ops_filename
= {
63 .set
= simdisk_param_set_filename
,
65 module_param_cb(filename
, &simdisk_param_ops_filename
, &n_files
, 0);
66 MODULE_PARM_DESC(filename
, "Backing storage filename.");
68 static int simdisk_major
= SIMDISK_MAJOR
;
70 static void simdisk_transfer(struct simdisk
*dev
, unsigned long sector
,
71 unsigned long nsect
, char *buffer
, int write
)
73 unsigned long offset
= sector
<< SECTOR_SHIFT
;
74 unsigned long nbytes
= nsect
<< SECTOR_SHIFT
;
76 if (offset
> dev
->size
|| dev
->size
- offset
< nbytes
) {
77 pr_notice("Beyond-end %s (%ld %ld)\n",
78 write
? "write" : "read", offset
, nbytes
);
82 spin_lock(&dev
->lock
);
86 simc_lseek(dev
->fd
, offset
, SEEK_SET
);
89 io
= simc_write(dev
->fd
, buffer
, nbytes
);
91 io
= simc_read(dev
->fd
, buffer
, nbytes
);
93 pr_err("SIMDISK: IO error %d\n", errno
);
100 spin_unlock(&dev
->lock
);
103 static void simdisk_submit_bio(struct bio
*bio
)
105 struct simdisk
*dev
= bio
->bi_bdev
->bd_disk
->private_data
;
107 struct bvec_iter iter
;
108 sector_t sector
= bio
->bi_iter
.bi_sector
;
110 bio_for_each_segment(bvec
, bio
, iter
) {
111 char *buffer
= bvec_kmap_local(&bvec
);
112 unsigned len
= bvec
.bv_len
>> SECTOR_SHIFT
;
114 simdisk_transfer(dev
, sector
, len
, buffer
,
115 bio_data_dir(bio
) == WRITE
);
117 kunmap_local(buffer
);
123 static int simdisk_open(struct gendisk
*disk
, blk_mode_t mode
)
125 struct simdisk
*dev
= disk
->private_data
;
127 spin_lock(&dev
->lock
);
129 spin_unlock(&dev
->lock
);
133 static void simdisk_release(struct gendisk
*disk
)
135 struct simdisk
*dev
= disk
->private_data
;
136 spin_lock(&dev
->lock
);
138 spin_unlock(&dev
->lock
);
141 static const struct block_device_operations simdisk_ops
= {
142 .owner
= THIS_MODULE
,
143 .submit_bio
= simdisk_submit_bio
,
144 .open
= simdisk_open
,
145 .release
= simdisk_release
,
148 static struct simdisk
*sddev
;
149 static struct proc_dir_entry
*simdisk_procdir
;
151 static int simdisk_attach(struct simdisk
*dev
, const char *filename
)
155 filename
= kstrdup(filename
, GFP_KERNEL
);
156 if (filename
== NULL
)
159 spin_lock(&dev
->lock
);
165 dev
->fd
= simc_open(filename
, O_RDWR
, 0);
167 pr_err("SIMDISK: Can't open %s: %d\n", filename
, errno
);
171 dev
->size
= simc_lseek(dev
->fd
, 0, SEEK_END
);
172 set_capacity(dev
->gd
, dev
->size
>> SECTOR_SHIFT
);
173 dev
->filename
= filename
;
174 pr_info("SIMDISK: %s=%s\n", dev
->gd
->disk_name
, dev
->filename
);
178 spin_unlock(&dev
->lock
);
183 static int simdisk_detach(struct simdisk
*dev
)
187 spin_lock(&dev
->lock
);
189 if (dev
->users
!= 0) {
191 } else if (dev
->fd
!= -1) {
192 if (simc_close(dev
->fd
)) {
193 pr_err("SIMDISK: error closing %s: %d\n",
194 dev
->filename
, errno
);
197 pr_info("SIMDISK: %s detached from %s\n",
198 dev
->gd
->disk_name
, dev
->filename
);
200 kfree(dev
->filename
);
201 dev
->filename
= NULL
;
204 spin_unlock(&dev
->lock
);
208 static ssize_t
proc_read_simdisk(struct file
*file
, char __user
*buf
,
209 size_t size
, loff_t
*ppos
)
211 struct simdisk
*dev
= pde_data(file_inode(file
));
212 const char *s
= dev
->filename
;
214 ssize_t len
= strlen(s
);
215 char *temp
= kmalloc(len
+ 2, GFP_KERNEL
);
220 len
= scnprintf(temp
, len
+ 2, "%s\n", s
);
221 len
= simple_read_from_buffer(buf
, size
, ppos
,
227 return simple_read_from_buffer(buf
, size
, ppos
, "\n", 1);
230 static ssize_t
proc_write_simdisk(struct file
*file
, const char __user
*buf
,
231 size_t count
, loff_t
*ppos
)
233 char *tmp
= memdup_user_nul(buf
, count
);
234 struct simdisk
*dev
= pde_data(file_inode(file
));
240 err
= simdisk_detach(dev
);
244 if (count
> 0 && tmp
[count
- 1] == '\n')
248 err
= simdisk_attach(dev
, tmp
);
257 static const struct proc_ops simdisk_proc_ops
= {
258 .proc_read
= proc_read_simdisk
,
259 .proc_write
= proc_write_simdisk
,
260 .proc_lseek
= default_llseek
,
263 static int __init
simdisk_setup(struct simdisk
*dev
, int which
,
264 struct proc_dir_entry
*procdir
)
266 struct queue_limits lim
= {
267 .features
= BLK_FEAT_ROTATIONAL
,
269 char tmp
[2] = { '0' + which
, 0 };
273 dev
->filename
= NULL
;
274 spin_lock_init(&dev
->lock
);
277 dev
->gd
= blk_alloc_disk(&lim
, NUMA_NO_NODE
);
278 if (IS_ERR(dev
->gd
)) {
279 err
= PTR_ERR(dev
->gd
);
282 dev
->gd
->major
= simdisk_major
;
283 dev
->gd
->first_minor
= which
;
284 dev
->gd
->minors
= SIMDISK_MINORS
;
285 dev
->gd
->fops
= &simdisk_ops
;
286 dev
->gd
->private_data
= dev
;
287 snprintf(dev
->gd
->disk_name
, 32, "simdisk%d", which
);
288 set_capacity(dev
->gd
, 0);
289 err
= add_disk(dev
->gd
);
291 goto out_cleanup_disk
;
293 dev
->procfile
= proc_create_data(tmp
, 0644, procdir
, &simdisk_proc_ops
, dev
);
303 static int __init
simdisk_init(void)
307 if (register_blkdev(simdisk_major
, "simdisk") < 0) {
308 pr_err("SIMDISK: register_blkdev: %d\n", simdisk_major
);
311 pr_info("SIMDISK: major: %d\n", simdisk_major
);
313 if (n_files
> simdisk_count
)
314 simdisk_count
= n_files
;
315 if (simdisk_count
> MAX_SIMDISK_COUNT
)
316 simdisk_count
= MAX_SIMDISK_COUNT
;
318 sddev
= kmalloc_array(simdisk_count
, sizeof(*sddev
), GFP_KERNEL
);
322 simdisk_procdir
= proc_mkdir("simdisk", 0);
323 if (simdisk_procdir
== NULL
)
324 goto out_free_unregister
;
326 for (i
= 0; i
< simdisk_count
; ++i
) {
327 if (simdisk_setup(sddev
+ i
, i
, simdisk_procdir
) == 0) {
328 if (filename
[i
] != NULL
&& filename
[i
][0] != 0 &&
329 (n_files
== 0 || i
< n_files
))
330 simdisk_attach(sddev
+ i
, filename
[i
]);
339 unregister_blkdev(simdisk_major
, "simdisk");
342 module_init(simdisk_init
);
344 static void simdisk_teardown(struct simdisk
*dev
, int which
,
345 struct proc_dir_entry
*procdir
)
347 char tmp
[2] = { '0' + which
, 0 };
351 del_gendisk(dev
->gd
);
354 remove_proc_entry(tmp
, procdir
);
357 static void __exit
simdisk_exit(void)
361 for (i
= 0; i
< simdisk_count
; ++i
)
362 simdisk_teardown(sddev
+ i
, i
, simdisk_procdir
);
363 remove_proc_entry("simdisk", 0);
365 unregister_blkdev(simdisk_major
, "simdisk");
367 module_exit(simdisk_exit
);
369 MODULE_ALIAS_BLOCKDEV_MAJOR(SIMDISK_MAJOR
);
371 MODULE_LICENSE("GPL");