Linux SCSI设备容量打印代码分析

探寻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软件分区一般默认都不会预留空间?

怎么在代码中手动预留除空间不让其访问到边界。

猜你喜欢

转载自blog.csdn.net/TSZ0000/article/details/88909445
今日推荐