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