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]
scsi_manager() -> &'static ScsiManager15 pub fn scsi_manager() -> &'static ScsiManager {
16 unsafe { SCSI_MANAGER.as_ref().unwrap() }
17 }
18
19 #[unified_init(INITCALL_POSTCORE)]
scsi_manager_init() -> Result<(), SystemError>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
new() -> Self39 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
inner(&self) -> SpinLockGuard<InnerScsiManager>48 fn inner(&self) -> SpinLockGuard<InnerScsiManager> {
49 self.inner.lock()
50 }
51
alloc_id(&self) -> Option<BlockDevName>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.
format_name(id: usize) -> BlockDevName62 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 #[allow(dead_code)]
free_id(&self, id: usize)68 pub fn free_id(&self, id: usize) {
69 if id >= Self::MAX_DEVICES {
70 return;
71 }
72 self.inner().id_bmp.set(id, false);
73 self.inner().devname[id] = None;
74 }
75 }
76