xref: /DragonOS/kernel/src/driver/scsi/mod.rs (revision f9fe30be89e89499aad4ef52b4648986bef5a7d8)
1 use bitmap::traits::BitMapOps;
2 use system_error::SystemError;
3 use unified_init::macros::unified_init;
4 
5 use crate::{
6     init::initcall::INITCALL_POSTCORE,
7     libs::spinlock::{SpinLock, SpinLockGuard},
8 };
9 
10 use super::base::block::block_device::BlockDevName;
11 
12 static mut SCSI_MANAGER: Option<ScsiManager> = None;
13 
14 #[inline]
15 pub fn scsi_manager() -> &'static ScsiManager {
16     unsafe { SCSI_MANAGER.as_ref().unwrap() }
17 }
18 
19 #[unified_init(INITCALL_POSTCORE)]
20 fn scsi_manager_init() -> Result<(), SystemError> {
21     unsafe {
22         SCSI_MANAGER = Some(ScsiManager::new());
23     }
24     Ok(())
25 }
26 
27 pub struct ScsiManager {
28     inner: SpinLock<InnerScsiManager>,
29 }
30 
31 struct InnerScsiManager {
32     id_bmp: bitmap::StaticBitmap<{ ScsiManager::MAX_DEVICES }>,
33     devname: [Option<BlockDevName>; ScsiManager::MAX_DEVICES],
34 }
35 
36 impl ScsiManager {
37     pub const MAX_DEVICES: usize = 25;
38 
39     pub fn new() -> Self {
40         Self {
41             inner: SpinLock::new(InnerScsiManager {
42                 id_bmp: bitmap::StaticBitmap::new(),
43                 devname: [const { None }; Self::MAX_DEVICES],
44             }),
45         }
46     }
47 
48     fn inner(&self) -> SpinLockGuard<InnerScsiManager> {
49         self.inner.lock()
50     }
51 
52     pub fn alloc_id(&self) -> Option<BlockDevName> {
53         let mut inner = self.inner();
54         let idx = inner.id_bmp.first_false_index()?;
55         inner.id_bmp.set(idx, true);
56         let name = Self::format_name(idx);
57         inner.devname[idx] = Some(name.clone());
58         Some(name)
59     }
60 
61     /// Generate a new block device name like 'sda', 'sdb', etc.
62     fn format_name(id: usize) -> BlockDevName {
63         let x = (b'a' + id as u8) as char;
64         BlockDevName::new(format!("sd{}", x), id)
65     }
66 
67     pub fn free_id(&self, id: usize) {
68         if id >= Self::MAX_DEVICES {
69             return;
70         }
71         self.inner().id_bmp.set(id, false);
72         self.inner().devname[id] = None;
73     }
74 }
75