参照元

説明

引数

返り値

参考

static DEFINE_IDR(sd_index_idr);
static struct scsi_driver sd_template = {
        .owner                  = THIS_MODULE,
        .gendrv = {
                .name           = "sd",
                .probe          = sd_probe,
                .remove         = sd_remove,
                .suspend        = sd_suspend,
                .resume         = sd_resume,
                .shutdown       = sd_shutdown,
        },
        .rescan                 = sd_rescan,
        .done                   = sd_done,
};
static struct class sd_disk_class = {
        .name           = "scsi_disk",
        .owner          = THIS_MODULE,
        .release        = scsi_disk_release,
        .class_dev_attrs = sd_disk_attrs,
};
static struct class_device_attribute sd_disk_attrs[] = {
        __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
               sd_store_cache_type),
        __ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
        __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
               sd_store_allow_restart),
        __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
               sd_store_manage_start_stop),
        __ATTR_NULL,
};

実装

/**
 *      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(16);
        if (!gd)
                goto out_free;
        if (!idr_pre_get(&sd_index_idr, GFP_KERNEL))
                goto out_put;
        spin_lock(&sd_index_lock);
        error = idr_get_new(&sd_index_idr, NULL, &index);
        spin_unlock(&sd_index_lock);
        if (index >= SD_MAX_DISKS)
                error = -EBUSY;
        if (error)
                goto out_put;

        sdkp->device = sdp;
        sdkp->driver = &sd_template;
        sdkp->disk = gd;
        sdkp->index = index;
        sdkp->openers = 0;
        sdkp->previous_state = 1;
        if (!sdp->timeout) {
                if (sdp->type != TYPE_MOD)
                        sdp->timeout = SD_TIMEOUT;
                else
                        sdp->timeout = SD_MOD_TIMEOUT;
        }
        class_device_initialize(&sdkp->cdev);
        sdkp->cdev.dev = &sdp->sdev_gendev;
        sdkp->cdev.class = &sd_disk_class;
        strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
        if (class_device_add(&sdkp->cdev))
                goto out_put;
        get_device(&sdp->sdev_gendev);
        gd->major = sd_major((index & 0xf0) >> 4);
        gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
        gd->minors = 16;
        gd->fops = &sd_fops;
        if (index < 26) {
                sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
        } else if (index < (26 + 1) * 26) {
                sprintf(gd->disk_name, "sd%c%c",
                        'a' + index / 26 - 1,'a' + index % 26);
        } else {
                const unsigned int m1 = (index / 26 - 1) / 26 - 1;
                const unsigned int m2 = (index / 26 - 1) % 26;
                const unsigned int m3 =  index % 26;
                sprintf(gd->disk_name, "sd%c%c%c",
                        'a' + m1, 'a' + m2, 'a' + m3);
        }
        gd->private_data = &sdkp->driver;
        gd->queue = sdkp->device->request_queue;
        sd_revalidate_disk(gd);
        blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
        gd->driverfs_dev = &sdp->sdev_gendev;
        gd->flags = GENHD_FL_DRIVERFS;
        if (sdp->removable)
                gd->flags |= GENHD_FL_REMOVABLE;
        dev_set_drvdata(dev, sdkp);
        add_disk(gd);
        sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
                  sdp->removable ? "removable " : "");

        return 0;

 out_put:
        put_disk(gd);
 out_free:
        kfree(sdkp);
 out:
        return error;
}

コメント


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS