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