static int __init scsi_debug_init()

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;
}