*参照元 [#hf41c32b] #backlinks *説明 [#d462b787] -パス: [[linux-2.6.25/drivers/scsi/sd.c]] -FIXME: これは何? --説明 **引数 [#j04dc2b9] -struct device *dev -- **返り値 [#x0edd28e] -int -- **参考 [#s40c9fe7] -sd_index_idr は --[[linux-2.6.25/DEFINE_IDR()]] static DEFINE_IDR(sd_index_idr); -sd_template は SCSI ブロックデバイスのデフォルトの動作を表す。 --[[linux-2.6.25/sd_template]] --[[linux-2.6.25/sd_probe()]] --[[linux-2.6.25/sd_remove()]] --[[linux-2.6.25/sd_suspend()]] --[[linux-2.6.25/sd_resume()]] --[[linux-2.6.25/sd_shutdown()]] --[[linux-2.6.25/sd_rescan()]] --[[linux-2.6.25/sd_done()]] 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 ブロックデバイスドライバのクラスを表す。 --[[linux-2.6.25/class]] --[[linux-2.6.25/THIS_MODULE]] --[[linux-2.6.25/scsi_disk_release()]] --sd_disk_attrs も static 変数である。 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 ブロックデバイスドライバのクラスの 属性を表す。 --[[linux-2.6.25/__ATTR()]] --cache_type メンバ --- ---読み、[[linux-2.6.25/sd_show_cache_type()]] ---書き、[[linux-2.6.25/sd_store_cache_type()]] --FUA メンバ --- ---読み、[[linux-2.6.25/sd_show_fua()]] ---書けない --allow_restart メンバ --- ---読み、[[linux-2.6.25/sd_show_allow_restart()]] ---書き、[[linux-2.6.25/sd_store_allow_restart()]] --manage_start_stop メンバ --- ---読み、[[linux-2.6.25/sd_show_manage_start_stop()]] ---書き、[[linux-2.6.25/sd_store_manage_start_stop()]] 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, }; *実装 [#kf000cbc] /** * 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; - --[[linux-2.6.25/to_scsi_device()]] --[[linux-2.6.25/scsi_device]] --[[linux-2.6.25/scsi_disk]] --[[linux-2.6.25/gendisk]] 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")); - --[[linux-2.6.25/SCSI_LOG_HLQUEUE()]] --[[linux-2.6.25/sdev_printk()]] error = -ENOMEM; sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) goto out; -scsi_disk 構造体のメモリを確保&領域をゼロクリアする。 --kzalloc は kmalloc + memset によるゼロクリアで、libc の calloc に相当する。 --[[linux-2.6.25/kzalloc()]] gd = alloc_disk(16); if (!gd) goto out_free; -16個のマイナー番号を用いるディスクを確保する。 --[[linux-2.6.25/alloc_disk()]] if (!idr_pre_get(&sd_index_idr, GFP_KERNEL)) goto out_put; - --[[linux-2.6.25/idr_pre_get()]] spin_lock(&sd_index_lock); error = idr_get_new(&sd_index_idr, NULL, &index); spin_unlock(&sd_index_lock); - --[[linux-2.6.25/idr_get_new()]] 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; - --sdkp の型は scsi_disk 構造体である。 --[[linux-2.6.25/scsi_disk]] --sd_template はドライバが行うデフォルトの処理を 記述したテンプレート変数である。 ---[[linux-2.6.25/scsi_driver]] if (!sdp->timeout) { if (sdp->type != TYPE_MOD) sdp->timeout = SD_TIMEOUT; else sdp->timeout = SD_MOD_TIMEOUT; } -タイムアウト時間が設定されていない場合はデフォルト値を入れる。 --SD_TIMEOUT は 30秒 --SD_MOD_TIMEOUT は 75秒 --[[linux-2.6.25/include/scsi/sd.h]] で定義されている。 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); - --[[linux-2.6.25/class_device_initialize()]] --[[linux-2.6.25/strncpy()]] --sd_disk_class は SCSI ブロックデバイスドライバのクラスを表す。 ---[[linux-2.6.25/class]] if (class_device_add(&sdkp->cdev)) goto out_put; - --[[linux-2.6.25/class_device_add()]] get_device(&sdp->sdev_gendev); - --[[linux-2.6.25/get_device()]] gd->major = sd_major((index & 0xf0) >> 4); gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = 16; gd->fops = &sd_fops; - --sd_fops は SCSI ブロックデバイスの操作を記述した構造体である。 --[[linux-2.6.25/sd_major()]] 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); - --[[linux-2.6.25/sd_revalidate_disk()]] blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); - --[[linux-2.6.25/blk_queue_prep_rq()]] 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); -システムにブロックデバイスを登録する。 --[[linux-2.6.25/dev_set_drvdata()]] --[[linux-2.6.25/add_disk()]] sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); return 0; out_put: put_disk(gd); -システムからブロックデバイスを削除する。 --[[linux-2.6.25/put_disk()]] out_free: kfree(sdkp); -SCSI ブロックデバイスのための領域を削除する。 --[[linux-2.6.25/put_disk()]] out: return error; } *コメント [#wc426329]