3108 raid卡驅動路徑在drivers/scsi/megaraid。其入口函式在megaraid_sas_base.c中megasas_init。
從megasas_init中可以看到首先註冊了乙個字元裝置,用於從user space控制raid卡
/* * register character device node
*/rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
if (rval < 0)
其次會註冊乙個pci driver
/* * register ourselves as pci hotplug module
*/rval = pci_register_driver(&megasas_pci_driver);
if (rval)
最終會呼叫這個pci裝置的probe函式megasas_probe_one
在megasas_probe_one 中會呼叫會這個pcie裝置做一些初始化,然後會呼叫megasas_io_attach 來向scsi mid-layer註冊host
/* * register with scsi mid-layer
*/if (megasas_io_attach(instance))
goto fail_io_attach;
megasas_io_attach 原始碼如下:
static int megasas_io_attach(struct megasas_instance *instance)
return 0;
}呼叫scsi_add_host 新增host後就呼叫
* trigger scsi to scan our drives
*/scsi_scan_host(host);
來scan。
所以對kernel來說3108 raid卡就是乙個硬碟的控制器
其次在3108 驅動中通過一定的格式和fw通訊
3108總共支援的命令如下:
/* * mfi command opcodes
*/#define mfi_cmd_init 0x00
#define mfi_cmd_ld_read 0x01
#define mfi_cmd_ld_write 0x02
#define mfi_cmd_ld_scsi_io 0x03
#define mfi_cmd_pd_scsi_io 0x04
#define mfi_cmd_dcmd 0x05
#define mfi_cmd_abort 0x06
#define mfi_cmd_smp 0x07
#define mfi_cmd_stp 0x08
#define mfi_cmd_invalid 0xff
這裡以傳送mfi_cmd_dcmd命令且運算元為mr_dcmd_ld_list_query為例
static int
megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
dcmd = &cmd->frame->dcmd;
ci = pci_alloc_consistent(instance->pdev,
sizeof(struct mr_ld_targetid_list), &ci_h);
if (!ci)
memset(ci, 0, sizeof(*ci));
memset(dcmd->mbox.b, 0, mfi_mbox_size);
dcmd->mbox.b[0] = query_type;
if (instance->supportmax256vd)
dcmd->mbox.b[2] = 1;
//初始化需要傳送的命令
dcmd->cmd = mfi_cmd_dcmd;
dcmd->cmd_status = mfi_stat_invalid_status;
dcmd->sge_count = 1;
dcmd->flags = cpu_to_le16(mfi_frame_dir_read);
dcmd->timeout = 0;
dcmd->data_xfer_len = cpu_to_le32(sizeof(struct mr_ld_targetid_list));
dcmd->opcode = cpu_to_le32(mr_dcmd_ld_list_query);
dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct mr_ld_targetid_list));
dcmd->pad_0 = 0;
//傳送命令有兩種,一種是呼叫megasas_issue_blocked_cmd 這個函式會採用等待佇列得到fw對這個命令的回饋,期間這個程序可能會sleep,另外一種是megasas_issue_polled 會一直poll,直到結果返回
if (instance->ctrl_context && !instance->mask_interrupts)
ret = megasas_issue_blocked_cmd(instance, cmd, mfi_io_timeout_secs);
else
ret = megasas_issue_polled(instance, cmd);
下面這個switch 是執行命令反饋的結果,有三種,dcmd_failed/dcmd_timeout/dcmd_success ,正常case應該是dcmd_success
switch (ret)
break;
case dcmd_success:
tgtid_count = le32_to_cpu(ci->count);
if ((tgtid_count > (instance->fw_supported_vd_count)))
break;
memset(instance->ld_ids, 0xff, megasas_max_ld_ids);
for (ld_index = 0; ld_index < tgtid_count; ld_index++)
break;
} pci_free_consistent(instance->pdev, sizeof(struct mr_ld_targetid_list),
ci, ci_h);
//執行結果是ok的話,需要將之前申請的cmd返回。
if (ret != dcmd_timeout)
megasas_return_cmd(instance, cmd);
return ret;
}每次3108在傳送命令前都會通過megasas_get_cmd得到乙個空閒的命令
struct megasas_cmd *megasas_get_cmd(struct megasas_instance
*instance)
else
spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
return cmd;
}可以知道掛在instance->cmd_pool 這個pool上的cmd都是空閒的,如果要人要用的話,就從instance->cmd_pool 中找到地乙個空閒的,並從instance->cmd_pool 中刪掉
與之對應的就是執行完成命令後將cmd返回到instance->cmd_pool這個list中
void
megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
cmd->scmd = null;
cmd->frame_count = 0;
cmd->flags = 0;
memset(cmd->frame, 0, instance->mfi_frame_size);
cmd->frame->io.context = cpu_to_le32(cmd->index);
if (!fusion && reset_devices)
cmd->frame->hdr.cmd = mfi_cmd_invalid;
list_add(&cmd->list, (&instance->cmd_pool)->next);
spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
}
你知道RAID的初始化過程嗎
raid 系統是用來對儲存資料進行資料保護的有效手段。在 raid 建立過程中往往會存在乙個時間極長的系統初始化過程,為什麼 raid 初始化過程中會存在這樣的乙個操作呢?這個操作對 ssd會導致什麼方面的影響呢?儲存老吳從技術研發的角度和大家一起對 raid 初始化過程進行分析 研究。傳統raid...
初始化 指定初始化
id alloc 物件的誕生過程,主要是從作業系統獲得一塊足夠大的記憶體,以存放該類的全部例項變數,並將其指定為存放記憶體物件的實力變數的位置。alloc方法同時將這塊記憶體全部設定為0。結果是 bool變數初始化為no,所有的int型別變數為0,float變數為0.0,所有的指標為nil.obje...
初始化 1 預設初始化 列表初始化
初始化的基本概念 事實 初始化和賦值是兩個完全不同的操作。初始化,是建立變數時賦予其乙個初始值。賦值,是把物件的當前值擦除,用乙個新值代替。列表初始化 p39 作為c 11新標準的一部分,用花括號 來初始化變數得到了全面應用。出於某些原因,這種初始化的方式叫做列表初始化。現在,無論是初始化物件還是某...