参照元†
返り値†
static DEFINE_IDR(sd_index_idr);
- sd_template は SCSI ブロックデバイスのデフォルトの動作を表す。
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,
};
- sd_disk_class は SCSI ブロックデバイスドライバのクラスを表す。
static struct class sd_disk_class = {
.name = "scsi_disk",
.owner = THIS_MODULE,
.release = scsi_disk_release,
.class_dev_attrs = sd_disk_attrs,
};
- sd_disk_attrs は SCSI ブロックデバイスドライバのクラスの
属性を表す。
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_fops は SCSI ブロックデバイスに対する操作を表す。
- これらの関数はブロックデバイスへの要求に応じて、
ブロックデバイスサブシステムから呼び出される。
static struct block_device_operations sd_fops = {
.owner = THIS_MODULE,
.open = sd_open,
.release = sd_release,
.ioctl = sd_ioctl,
.getgeo = sd_getgeo,
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
#endif
.media_changed = sd_media_changed,
.revalidate_disk = sd_revalidate_disk,
};
/**
* 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;
- scsi_disk 構造体のメモリを確保&領域をゼロクリアする。
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);
}
- SCSI ディスクデバイスの名前を生成する。
- 1 <= n <= 26: sda, sdb, ...
- 27 <= n <= 26^2 + 26 = 702: sdaa, sdab, ..., sdba, sdbb, ...
- 702 <= n <= 65535: sdaaa, sdaab, ...
- linux-2.6.25/sprintf()
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);
- SCSI ブロックデバイスのための領域を削除する。
out:
return error;
}
コメント†