最近碰到sata类型的多家厂商硬盘读写问题,大概是在128G的地方读写失败,问题查了很久,不过最终还是解决了。问题大概是是ata协议的部分漏洞吧,针对于lba28模式和lba48模式的区分太模糊,例如对于DMA方式的写命令有两种:WRITE DMA、WRITE DMA EXT,前者基于lba28、后者基于lba48;命令格式如下:
lba28:
lba48:
两种命令在sata规范里面并没有确切的区分,在linux2.4.17内核里面,libata判断如果硬盘支持lba48模式,那么优先使用lba48模式的命令;但是在linux2.6.24内核里面,libata在将scsi命令转换为ata命令时并没有这么优先考虑,而是使用了
static inline int lba_28_ok(u64 block, u32 n_block) { /* check the ending block number */ return ((block + n_block - 1) < ((u64)1 << 28))
&& (n_block <= 256); } static inline int lba_48_ok(u64 block, u32 n_block) { /* check the ending block number */ return ((block + n_block - 1) < ((u64)1 << 48))
&& (n_block <= 65536); }
|
这两个内联函数来区分lba28和lba48模式,问题也就出在这里,(( + n_block - 1) < (()1 << 28)) && (n_block <= 256)并没有严格的区分两种类型命令的临界状态,去掉-1问题就能够解决;在linux2.6.30里面已经做了这样的修改,所以如果你依旧使用2.6.30以前的内核,需要修改这个地方。
顺便记录下来,希望对看我博客的朋友有帮助。
阅读(3114) | 评论(1) | 转发(0) |