Пример #1
0
static int modisk_attach(struct scst_device *dev)
{
	int res, rc;
	uint8_t cmd[10];
	const int buffer_size = 512;
	uint8_t *buffer = NULL;
	int retries;
	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
	enum dma_data_direction data_dir;

	TRACE_ENTRY();

	if (dev->scsi_dev == NULL ||
	    dev->scsi_dev->type != dev->type) {
		PRINT_ERROR("%s", "SCSI device not define or illegal type");
		res = -ENODEV;
		goto out;
	}

	dev->block_shift = MODISK_DEF_BLOCK_SHIFT;
	dev->block_size = 1 << dev->block_shift;

	/*
	 * If the device is offline, don't try to read capacity or any
	 * of the other stuff
	 */
	if (dev->scsi_dev->sdev_state == SDEV_OFFLINE) {
		TRACE_DBG("%s", "Device is offline");
		res = -ENODEV;
		goto out;
	}

	buffer = kmalloc(buffer_size, GFP_KERNEL);
	if (!buffer) {
		PRINT_ERROR("Buffer memory allocation (size %d) failure",
			buffer_size);
		res = -ENOMEM;
		goto out;
	}

	/*
	 * Clear any existing UA's and get modisk capacity (modisk block
	 * size).
	 */
	memset(cmd, 0, sizeof(cmd));
	cmd[0] = READ_CAPACITY;
	cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ?
	    ((dev->scsi_dev->lun << 5) & 0xe0) : 0;
	retries = SCST_DEV_RETRIES_ON_UA;
	while (1) {
		memset(buffer, 0, buffer_size);
		memset(sense_buffer, 0, sizeof(sense_buffer));
		data_dir = SCST_DATA_READ;

		TRACE_DBG("%s", "Doing READ_CAPACITY");
		rc = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
				   buffer_size, sense_buffer,
				   SCST_GENERIC_MODISK_REG_TIMEOUT, 3, 0
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
				   , NULL
#endif
				  );

		TRACE_DBG("READ_CAPACITY done: %x", rc);

		if (!rc || !scst_analyze_sense(sense_buffer,
				sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
				UNIT_ATTENTION, 0, 0))
			break;

		if (!--retries) {
			PRINT_ERROR("UA not cleared after %d retries",
				    SCST_DEV_RETRIES_ON_UA);
			res = -ENODEV;
			goto out_free_buf;
		}
	}

	if (rc == 0) {
		uint32_t sector_size = get_unaligned_be32(&buffer[4]);

		if (sector_size == 0)
			dev->block_shift = MODISK_DEF_BLOCK_SHIFT;
		else
			dev->block_shift = scst_calc_block_shift(sector_size);
		TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
		      sector_size, dev->scsi_dev->scsi_level, SCSI_2);
		if (dev->block_shift < 9) {
			PRINT_ERROR("READ CAPACITY reported an invalid sector size: %d",
				    sector_size);
			res = -EINVAL;
			goto out_free_buf;
		}
	} else {
		dev->block_shift = MODISK_DEF_BLOCK_SHIFT;
		TRACE(TRACE_MINOR, "Read capacity failed: %x, using default "
			"sector size %d", rc, dev->block_shift);
		PRINT_BUFF_FLAG(TRACE_MINOR, "Returned sense", sense_buffer,
			sizeof(sense_buffer));
	}
	dev->block_size = 1 << dev->block_shift;

	res = scst_obtain_device_parameters(dev, NULL);
	if (res != 0) {
		PRINT_ERROR("Failed to obtain control parameters for device "
			"%s: %x", dev->virt_name, res);
		goto out_free_buf;
	}

out_free_buf:
	kfree(buffer);

out:
	TRACE_EXIT_RES(res);
	return res;
}
Пример #2
0
int main(int argc, char **argv)
{
	int res = 0;
	int ch, longindex;
	struct sigaction act;

	setlinebuf(stdout);

	res = debug_init();
	if (res != 0)
		goto out;

	app_name = argv[0];

	memset(devs, 0, sizeof(devs));

	while ((ch = getopt_long(argc, argv, "+b:e:trongluF:I:cp:f:m:d:vsS:P:hDR:Z:",
			long_options, &longindex)) >= 0) {
		switch (ch) {
		case 'b':
			block_size = atoi(optarg);
			PRINT_INFO("block_size %x (%s)", block_size, optarg);
			block_shift = scst_calc_block_shift(block_size);
			if (block_shift < 9) {
				res = -EINVAL;
				goto out_usage;
			}
			break;
		case 'e':
			threads = strtol(optarg, (char **)NULL, 0);
			break;
		case 't':
			wt_flag = 1;
			break;
#if defined(DEBUG) || defined(TRACING)
		case 'd':
			trace_flag = strtol(optarg, (char **)NULL, 0);
			break;
#endif
		case 'r':
			rd_only_flag = 1;
			break;
		case 'o':
			o_direct_flag = 1;
			break;
		case 'n':
			nullio = 1;
			break;
		case 'c':
			nv_cache = 1;
			break;
		case 'p':
			if (strncmp(optarg, "std", 3) == 0)
				parse_type = SCST_USER_PARSE_STANDARD;
			else if (strncmp(optarg, "call", 3) == 0)
				parse_type = SCST_USER_PARSE_CALL;
			else if (strncmp(optarg, "excpt", 5) == 0)
				parse_type = SCST_USER_PARSE_EXCEPTION;
			else
				goto out_usage;
			break;
		case 'f':
			on_free_cmd_type_set = 1;
			if (strncmp(optarg, "ignore", 6) == 0)
				on_free_cmd_type = SCST_USER_ON_FREE_CMD_IGNORE;
			else if (strncmp(optarg, "call", 3) == 0)
				on_free_cmd_type = SCST_USER_ON_FREE_CMD_CALL;
			else
				goto out_usage;
			break;
		case 's':
			sgv_shared = 1;
			break;
		case 'S':
			sgv_single_alloc_pages = atoi(optarg);
			break;
		case 'P':
			sgv_purge_interval = atoi(optarg);
			break;
		case 'D':
			sgv_disable_clustered_pool = 1;
			break;
		case 'R':
			prealloc_buffers_num = atoi(optarg);
			break;
		case 'Z':
			prealloc_buffer_size = atoi(optarg) * 1024;
			break;
		case 'm':
			if (strncmp(optarg, "all", 3) == 0)
				memory_reuse_type = SCST_USER_MEM_REUSE_ALL;
			else if (strncmp(optarg, "read", 4) == 0)
				memory_reuse_type = SCST_USER_MEM_REUSE_READ;
			else if (strncmp(optarg, "write", 5) == 0)
				memory_reuse_type = SCST_USER_MEM_REUSE_WRITE;
			else if (strncmp(optarg, "none", 4) == 0)
				memory_reuse_type = SCST_USER_MEM_NO_REUSE;
			else
				goto out_usage;
			break;
		case 'l':
			non_blocking = 1;
			break;
		case 'I':
			vdisk_ID = strtol(optarg, (char **)NULL, 0);
			break;
		case 'F':
			flush_interval = strtol(optarg, (char **)NULL, 0);
			if (flush_interval < 0) {
				PRINT_ERROR("Wrong flush interval %d",
					flush_interval);
				flush_interval = 0;
			}
			break;
		case 'u':
			unreg_before_close = 1;
			break;
#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
		case 'g':
			debug_tm_ignore = 1;
			break;
#endif
		case 'v':
			printf("%s version %s\n", app_name, VERSION_STR);
			goto out_done;
		default:
			goto out_usage;
		}
	}

	if (optind > (argc-2))
		goto out_usage;

	if (!on_free_cmd_type_set &&
	    (memory_reuse_type != SCST_USER_MEM_REUSE_ALL))
		on_free_cmd_type = SCST_USER_ON_FREE_CMD_CALL;

	PRINT_INFO("%s", "Options:");

	if (rd_only_flag)
		PRINT_INFO("	%s", "READ ONLY");
	if (wt_flag)
		PRINT_INFO("	%s", "WRITE THROUGH");
	if (nv_cache)
		PRINT_INFO("	%s", "NV_CACHE");
	if (o_direct_flag)
		PRINT_INFO("	%s", "O_DIRECT");
	if (nullio)
		PRINT_INFO("	%s", "NULLIO");
	if (non_blocking)
		PRINT_INFO("	%s", "NON-BLOCKING");

	switch(parse_type) {
	case SCST_USER_PARSE_STANDARD:
		PRINT_INFO("	%s", "Standard parse");
		break;
	case SCST_USER_PARSE_CALL:
		PRINT_INFO("	%s", "Call parse");
		break;
	case SCST_USER_PARSE_EXCEPTION:
		PRINT_INFO("	%s", "Exception parse");
		break;
	default:
		sBUG();
	}

	switch(on_free_cmd_type) {
	case SCST_USER_ON_FREE_CMD_IGNORE:
		PRINT_INFO("	%s", "Ignore on_free_cmd");
		break;
	case SCST_USER_ON_FREE_CMD_CALL:
		PRINT_INFO("	%s", "Call on_free_cmd");
		break;
	default:
		sBUG();
	}

	switch(memory_reuse_type) {
	case SCST_USER_MEM_REUSE_ALL:
		PRINT_INFO("	%s", "Full memory reuse enabled");
		break;
	case SCST_USER_MEM_REUSE_READ:
		PRINT_INFO("	%s", "READ memory reuse enabled");
		break;
	case SCST_USER_MEM_REUSE_WRITE:
		PRINT_INFO("	%s", "WRITE memory reuse enabled");
		break;
	case SCST_USER_MEM_NO_REUSE:
		PRINT_INFO("	%s", "Memory reuse disabled");
		break;
	default:
		sBUG();
	}

	if (sgv_shared)
		PRINT_INFO("	%s", "SGV shared");

	if (sgv_single_alloc_pages != 0)
		PRINT_INFO("	Use single entry SGV cache with %d pages/entry",
			sgv_single_alloc_pages);

	if (sgv_purge_interval != 0) {
		if (sgv_purge_interval > 0)
			PRINT_INFO("	Use SGV cache purge interval %d seconds",
				sgv_purge_interval);
		else
			PRINT_INFO("	%s", "SGV cache purging disabled");
	}

	if (sgv_disable_clustered_pool)
		PRINT_INFO("	%s", "Disable clustered SGV pool");

	if ((prealloc_buffers_num > 0) && (prealloc_buffer_size > 0))
		PRINT_INFO("	Prealloc %d buffers of %dKB",
			prealloc_buffers_num, prealloc_buffer_size / 1024);

	if (!o_direct_flag && (memory_reuse_type == SCST_USER_MEM_NO_REUSE)) {
		PRINT_INFO("	%s", "Using unaligned buffers");
		alloc_fn = malloc;
	}

#if defined(DEBUG_TM_IGNORE) || defined(DEBUG_TM_IGNORE_ALL)
	if (debug_tm_ignore)
		PRINT_INFO("	%s", "DEBUG_TM_IGNORE");
#endif

#ifdef DEBUG
	PRINT_INFO("trace_flag %lx", trace_flag);
#endif

	memset(&act, 0, sizeof(act));
	act.sa_handler = sigusr1_handler;
	act.sa_flags = SA_RESTART;
	sigemptyset(&act.sa_mask);
	res = sigaction(SIGUSR1, &act, NULL);
	if (res != 0) {
		res = errno;
		PRINT_ERROR("sigaction() failed: %s",
			strerror(res));
		/* don't do anything */
	}

	if (flush_interval != 0) {
		memset(&act, 0, sizeof(act));
		act.sa_handler = sigalrm_handler;
		act.sa_flags = SA_RESTART;
		sigemptyset(&act.sa_mask);
		res = sigaction(SIGALRM, &act, NULL);
		if (res != 0) {
			res = errno;
			PRINT_ERROR("sigaction() failed: %s",
				strerror(res));
			goto out_done;
		}       

		res = alarm(flush_interval);
		if (res != 0) {
			res = errno;
			PRINT_ERROR("alarm() failed: %s",
				strerror(res));
			goto out_done;
		}
	}

	res = start(argc, argv);

out_done:
	debug_done();

out:
	return res;

out_usage:
	usage();
	goto out_done;
}