in scsi_debug.c [6688:6935]
static int __init scsi_debug_init(void)
{
bool want_store = (sdebug_fake_rw == 0);
unsigned long sz;
int k, ret, hosts_to_add;
int idx = -1;
ramdisk_lck_a[0] = &atomic_rw;
ramdisk_lck_a[1] = &atomic_rw2;
atomic_set(&retired_max_queue, 0);
if (sdebug_ndelay >= 1000 * 1000 * 1000) {
pr_warn("ndelay must be less than 1 second, ignored\n");
sdebug_ndelay = 0;
} else if (sdebug_ndelay > 0)
sdebug_jdelay = JDELAY_OVERRIDDEN;
switch (sdebug_sector_size) {
case 512:
case 1024:
case 2048:
case 4096:
break;
default:
pr_err("invalid sector_size %d\n", sdebug_sector_size);
return -EINVAL;
}
switch (sdebug_dif) {
case T10_PI_TYPE0_PROTECTION:
break;
case T10_PI_TYPE1_PROTECTION:
case T10_PI_TYPE2_PROTECTION:
case T10_PI_TYPE3_PROTECTION:
have_dif_prot = true;
break;
default:
pr_err("dif must be 0, 1, 2 or 3\n");
return -EINVAL;
}
if (sdebug_num_tgts < 0) {
pr_err("num_tgts must be >= 0\n");
return -EINVAL;
}
if (sdebug_guard > 1) {
pr_err("guard must be 0 or 1\n");
return -EINVAL;
}
if (sdebug_ato > 1) {
pr_err("ato must be 0 or 1\n");
return -EINVAL;
}
if (sdebug_physblk_exp > 15) {
pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
return -EINVAL;
}
sdebug_lun_am = sdebug_lun_am_i;
if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
}
if (sdebug_max_luns > 256) {
if (sdebug_max_luns > 16384) {
pr_warn("max_luns can be no more than 16384, use default\n");
sdebug_max_luns = DEF_MAX_LUNS;
}
sdebug_lun_am = SAM_LUN_AM_FLAT;
}
if (sdebug_lowest_aligned > 0x3fff) {
pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
return -EINVAL;
}
if (submit_queues < 1) {
pr_err("submit_queues must be 1 or more\n");
return -EINVAL;
}
if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
return -EINVAL;
}
if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
(sdebug_host_max_queue < 0)) {
pr_err("host_max_queue must be in range [0 %d]\n",
SDEBUG_CANQUEUE);
return -EINVAL;
}
if (sdebug_host_max_queue &&
(sdebug_max_queue != sdebug_host_max_queue)) {
sdebug_max_queue = sdebug_host_max_queue;
pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
sdebug_max_queue);
}
sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
GFP_KERNEL);
if (sdebug_q_arr == NULL)
return -ENOMEM;
for (k = 0; k < submit_queues; ++k)
spin_lock_init(&sdebug_q_arr[k].qc_lock);
/*
* check for host managed zoned block device specified with
* ptype=0x14 or zbc=XXX.
*/
if (sdebug_ptype == TYPE_ZBC) {
sdeb_zbc_model = BLK_ZONED_HM;
} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
k = sdeb_zbc_model_str(sdeb_zbc_model_s);
if (k < 0) {
ret = k;
goto free_q_arr;
}
sdeb_zbc_model = k;
switch (sdeb_zbc_model) {
case BLK_ZONED_NONE:
case BLK_ZONED_HA:
sdebug_ptype = TYPE_DISK;
break;
case BLK_ZONED_HM:
sdebug_ptype = TYPE_ZBC;
break;
default:
pr_err("Invalid ZBC model\n");
ret = -EINVAL;
goto free_q_arr;
}
}
if (sdeb_zbc_model != BLK_ZONED_NONE) {
sdeb_zbc_in_use = true;
if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
}
if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
if (sdebug_dev_size_mb < 1)
sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
sz = (unsigned long)sdebug_dev_size_mb * 1048576;
sdebug_store_sectors = sz / sdebug_sector_size;
sdebug_capacity = get_sdebug_capacity();
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
sdebug_sectors_per = 32;
if (sdebug_dev_size_mb >= 256)
sdebug_heads = 64;
else if (sdebug_dev_size_mb >= 16)
sdebug_heads = 32;
sdebug_cylinders_per = (unsigned long)sdebug_capacity /
(sdebug_sectors_per * sdebug_heads);
if (sdebug_cylinders_per >= 1024) {
/* other LLDs do this; implies >= 1GB ram disk ... */
sdebug_heads = 255;
sdebug_sectors_per = 63;
sdebug_cylinders_per = (unsigned long)sdebug_capacity /
(sdebug_sectors_per * sdebug_heads);
}
if (scsi_debug_lbp()) {
sdebug_unmap_max_blocks =
clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
sdebug_unmap_max_desc =
clamp(sdebug_unmap_max_desc, 0U, 256U);
sdebug_unmap_granularity =
clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
if (sdebug_unmap_alignment &&
sdebug_unmap_granularity <=
sdebug_unmap_alignment) {
pr_err("ERR: unmap_granularity <= unmap_alignment\n");
ret = -EINVAL;
goto free_q_arr;
}
}
xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
if (want_store) {
idx = sdebug_add_store();
if (idx < 0) {
ret = idx;
goto free_q_arr;
}
}
pseudo_primary = root_device_register("pseudo_0");
if (IS_ERR(pseudo_primary)) {
pr_warn("root_device_register() error\n");
ret = PTR_ERR(pseudo_primary);
goto free_vm;
}
ret = bus_register(&pseudo_lld_bus);
if (ret < 0) {
pr_warn("bus_register error: %d\n", ret);
goto dev_unreg;
}
ret = driver_register(&sdebug_driverfs_driver);
if (ret < 0) {
pr_warn("driver_register error: %d\n", ret);
goto bus_unreg;
}
hosts_to_add = sdebug_add_host;
sdebug_add_host = 0;
for (k = 0; k < hosts_to_add; k++) {
if (want_store && k == 0) {
ret = sdebug_add_host_helper(idx);
if (ret < 0) {
pr_err("add_host_helper k=%d, error=%d\n",
k, -ret);
break;
}
} else {
ret = sdebug_do_add_host(want_store &&
sdebug_per_host_store);
if (ret < 0) {
pr_err("add_host k=%d error=%d\n", k, -ret);
break;
}
}
}
if (sdebug_verbose)
pr_info("built %d host(s)\n", sdebug_num_hosts);
return 0;
bus_unreg:
bus_unregister(&pseudo_lld_bus);
dev_unreg:
root_device_unregister(pseudo_primary);
free_vm:
sdebug_erase_store(idx, NULL);
free_q_arr:
kfree(sdebug_q_arr);
return ret;
}