2014年5月13日 星期二

在 Fedora 18 (3.11.10) 安裝 RocketRAID 2220 的驅動程式

使用 HighPoint RocketRAID 2220 這張 RAID 卡,覺得 C/P 值不錯。可惜的是,Linux 原生支援的驅動程式,並不能正常啟用 RAID 加速晶片,只能當一張多埠的 SATA 擴充卡來用。為了讓這張 RAID 卡發揮功能,只好從網路上遍尋一些直接、間接的高人異士修改的『驅動原始碼』。
  之前幾篇有關 2220 驅動程式的相關發文:
在 Fedora 18 的 Linux 的核心更新到 3.10 之後,便不能用了。雖然有心想要嘗試修改『驅動原始碼』,可是一直抽不出時間來研究它,只好一直勉強將 kernel 留在 3.9 版,不敢更新。
  最近發現在網路上發現了高手修改的例子,它是給 2320 用的,既然有得參考,修改起來將事半功倍,就試試看吧!
    本文內容將包含:驅動程式原始碼的修改、Fedora 18 首次安裝、核心更新後驅動程式的編譯三大部份。

一、安裝前的準備工作

官方網站下載原始碼(在各型號的『驅動程式下載』中,標示為『Linux Opensource』),編譯時並不需要 root 權限,用一般用戶帳號即可。下載後解壓縮,以 R2220 為例,
[SiB@Celeron-D ~]$ tar zxf rr222x-linux-src-v1.9-090924-1445.tar.gz
會在 SiB 的家目錄下產生一個新目錄『 ~/rr222x-linux-src-v1.9 』(:後續文章以『原始碼目錄』稱之),參考 Nagilum 的「修補檔」,這是 RocketRAID 2320 的「修補檔」不能直接用來修改 RocketRAID 2220,筆者參考後,再修改 RocketRAID 2220 所用的原始碼。
    為留存完整記錄,將修改處整理在後,避免將來網路下載不到修補檔。整理出的修改如下:(以 RocketRAID 2220 為例)
目錄檔案名修改處的列號(反序列出)
原始碼目錄/inc/linux/Makefile.def77~89
原始碼目錄/osm/linux/install.sh13~16
原始碼目錄/osm/linux/os_linux.c262~266, 210~211, 199~204
原始碼目錄/osm/linux/osm_linux.h11~13
原始碼目錄/osm/linux/osm_linux.c2100~2105, 1793~1801, 1411, 878, 477~481, 447~452
上表中修改處的數字為列數。因為檔案前面的修改都會加入文字,影響之後的列數,故由程式後端開始修改。

⑴ 檔案『原始碼目錄/inc/linux/Makefile.def』的修改

第 77 ~ 89 列,原文
KERNEL_VER := 2.$(shell expr `grep LINUX_VERSION_CODE $(KERNELDIR)/include/linux/version.h | cut -d\  -f3` / 256 % 256)

ifeq ($(KERNEL_VER),)
$(error Cannot find kernel version. Check $(KERNELDIR)/include/linux/version.h.)
endif

ifneq ($(KERNEL_VER), 2.6)
ifneq ($(KERNEL_VER), 2.4)
$(error Only kernel 2.4/2.6 is supported but you use $(KERNEL_VER))
endif
endif

ifeq ($(KERNEL_VER), 2.6)
修改為
VERS_HDR :=$(shell ls $(KERNELDIR)/include/linux/version.h $(KERNELDIR)/include/generated/uapi/linux/version.h 2>/dev/null|head -1)

KERNEL_VER := $(shell expr `grep LINUX_VERSION_CODE $(VERS_HDR)| cut -d\  -f3` / 256 / 256).$(shell expr `grep LINUX_VERSION_CODE $(VERS_HDR) | cut -d\  -f3` / 256 % 256)

ifeq ($(KERNEL_VER),)
$(error Cannot find kernel version. Check $(VERS_HDR).)
endif

KERNTWOFOUR := $(shell expr $(KERNEL_VER) \>= 2.4)
KERNTWOSIX := $(shell expr $(KERNEL_VER) \>= 2.6)
ifeq ($(KERNTWOFOUR), 1)
else
$(error Only kernel 2.4/2.6/3.x is supported but you use $(KERNEL_VER))
endif

ifeq ($(KERNTWOSIX), 1)
完成以上修改後,存檔備用。

⑵ 檔案『原始碼目錄/osm/linux/install.sh』的修改

第 13 ~ 16 列,原文
    2.6 )
    OBJ=ko
    MODVER=`modinfo -F vermagic ${PWD}/${TARGETNAME}.${OBJ} | cut -d' ' -f1`
    ;;
修改為
    2.6 )
    OBJ=ko
    MODVER=`modinfo -F vermagic ${PWD}/${TARGETNAME}.${OBJ} | cut -d' ' -f1`
    ;;
    3.* )
    OBJ=ko
    MODVER=`modinfo -F vermagic ${PWD}/${TARGETNAME}.${OBJ} | cut -d' ' -f1`
    ;;
完成以上修改後,存檔備用。

 檔案『原始碼目錄/osm/linux/os_linux.c』的修改(由後而前)

第 262 ~ 266 列,原文
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
    blkdev_get(bdev, FMODE_READ)
#else 
    blkdev_get(bdev, FMODE_READ, 0 __BDEV_RAW)
#endif
修改為
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
    blkdev_get(bdev, FMODE_READ, NULL)
#else 
    blkdev_get(bdev, FMODE_READ)
#endif
#else 
    blkdev_get(bdev, FMODE_READ, 0 __BDEV_RAW)
#endif
第 210 ~ 211 列,原文
    if ((HPT_UPTR)ptr >= (HPT_UPTR)high_memory)
        kunmap_atomic(ptr, HPT_KMAP_TYPE);
修改為
    if ((HPT_UPTR)ptr >= (HPT_UPTR)high_memory)
        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
        kunmap_atomic(ptr);
        #else
        kunmap_atomic(ptr, HPT_KMAP_TYPE);
        #endif
第 199 ~ 204 列,原文
    if (page)
        return (PageHighMem(page)?
                    (char *)kmap_atomic(page, HPT_KMAP_TYPE) :
                    (char *)page_address(page))
                + (psg->addr.bus & 0xffffffff);
    else
修改為
    if (page)
        return (PageHighMem(page)?
                    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
                    (char *)kmap_atomic(page) :
                    #else
                    (char *)kmap_atomic(page, HPT_KMAP_TYPE) :
                    #endif
                    (char *)page_address(page))
                + (psg->addr.bus & 0xffffffff);
    else
完成以上修改後,存檔備用。

 檔案『原始碼目錄/osm/linux/osm_linux.h』的修改

第 11 ~ 13 列,原文,將這幾列文字刪除
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
或註解掉
//#ifndef AUTOCONF_INCLUDED
//#include <linux/config.h>
//#endif 
完成以上修改後,存檔備用。

 檔案『原始碼目錄/osm/linux/osm_linux.c』的修改(由後而前)

第 2100 ~ 2105 列,原文
#else /* 2.6.x */
    proc_name:               driver_name,
    proc_info:               hpt_proc_info26,
    max_sectors:             128,
#endif
    this_id:                 -1
修改為
#else /* 2.6.x */
    proc_name:               driver_name,
    #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) /* 3.10.x */
    proc_info:               hpt_proc_info26,
    #else
    write_info:              hpt_proc_info26,
    #endif
    max_sectors:             128,
#endif
    this_id:                 -1
第 1793 ~ 1801 列,原文
static int hpt_proc_info26(struct Scsi_Host *host, char *buffer, char **start,
     off_t offset, int length, int inout)
{

    if (inout)
        return hpt_proc_set_info(host, buffer, length);
    else
        return hpt_proc_get_info(host, buffer, start, offset, length);
}
修改為
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
static int hpt_proc_info26(struct Scsi_Host *host, char *buffer, char **start,
     off_t offset, int length, int inout)
{

    if (inout)
        return hpt_proc_set_info(host, buffer, length);
    else
        return hpt_proc_get_info(host, buffer, start, offset, length);
}
#else
static int hpt_proc_info26(struct Scsi_Host *host, char *buffer, int length)
{
    return hpt_proc_set_info(host, buffer, length);
}
#endif
第 1411 列,原文為空白列,在這裏要加入這 5 列文字
#ifdef DEF_SCSI_QCMD
DEF_SCSI_QCMD(hpt_queuecommand)
#else
#define hpt_queuecommand hpt_queuecommand_lck
#endif
第 878 列,原文
static int hpt_queuecommand (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
修改為
static int hpt_queuecommand_lck (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
第 477 ~ 481 列,原文
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
    struct scatterlist *sg;
    sg = scsi_sglist(cmd);
    kunmap_atomic((char *)buf - sg->offset, HPT_KMAP_TYPE);
#else
修改為
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
    struct scatterlist *sg;
    sg = scsi_sglist(cmd);
    /* 1-argument form of k[un]map_atomic was introduced in 2.6.37-rc1;
       2-argument form was deprecated in 3.4-rc1 */
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
    kunmap_atomic((char *)buf - sg->offset);
    #else
    kunmap_atomic((char *)buf - sg->offset, HPT_KMAP_TYPE);
    #endif
#else
第 447 ~ 452 列,原文
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
    struct scatterlist *sg;
    sg = scsi_sglist(cmd);
    *pbuf = kmap_atomic(HPT_SG_PAGE(sg), HPT_KMAP_TYPE) + sg->offset;
    buflen = sg->length;
#else
修改為
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
    struct scatterlist *sg;
    sg = scsi_sglist(cmd);
    /* 1-argument form of k[un]map_atomic was introduced in 2.6.37-rc1;
       2-argument form was deprecated in 3.4-rc1 */
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
    *pbuf = kmap_atomic(HPT_SG_PAGE(sg)) + sg->offset;
    #else
    *pbuf = kmap_atomic(HPT_SG_PAGE(sg), HPT_KMAP_TYPE) + sg->offset;
    #endif
    buflen = sg->length;
#else
完成以上修改後,存檔備用。

 編譯「驅動程式的核心模組」

以編譯 kernel 3.6.10-4 (註:Fedora 18 初始安裝的核心版本)為例,編譯的命令為
[SiB@Celeron-D ~]$ cd ~/rr222x-linux-src-v1.9/product/rr2220/linux/
[SiB@Celeron-D linux]$ make KERNELDIR=/lib/modules/3.6.10-4.fc18.i686/build/ KERNEL_VER=3.6
就可以在 ~/rr222x-linux-src-v1.9/product/rr2220/linux/ 這個目錄得到一個 hptmv6.ko 的『驅動程式核心模組』。相關的詳細操作,請參考以前的發文:
如果是要編譯用來安裝 Fedora 18 之用,就要用另一台電腦或虛擬機器編譯這個「核心模組」。本文以『整個 Fedora 系統都安裝在 RocketRAID 2220 的硬碟組』為主,故編譯好的『核心模組』複製到以 “適用 Fedora 18 的「可選版本 USB 安裝隨身碟」”製做成的 USB 隨身碟中的 FedoraUISO 根目錄中,待會安裝時要使用。

:如果是將 RAID 做為資料碟而非系統碟,整個操作會更簡單。

二、開始安裝

插入『Fedora 18 的可選版本 USB 安裝隨身碟』,設定 BIOS 由 USB 啟動。在『開機選單倒數計時』結束前,
在『Install Fedora』選項按【Tab】鍵,在啟動命令列最後,加入參數『modprobe.blacklist=sata_mv』抑制 stat_mv 這個驅動程式的載入(註:這個 Linux 偵測到的硬體,若載入它則系統會無『硬體加速的 RAID』之功能,只有多幾個硬碟而已 )。接著,在『安裝語言選擇』視窗出現時,先暫停一下,

載入驅動程式的「核心模組」

為載入 RocketRAID 的正確「核心模組」,要同時按下 [Alt]-[Ctrl]-[F2] 三個鍵,切換到「主控台(Console)」,將隨身碟掛載到一個臨時性目錄,用命令『modprobe hptmv6』或『insmod hptmv6.ko』將核心模組載入。
mkdir /tmp/dd
mount /dev/sda2 /tmp/dd
insmod /tmp/dd/hptmv6.ko
若成功載入,當切換到第四「終端機」(同時按 [Alt]-[Ctrl]-[F4] 可切換過去)時,可以看到系統偵測到 RocketRAID 的訊息。
    同時按 [Alt]-[Ctrl]-[F6] 三個鍵,將畫面切換回原安裝圖形畫面,選「中文(臺灣)」,除安裝時為中文介面外,安裝後整個系統也是中文。接著,按【Next】鈕繼續平常的安裝步驟。

:上例是筆者安裝時,Fedora 系統所偵測到的 USB 隨身碟編號(/dev/sdx 表示第 x 個硬碟,而 2 是第二個分割區),讀者如果在 mount 命令執行後,用『ls /tmp/dd』看不到 hptmv6.ko 這個核心模組,就要換個硬碟編號試試。

三、安裝好 Fedora 後,重新開機之前的操作

安裝好 Fedora 後,重新開機之前
  1. 當 Fedora 系統安裝完後,在重開機前會停在一個有【重新開機】或【Reboot】按鈕的畫面。別急著按下去!
  2. 同時按【Alt + Ctrl + F2】三個鍵,切換至「終端機」,開始接下來安裝驅動程式的核心模組的操作。
  3. 待會要切換到新系統做些操作,要先複製隨身碟中的驅動程式之核心模組到新系統的 tmp 目錄中,以方便切換根目錄後還能找到這個核心模組。
    [anaconda root@localhost ~]# cp hptmv6.ko /mnt/sysimage/tmp/
    其中『 /mnt/sysimage/ 』是新安裝作業系統的根目錄,而『 /mnt/sysimage/tmp/ 』則是新系統的命令中的暫時目錄 /tmp。hptmv6.ko 是 RR2220 的核心模組。
切換到新系統的根目錄,進行核心模組安裝
  1. 這個操作有些複雜,請小心操作。新安裝的系統的根目錄在『 /mnt/sysimage 』,因為驅動程式是要裝在新系統上,所以要將目前檔案的根目錄切換過去,
    [anaconda root@localhost ~]# chroot /mnt/sysimage/
    
    接下來的操作,就會作用在新系統上。
  2. 抑制系統載入程式使用『 sata_mv.ko 』這個模組,它會測試到 RocketRAID 所用的晶片,並載入系統執行,但是又不支援 RocketRAID 的 RAID 功能,導致其不能正常運作。要抑制『 sata_mv.ko 』這個模組的載入,有兩個作法:
    [anaconda root@localhost ~]# echo "blacklist sata_mv" >> /etc/modprobe.d/blacklist.conf
    
    將『 sata_mv.ko 』列入開機載入模組的測試「黑名單」。或是直接刪除『 sata_mv.ko 』這個模組,
    [anaconda root@localhost ~]# rm -f /lib/modules/3.6.10-4.fc18.x86_64/kernel/drivers/ata/sata_mv.ko
    
    其中,3.6.10-4.fc18.x86_64 是 Fedora 18 DVD 中 Linux 核心的編號。

    注意:如果用直接刪除,則每次更新 Linux 核心後,都要刪除一次。
  3. 複製暫時目錄 /tmp 中的驅動程式核心模組到新系統的驅動程式目錄中
    [anaconda root@localhost ~]# cp /tmp/hptmv6.ko /lib/modules/3.6.10-4.fc18.x86_64/kernel/drivers/ata/
    命令中的 hptmv6.ko 是 RR2220 的核心模組。
  4. 準備建立開機載入 ramdisk 的映像檔,先檢查各模組的相依性,
    [anaconda root@localhost ~]# depmod -a 3.6.10-4.fc18.x86_64
    做為重新建立開機載入 ramdisk 的映像檔之用。
  5. 接著,建立載入 ramdisk 的映像檔的命令為
    [anaconda root@localhost ~]# dracut --add-drivers hptmv6 --omit-drivers sata_mv /boot/initramfs-3.6.10-4.fc18.x86_64.img 3.6.10-4.fc18.x86_64
    命令中的 hptmv6.ko 是 RR2220 的核心模組,而『--omit-drivers sata_mv』這個參數要強制令 dracut 不將 stat_mv 置入 ramdisk。
注意一:建立 ramdisk 映像檔命令中的『--omit-drivers sata_mv』,如果是將整個系統都裝在 RocketRAID 2220 的 RAID 模組中時,一定要加入。不然,因系統啟動時,在『/tmp/modprobe.d/blacklist.conf』中的『blacklist stat_mv』這的抑制參數尚不能讀取,所以仍會被載入。
注意二:如果忘了加『--omit-drivers sata_mv』這個參數,就要在系統的啟動命令(在 /boot/grub2/grub.conf 中)加上『modprobe.blacklist=sata_mv』。

切換回原安裝過程,進行最後的安裝操作
  1. 在「終端機」中鍵入命令『 exit 』,將根目錄切換回原安裝過程。

    注意:如果不能確定自已目前的根目錄在哪個系統,可以用命令『 ls /mnt 』測試一下,如果有其它目錄在其下,這時你應該已經回到『原安裝過程』中;如果沒有任何目錄,那就是還在『新系統」中。
      
  2. 同時按【Alt + Ctrl + F6】三個鍵,將畫面切換回原安裝圖形畫面,按【重新開機】或【Reboot】按鈕繼續安裝步驟,應該是重新開機了。
  3. 重新開機後,依一般安裝過程設定,可以先使用新系統,不要急著更新,看完下一段文章後,再進行更新。

五、舊系統或系統更新後,加裝驅動程式的核心模組

因為驅動程式的核心模組是用 HighPoint 提供的「開源碼驅動程式」編譯而得,因此每次只要 Linux 核心更新,這個核心模組就要再編譯一次。所幸,Linux 核心更新後,編譯驅動程式核心模組的過程比較簡單。
    假定更新後的 Linux 核心為 3.11.10-101.fc18.x86_64,而從 HighPoint 下載的「開源碼驅動程式」,將其解壓縮後的目錄在 root 之下,則所需的命令如下:
[root@Celeron-D ~]# cd ~/rr222x-linux-src-v1.9/product/rr2220/linux/
[root@Celeron-D linux]# make KERNELDIR=/lib/modules/3.11.10-101.fc18.x86_64/build/ KERNEL_VER=2.6
[root@Celeron-D linux]# cp hptmv6.ko /lib/modules/3.11.10-101.fc18.x86_64/kernel/drivers/ata/
[root@Celeron-D linux]# depmod -a 3.11.10-101.fc18.x86_64
[root@Celeron-D linux]# mv /boot/initramfs-3.11.10-101.fc18.x86_64.img /boot/initramfs-3.11.10-101.fc18.x86_64.img.save
[root@Celeron-D linux]# dracut --add-drivers hptmv6 --omit-drivers sata_mv /boot/initramfs-3.11.10-101.fc18.x86_64.img 3.11.10-101.fc18.x86_64
其中,『 mv ... 』那一列命令是將原來之映像檔換個檔名,做個備份。其他命令與文章前段相同,請參考前面說明。做個『懶人包』方便讀者剪貼使用:
cd ~/rr222x-linux-src-v1.9/product/rr2220/linux/
make KERNELDIR=/lib/modules/3.11.10-101.fc18.x86_64/build/ KERNEL_VER=2.6
cp hptmv6.ko /lib/modules/3.11.10-101.fc18.x86_64/kernel/drivers/ata/
depmod -a 3.11.10-101.fc18.x86_64
mv /boot/initramfs-3.11.10-101.fc18.x86_64.img /boot/initramfs-3.11.10-101.fc18.x86_64.img.save
dracut --add-drivers hptmv6 --omit-drivers sata_mv /boot/initramfs-3.11.10-101.fc18.x86_64.img 3.11.10-101.fc18.x86_64
接著,就可以重新開機,測試新系統了。

六、其它安裝時的經驗

如果整個 RAID 硬碟模組的總容量大於 2TB 以上,用一般的 MBR 分割硬碟會失敗,或效能變得很差。而 Fedora 18 在安裝時,用 GPT 分割碟碟又不太方便,有些網路的解決辦法是先用別的將 RAID 碟碟模組掛到別的系統去分割。筆者也有試過,試了幾次都沒安裝成功,最後用了一個比較偷懶的辦法。這個辦法就是:
在安裝 Fedora 18 時,在分割硬碟這個步驟時,使用系統『自動分割碟碟』功能。這個功能會將硬碟分割為:『/boot』:500MB,『swap』:約是記憶體的兩倍(當記憶體超過 4GB 以上時,會降低倍數),『/root」:50GB,而其它容量全部切到『/home』這個分割。
反正安裝時的分割又不常做,而且 Linux 系統的『/root』分割如果不足,可以將某些目錄用『鏈結(link)』的方式使用『/home』這個分割的空間。

七、待改進之處

這個修改步驟,只能令 RocketRAID 2220 版的驅動程式能啟用 RAID 加速功能,而 RocketRAID 2220 的管理程式(包含『命令列介面』版),都無法正確偵測到 RAID 卡資訊,也就不能管理了。
  筆者的做法是保留 kernel 3.9.11-200,當要執行管理功能(硬碟檢測、更換硬碟等)時,在開機時選用 3.9 這一版本;而其它用途時,則使用最新版本的 Linux 核心。

已測試版本:

  • Fedora: 18 (kernel 3.11.10-101)
  • HighPoint RocketRAID: 2220

參考資料:

沒有留言:

張貼留言

感謝你耐心看完本文,歡迎留下任何指正、建議,筆者會儘快回應。(English is also welcome.)