1 use super::{_port, hba::HbaCmdTable, virt_2_phys};
2 use crate::driver::base::block::block_device::{BlockDevice, BlockId};
3 use crate::driver::base::block::disk_info::Partition;
4 use crate::driver::base::block::SeekFrom;
5 use crate::driver::base::class::Class;
6 use crate::driver::base::device::bus::Bus;
7 
8 use crate::driver::base::device::driver::Driver;
9 use crate::driver::base::device::{Device, DeviceType, IdTable};
10 use crate::driver::base::kobject::{KObjType, KObject, KObjectState};
11 use crate::driver::base::kset::KSet;
12 use crate::driver::disk::ahci::HBA_PxIS_TFES;
13 
14 use crate::filesystem::kernfs::KernFSInode;
15 use crate::filesystem::mbr::MbrDiskPartionTable;
16 
17 use crate::kdebug;
18 use crate::libs::rwlock::{RwLockReadGuard, RwLockWriteGuard};
19 use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
20 use crate::mm::{phys_2_virt, verify_area, VirtAddr};
21 use crate::{
22     driver::disk::ahci::hba::{
23         FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT,
24         ATA_DEV_BUSY, ATA_DEV_DRQ,
25     },
26     kerror,
27 };
28 use system_error::SystemError;
29 
30 use alloc::sync::Weak;
31 use alloc::{string::String, sync::Arc, vec::Vec};
32 
33 use core::fmt::Debug;
34 use core::sync::atomic::{compiler_fence, Ordering};
35 use core::{mem::size_of, ptr::write_bytes};
36 
37 /// @brief: 只支持MBR分区格式的磁盘结构体
38 pub struct AhciDisk {
39     pub name: String,
40     pub flags: u16,                      // 磁盘的状态flags
41     pub partitions: Vec<Arc<Partition>>, // 磁盘分区数组
42     // port: &'static mut HbaPort,      // 控制硬盘的端口
43     pub ctrl_num: u8,
44     pub port_num: u8,
45     /// 指向LockAhciDisk的弱引用
46     self_ref: Weak<LockedAhciDisk>,
47 }
48 
49 /// @brief: 带锁的AhciDisk
50 #[derive(Debug)]
51 pub struct LockedAhciDisk(pub SpinLock<AhciDisk>);
52 /// 函数实现
53 impl Debug for AhciDisk {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result54     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55         write!(
56             f,
57             "{{ name: {}, flags: {}, part_s: {:?} }}",
58             self.name, self.flags, self.partitions
59         )?;
60         return Ok(());
61     }
62 }
63 
64 impl AhciDisk {
read_at( &self, lba_id_start: BlockId, count: usize, buf: &mut [u8], ) -> Result<usize, SystemError>65     fn read_at(
66         &self,
67         lba_id_start: BlockId, // 起始lba编号
68         count: usize,          // 读取lba的数量
69         buf: &mut [u8],
70     ) -> Result<usize, SystemError> {
71         assert!((buf.len() & 511) == 0);
72         compiler_fence(core::sync::atomic::Ordering::SeqCst);
73         let check_length = ((count - 1) >> 4) + 1; // prdt length
74         if count * 512 > buf.len() || check_length > 8 as usize {
75             kerror!("ahci read: e2big");
76             // 不可能的操作
77             return Err(SystemError::E2BIG);
78         } else if count == 0 {
79             return Ok(0);
80         }
81 
82         let port = _port(self.ctrl_num, self.port_num);
83         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
84 
85         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
86 
87         if slot == u32::MAX {
88             return Err(SystemError::EIO);
89         }
90 
91         #[allow(unused_unsafe)]
92         let cmdheader: &mut HbaCmdHeader = unsafe {
93             (phys_2_virt(
94                 volatile_read!(port.clb) as usize
95                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
96             ) as *mut HbaCmdHeader)
97                 .as_mut()
98                 .unwrap()
99         };
100 
101         cmdheader.cfl = (size_of::<FisRegH2D>() / size_of::<u32>()) as u8;
102 
103         volatile_set_bit!(cmdheader.cfl, 1 << 6, false); //  Read/Write bit : Read from device
104         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
105 
106         // 设置数据存放地址
107         let mut buf_ptr = buf as *mut [u8] as *mut usize as usize;
108 
109         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
110         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
111 
112         let user_buf = verify_area(VirtAddr::new(buf_ptr as usize), buf.len()).is_ok();
113         let mut kbuf = if user_buf {
114             let mut x: Vec<u8> = Vec::new();
115             x.resize(buf.len(), 0);
116             Some(x)
117         } else {
118             None
119         };
120 
121         if kbuf.is_some() {
122             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
123         }
124 
125         #[allow(unused_unsafe)]
126         let cmdtbl = unsafe {
127             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
128                 .as_mut()
129                 .unwrap() // 必须使用 as_mut ,得到的才是原来的变量
130         };
131         let mut tmp_count = count;
132 
133         unsafe {
134             // 清空整个table的旧数据
135             write_bytes(cmdtbl, 0, 1);
136         }
137         // kdebug!("cmdheader.prdtl={}", volatile_read!(cmdheader.prdtl));
138 
139         // 8K bytes (16 sectors) per PRDT
140         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
141             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
142             cmdtbl.prdt_entry[i].dbc = 8 * 1024 - 1;
143             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i
144             buf_ptr += 8 * 1024;
145             tmp_count -= 16;
146         }
147 
148         // Last entry
149         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
150         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
151         cmdtbl.prdt_entry[las].dbc = ((tmp_count << 9) - 1) as u32; // 数据长度
152 
153         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
154 
155         // 设置命令
156         let cmdfis = unsafe {
157             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
158                 .as_mut()
159                 .unwrap()
160         };
161         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
162         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
163         volatile_write!(cmdfis.command, ATA_CMD_READ_DMA_EXT);
164 
165         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
166         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
167         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
168         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
169         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
170         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
171 
172         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
173         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
174 
175         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
176 
177         // 等待之前的操作完成
178         let mut spin_count = 0;
179         const SPIN_LIMIT: u32 = 10000;
180 
181         while (volatile_read!(port.tfd) as u8 & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0
182             && spin_count < SPIN_LIMIT
183         {
184             spin_count += 1;
185         }
186 
187         if spin_count == SPIN_LIMIT {
188             kerror!("Port is hung");
189             return Err(SystemError::EIO);
190         }
191 
192         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
193                                                      // kdebug!("To wait ahci read complete.");
194                                                      // 等待操作完成
195         loop {
196             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
197                 break;
198             }
199             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
200                 kerror!("Read disk error");
201                 return Err(SystemError::EIO);
202             }
203         }
204 
205         if kbuf.is_some() {
206             buf.copy_from_slice(kbuf.as_ref().unwrap());
207         }
208 
209         compiler_fence(core::sync::atomic::Ordering::SeqCst);
210         // successfully read
211         return Ok(count * 512);
212     }
213 
write_at( &self, lba_id_start: BlockId, count: usize, buf: &[u8], ) -> Result<usize, SystemError>214     fn write_at(
215         &self,
216         lba_id_start: BlockId,
217         count: usize,
218         buf: &[u8],
219     ) -> Result<usize, SystemError> {
220         assert!((buf.len() & 511) == 0);
221         compiler_fence(core::sync::atomic::Ordering::SeqCst);
222         let check_length = ((count - 1) >> 4) + 1; // prdt length
223         if count * 512 > buf.len() || check_length > 8 as usize {
224             // 不可能的操作
225             return Err(SystemError::E2BIG);
226         } else if count == 0 {
227             return Ok(0);
228         }
229 
230         let port = _port(self.ctrl_num, self.port_num);
231 
232         volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits
233 
234         let slot = port.find_cmdslot().unwrap_or(u32::MAX);
235 
236         if slot == u32::MAX {
237             return Err(SystemError::EIO);
238         }
239 
240         compiler_fence(core::sync::atomic::Ordering::SeqCst);
241         #[allow(unused_unsafe)]
242         let cmdheader: &mut HbaCmdHeader = unsafe {
243             (phys_2_virt(
244                 volatile_read!(port.clb) as usize
245                     + slot as usize * size_of::<HbaCmdHeader>() as usize,
246             ) as *mut HbaCmdHeader)
247                 .as_mut()
248                 .unwrap()
249         };
250         compiler_fence(core::sync::atomic::Ordering::SeqCst);
251 
252         volatile_write_bit!(
253             cmdheader.cfl,
254             (1 << 5) - 1 as u8,
255             (size_of::<FisRegH2D>() / size_of::<u32>()) as u8
256         ); // Command FIS size
257 
258         volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit :  Write from device
259         volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count
260 
261         // 设置数据存放地址
262         compiler_fence(core::sync::atomic::Ordering::SeqCst);
263         let mut buf_ptr = buf as *const [u8] as *mut usize as usize;
264 
265         // 由于目前的内存管理机制无法把用户空间的内存地址转换为物理地址,所以只能先把数据拷贝到内核空间
266         // TODO:在内存管理重构后,可以直接使用用户空间的内存地址
267         let user_buf = verify_area(VirtAddr::new(buf_ptr as usize), buf.len()).is_ok();
268         let mut kbuf = if user_buf {
269             let mut x: Vec<u8> = Vec::with_capacity(buf.len());
270             x.resize(buf.len(), 0);
271             x.copy_from_slice(buf);
272             Some(x)
273         } else {
274             None
275         };
276 
277         if kbuf.is_some() {
278             buf_ptr = kbuf.as_mut().unwrap().as_mut_ptr() as usize;
279         }
280 
281         #[allow(unused_unsafe)]
282         let cmdtbl = unsafe {
283             (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable)
284                 .as_mut()
285                 .unwrap()
286         };
287         let mut tmp_count = count;
288         compiler_fence(core::sync::atomic::Ordering::SeqCst);
289 
290         unsafe {
291             // 清空整个table的旧数据
292             write_bytes(cmdtbl, 0, 1);
293         }
294 
295         // 8K bytes (16 sectors) per PRDT
296         for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) {
297             volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64);
298             volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度
299             volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断
300             buf_ptr += 8 * 1024;
301             tmp_count -= 16;
302         }
303 
304         // Last entry
305         let las = (volatile_read!(cmdheader.prdtl) - 1) as usize;
306         volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64);
307         volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断
308         volatile_write_bit!(
309             cmdtbl.prdt_entry[las].dbc,
310             (1 << 22) - 1,
311             ((tmp_count << 9) - 1) as u32
312         ); // 数据长度
313 
314         // 设置命令
315         let cmdfis = unsafe {
316             ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D)
317                 .as_mut()
318                 .unwrap()
319         };
320         volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8);
321         volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set
322         volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT);
323 
324         volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8);
325         volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8);
326         volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8);
327         volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8);
328         volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8);
329         volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8);
330 
331         volatile_write!(cmdfis.countl, (count & 0xFF) as u8);
332         volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8);
333 
334         volatile_write!(cmdfis.device, 1 << 6); // LBA Mode
335 
336         volatile_set_bit!(port.ci, 1 << slot, true); // Issue command
337 
338         // 等待操作完成
339         loop {
340             if (volatile_read!(port.ci) & (1 << slot)) == 0 {
341                 break;
342             }
343             if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 {
344                 kerror!("Write disk error");
345                 return Err(SystemError::EIO);
346             }
347         }
348 
349         compiler_fence(core::sync::atomic::Ordering::SeqCst);
350         // successfully read
351         return Ok(count * 512);
352     }
353 
sync(&self) -> Result<(), SystemError>354     fn sync(&self) -> Result<(), SystemError> {
355         // 由于目前没有block cache, 因此sync返回成功即可
356         return Ok(());
357     }
358 }
359 
360 impl LockedAhciDisk {
new( name: String, flags: u16, ctrl_num: u8, port_num: u8, ) -> Result<Arc<LockedAhciDisk>, SystemError>361     pub fn new(
362         name: String,
363         flags: u16,
364         ctrl_num: u8,
365         port_num: u8,
366     ) -> Result<Arc<LockedAhciDisk>, SystemError> {
367         // 构建磁盘结构体
368         let result: Arc<LockedAhciDisk> = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk {
369             name,
370             flags,
371             partitions: Default::default(),
372             ctrl_num,
373             port_num,
374             self_ref: Weak::default(),
375         })));
376 
377         let table: MbrDiskPartionTable = result.read_mbr_table()?;
378 
379         // 求出有多少可用分区
380         for i in 0..4 {
381             compiler_fence(Ordering::SeqCst);
382             if table.dpte[i].part_type != 0 {
383                 let w = Arc::downgrade(&result);
384                 result.0.lock().partitions.push(Partition::new(
385                     table.dpte[i].starting_sector() as u64,
386                     table.dpte[i].starting_lba as u64,
387                     table.dpte[i].total_sectors as u64,
388                     w,
389                     i as u16,
390                 ));
391             }
392         }
393 
394         result.0.lock().self_ref = Arc::downgrade(&result);
395 
396         return Ok(result);
397     }
398 
399     /// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor
read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError>400     pub fn read_mbr_table(&self) -> Result<MbrDiskPartionTable, SystemError> {
401         let mut table: MbrDiskPartionTable = Default::default();
402 
403         // 数据缓冲区
404         let mut buf: Vec<u8> = Vec::new();
405         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
406 
407         self.read_at(0, 1, &mut buf)?;
408         // 创建 Cursor 用于按字节读取
409         let mut cursor = VecCursor::new(buf);
410         cursor.seek(SeekFrom::SeekCurrent(446))?;
411 
412         for i in 0..4 {
413             kdebug!("infomation of partition {}:\n", i);
414 
415             table.dpte[i].flags = cursor.read_u8()?;
416             table.dpte[i].starting_head = cursor.read_u8()?;
417             table.dpte[i].starting_sector_cylinder = cursor.read_u16()?;
418             table.dpte[i].part_type = cursor.read_u8()?;
419             table.dpte[i].ending_head = cursor.read_u8()?;
420             table.dpte[i].ending_sector_cylingder = cursor.read_u16()?;
421             table.dpte[i].starting_lba = cursor.read_u32()?;
422             table.dpte[i].total_sectors = cursor.read_u32()?;
423 
424             kdebug!("dpte[i] = {:?}", table.dpte[i]);
425         }
426         table.bs_trailsig = cursor.read_u16()?;
427         // kdebug!("bs_trailsig = {}", unsafe {
428         //     read_unaligned(addr_of!(table.bs_trailsig))
429         // });
430 
431         return Ok(table);
432     }
433 }
434 
435 impl KObject for LockedAhciDisk {
as_any_ref(&self) -> &dyn core::any::Any436     fn as_any_ref(&self) -> &dyn core::any::Any {
437         self
438     }
439 
inode(&self) -> Option<Arc<KernFSInode>>440     fn inode(&self) -> Option<Arc<KernFSInode>> {
441         todo!()
442     }
443 
kobj_type(&self) -> Option<&'static dyn KObjType>444     fn kobj_type(&self) -> Option<&'static dyn KObjType> {
445         todo!()
446     }
447 
kset(&self) -> Option<Arc<KSet>>448     fn kset(&self) -> Option<Arc<KSet>> {
449         todo!()
450     }
451 
parent(&self) -> Option<Weak<dyn KObject>>452     fn parent(&self) -> Option<Weak<dyn KObject>> {
453         todo!()
454     }
455 
set_inode(&self, _inode: Option<Arc<KernFSInode>>)456     fn set_inode(&self, _inode: Option<Arc<KernFSInode>>) {
457         todo!()
458     }
459 
kobj_state(&self) -> RwLockReadGuard<KObjectState>460     fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
461         todo!()
462     }
463 
kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState>464     fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
465         todo!()
466     }
467 
set_kobj_state(&self, _state: KObjectState)468     fn set_kobj_state(&self, _state: KObjectState) {
469         todo!()
470     }
471 
name(&self) -> alloc::string::String472     fn name(&self) -> alloc::string::String {
473         todo!()
474     }
475 
set_name(&self, _name: alloc::string::String)476     fn set_name(&self, _name: alloc::string::String) {
477         todo!()
478     }
479 
set_kset(&self, _kset: Option<Arc<KSet>>)480     fn set_kset(&self, _kset: Option<Arc<KSet>>) {
481         todo!()
482     }
483 
set_parent(&self, _parent: Option<Weak<dyn KObject>>)484     fn set_parent(&self, _parent: Option<Weak<dyn KObject>>) {
485         todo!()
486     }
487 
set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>)488     fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {
489         todo!()
490     }
491 }
492 
493 impl Device for LockedAhciDisk {
dev_type(&self) -> DeviceType494     fn dev_type(&self) -> DeviceType {
495         return DeviceType::Block;
496     }
497 
id_table(&self) -> IdTable498     fn id_table(&self) -> IdTable {
499         todo!()
500     }
501 
bus(&self) -> Option<Weak<dyn Bus>>502     fn bus(&self) -> Option<Weak<dyn Bus>> {
503         todo!("LockedAhciDisk::bus()")
504     }
505 
set_bus(&self, _bus: Option<Weak<dyn Bus>>)506     fn set_bus(&self, _bus: Option<Weak<dyn Bus>>) {
507         todo!("LockedAhciDisk::set_bus()")
508     }
509 
driver(&self) -> Option<Arc<dyn Driver>>510     fn driver(&self) -> Option<Arc<dyn Driver>> {
511         todo!("LockedAhciDisk::driver()")
512     }
513 
is_dead(&self) -> bool514     fn is_dead(&self) -> bool {
515         false
516     }
517 
set_driver(&self, _driver: Option<Weak<dyn Driver>>)518     fn set_driver(&self, _driver: Option<Weak<dyn Driver>>) {
519         todo!("LockedAhciDisk::set_driver()")
520     }
521 
can_match(&self) -> bool522     fn can_match(&self) -> bool {
523         todo!()
524     }
525 
set_can_match(&self, _can_match: bool)526     fn set_can_match(&self, _can_match: bool) {
527         todo!()
528     }
529 
state_synced(&self) -> bool530     fn state_synced(&self) -> bool {
531         todo!()
532     }
533 
set_class(&self, _class: Option<Arc<dyn Class>>)534     fn set_class(&self, _class: Option<Arc<dyn Class>>) {
535         todo!()
536     }
537 }
538 
539 impl BlockDevice for LockedAhciDisk {
540     #[inline]
as_any_ref(&self) -> &dyn core::any::Any541     fn as_any_ref(&self) -> &dyn core::any::Any {
542         self
543     }
544 
545     #[inline]
blk_size_log2(&self) -> u8546     fn blk_size_log2(&self) -> u8 {
547         9
548     }
549 
sync(&self) -> Result<(), SystemError>550     fn sync(&self) -> Result<(), SystemError> {
551         return self.0.lock().sync();
552     }
553 
554     #[inline]
device(&self) -> Arc<dyn Device>555     fn device(&self) -> Arc<dyn Device> {
556         return self.0.lock().self_ref.upgrade().unwrap();
557     }
558 
block_size(&self) -> usize559     fn block_size(&self) -> usize {
560         todo!()
561     }
562 
partitions(&self) -> Vec<Arc<Partition>>563     fn partitions(&self) -> Vec<Arc<Partition>> {
564         return self.0.lock().partitions.clone();
565     }
566 
567     #[inline]
read_at( &self, lba_id_start: BlockId, count: usize, buf: &mut [u8], ) -> Result<usize, SystemError>568     fn read_at(
569         &self,
570         lba_id_start: BlockId, // 起始lba编号
571         count: usize,          // 读取lba的数量
572         buf: &mut [u8],
573     ) -> Result<usize, SystemError> {
574         self.0.lock().read_at(lba_id_start, count, buf)
575     }
576 
577     #[inline]
write_at( &self, lba_id_start: BlockId, count: usize, buf: &[u8], ) -> Result<usize, SystemError>578     fn write_at(
579         &self,
580         lba_id_start: BlockId,
581         count: usize,
582         buf: &[u8],
583     ) -> Result<usize, SystemError> {
584         self.0.lock().write_at(lba_id_start, count, buf)
585     }
586 }
587