Linux下的SCSI設備都是按照設備的發現順序命名的,對於磁盤盤符名稱就是sda,sdb,sdc等等。存儲設備一般都配有很多塊磁盤,盤符名稱和槽位號沒有對應關係,當磁盤插入,拔出時對應的盤符可能會變化。這給使用和運維帶來很多不便。
對於SCSI磁盤可通過修改sd_mod模塊中的sd_probe(drivers/scsi/sd.c)來完成“磁盤槽位和盤符”的綁定。
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
* for each scsi device (not just disks) present.
* @dev: pointer to device object
*
* Returns 0 if successful (or not interested in this scsi device
* (e.g. scanner)); 1 when there is an error.
*
* Note: this function is invoked from the scsi mid-level.
* This function sets up the mapping between a given
* <host,channel,id,lun> (found in sdp) and new device name
* (e.g. /dev/sda). More precisely it is the block device major
* and minor number that is chosen here.
*
* Assume sd_attach is not re-entrant (for time being)
* Also think about sd_attach() and sd_remove() running coincidentally.
**/
static int sd_probe(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp;
struct gendisk *gd;
u32 index;
int error;
error = -ENODEV;
if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC)
goto out;
SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp,
"sd_attach\n"));
error = -ENOMEM;
sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL);
if (!sdkp)
goto out;
gd = alloc_disk(SD_MINORS);
if (!gd)
goto out_free;
do {
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
goto out_put;
spin_lock(&sd_index_lock);
error = ida_get_new(&sd_index_ida, &index);
spin_unlock(&sd_index_lock);
} while (error == -EAGAIN);
if (error)
goto out_put;
if (index >= SD_MAX_DISKS) {
error = -ENODEV;
sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name space exhausted.\n");
goto out_free_index;
}
error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
if (error)
goto out_free_index;
sdkp->device = sdp;
sdkp->driver = &sd_template;
sdkp->disk = gd;
sdkp->index = index;
sdkp->openers = 0;
sdkp->previous_state = 1;
......
}
具體負責給gendisk分配磁盤名稱的就是 sd_format_disk_name,而決定磁盤名稱的index這個參數。index通過ida_get_new(include/linux/idr.h)獲取。ida是基於idr(底層是radix tree)實現的id分配器。從ida分配的index會被賦值給scsi_disk(drivers/scsi/sd.h)中的index,這個域作爲SCSI磁盤的索引,系統內唯一,不僅確定了設備名而且確定了設備的主設備號和次設備號(關於scsi_disk->index如何確定設備號可參見sd_probe_async)。爲了完成槽位和盤符綁定我們需要一個磁盤槽位和index的對應關係,這個對應關係可以根據系統中的一些不變量,如磁盤控制器的SCSI host號(系統範圍內唯一編號,用於標識這個主機適配器)來確定。Linux系統中SATA磁盤控制器上的每個磁盤都會被映射到一個單獨的SCSI host,對於只使用SATA控制器的陣列而言,可以採用如下方式綁定磁盤槽位和盤符。
以下是筆者根據scsi host(針對某款特定主板)確定SATA磁盤盤符對應關係的Patch:
將sd_probe中ida_get_new替換爲ida_get_new_above,這樣每次分配的index == host_no。
do {
if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
goto out_put;
host_no = sdp->host->host_no;
spin_lock(&sd_index_lock);
//error = ida_get_new(&sd_index_ida, &index);
error = ida_get_new_above(&sd_index_ida, host_no, &index);
spin_unlock(&sd_index_lock);
} while (error == -EAGAIN);
轉載請註明出處:http://blog.csdn.net/lkkey80/article/details/50263083