跳转到主内容
极星编程网:以代码为星,赴技术山海!

Linux 2.6内核源码深度解读:drivers/scsi/目录全景分析

一、引言:企业级存储系统的核心引擎

drivers/scsi/

目录是Linux内核中 SCSI(Small Computer System Interface)子系统的完整实现 ,它构建了从物理存储设备到块设备抽象层的核心桥梁。

在Linux 2.6内核时期,SCSI子系统正处于 从传统并行SCSI向串行SCSI(SAS、FC、iSCSI)转型 的关键阶段,同时也是 SCSI中间层架构成熟 的重要时期。

SCSI子系统不仅要处理硬盘、磁带机、光驱等传统SCSI设备,还要应对RAID控制器、存储区域网络(SAN)、iSCSI、SAS等现代存储技术。

理解这个目录,就是理解Linux如何支持企业级存储设备,如何在保持高性能的同时处理复杂的错误恢复,以及如何通过统一的驱动模型管理多样化的存储硬件。

该目录包含超过100个子目录和数百个文件,总计超过50万行代码,构建了从 SCSI核心、主机适配器驱动、设备驱动、到传输层协议 的完整存储生态。

在2.6版本中,SCSI子系统实现了重大架构演进: 成熟的SCSI中间层、统一的上层块设备接口、完善的错误处理机制 ,并为后续的 多路径I/O、存储虚拟化、NVMe 等技术奠定了基础。

二、目录宏观架构:分层与模块化设计 2.1 目录结构概览

drivers/scsi/

目录采用严格的分层架构,将不同功能的代码模块分离到独立子目录中:

drivers/scsi/

├── scsi.c # SCSI核心(初始化和退出) ├── scsi_error.c # 错误处理与恢复 ├── scsi_lib.c # SCSI库函数(请求队列、命令构建) ├── scsi_scan.c # 设备扫描和探测 ├── scsi_devinfo.c # 设备信息管理 ├── scsi_proc.c # /proc/scsi接口 ├── scsi_sysfs.c # sysfs接口(/sys/class/scsi_*) ├── scsi_ioctl.c # ioctl处理 ├── scsi_mod.c # SCSI模块支持 ├── scsi_dh.c # 设备处理器框架 ├── constants.c # SCSI常量定义 ├── hosts.c # 主机适配器管理 ├── sd.c # SCSI磁盘驱动(sd_mod,最重要的设备驱动) ├── sr.c # SCSI光盘驱动(sr_mod) ├── st.c # SCSI磁带驱动 ├── sg.c # 通用SCSI设备(sg,直通访问) ├── ch.c # SCSI更换器(自动换片机) ├── osd/ # 对象存储设备 ├── aacraid/ # Adaptec RAID控制器 ├── aic7xxx/ # Adaptec AIC-7xxx系列 ├── arcmsr/ # Areca RAID控制器 ├── bfa/ # Brocade FC适配器 ├── bnx2i/ # Broadcom iSCSI ├── cxgb3i/ # Chelsio iSCSI ├── device_handler/ # 多路径设备处理器 │ ├── scsi_dh_alua.c # ALUA(非对称逻辑单元访问) │ ├── scsi_dh_emc.c # EMC多路径 │ ├── scsi_dh_hp_sw.c # HP多路径 │ └── ... ├── fcoe/ # 光纤通道 over Ethernet ├── hpsa.c # HP Smart Array ├── ibmvscsi/ # IBM虚拟SCSI ├── iscsi_tcp/ # iSCSI TCP传输 ├── libfc/ # 光纤通道库 ├── libsas/ # SAS库 ├── lpfc/ # Emulex光纤通道 ├── megaraid/ # LSI MegaRAID ├── mpt2sas/ # LSI MPT SAS 2.0 ├── mpt3sas/ # LSI MPT SAS 3.0 ├── qla2xxx/ # QLogic光纤通道 ├── scsi_transport_fc/ # FC传输属性 ├── scsi_transport_iscsi/ # iSCSI传输属性 ├── scsi_transport_sas/ # SAS传输属性 ├── scsi_transport_spi/ # SPI传输属性 ├── smartpqi/ # Microsemi Smart PQI ├── storvsc/ # Hyper-V存储 ├── sym53c8xx_2/ # LSI 53C8xx/53C1010 ├── ufs/ # 通用闪存存储 └── ... # 其他厂商驱动 2.2 SCSI软件栈分层架构

块设备层(Block Layer)

↓ --- SCSI上层驱动 --- ↓ SCSI磁盘驱动(sd.c)、磁带驱动(st.c)、光盘驱动(sr.c) ↓ --- SCSI中间层(Mid-Level) --- ↓ SCSI核心(scsi.c)、错误处理、设备扫描、命令处理 ↓ --- SCSI底层驱动(Low-Level Drivers) --- ↓ 主机适配器驱动(HBA驱动:qla2xxx, lpfc, mpt2sas等) ↓ --- 物理传输层 --- ↓ FC、SAS、iSCSI、并行SCSI等物理连接 ↓ 物理存储设备(硬盘、磁带、光驱等) 三、核心数据结构:SCSI世界的抽象模型 3.1 SCSI命令结构:

struct scsi_cmnd

这是SCSI子系统最核心的数据结构,代表一个SCSI命令:

struct scsi_cmnd {

struct scsi_device *device; /* 目标设备 */ struct list_head list; /* 链表节点 */

/* 命令状态 */ int eh_eflags; /* 错误处理标志 */ unsigned short cmd_len; /* CDB长度 */ unsigned char cmnd[16]; /* CDB(命令描述块) */

/* 数据缓冲区 */ unsigned buffers; /* 缓冲区计数 */ struct request *request; /* 关联的块层请求 */ unsigned char *buffer; /* 数据缓冲区指针 */ unsigned bufflen; /* 缓冲区长度 */ unsigned resid_len; /* 剩余长度(出错时) */

/* 传输控制 */ unsigned underflow; /* 下溢处理 */ unsigned transfersize; /* 传输大小 */ struct scsi_data_buffer sdb; /* 散点-聚集列表 */

/* 完成回调 */ void (*done)(struct scsi_cmnd *); /* 完成回调函数 */

/* 定时器和超时 */ struct timer_list eh_timeout; /* 错误处理超时 */ unsigned long jiffies_at_alloc; /* 分配时的jiffies */

/* 结果和状态 */ int result; /* 命令结果 */ unsigned char scsi_status; /* SCSI状态字节 */ unsigned char tag; /* 命令标签 */

/* 私有数据 */ void *host_scribble; /* 主机驱动私有数据 */ unsigned int host_scribble_len; /* 私有数据长度 */

/* 标志 */ unsigned int cmd_per_lun; /* 每逻辑单元命令数 */ unsigned char tag_supported:1; /* 是否支持标签命令 */ unsigned char tag_type:3; /* 标签类型 */ unsigned char use_sg:4; /* 散点-聚集条目数 */ }; 关键字段解析 :

cmnd

:CDB(Command Descriptor Block),包含实际的SCSI命令

sdb

:散点-聚集列表,支持分散的内存缓冲区

done

:命令完成回调函数,异步处理的核心

host_scribble

:主机适配器驱动私有数据区 3.2 SCSI设备结构:

struct scsi_device

代表一个SCSI逻辑单元(LUN):

struct scsi_device {

struct Scsi_Host *host; /* 所属主机适配器 */ struct request_queue *request_queue; /* 请求队列 */

/* 设备标识 */ u16 id; /* SCSI ID */ u16 lun; /* 逻辑单元号 */ u64 unique_id; /* 唯一标识符 */

/* 设备能力 */ unsigned inquiry_len; /* INQUIRY数据长度 */ unsigned char inquiry[INQUIRY_BUFFER_LEN]; /* INQUIRY数据 */ unsigned char vendor[9]; /* 厂商字符串 */ unsigned char model[17]; /* 型号字符串 */ unsigned char rev[5]; /* 修订版本 */

/* 设备类型 */ unsigned type:5; /* 设备类型(0x00=磁盘等) */ unsigned removable:1; /* 是否可移动 */ unsigned changed:1; /* 介质是否改变 */ unsigned busy:1; /* 设备是否忙 */ unsigned lockable:1; /* 是否可锁定 */ unsigned locked:1; /* 是否已锁定 */

/* 队列管理 */ unsigned queue_depth; /* 队列深度 */ unsigned short device_busy; /* 设备繁忙计数 */ struct scsi_target *sdev_target; /* 目标设备 */

/* 设备模型集成 */ struct device sdev_gendev; /* 通用设备结构 */ struct device sdev_dev; /* 类设备结构 */

/* 电源管理 */ struct list_head same_target_siblings; /* 同目标兄弟设备 */ struct list_head siblings; /* 兄弟设备列表 */

/* 异步事件 */ struct async_scan_data *async_scan_data; /* 异步扫描数据 */

/* 多路径 */ struct scsi_dh_data *scsi_dh_data; /* 设备处理器数据 */ }; 3.3 SCSI主机结构:

struct Scsi_Host

代表一个SCSI主机适配器(HBA):

struct Scsi_Host {

/* 主机适配器特性 */ struct module *hostt; /* 主机模板 */ unsigned int unique_id; /* 唯一标识符 */ unsigned int host_no; /* 主机号 */ unsigned int max_channel; /* 最大通道数 */ unsigned int max_id; /* 最大目标ID */ unsigned int max_lun; /* 最大LUN */

/* 命令处理 */ unsigned int can_queue; /* 最大命令数 */ unsigned int cmd_per_lun; /* 每LUN最大命令数 */ unsigned short sg_tablesize; /* 散点-聚集表大小 */ unsigned short max_sectors; /* 最大扇区数 */ unsigned long dma_boundary; /* DMA边界 */

/* 工作队列 */ struct workqueue_struct *work_q; /* 工作队列 */ char work_q_name[20]; /* 工作队列名称 */

/* 设备模型 */ struct device shost_dev; /* 主机设备结构 */ struct device shost_gendev; /* 通用主机设备 */

/* 链表管理 */ struct list_head __devices; /* 设备链表 */ struct list_head __targets; /* 目标设备链表 */

/* 主机模板操作 */ struct scsi_host_template *hostt; /* 主机模板 */

/* 私有数据 */ void *hostdata; /* 主机驱动私有数据 */ char hostdata[0] ____cacheline_aligned; /* 内联私有数据 */

/* 统计信息 */ unsigned int host_busy; /* 主机繁忙计数 */ unsigned int host_failed; /* 主机失败计数 */ unsigned int host_eh_scheduled; /* 错误处理调度计数 */

/* 锁 */ spinlock_t host_lock; /* 主机锁 */ struct mutex scan_mutex; /* 扫描互斥锁 */

/* 异步事件 */ struct list_head starved_list; /* 饥饿设备列表 */ unsigned int starved_list_len; /* 饥饿列表长度 */ }; 3.4 主机模板结构:

struct scsi_host_template

主机适配器驱动通过此模板注册:

struct scsi_host_template {

struct module *module; /* 所属模块 */ const char *name; /* 驱动名称 */

/* 探测和移除 */ int (*detect)(struct scsi_host_template *); /* 探测函数 */ int (*release)(struct Scsi_Host *); /* 释放函数 */

/* 命令处理 */ int (*queuecommand)(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); int (*eh_abort_handler)(struct scsi_cmnd *); /* 中止处理 */ int (*eh_device_reset_handler)(struct scsi_cmnd *); /* 设备重置 */ int (*eh_bus_reset_handler)(struct scsi_cmnd *); /* 总线重置 */ int (*eh_host_reset_handler)(struct scsi_cmnd *); /* 主机重置 */

/* 中断处理 */ irqreturn_t (*irq_handler)(int, void *); /* 中断处理程序 */

/* 同步点 */ int (*slave_configure)(struct scsi_device *); /* 从设备配置 */ int (*slave_destroy)(struct scsi_device *); /* 从设备销毁 */

/* 超时 */ int (*change_queue_depth)(struct scsi_device *, int); /* 改变队列深度 */

/* 杂项 */ unsigned int supported_mode:2; /* 支持模式 */ unsigned int unchecked_isa_dma:1; /* 无检查ISA DMA */ unsigned int use_clustering:1; /* 使用聚集 */ unsigned int emulated:1; /* 是否模拟 */

/* DMA */ unsigned int dma_boundary; /* DMA边界 */

/* 命令标志 */ unsigned int cmd_size; /* 命令结构大小 */ struct scsi_host_cmd_pool *cmd_pool; /* 命令池 */

/* 设备模型 */ char *proc_name; /* /proc名称 */ struct proc_dir_entry *proc_dir; /* /proc目录 */ }; 四、SCSI中间层:核心处理逻辑 4.1 命令提交流程

scsi_lib.c

处理从块层到SCSI层的命令转换:

static int scsi_setup_cmnd(struct scsi_device *sdev, struct request *req)

{ struct scsi_cmnd *cmd = req->special; int ret = BLKPREP_OK;

/* 1. 初始化命令 */ memset(cmd, 0, sizeof(*cmd));

/* 2. 设置设备指针 */ cmd->device = sdev;

/* 3. 构建CDB */ if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* 直通命令(sg) */ memcpy(cmd->cmnd, req->cmd, req->cmd_len); cmd->cmd_len = req->cmd_len; } else { /* 块设备请求,转换为SCSI命令 */ cmd->cmnd[0] = req->cmd[0]; if (req->cmd[0] == READ_10) cmd->cmnd[1] = 0; else if (req->cmd[0] == WRITE_10) cmd->cmnd[1] = 0;

/* 设置LBA和长度 */ put_unaligned_be32(blk_rq_pos(req), &cmd->cmnd[2]); put_unaligned_be16(blk_rq_sectors(req), &cmd->cmnd[7]); cmd->cmd_len = 10; }

/* 4. 设置数据缓冲区 */ if (rq_data_dir(req) == WRITE) { cmd->sc_data_direction = DMA_TO_DEVICE; } else { cmd->sc_data_direction = DMA_FROM_DEVICE; }

/* 5. 设置完成回调 */ cmd->done = scsi_done;

return ret; } 4.2 命令完成处理

void scsi_done(struct scsi_cmnd *cmd)

{ struct request *req = cmd->request; int result = cmd->result;

/* 1. 更新统计 */ cmd->device->device_busy--;

/* 2. 处理结果 */ if (result) { /* 错误处理 */ if (driver_byte(result) & DRIVER_SENSE) scsi_log_completion(cmd, SCAN_MEDIUM_ERROR); else scsi_log_completion(cmd, SCAN_HOST_BYTE_ERROR); }

/* 3. 调用请求完成回调 */ if (req->end_io) { req->end_io(req, result); } else { /* 默认完成处理 */ __blk_end_request_all(req, result); }

/* 4. 释放命令 */ scsi_release_buffers(cmd); scsi_free_sgtables(cmd); scsi_put_command(cmd); } 4.3 设备扫描

scsi_scan.c

负责发现和配置SCSI设备:

int scsi_scan_host(struct Scsi_Host *shost)

{ struct async_scan_data *data; int ret;

/* 1. 分配异步扫描数据 */ data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;

/* 2. 初始化异步扫描 */ init_completion(&data->prev_finished); data->shost = shost;

/* 3. 启动异步扫描线程 */ ret = async_schedule(scsi_scan_host_async, data); if (ret) { kfree(data); return ret; }

return 0; }

static void scsi_scan_host_async(void *data, async_cookie_t cookie) { struct async_scan_data *async_data = data; struct Scsi_Host *shost = async_data->shost; int id, channel;

/* 4. 扫描所有通道和目标 */ for (channel = 0; channel <= shost->max_channel; channel++) { for (id = 0; id <= shost->max_id; id++) { scsi_scan_target(&shost->shost_gendev, channel, id, SCAN_WILD_CARD, 1); } }

/* 5. 完成扫描 */ complete(&async_data->prev_finished); kfree(async_data); } 五、SCSI磁盘驱动:

sd.c

5.1 驱动初始化

static int __init init_sd(void)

{ int majors = 0, i, err;

/* 1. 为每个可能的SCSI磁盘分配主设备号 */ for (i = 0; i < SD_MAJORS; i++) { if (register_blkdev(sd_major(i), "sd") == 0) majors++; }

if (!majors) return -ENODEV;

/* 2. 注册SCSI驱动模板 */ err = scsi_register_driver(&sd_template.gendrv); if (err) goto err_out;

return 0;

err_out: while (--majors >= 0) unregister_blkdev(sd_major(majors), "sd"); return err; } 5.2 设备探测

static int sd_probe(struct device *dev)

{ struct scsi_device *sdp = to_scsi_device(dev); struct gendisk *gd; struct sd_disk *sdkp; int index; int error;

/* 1. 检查设备类型 */ if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD) return -ENODEV;

/* 2. 分配sd_disk结构 */ sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) return -ENOMEM;

/* 3. 分配gendisk结构 */ gd = alloc_disk(SD_MINORS); if (!gd) { error = -ENOMEM; goto out_free; }

/* 4. 初始化gendisk */ gd->major = sd_major(sdp->index); gd->first_minor = sdp->index * SD_MINORS; gd->minors = SD_MINORS; gd->fops = &sd_fops; gd->private_data = sdkp;

/* 5. 设置磁盘名 */ sprintf(gd->disk_name, "sd%c", 'a' + (sdp->index % 26));

/* 6. 初始化请求队列 */ gd->queue = sdp->request_queue; blk_queue_prep_rq(gd->queue, sd_prep_fn);

/* 7. 读取容量信息 */ error = sd_read_capacity(sdkp, sdp); if (error) goto out_put;

/* 8. 添加到系统 */ add_disk(gd);

/* 9. 保存反向指针 */ sdp->sdev_gendev.parent = get_device(dev); sdp->sdev_gendev.driver_data = sdkp;

return 0;

out_put: put_disk(gd); out_free: kfree(sdkp); return error; } 5.3 请求处理

static int sd_init_command(struct scsi_cmnd *cmd)

{ struct request *rq = cmd->request; struct scsi_device *sdp = cmd->device; u32 lba = blk_rq_pos(rq); u32 blocks = blk_rq_sectors(rq);

/* 1. 设置CDB */ if (blocks > 0xffff) { /* 使用16字节CDB */ cmd->cmnd[0] = (rq_data_dir(rq) == WRITE) ? WRITE_16 : READ_16; put_unaligned_be64(lba, &cmd->cmnd[2]); put_unaligned_be32(blocks, &cmd->cmnd[10]); cmd->cmd_len = 16; } else if (blocks > 0xff) { /* 使用10字节CDB */ cmd->cmnd[0] = (rq_data_dir(rq) == WRITE) ? WRITE_10 : READ_10; put_unaligned_be32(lba, &cmd->cmnd[2]); put_unaligned_be16(blocks, &cmd->cmnd[7]); cmd->cmd_len = 10; } else { /* 使用6字节CDB */ cmd->cmnd[0] = (rq_data_dir(rq) == WRITE) ? WRITE_6 : READ_6; cmd->cmnd[1] = (lba >> 16) & 0x1f; cmd->cmnd[2] = (lba >> 8) & 0xff; cmd->cmnd[3] = lba & 0xff; cmd->cmnd[4] = blocks; cmd->cmd_len = 6; }

/* 2. 设置数据方向 */ if (rq_data_dir(rq) == WRITE) cmd->sc_data_direction = DMA_TO_DEVICE; else cmd->sc_data_direction = DMA_FROM_DEVICE;

/* 3. 设置完成回调 */ cmd->done = sd_done;

return 0; } 六、错误处理与恢复 6.1 错误处理框架

scsi_error.c

实现复杂的错误恢复机制:

void scsi_eh_scmd_add(struct scsi_cmnd *scmd)

{ struct Scsi_Host *shost = scmd->device->host; unsigned long flags;

spin_lock_irqsave(shost->host_lock, flags);

if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) { /* 已计划中止,不重复添加 */ spin_unlock_irqrestore(shost->host_lock, flags); return; }

/* 标记命令需要错误处理 */ scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;

/* 添加到错误处理列表 */ list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->host_failed++;

spin_unlock_irqrestore(shost->host_lock, flags);

/* 调度错误处理 */ scsi_schedule_eh(shost); } 6.2 错误处理线程

static int scsi_error_handler(void *data)

{ struct Scsi_Host *shost = data;

/* 设置线程名称 */ daemonize("%s_eh", shost->hostt->name); allow_signal(SIGKILL);

while (true) { struct scsi_cmnd *scmd, *next; LIST_HEAD(work_q);

/* 1. 等待错误处理事件 */ wait_event_interruptible(shost->host_wait, shost->host_failed || kthread_should_stop());

if (kthread_should_stop()) break;

spin_lock_irq(shost->host_lock);

/* 2. 收集需要处理的命令 */ list_splice_init(&shost->eh_cmd_q, &work_q); shost->host_failed = 0; shost->host_eh_scheduled = 0;

spin_unlock_irq(shost->host_lock);

/* 3. 处理每个失败的命令 */ list_for_each_entry_safe(scmd, next, &work_q, eh_entry) { list_del_init(&scmd->eh_entry);

/* 执行错误恢复 */ scsi_eh_abort_cmnds(shost, &work_q, scmd); } }

return 0; } 6.3 命令中止

int scsi_abort_command(struct scsi_cmnd *scmd)

{ struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; unsigned long timeout; int rtn;

/* 1. 调用主机适配器的中止处理程序 */ if (!shost->hostt->eh_abort_handler) return FAILED;

/* 2. 执行中止 */ rtn = shost->hostt->eh_abort_handler(scmd);

if (rtn == SUCCESS) { /* 等待命令完成 */ timeout = jiffies + shost->eh_abort_timeout; while (time_before(jiffies, timeout)) { if (!scsi_cmd_is_active(scmd)) return SUCCESS; msleep(1); } }

return FAILED; } 七、主机适配器驱动示例:QLogic光纤通道 7.1 驱动初始化

static int __init qla2x00_module_init(void)

{ int ret;

/* 1. 注册PCI驱动 */ ret = pci_register_driver(&qla2x00_pci_driver); if (ret) { printk(KERN_WARNING "qla2xxx: PCI driver registration failed: %d\n", ret); return ret; }

/* 2. 创建调试文件系统 */ qla2x00_create_debugfs_root();

/* 3. 初始化全局锁 */ spin_lock_init(&qla2x00_global_lock);

return 0; } 7.2 命令队列

static int qla2x00_queuecommand(struct scsi_cmnd *cmd,

void (*done)(struct scsi_cmnd *)) { srb_t *sp; fc_port_t *fcport; int rval;

/* 1. 分配SRB(SCSI Request Block) */ sp = qla2x00_get_sp(cmd->device->host, cmd, done); if (!sp) return SCSI_MLQUEUE_HOST_BUSY;

/* 2. 获取FC端口 */ fcport = (fc_port_t *)cmd->device->hostdata;

/* 3. 构建FCP命令 */ rval = qla2x00_build_scsi_cmd(sp, fcport); if (rval != QLA_SUCCESS) { qla2x00_rel_sp(sp); return SCSI_MLQUEUE_HOST_BUSY; }

/* 4. 提交到硬件队列 */ rval = qla2x00_start_scsi(sp); if (rval != QLA_SUCCESS) { qla2x00_rel_sp(sp); cmd->result = DID_ERROR << 16; done(cmd); return 0; }

return 0; } 7.3 中断处理

static irqreturn_t qla2x00_intr_handler(int irq, void *dev_id)

{ struct qla_hw_data *ha = dev_id; uint32_t stat;

/* 1. 读取中断状态 */ stat = RD_REG_DWORD(&ha->iobase->istatus);

/* 2. 检查是否为本适配器中断 */ if (!(stat & ISP_INTERRUPT_MASK)) return IRQ_NONE;

/* 3. 处理响应队列 */ if (stat & RISC_INT) { if (ha->flags.fw_dump_reading) qla2x00_fw_dump(ha); else qla2x00_process_response_queue(ha); }

/* 4. 处理完成队列 */ if (stat & MBX_INTERRUPT) { qla2x00_mbx_completion(ha, MS_MASK); }

return IRQ_HANDLED; } 八、2.6内核SCSI子系统的演进 8.1 相对于2.4的架构改进 特性2.4内核2.6内核 设备模型集成​基本集成深度集成,完善的sysfs支持错误处理​相对简单完善的错误恢复框架(SCSI EH)多路径支持​有限支持设备处理器框架,支持ALUA等传输层支持​并行SCSI为主FC、iSCSI、SAS完整支持性能优化​基本队列标记命令队列(TCQ),优化调度电源管理​基本支持完善的电源管理框架热插拔​有限支持完整的热插拔支持 8.2 关键技术创新 SCSI中间层成熟 :清晰的上下层分离,提高代码重用性 统一的错误处理 :标准化错误恢复流程,提高系统可靠性 多路径I/O框架 :支持存储高可用性和负载均衡 传输抽象层 :支持多种物理传输(FC、iSCSI、SAS) 设备处理器框架 :可插拔的设备特定处理模块 异步扫描 :加速大型存储系统的设备发现 8.3 性能优化 命令聚集 :合并小的I/O请求,提高吞吐量 标记命令队列 :支持设备端的命令重新排序 中断合并 :减少中断频率,提高CPU效率 DMA映射优化 :支持64位寻址,提高大内存系统性能 缓存优化 :优化数据结构布局,提高缓存命中率 九、总结:企业级存储的软件基石

drivers/scsi/

目录是Linux内核 企业级存储能力 的核心体现。

它将复杂的存储硬件、多样的传输协议、复杂的错误处理,通过分层的软件架构统一管理。

在2.6版本中,这个子系统完成了从"功能实现"到"企业级可靠"的关键演进。

SCSI子系统的设计体现了几个核心工程原则: 严格分层 :硬件细节隐藏在HBA驱动中,SCSI协议处理在中间层,块设备接口在上层 错误隔离 :完善的错误处理框架,防止单个设备故障影响整个系统 性能与可靠性平衡 :在追求高性能的同时,不牺牲数据完整性 硬件抽象 :统一的接口支持多种存储技术和厂商设备 可扩展性 :模块化设计支持新硬件和新协议 通过分析

drivers/scsi/

,我们看到的不仅是存储驱动的实现,更是 企业级存储系统的设计哲学 。

它为Linux在数据中心、云计算、高性能计算等领域的存储应用提供了坚实基础,是现代操作系统存储子系统的典范之作。

相关文章