raid 3108 的初始化

2021-08-07 05:31:58 字數 4328 閱讀 2966

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新標準的一部分,用花括號 來初始化變數得到了全面應用。出於某些原因,這種初始化的方式叫做列表初始化。現在,無論是初始化物件還是某...