如何修改linux内核以强制sda始终为sata磁盘?

时间:2019-11-17 07:56:05

标签: c kernel usb scsi sata

动机

我正在研究iso安装程序。出于某些奇怪的原因,此安装程序必须选择sda作为要在其中安装os的磁盘。因此,安装程序本身没有解决方法,我想修改内核以归档目标。

我的想法

AFAIK,usb和sata / ata设备都可以是sda,因为它们都可以与scsi通讯,并且scsi驱动程序会将scsi设备重新识别为sda..z。因此,将USB设备重新识别为sda并不奇怪。作为内核新手,我不知道大型内核代码库的背后是什么。例如,内核如何将scsi设备注册为sda(好的,我只能找到函数sd_format_disk_name

/**
 *  sd_format_disk_name - format disk name
 *  @prefix: name prefix - ie. "sd" for SCSI disks
 *  @index: index of the disk to format name for
 *  @buf: output buffer
 *  @buflen: length of the output buffer
 *
 *  SCSI disk names starts at sda.  The 26th device is sdz and the
 *  27th is sdaa.  The last one for two lettered suffix is sdzz
 *  which is followed by sdaaa.
 *
 *  This is basically 26 base counting with one extra 'nil' entry
 *  at the beginning from the second digit on and can be
 *  determined using similar method as 26 base conversion with the
 *  index shifted -1 after each digit is computed.
 *
 *  CONTEXT:
 *  Don't care.
 *
 *  RETURNS:
 *  0 on success, -errno on failure.
 */
static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
{
    const int base = 'z' - 'a' + 1;
    char *begin = buf + strlen(prefix);
    char *end = buf + buflen;
    char *p;
    int unit;

    p = end - 1;
    *p = '\0';
    unit = base;
    do {
        if (p == begin)
            return -EINVAL;
        *--p = 'a' + (index % unit);
        index = (index / unit) - 1;
    } while (index >= 0);

    memmove(begin, p, end - p);
    memcpy(buf, prefix, strlen(prefix));

    return 0;
}

sd_probe中被称为

/**
 *  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_probe is not re-entrant (for time being)
 *  Also think about sd_probe() 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;
    int index;
    int error;

    scsi_autopm_get_device(sdp);
    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_probe\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) {
        sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted.\n");
        goto out_put;
    }

    error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
    if (error) {
        sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n");
        goto out_free_index;
    }

    sdkp->device = sdp;
    sdkp->driver = &sd_template;
    sdkp->disk = gd;
    sdkp->index = index;
    atomic_set(&sdkp->openers, 0);
    atomic_set(&sdkp->device->ioerr_cnt, 0);

    if (!sdp->request_queue->rq_timeout) {
        if (sdp->type != TYPE_MOD)
            blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
        else
            blk_queue_rq_timeout(sdp->request_queue,
                         SD_MOD_TIMEOUT);
    }

    device_initialize(&sdkp->dev);
    sdkp->dev.parent = dev;
    sdkp->dev.class = &sd_disk_class;
    dev_set_name(&sdkp->dev, "%s", dev_name(dev));

    error = device_add(&sdkp->dev);
    if (error)
        goto out_free_index;

    get_device(dev);
    dev_set_drvdata(dev, sdkp);

    get_device(&sdkp->dev); /* prevent release before async_schedule */
    async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);

    return 0;

 out_free_index:
    spin_lock(&sd_index_lock);
    ida_remove(&sd_index_ida, index);
    spin_unlock(&sd_index_lock);
 out_put:
    put_disk(gd);
 out_free:
    kfree(sdkp);
 out:
    scsi_autopm_put_device(sdp);
    return error;
}

可悲的是,这两个功能远远不能满足我的要求。

问题:

  1. 如标题所述,如何修改linux内核以强制sda始终为sata磁盘?
  2. 如果Q1太大而无法回答,我想知道scsi如何进行随机命名
  3. 如果Q2仍然太大而无法回答,我想知道注册为scsi的usb / sata的usb是否对sdx排序很重要?

0 个答案:

没有答案
相关问题