探寻SCSI设备容量如何获取代码。
分析
8G USB转SD卡启动打印信息:
sd 3:0:0:0: [sdb] 15523840 512-byte logical blocks: (7.94 GB/7.40 GiB)
获取设备容量,单位是sector,后面 的7.94 GB是容量字节除1000单位,7.40 GiB是容量字节除1024单位.
if (sdkp->first_scan || old_capacity != sdkp->capacity) {
sd_printk(KERN_NOTICE, sdkp,
"%llu %d-byte logical blocks: (%s/%s)\n",
(unsigned long long)sdkp->capacity,
sector_size, cap_str_10, cap_str_2);
代码分析:
drivers/scsi/sd.c
module_init(init_sd);
scsi_register_driver(&sd_template.gendrv);
static struct scsi_driver sd_template = {
.owner = THIS_MODULE,
.gendrv = {
.name = "sd",
.probe = sd_probe,
sd_probe
async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
sd_probe_async
sd_revalidate_disk(gd);
sd_read_capacity(sdkp, buffer);
重点代函数sd_read_capacity,
/*
* read disk capacity
*/
static void
sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
{
sector_size = read_capacity_10(sdkp, sdp, buffer); 由于容量没有超过2T所以使用READ/WRITE_10
scsi_execute_req函数实现最终发送READ_CAPACITY命令下去,这里获取设备8字节 信息。最后解析除sectors_size和capacity个数。
#define READ_CAPACITY 0x25
#define READ_10 0x28
#define WRITE_10 0x2a
static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
unsigned char *buffer)
{
do {
cmd[0] = READ_CAPACITY;
memset(&cmd[1], 0, 9);
memset(buffer, 0, 8);
the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
buffer, 8, &sshdr,
SD_TIMEOUT, SD_MAX_RETRIES, NULL);
} while (the_result && retries);
sector_size = get_unaligned_be32(&buffer[4]);
lba = get_unaligned_be32(&buffer[0]);
sdkp->capacity = lba + 1;
sdkp->physical_block_size = sector_size;
return sector_size;
}
获取到容量信息和打印出来,就是文章开头的打印信息和打印代码。
扩展
1、Write Protect 标志:sd 3:0:0:0: [sdb] Write Protect is off
static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
{
if (sdp->use_192_bytes_for_3f) {
res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL)
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
set_disk_ro(sdkp->disk, sdkp->write_prot);
if (sdkp->first_scan || old_wp != sdkp->write_prot) {
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
sdkp->write_prot ? "on" : "off");
sd_printk(KERN_DEBUG, sdkp,
"Mode Sense: %02x %02x %02x %02x\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
}
通过MODE_SENSE命令获取数据然后解析除Write Protect标志。
2、分区中的start和end是怎么获取出来的?
Device Boot Start End Blocks Id System
/dev/sdb1 * 2048 15523839 7760896 b Win95 FAT32
设备容量是固定的,是几个分区容量的总和,但是start和end是我们在新建分区时确定下来的参数,fdisk有这个参数吗?
为何fdisk新建的分区都会预留空间,而Disk软件分区一般默认都不会预留空间?
怎么在代码中手动预留除空间不让其访问到边界。