From: <vl...@us...> - 2007-10-25 09:54:06
|
Revision: 210 http://scst.svn.sourceforge.net/scst/?rev=210&view=rev Author: vlnb Date: 2007-10-25 02:54:00 -0700 (Thu, 25 Oct 2007) Log Message: ----------- - Cleanups and fixes in transfer length and direction processing. Modified Paths: -------------- trunk/scst/README trunk/scst/include/scst_const.h trunk/scst/src/Makefile trunk/scst/src/scst_cdbprobe.h trunk/scst/src/scst_lib.c trunk/scst/src/scst_main.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/README 2007-10-25 09:54:00 UTC (rev 210) @@ -172,35 +172,67 @@ There are the following compilation options, that could be commented in/out in Makefile: - - DEBUG - turns on some debugging code, including some logging. Makes - the driver considerably bigger and slower, producing large amount of - log data. + - DEBUG - if defined, turns on some debugging code, including some + logging. Makes the driver considerably bigger and slower, producing + large amount of log data. - - TRACING - turns on ability to log events. Makes the driver considerably - bigger and lead to some performance loss. + - TRACING - if defined, turns on ability to log events. Makes the + driver considerably bigger and lead to some performance loss. - - EXTRACHECKS - adds extra validity checks in the various places. + - EXTRACHECKS - if defined, adds extra validity checks in the various + places. - - DEBUG_TM - turns on task management functions debugging, when on - LUN 0 in the default access control group some of the commands will - be delayed for about 60 sec., so making the remote initiator send TM - functions, eg ABORT TASK and TARGET RESET. Also set TM_DBG_GO_OFFLINE - symbol in the Makefile to 1 if you want that the device eventually - become completely unresponsive, or to 0 otherwise to circle around - ABORTs and RESETs code. Needs DEBUG turned on. + - USE_EXPECTED_VALUES - if not defined (default), initiator supplied + expected data transfer length and direction will be used only for + verification purposes to return error or warn in case if one of them + is invalid. Instead, locally decoded from SCSI command values will be + used. This is necessary for security reasons, because otherwise a + faulty initiator can crash target by supplying invalid value in one + of those parameters. This is especially important in case of + pass-through mode. If USE_EXPECTED_VALUES is defined, initiator + supplied expected data transfer length and direction will override + the locally decoded values. This might be necessary if internal SCST + commands translation table doesn't contain SCSI command, which is + used in your environment. You can know that if you have messages like + "Unknown opcode XX for YY. Should you update scst_scsi_op_table?" in + your kernel log and your initiator returns an error. Also report + those messages in the SCST mailing list + scs...@li.... Note, that not all SCSI transports + support supplying expected values. - - STRICT_SERIALIZING - makes SCST send all commands to underlying SCSI - device synchronously, one after one. This makes task management more - reliable, with cost of some performance penalty. This is mostly - actual for stateful SCSI devices like tapes, where the result of - command's execution depends from device's settings set by previous - commands. Disk and RAID devices are stateless in the most cases. The - current SCSI core in Linux doesn't allow to abort all commands - reliably if they sent asynchronously to a stateful device. Turned off - by default, turn it on if you use stateful device(s) and need as much - error recovery reliability as possible. As a side effect, no kernel - patching is necessary. + - DEBUG_TM - if defined, turns on task management functions debugging, + when on LUN 0 in the default access control group some of the + commands will be delayed for about 60 sec., so making the remote + initiator send TM functions, eg ABORT TASK and TARGET RESET. Also + define TM_DBG_GO_OFFLINE symbol in the Makefile to 1 if you want that + the device eventually become completely unresponsive, or to 0 + otherwise to circle around ABORTs and RESETs code. Needs DEBUG turned + on. + - STRICT_SERIALIZING - if defined, makes SCST send all commands to + underlying SCSI device synchronously, one after one. This makes task + management more reliable, with cost of some performance penalty. This + is mostly actual for stateful SCSI devices like tapes, where the + result of command's execution depends from device's settings defined + by previous commands. Disk and RAID devices are stateless in the most + cases. The current SCSI core in Linux doesn't allow to abort all + commands reliably if they sent asynchronously to a stateful device. + Turned off by default, turn it on if you use stateful device(s) and + need as much error recovery reliability as possible. As a side + effect, no kernel patching is necessary. + + - ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be allowed + to submit pass-through commands to real SCSI devices via the SCSI + middle layer using scsi_execute_async() function from soft IRQ + context (tasklets). This used to be the default, but currently it + seems the SCSI middle layer starts expecting only thread context on + the IO submit path, so it is disabled now by default. Enabling it + will decrease amount of context switches and improve performance. It + is more or less safe, in the worst case, if in your configuration the + SCSI middle layer really doesn't expect SIRQ context in + scsi_execute_async() function, you will get a warning message in the + kernel log. + - SCST_HIGHMEM - if defined on HIGHMEM systems with 2.6 kernels, it allows SCST to use HIGHMEM. This is very experimental feature, which is currently broken and unsupported, since it is unclear, if it @@ -216,8 +248,8 @@ HIGHMEM kernel configurations are fully supported, but not recommended for performance reasons, except for scst_user, where they are not supported, because this module deals with user supplied memory on a -zero-copy manner. Consider change VMSPLIT option or use 64-bit system -configuration instead. +zero-copy manner. If you need to use it, consider change VMSPLIT option +or use 64-bit system configuration instead. For changing VMSPLIT option (CONFIG_VMSPLIT to be precise) you should in "make menuconfig" command set the following variables: @@ -437,15 +469,23 @@ workloads write through caching might perform better, than write back one with the barrier protection turned on. -IMPORTANT: Many disk and partition table management utilities don't support +IMPORTANT: Some disk and partition table management utilities don't support ========= block sizes >512 bytes, therefore make sure that your favorite one - supports it. Also, if you export disk file or device with - some block size, different from one, with which it was - already divided on partitions, you could get various weird + supports it. Currently only cfdisk is known to work only with + 512 bytes blocks, other utilities like fdisk on Linux or + standard disk manager on Windows are proved to work well with + non-512 bytes blocks. Note, if you export a disk file or + device with some block size, different from one, with which + it was already partitioned, you could get various weird things like utilities hang up or other unexpected behavior. - Hence, to be sure, zero the exported file or device before the - first access to it from the remote initiator with another - block size. + Hence, to be sure, zero the exported file or device before + the first access to it from the remote initiator with another + block size. On Window initiator make sure you "Set Signature" + in the disk manager on the imported from the target drive + before doing any other partitioning on it. After you + successfully mounted a file system over non-512 bytes block + size device, the block size stops matter, any program will + work with files on such file system. BLOCKIO VDISK mode ------------------ @@ -465,9 +505,10 @@ their data access, can actually see worse performance with non-discriminate caching. -4) Multiple layers of targets were the secondary/triary layers need to -have a consistent view of the primary targets in order to preserve data -integrity which a page cache backed IO type might not provide reliably. +4) Multiple layers of targets were the secondary and above layers need +to have a consistent view of the primary targets in order to preserve +data integrity which a page cache backed IO type might not provide +reliably. Also it has an advantage over FILEIO that it doesn't copy data between the system cache and the commands data buffers, so it saves a @@ -533,6 +574,8 @@ - Disable in Makefile STRICT_SERIALIZING, EXTRACHECKS, TRACING, DEBUG*, SCST_STRICT_SECURITY, SCST_HIGHMEM + - For pass-through devices enable ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ. + 2. For target drivers: - Disable in Makefiles EXTRACHECKS, TRACING, DEBUG* @@ -552,7 +595,8 @@ than for performance. If you use SCST version taken directly from its SVN repository, you can -set the above options using debug2perf script file. +set the above options, except ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, using +debug2perf script file. 4. For kernel: Modified: trunk/scst/include/scst_const.h =================================================================== --- trunk/scst/include/scst_const.h 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/include/scst_const.h 2007-10-25 09:54:00 UTC (rev 210) @@ -121,6 +121,7 @@ #define scst_sense_read_error MEDIUM_ERROR, 0x11, 0 #define scst_sense_write_error MEDIUM_ERROR, 0x03, 0 #define scst_sense_not_ready NOT_READY, 0x04, 0x10 +#define scst_sense_invalid_message ILLEGAL_REQUEST, 0x49, 0 /************************************************************* * SCSI opcodes not listed anywhere else Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/Makefile 2007-10-25 09:54:00 UTC (rev 210) @@ -116,6 +116,9 @@ EXTRA_CFLAGS += -DEXTRACHECKS +#EXTRA_CFLAGS += -DUSE_EXPECTED_VALUES +#EXTRA_CFLAGS += -DALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ + #EXTRA_CFLAGS += -fno-inline #EXTRA_CFLAGS += -DTRACING Modified: trunk/scst/src/scst_cdbprobe.h =================================================================== --- trunk/scst/src/scst_cdbprobe.h 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/scst_cdbprobe.h 2007-10-25 09:54:00 UTC (rev 210) @@ -249,16 +249,6 @@ SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 7, get_trans_len_2}, {0x2F, "O OO O ", "VERIFY(10)", SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 7, get_trans_len_2}, -/* - {0x30, "O OO O ", "SEARCH DATA HIGH(10)", - SCST_DATA_NONE, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, - {0x31, " O ", "OBJECT POSITION", - SCST_DATA_NONE, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, - {0x31, "O OO O ", "SEARCH DATA EQUAL(10)", - SCST_DATA_NONE, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, - {0x32, "O OO O ", "SEARCH DATA LOW(10)", - SCST_DATA_NONE, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, -*/ {0x33, "O OO O ", "SET LIMITS(10)", SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, {0x34, " O ", "READ POSITION", @@ -402,7 +392,7 @@ {0x93, " M ", "ERASE(16)", SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none}, {0x9E, "O ", "SERVICE ACTION IN", - SCST_DATA_READ, FLAG_NONE, 0, get_trans_len_none}, + SCST_DATA_READ, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, /* 12-bytes length CDB */ {0xA0, "VVVVVVVVVV M ", "REPORT LUN", @@ -443,7 +433,7 @@ SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, {0xAC, " O ", "ERASE(12)", SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, - {0xAC, " O ", "GET PERFORMANCE", + {0xAC, " M ", "GET PERFORMANCE", SCST_DATA_READ, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none}, {0xAD, " O ", "READ DVD STRUCTURE", SCST_DATA_READ, FLAG_NONE, 8, get_trans_len_2}, @@ -467,8 +457,8 @@ SCST_DATA_READ, FLAG_NONE, 9, get_trans_len_1}, {0xB6, " O ", "SEND VOLUME TAG", SCST_DATA_WRITE, FLAG_NONE, 9, get_trans_len_1}, - {0xB6, " O ", "SET STREAMING", - SCST_DATA_WRITE, FLAG_NONE, 0, get_trans_len_none}, + {0xB6, " M ", "SET STREAMING", + SCST_DATA_WRITE, FLAG_NONE, 9, get_trans_len_2}, {0xB7, " O ", "READ DEFECT DATA(12)", SCST_DATA_READ, FLAG_NONE, 9, get_trans_len_1}, {0xB8, " O ", "READ ELEMENT STATUS", Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/scst_lib.c 2007-10-25 09:54:00 UTC (rev 210) @@ -1626,7 +1626,7 @@ static uint32_t get_trans_len_read_capacity(const uint8_t *cdb, uint8_t off) { - return 8; + return READ_CAP_LEN; } static uint32_t get_trans_len_single(const uint8_t *cdb, uint8_t off) @@ -1698,7 +1698,7 @@ #ifdef EXTRACHECKS if (unlikely((info_p->transfer_len == 0) && (info_p->direction != SCST_DATA_NONE))) { - TRACE_DBG("Warning! transfer_len 0, direction %d change on %d", + TRACE_MGMT_DBG("Warning! transfer_len 0, direction %d change on %d", info_p->direction, SCST_DATA_NONE); info_p->direction = SCST_DATA_NONE; } @@ -1846,10 +1846,6 @@ info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; case SERVICE_ACTION_IN: if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) { cmd->bufflen = READ_CAP16_LEN; @@ -1911,18 +1907,6 @@ cmd->cdb[1] &= 0x1f; switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case GPCMD_SET_STREAMING: - cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + - ((*(cmd->cdb + 10)) & 0xff); - cmd->bufflen &= 0xffff; - break; - case GPCMD_READ_CD: - cmd->bufflen = cmd->bufflen >> 8; - break; case VERIFY_6: case VERIFY: case VERIFY_12: @@ -1972,18 +1956,6 @@ cmd->cdb[1] &= 0x1f; switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case 0xB6 /* SET_STREAMING */ : - cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + - ((*(cmd->cdb + 10)) & 0xff); - cmd->bufflen &= 0xffff; - break; - case 0xBE /* READ_CD */ : - cmd->bufflen = cmd->bufflen >> 8; - break; case VERIFY_6: case VERIFY: case VERIFY_12: Modified: trunk/scst/src/scst_main.c =================================================================== --- trunk/scst/src/scst_main.c 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/scst_main.c 2007-10-25 09:54:00 UTC (rev 210) @@ -606,8 +606,13 @@ goto out; } - if (dev_handler->exec == NULL) + if (dev_handler->exec == NULL) { +#ifdef ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ dev_handler->exec_atomic = 1; +#else + dev_handler->exec_atomic = 0; +#endif + } if (dev_handler->dev_done == NULL) dev_handler->dev_done_atomic = 1; Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/scst_priv.h 2007-10-25 09:54:00 UTC (rev 210) @@ -126,6 +126,8 @@ return SCST_CONTEXT_DIRECT; } +extern unsigned long scst_max_cmd_mem; + #define SCST_MGMT_CMD_CACHE_STRING "scst_mgmt_cmd" extern struct kmem_cache *scst_mgmt_cachep; extern mempool_t *scst_mgmt_mempool; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-10-23 15:35:20 UTC (rev 209) +++ trunk/scst/src/scst_targ.c 2007-10-25 09:54:00 UTC (rev 210) @@ -305,23 +305,20 @@ */ if (unlikely(scst_get_cdb_info(cmd->cdb, dev->handler->type, - &cdb_info) != 0)) - { - static int t; - if (t < 10) { - t++; - PRINT_INFO_PR("Unknown opcode 0x%02x for %s. " - "Should you update scst_scsi_op_table?", - cmd->cdb[0], dev->handler->name); - } + &cdb_info) != 0)) { + PRINT_ERROR_PR("Unknown opcode 0x%02x for %s. " + "Should you update scst_scsi_op_table?", + cmd->cdb[0], dev->handler->name); +#ifdef USE_EXPECTED_VALUES if (scst_cmd_is_expected_set(cmd)) { TRACE(TRACE_SCSI, "Using initiator supplied values: " "direction %d, transfer_len %d", cmd->expected_data_direction, cmd->expected_transfer_len); cmd->data_direction = cmd->expected_data_direction; + cmd->bufflen = cmd->expected_transfer_len; - /* Restore (most probably) lost CDB length */ + /* Restore (likely) lost CDB length */ cmd->cdb_len = scst_get_cdb_len(cmd->cdb); if (cmd->cdb_len == -1) { PRINT_ERROR_PR("Unable to get CDB length for " @@ -333,13 +330,17 @@ } } else { PRINT_ERROR_PR("Unknown opcode 0x%02x for %s and " - "target %s not supplied expected values. " - "Returning INVALID OPCODE.", cmd->cdb[0], - dev->handler->name, cmd->tgtt->name); + "target %s not supplied expected values", + cmd->cdb[0], dev->handler->name, cmd->tgtt->name); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); goto out_xmit; } +#else + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_opcode)); + goto out_xmit; +#endif } else { TRACE(TRACE_SCSI, "op_name <%s>, direction=%d (expected %d, " "set %s), transfer_len=%d (expected len %d), flags=%d", @@ -349,13 +350,25 @@ cdb_info.transfer_len, cmd->expected_transfer_len, cdb_info.flags); - /* Restore (most probably) lost CDB length */ - cmd->cdb_len = cdb_info.cdb_len; + cmd->data_direction = cdb_info.direction; - cmd->data_direction = cdb_info.direction; - if (!(cdb_info.flags & SCST_UNKNOWN_LENGTH)) + if (unlikely((cdb_info.flags & SCST_UNKNOWN_LENGTH) != 0)) { + if (scst_cmd_is_expected_set(cmd)) { + /* + * Command data length can't be easily + * determined from the CDB. Get it from + * the supplied expected value, but + * limit it to some reasonable value (50MB). + */ + cmd->bufflen = min(cmd->expected_transfer_len, + 50*1024*1024); + } else + cmd->bufflen = 0; + } else cmd->bufflen = cdb_info.transfer_len; - /* else cmd->bufflen remained as it was inited in 0 */ + + /* Restore (likely) lost CDB length */ + cmd->cdb_len = cdb_info.cdb_len; } if (unlikely(cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT)) { @@ -402,25 +415,14 @@ if (state == SCST_CMD_STATE_DEFAULT) state = SCST_CMD_STATE_PREPARE_SPACE; - } - else + } else state = SCST_CMD_STATE_PREPARE_SPACE; - if (scst_cmd_is_expected_set(cmd)) { - if (cmd->expected_transfer_len < cmd->bufflen) { - TRACE(TRACE_SCSI, "cmd->expected_transfer_len(%d) < " - "cmd->bufflen(%d), using expected_transfer_len " - "instead", cmd->expected_transfer_len, - cmd->bufflen); - cmd->bufflen = cmd->expected_transfer_len; - } - } - if (cmd->data_len == -1) cmd->data_len = cmd->bufflen; - if (cmd->data_buf_alloced && (orig_bufflen > cmd->bufflen)) { - PRINT_ERROR_PR("Target driver supplied data buffer (size %d), " + if (cmd->data_buf_alloced && unlikely((orig_bufflen > cmd->bufflen))) { + PRINT_ERROR_PR("Dev handler supplied data buffer (size %d), " "is less, than required (size %d)", cmd->bufflen, orig_bufflen); goto out_error; @@ -448,6 +450,42 @@ } #endif + if (scst_cmd_is_expected_set(cmd)) { +#ifdef USE_EXPECTED_VALUES +# ifdef EXTRACHECKS + if ((cmd->data_direction != cmd->expected_data_direction) || + (cmd->bufflen != cmd->expected_transfer_len)) { + PRINT_ERROR_PR("Expected values don't match decoded ones: " + "data_direction %d, expected_data_direction %d, " + "bufflen %d, expected_transfer_len %d", + cmd->data_direction, cmd->expected_data_direction, + cmd->bufflen, cmd->expected_transfer_len); + } +# endif + cmd->data_direction = cmd->expected_data_direction; + cmd->bufflen = cmd->expected_transfer_len; +#else + if (unlikely(cmd->data_direction != cdb_info.direction)) { + PRINT_ERROR_PR("Expected data direction %d for opcode " + "0x%02x (handler %s, target %s) doesn't match " + "decoded value %d", cmd->data_direction, + cmd->cdb[0], dev->handler->name, + cmd->tgtt->name, cdb_info.direction); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_message)); + goto out_dev_done; + } + if (unlikely(cmd->bufflen != cmd->expected_transfer_len)) { + PRINT_INFO_PR("Warning: expected transfer length %d for " + "opcode 0x%02x (handler %s, target %s) doesn't " + "match decoded value %d. Faulty initiator?", + cmd->expected_transfer_len, cmd->cdb[0], + dev->handler->name, cmd->tgtt->name, + cmd->bufflen); + } +#endif + } + switch (state) { case SCST_CMD_STATE_PREPARE_SPACE: case SCST_CMD_STATE_DEV_PARSE: @@ -488,6 +526,10 @@ out_error: /* dev_done() will be called as part of the regular cmd's finish */ scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + +#ifndef USE_EXPECTED_VALUES +out_dev_done: +#endif cmd->state = SCST_CMD_STATE_DEV_DONE; res = SCST_CMD_STATE_RES_CONT_SAME; goto out; @@ -498,8 +540,6 @@ goto out; } - - static int scst_prepare_space(struct scst_cmd *cmd) { int r = 0, res = SCST_CMD_STATE_RES_CONT_SAME; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |