xref: /linux/drivers/block/rnull/rnull.rs (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1edd86506SAndreas Hindborg // SPDX-License-Identifier: GPL-2.0
2edd86506SAndreas Hindborg 
3edd86506SAndreas Hindborg //! This is a Rust implementation of the C null block driver.
4d969d504SAndreas Hindborg 
5d969d504SAndreas Hindborg mod configfs;
6edd86506SAndreas Hindborg 
7*34585dc6SAndreas Hindborg use configfs::IRQMode;
8edd86506SAndreas Hindborg use kernel::{
9d969d504SAndreas Hindborg     block::{
10d969d504SAndreas Hindborg         self,
11d969d504SAndreas Hindborg         mq::{
12edd86506SAndreas Hindborg             self,
13edd86506SAndreas Hindborg             gen_disk::{self, GenDisk},
14edd86506SAndreas Hindborg             Operations, TagSet,
15edd86506SAndreas Hindborg         },
16d969d504SAndreas Hindborg     },
17edd86506SAndreas Hindborg     error::Result,
18d969d504SAndreas Hindborg     pr_info,
19edd86506SAndreas Hindborg     prelude::*,
20d969d504SAndreas Hindborg     sync::Arc,
21edd86506SAndreas Hindborg     types::ARef,
22edd86506SAndreas Hindborg };
23d969d504SAndreas Hindborg use pin_init::PinInit;
24edd86506SAndreas Hindborg 
25edd86506SAndreas Hindborg module! {
26edd86506SAndreas Hindborg     type: NullBlkModule,
27edd86506SAndreas Hindborg     name: "rnull_mod",
28edd86506SAndreas Hindborg     authors: ["Andreas Hindborg"],
29edd86506SAndreas Hindborg     description: "Rust implementation of the C null block driver",
30edd86506SAndreas Hindborg     license: "GPL v2",
31edd86506SAndreas Hindborg }
32edd86506SAndreas Hindborg 
33edd86506SAndreas Hindborg #[pin_data]
34edd86506SAndreas Hindborg struct NullBlkModule {
35edd86506SAndreas Hindborg     #[pin]
36d969d504SAndreas Hindborg     configfs_subsystem: kernel::configfs::Subsystem<configfs::Config>,
37edd86506SAndreas Hindborg }
38edd86506SAndreas Hindborg 
39edd86506SAndreas Hindborg impl kernel::InPlaceModule for NullBlkModule {
40edd86506SAndreas Hindborg     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
41edd86506SAndreas Hindborg         pr_info!("Rust null_blk loaded\n");
42edd86506SAndreas Hindborg 
43edd86506SAndreas Hindborg         try_pin_init!(Self {
44d969d504SAndreas Hindborg             configfs_subsystem <- configfs::subsystem(),
45edd86506SAndreas Hindborg         })
46edd86506SAndreas Hindborg     }
47edd86506SAndreas Hindborg }
48edd86506SAndreas Hindborg 
49edd86506SAndreas Hindborg struct NullBlkDevice;
50edd86506SAndreas Hindborg 
51d969d504SAndreas Hindborg impl NullBlkDevice {
52d969d504SAndreas Hindborg     fn new(
53d969d504SAndreas Hindborg         name: &CStr,
54d969d504SAndreas Hindborg         block_size: u32,
55d969d504SAndreas Hindborg         rotational: bool,
56d969d504SAndreas Hindborg         capacity_mib: u64,
57*34585dc6SAndreas Hindborg         irq_mode: IRQMode,
58d969d504SAndreas Hindborg     ) -> Result<GenDisk<Self>> {
59d969d504SAndreas Hindborg         let tagset = Arc::pin_init(TagSet::new(1, 256, 1), GFP_KERNEL)?;
60d969d504SAndreas Hindborg 
61*34585dc6SAndreas Hindborg         let queue_data = Box::new(QueueData { irq_mode }, GFP_KERNEL)?;
62*34585dc6SAndreas Hindborg 
63d969d504SAndreas Hindborg         gen_disk::GenDiskBuilder::new()
64d969d504SAndreas Hindborg             .capacity_sectors(capacity_mib << (20 - block::SECTOR_SHIFT))
65d969d504SAndreas Hindborg             .logical_block_size(block_size)?
66d969d504SAndreas Hindborg             .physical_block_size(block_size)?
67d969d504SAndreas Hindborg             .rotational(rotational)
68*34585dc6SAndreas Hindborg             .build(fmt!("{}", name.to_str()?), tagset, queue_data)
69d969d504SAndreas Hindborg     }
70d969d504SAndreas Hindborg }
71d969d504SAndreas Hindborg 
72*34585dc6SAndreas Hindborg struct QueueData {
73*34585dc6SAndreas Hindborg     irq_mode: IRQMode,
74*34585dc6SAndreas Hindborg }
75*34585dc6SAndreas Hindborg 
76edd86506SAndreas Hindborg #[vtable]
77edd86506SAndreas Hindborg impl Operations for NullBlkDevice {
78*34585dc6SAndreas Hindborg     type QueueData = KBox<QueueData>;
7990d952faSAndreas Hindborg 
80edd86506SAndreas Hindborg     #[inline(always)]
81*34585dc6SAndreas Hindborg     fn queue_rq(queue_data: &QueueData, rq: ARef<mq::Request<Self>>, _is_last: bool) -> Result {
82*34585dc6SAndreas Hindborg         match queue_data.irq_mode {
83*34585dc6SAndreas Hindborg             IRQMode::None => mq::Request::end_ok(rq)
84edd86506SAndreas Hindborg                 .map_err(|_e| kernel::error::code::EIO)
85edd86506SAndreas Hindborg                 // We take no refcounts on the request, so we expect to be able to
86edd86506SAndreas Hindborg                 // end the request. The request reference must be unique at this
87edd86506SAndreas Hindborg                 // point, and so `end_ok` cannot fail.
88*34585dc6SAndreas Hindborg                 .expect("Fatal error - expected to be able to end request"),
89*34585dc6SAndreas Hindborg             IRQMode::Soft => mq::Request::complete(rq),
90*34585dc6SAndreas Hindborg         }
91edd86506SAndreas Hindborg         Ok(())
92edd86506SAndreas Hindborg     }
93edd86506SAndreas Hindborg 
94*34585dc6SAndreas Hindborg     fn commit_rqs(_queue_data: &QueueData) {}
954ec05284SAndreas Hindborg 
964ec05284SAndreas Hindborg     fn complete(rq: ARef<mq::Request<Self>>) {
974ec05284SAndreas Hindborg         mq::Request::end_ok(rq)
984ec05284SAndreas Hindborg             .map_err(|_e| kernel::error::code::EIO)
994ec05284SAndreas Hindborg             // We take no refcounts on the request, so we expect to be able to
1004ec05284SAndreas Hindborg             // end the request. The request reference must be unique at this
1014ec05284SAndreas Hindborg             // point, and so `end_ok` cannot fail.
1024ec05284SAndreas Hindborg             .expect("Fatal error - expected to be able to end request");
1034ec05284SAndreas Hindborg     }
104edd86506SAndreas Hindborg }
105