From: <vl...@us...> - 2006-10-17 09:23:03
|
Revision: 9 http://svn.sourceforge.net/scst/?rev=9&view=rev Author: vlnb Date: 2006-10-17 02:22:31 -0700 (Tue, 17 Oct 2006) Log Message: ----------- More intelligent IO flow control implemented Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/ToDo trunk/scst/include/scsi_tgt.h trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/ChangeLog 2006-10-17 09:22:31 UTC (rev 9) @@ -7,11 +7,13 @@ - Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status implemented. + - More intelligent IO flow control implemented. + - Fixed broken CDROM FILEIO. Before that it always reported "No medium found" - Fixed READ(6)/WRITE(6) CDB decoding for block devices. - This bug prevented FreeBSD initiator from working. + This bug prevented FreeBSD initiators from working. - Implemented sgv_pool. It is mempool-like interface, which caches built SG-vectors in order not to rebuild them again for every @@ -33,7 +35,7 @@ - Exported symbols are now not GPL'ed - - Various cleanups and bug fixes. + - Various cleanups and a lot of bug fixes. Summary of changes between versions 0.9.3 and 0.9.4 --------------------------------------------------- Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/README 2006-10-17 09:22:31 UTC (rev 9) @@ -105,9 +105,6 @@ are seen remotely. There must be LUN 0 in each security group, i.e. LUs numeration must not start from, e.g., 1. -Module "scst_target" supports parameter "scst_threads", which allows to -set count of SCST's threads (CPU count by default). - IMPORTANT: without loading appropriate device handler, corresponding devices ========= will be invisible for remote initiators, which could lead to holes in the LUN addressing, so automatic device scanning by remote SCSI @@ -182,6 +179,18 @@ and eases CPU load, but could create a security hole (information leakage), so enable it, if you have strict security requirements. +Module parameters +----------------- + +Module scsi_tgt supports the following parameters: + + - scst_threads - allows to set count of SCST's threads. By default it + is CPU count. + + - scst_max_cmd_mem - sets maximum amount of memory in Mb allowed to be + consumed by the SCST commands for data buffers at any given time. By + default it is approximately TotalMem/4. + SCST "/proc" commands --------------------- Modified: trunk/scst/ToDo =================================================================== --- trunk/scst/ToDo 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/ToDo 2006-10-17 09:22:31 UTC (rev 9) @@ -32,8 +32,6 @@ To enable it, set SCST_HIGHMEM in 1 in scst_priv.h. HIGHMEM is not supported on 2.4 and is not going to be. - - More intelligent IO-throttling. - - Small ToDo's spread all over the code. - Investigate possible missed emulated UA cases. Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/include/scsi_tgt.h 2006-10-17 09:22:31 UTC (rev 9) @@ -341,12 +341,6 @@ /* Set if the cmd is dead and can be destroyed at any time */ #define SCST_CMD_CAN_BE_DESTROYED 6 -/* - * Set if the cmd is throtteled, ie put on hold since there - * are too many pending commands. - */ -#define SCST_CMD_THROTTELED 7 - /************************************************************* ** Tgt_dev's flags *************************************************************/ @@ -1014,6 +1008,12 @@ */ unsigned int sg_buff_modified:1; + /* + * Set if the cmd's memory requirements are checked and found + * acceptable + */ + unsigned int mem_checked:1; + /**************************************************************/ unsigned long cmd_flags; /* cmd's async flags */ @@ -1022,9 +1022,9 @@ struct scst_tgt *tgt; /* to save extra dereferences */ struct scst_device *dev; /* to save extra dereferences */ - lun_t lun; /* LUN for this cmd */ + lun_t lun; /* LUN for this cmd */ - struct scst_tgt_dev *tgt_dev; /* corresponding device for this cmd */ + struct scst_tgt_dev *tgt_dev; /* corresponding device for this cmd */ struct scsi_request *scsi_req; /* SCSI request */ @@ -1253,9 +1253,6 @@ */ int cmd_count; - /* Throttled commands, protected by scst_list_lock */ - struct list_head thr_cmd_list; - spinlock_t tgt_dev_lock; /* per-session device lock */ /* List of UA's for this device, protected by tgt_dev_lock */ @@ -2048,4 +2045,15 @@ */ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len); +/* + * Checks if total memory allocated by commands is less, than defined + * limit (scst_cur_max_cmd_mem) and returns 0, if it is so. Otherwise, + * returnes 1 and sets on cmd QUEUE FULL or BUSY status as well as + * SCST_CMD_STATE_XMIT_RESP state. Target drivers and dev handlers are + * required to call this function if they allocate data buffers on their + * own. + */ +int scst_check_mem(struct scst_cmd *cmd); + + #endif /* __SCST_H */ Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/src/scst.c 2006-10-17 09:22:31 UTC (rev 9) @@ -72,10 +72,18 @@ LIST_HEAD(scst_init_cmd_list); LIST_HEAD(scst_cmd_list); DECLARE_WAIT_QUEUE_HEAD(scst_list_waitQ); + +spinlock_t scst_cmd_mem_lock = SPIN_LOCK_UNLOCKED; +unsigned long scst_cur_cmd_mem, scst_cur_max_cmd_mem; + struct tasklet_struct scst_tasklets[NR_CPUS]; struct scst_sgv_pools scst_sgv; +DECLARE_WORK(scst_cmd_mem_work, scst_cmd_mem_work_fn, 0); + +unsigned long scst_max_cmd_mem; + LIST_HEAD(scst_mgmt_cmd_list); LIST_HEAD(scst_active_mgmt_cmd_list); LIST_HEAD(scst_delayed_mgmt_cmd_list); @@ -105,6 +113,10 @@ module_param_named(scst_threads, scst_threads, int, 0); MODULE_PARM_DESC(scst_threads, "SCSI target threads count"); +module_param_named(scst_max_cmd_mem, scst_max_cmd_mem, long, 0); +MODULE_PARM_DESC(scst_max_cmd_mem, "Maximum memory allowed to be consumed by " + "the SCST commands at any given time in Mb"); + int scst_register_target_template(struct scst_tgt_template *vtt) { int res = 0; @@ -1032,9 +1044,23 @@ } atomic_inc(&scst_threads_count); - PRINT_INFO_PR("SCST version %s loaded successfully", - SCST_VERSION_STRING); + if (scst_max_cmd_mem == 0) { + struct sysinfo si; + si_meminfo(&si); +#if BITS_PER_LONG == 32 + scst_max_cmd_mem = min(((uint64_t)si.totalram << PAGE_SHIFT) >> 2, + (uint64_t)1 << 30); +#else + scst_max_cmd_mem = (si.totalram << PAGE_SHIFT) >> 2; +#endif + } else + scst_max_cmd_mem <<= 20; + scst_cur_max_cmd_mem = scst_max_cmd_mem; + + PRINT_INFO_PR("SCST version %s loaded successfully (max mem for " + "commands %ld Mb)", SCST_VERSION_STRING, scst_max_cmd_mem >> 20); + out: TRACE_EXIT_RES(res); return res; @@ -1125,6 +1151,11 @@ } } + if (test_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags)) { + cancel_delayed_work(&scst_cmd_mem_work); + flush_scheduled_work(); + } + scst_proc_cleanup_module(); scsi_unregister_interface(&scst_interface); scst_destroy_acg(scst_default_acg); @@ -1207,6 +1238,7 @@ #endif EXPORT_SYMBOL(__scst_get_buf); +EXPORT_SYMBOL(scst_check_mem); /* * Other Commands Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/src/scst_lib.c 2006-10-17 09:22:31 UTC (rev 9) @@ -92,15 +92,13 @@ { scst_set_cmd_error_status(cmd, SAM_STAT_BUSY); TRACE_MGMT_DBG("Sending BUSY status to initiator %s " - "(cmds count %d, queue_type %x, sess->init_phase %d), " - "probably the system is overloaded", + "(cmds count %d, queue_type %x, sess->init_phase %d)", cmd->sess->initiator_name, cmd->sess->sess_cmd_count, cmd->queue_type, cmd->sess->init_phase); } else { scst_set_cmd_error_status(cmd, SAM_STAT_TASK_SET_FULL); TRACE_MGMT_DBG("Sending QUEUE_FULL status to initiator %s " - "(cmds count %d, queue_type %x, sess->init_phase %d), " - "probably the system is overloaded", + "(cmds count %d, queue_type %x, sess->init_phase %d)", cmd->sess->initiator_name, cmd->sess->sess_cmd_count, cmd->queue_type, cmd->sess->init_phase); } @@ -358,7 +356,6 @@ (uint64_t)tgt_dev->acg_dev->lun); } - INIT_LIST_HEAD(&tgt_dev->thr_cmd_list); spin_lock_init(&tgt_dev->tgt_dev_lock); INIT_LIST_HEAD(&tgt_dev->UA_list); spin_lock_init(&tgt_dev->sn_lock); @@ -2036,28 +2033,6 @@ return; } -/* Called under scst_list_lock and IRQs disabled */ -void scst_throttle_cmd(struct scst_cmd *cmd) -{ - struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; - - TRACE(TRACE_RETRY, "Too many pending commands in session, initiator " - "\"%s\". Moving cmd %p to thr cmd list", - (cmd->sess->initiator_name[0] == '\0') ? "Anonymous" : - cmd->sess->initiator_name, cmd); - list_move_tail(&cmd->cmd_list_entry, &tgt_dev->thr_cmd_list); - set_bit(SCST_CMD_THROTTELED, &cmd->cmd_flags); -} - -/* Called under scst_list_lock and IRQs disabled */ -void scst_unthrottle_cmd(struct scst_cmd *cmd) -{ - TRACE(TRACE_RETRY|TRACE_DEBUG, "Moving cmd %p from " - "thr cmd list to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); - clear_bit(SCST_CMD_THROTTELED, &cmd->cmd_flags); -} - static struct scst_cmd *scst_inc_expected_sn( struct scst_tgt_dev *tgt_dev, struct scst_cmd *out_of_sn_cmd) { Modified: trunk/scst/src/scst_mem.c =================================================================== --- trunk/scst/src/scst_mem.c 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/src/scst_mem.c 2006-10-17 09:22:31 UTC (rev 9) @@ -171,7 +171,7 @@ obj->sg_count = 0; for (pg = 0; pg < pages; pg++) { #ifdef DEBUG_OOM - if (((scst_random() % 100) == 55)) + if ((scst_random() % 10000) == 55) obj->entries[obj->sg_count].page = NULL; else #endif Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/src/scst_priv.h 2006-10-17 09:22:31 UTC (rev 9) @@ -73,6 +73,9 @@ /* Set if a TM command is being performed */ #define SCST_FLAG_TM_ACTIVE 2 +/* Set if scst_cmd_mem_work is scheduled */ +#define SCST_FLAG_CMD_MEM_WORK_SCHEDULED 3 + /** ** Return codes for cmd state process functions **/ @@ -93,6 +96,7 @@ #define SCST_THREAD_FLAGS CLONE_KERNEL #define SCST_TGT_RETRY_TIMEOUT (3/2*HZ) +#define SCST_CMD_MEM_TIMEOUT (120*HZ) static inline int scst_get_context(void) { /* Be overinsured */ @@ -141,6 +145,11 @@ extern struct list_head scst_init_cmd_list; extern struct list_head scst_cmd_list; +extern spinlock_t scst_cmd_mem_lock; +extern unsigned long scst_max_cmd_mem, scst_cur_max_cmd_mem, scst_cur_cmd_mem; +extern struct work_struct scst_cmd_mem_work; + +/* The following lists protected by scst_list_lock as well */ extern struct list_head scst_mgmt_cmd_list; extern struct list_head scst_active_mgmt_cmd_list; extern struct list_head scst_delayed_mgmt_cmd_list; @@ -202,6 +211,7 @@ void scst_cmd_tasklet(long p); int scst_mgmt_cmd_thread(void *arg); int scst_mgmt_thread(void *arg); +void scst_cmd_mem_work_fn(void *p); struct scst_device *scst_alloc_device(int gfp_mask); void scst_free_device(struct scst_device *tgt_dev); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-10-12 16:43:38 UTC (rev 8) +++ trunk/scst/src/scst_targ.c 2006-10-17 09:22:31 UTC (rev 9) @@ -468,6 +468,96 @@ goto out; } +void scst_cmd_mem_work_fn(void *p) +{ + TRACE_ENTRY(); + + spin_lock_bh(&scst_cmd_mem_lock); + + scst_cur_max_cmd_mem += (scst_cur_max_cmd_mem >> 3); + if (scst_cur_max_cmd_mem < scst_max_cmd_mem) { + TRACE_MGMT_DBG("%s", "Schedule cmd_mem_work"); + schedule_delayed_work(&scst_cmd_mem_work, SCST_CMD_MEM_TIMEOUT); + } else { + scst_cur_max_cmd_mem = scst_max_cmd_mem; + clear_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags); + } + TRACE_MGMT_DBG("New max cmd mem %ld Mb", scst_cur_max_cmd_mem >> 20); + + spin_unlock_bh(&scst_cmd_mem_lock); + + TRACE_EXIT(); + return; +} + +int scst_check_mem(struct scst_cmd *cmd) +{ + int res = 0; + + TRACE_ENTRY(); + + if (cmd->mem_checked) + goto out; + + spin_lock_bh(&scst_cmd_mem_lock); + + scst_cur_cmd_mem += cmd->bufflen; + cmd->mem_checked = 1; + if (likely(scst_cur_cmd_mem <= scst_cur_max_cmd_mem)) + goto out_unlock; + + TRACE(TRACE_OUT_OF_MEM, "Total memory allocated by commands (%ld Kb) " + "is too big, returning QUEUE FULL to initiator \"%s\" (maximum " + "allowed %ld Kb)", scst_cur_cmd_mem >> 10, + (cmd->sess->initiator_name[0] == '\0') ? + "Anonymous" : cmd->sess->initiator_name, + scst_cur_max_cmd_mem >> 10); + + scst_cur_cmd_mem -= cmd->bufflen; + cmd->mem_checked = 0; + scst_set_busy(cmd); + cmd->state = SCST_CMD_STATE_XMIT_RESP; + res = 1; + +out_unlock: + spin_unlock_bh(&scst_cmd_mem_lock); + +out: + TRACE_EXIT_RES(res); + return res; +} + +static void scst_low_cur_max_cmd_mem(void) +{ + TRACE_ENTRY(); + + if (test_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags)) { + cancel_delayed_work(&scst_cmd_mem_work); + flush_scheduled_work(); + clear_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags); + } + + spin_lock_bh(&scst_cmd_mem_lock); + + scst_cur_max_cmd_mem = (scst_cur_cmd_mem >> 1) + + (scst_cur_cmd_mem >> 2); + if (scst_cur_max_cmd_mem < 16*1024*1024) + scst_cur_max_cmd_mem = 16*1024*1024; + + if (!test_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags)) { + TRACE_MGMT_DBG("%s", "Schedule cmd_mem_work"); + schedule_delayed_work(&scst_cmd_mem_work, SCST_CMD_MEM_TIMEOUT); + set_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags); + } + + spin_unlock_bh(&scst_cmd_mem_lock); + + TRACE_MGMT_DBG("New max cmd mem %ld Mb", scst_cur_max_cmd_mem >> 20); + + TRACE_EXIT(); + return; +} + static int scst_prepare_space(struct scst_cmd *cmd) { int r, res = SCST_CMD_STATE_RES_CONT_SAME; @@ -479,6 +569,10 @@ goto out; } + r = scst_check_mem(cmd); + if (unlikely(r != 0)) + goto out; + if (cmd->data_buf_tgt_alloc) { TRACE_MEM("%s", "Custom tgt data buf allocation requested"); r = cmd->tgtt->alloc_data_buf(cmd); @@ -512,7 +606,8 @@ out_no_space: TRACE(TRACE_OUT_OF_MEM, "Unable to allocate or build requested buffer " - "(size %zd), sending BUSY status", cmd->bufflen); + "(size %zd), sending BUSY or QUEUE FULL status", cmd->bufflen); + scst_low_cur_max_cmd_mem(); scst_set_busy(cmd); cmd->state = SCST_CMD_STATE_DEV_DONE; res = SCST_CMD_STATE_RES_CONT_SAME; @@ -2090,6 +2185,12 @@ TRACE_ENTRY(); + if (cmd->mem_checked) { + spin_lock_bh(&scst_cmd_mem_lock); + scst_cur_cmd_mem -= cmd->bufflen; + spin_unlock_bh(&scst_cmd_mem_lock); + } + spin_lock_irq(&scst_list_lock); TRACE_DBG("Deleting cmd %p from cmd list", cmd); @@ -2098,18 +2199,8 @@ if (cmd->mgmt_cmnd) scst_complete_cmd_mgmt(cmd, cmd->mgmt_cmnd); - if (likely(cmd->tgt_dev != NULL)) { - struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; - tgt_dev->cmd_count--; - if (!list_empty(&tgt_dev->thr_cmd_list)) { - struct scst_cmd *t = - list_entry(tgt_dev->thr_cmd_list.next, - typeof(*t), cmd_list_entry); - scst_unthrottle_cmd(t); - if (!cmd->processible_env) - wake_up(&scst_list_waitQ); - } - } + if (likely(cmd->tgt_dev != NULL)) + cmd->tgt_dev->cmd_count--; cmd->sess->sess_cmd_count--; @@ -2261,18 +2352,7 @@ res = scst_translate_lun(cmd); if (likely(res == 0)) { cmd->state = SCST_CMD_STATE_DEV_PARSE; - if (cmd->tgt_dev->cmd_count > SCST_MAX_DEVICE_COMMANDS) -#if 0 /* don't know how it's better */ - { - scst_throttle_cmd(cmd); - } else { - BUG_ON(!list_empty(&cmd->tgt_dev->thr_cmd_list)); - TRACE_DBG("Moving cmd %p to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, - &scst_active_cmd_list); - } -#else - { + if (cmd->tgt_dev->cmd_count > SCST_MAX_DEVICE_COMMANDS) { TRACE(TRACE_RETRY, "Too many pending commands in " "session, returning BUSY to initiator \"%s\"", (cmd->sess->initiator_name[0] == '\0') ? @@ -2282,7 +2362,6 @@ } TRACE_DBG("Moving cmd %p to active cmd list", cmd); list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); -#endif } else if (res < 0) { TRACE_DBG("Finishing cmd %p", cmd); scst_set_cmd_error(cmd, @@ -2688,9 +2767,6 @@ set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags); smp_mb__after_set_bit(); - if (test_bit(SCST_CMD_THROTTELED, &cmd->cmd_flags)) - scst_unthrottle_cmd(cmd); - if (call_dev_task_mgmt_fn && cmd->tgt_dev) scst_call_dev_task_mgmt_fn(mcmd, cmd->tgt_dev, 0); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-20 18:19:19
|
Revision: 10 http://svn.sourceforge.net/scst/?rev=10&view=rev Author: vlnb Date: 2006-10-20 11:18:46 -0700 (Fri, 20 Oct 2006) Log Message: ----------- In FILEIO: - Improved errors reporting - Improved SYNCHRONIZE_CACHE support, fsync() reimplemented - Improved ORDERED commands support - Added FUA support - Added NV_CACHE - Improved CDROM FILEIO Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_dev_handler.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/ChangeLog 2006-10-20 18:18:46 UTC (rev 10) @@ -12,6 +12,9 @@ - Fixed broken CDROM FILEIO. Before that it always reported "No medium found" + - Data synchronization fixes and improvements in FILEIO. Added FUA + support. + - Fixed READ(6)/WRITE(6) CDB decoding for block devices. This bug prevented FreeBSD initiators from working. Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/README 2006-10-20 18:18:46 UTC (rev 10) @@ -13,13 +13,12 @@ SCST looks to be quite stable (for beta) and useful. It supports disks (SCSI type 0), tapes (type 1), processor (type 3), CDROM's (type 5), MO disks (type 7), medium changers (type 8) and RAID controller (type 0xC). -There are also FILEIO and "performance" device handlers. In addition, -starting from version 0.9.3 advanced per-initiator access and devices -visibility management is added, so different initiators could see -different set of devices with different access permissions. See below -for details. +There are also FILEIO and "performance" device handlers. In addition, it +supports advanced per-initiator access and devices visibility +management, so different initiators could see different set of devices +with different access permissions. See below for details. -This is more or less stable (but still beta) version. +This is quite stable (but still beta) version. Tested mostly on "vanilla" 2.6.17.8 kernel from kernel.org. @@ -53,9 +52,6 @@ exec() method skip (pretend to execute) all READ and WRITE operations and thus provide a way for direct link performance measurements without overhead of actual data transferring from/to underlying SCSI device. -Starting from 0.9.3 these handlers are incorporated inside of -corresponding device handler for real device and could be assigned on -run-time via "assign" command in "/proc/scsi_tgt/scsi_tgt" (see below). NOTE: Since "perf" device handlers on READ operations don't touch the ==== commands' data buffer, it is returned to remote initiators as it @@ -105,7 +101,7 @@ are seen remotely. There must be LUN 0 in each security group, i.e. LUs numeration must not start from, e.g., 1. -IMPORTANT: without loading appropriate device handler, corresponding devices +IMPORTANT: Without loading appropriate device handler, corresponding devices ========= will be invisible for remote initiators, which could lead to holes in the LUN addressing, so automatic device scanning by remote SCSI mid-level could not notice the devices. Therefore you will have @@ -113,15 +109,15 @@ 'echo "scsi add-single-device A 0 0 B" >/proc/scsi/scsi', where A - is the host number, B - LUN. -IMPORTANT 1: In the current version simultaneous access to local SCSI -=========== devices via standard high-level SCSI drivers (sd, st, sg, - etc.) and SCST's target drivers is unsupported. Especially - it is important for execution via sg and st commands that - change the state of devices and their parameters, because - that could lead to data corruption. If any such command - is done, at least related device handler driver(s) must be - restarted. For block devices READ/WRITE commands using direct - disk handler look to be safe. +IMPORTANT: In the current version simultaneous access to local SCSI devices +========= via standard high-level SCSI drivers (sd, st, sg, etc.) and + SCST's target drivers is unsupported. Especially it is + important for execution via sg and st commands that change + the state of devices and their parameters, because that could + lead to data corruption. If any such command is done, at + least related device handler driver(s) must be restarted. For + block devices READ/WRITE commands using direct disk handler + look to be safe. To uninstall, type 'make uninstall'. It is not implemented for 2.6 kernels. @@ -302,8 +298,10 @@ information of currently open device files. On write it supports the following command: - * "open NAME PATH [FLAGS]" - opens file "PATH" as device "NAME" with - flags "FLAGS. Possible flags: + * "open NAME PATH [BLOCK_SIZE] [FLAGS]" - opens file "PATH" as + device "NAME" with block size "BLOCK_SIZE" bytes with flags + "FLAGS". The block size must be power of 2 and >= 512 bytes + Default is 512. Possible flags: - WRITE_THROUGH - write back caching disabled @@ -315,21 +313,61 @@ - NULLIO - in this mode no real IO will be done, but success will be returned. Intended to be used for performance measurements at the same way as "*_perf" handlers. + + - NV_CACHE - enables "non-volatile cache" mode. In this mode it is + assumed that the target has GOOD uninterruptable power supply + and software/hardware bug free, i.e. all data from the target's + cache are guaranteed sooner or later to go to the media, hence + all data synchronization with media operations, like + SYNCHRONIZE_CACHE, are ignored (BTW, so violating SCSI standard) + in order to bring a bit more performance. Use with extreme + caution, since in this mode after a crash of the target + journaled file systems don't guarantee the consistency after + journal recovery, therefore manual fsck MUST be ran. The main + intent for it is to determine the performance impact caused by + the cache synchronization. Note, that since usually the journal + barrier protection (see "IMPORTANT" below) turned off, enabling + NV_CACHE could change nothing, since no data synchronization + with media operations will go from the initiator. * "close NAME" - closes device "NAME". For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/disk_fileio/disk_fileio" will open file /vdisks/disk1 as virtual FILEIO disk with name "disk1". -IMPORTANT: by default for performance reasons FILEIO devices use write back -========= caching policy, so if you care about the consistence of file systems, - laying over them, and your data you must supply your target - server with some king of UPS or disable write back caching - via WRITE_THROUGH flag. The FS joutnaling over write back - caching enabled devices doesn't protect from power failures - on the target side, therefore even after successful journal - rollback you very much risk to loose your data. +IMPORTANT: By default for performance reasons FILEIO devices use write back +========= caching policy. This is generally safe from the consistence of + journaled file systems, laying over them, point of view, but + your unsaved cached data will be lost in case of + power/hardware/software faulure, so you must supply your + target server with some kind of UPS or disable write back + caching using WRITE_THROUGH flag. You also should note, that + the file systems journaling over write back caching enabled + devices works reliably *ONLY* if it uses some kind of data + protection barriers (i.e. after writing journaling data some + kind of synchronization with media operations will be used), + otherwise, because of possible reordering in the cache, even + after successful journal rollback you very much risk to loose + your data on the FS. On Linux initiators for EXT3 and + ReiserFS file systems the barrier protection could be turned + on using "barrier=1" and "barrier=flush" mount options + correspondingly. Note, that usually it turned off by default + and the status of barriers usage isn't reported anywhere in + the system logs as well as there is no way to know it on the + mounted file system (at least we don't know how). Also note + that on some real-life workloads write through caching might + perform better, than write back one with barrier protection + turned on. +IMPORTANT: Many disk and partition table mananagement 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 + another block size, than one, with which it was already + divided on partitions, you could get various weird things + like utilities hang up or other unexpected behaviour. Thus, to + be sure, zero the exported file or device before the first + access to it from the remote initiator with another block size. + Performance ----------- @@ -384,6 +422,15 @@ that in some cases it could lead to 5-10 times less performance, than expected. +IMPORTANT: If you use on initiator some versions of Windows (at least W2K) +========= you can't get good write performance for FILEIO devices with + default 512 bytes block sizes. You could get about 10% of + the expected one. This is because of "unusual" write access + pattern, with which Windows'es write data and which is + (simplifying) incompatible with how Linux page cache works. + With 4096 bytes block sizes for FILEIO devices the write + performance will be as expected. + Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x kernel, where we did carefull performance study, aggregate throuhput about 390 Mb/sec from 2 qla2300 cards sitting on different 64-bit PCI @@ -394,10 +441,7 @@ The target computer configuration was not very modern for the moment: something like 2x1GHz Intel P3 Xeon CPUs. You can estimate the memory/PCI speed from that. CPU load was ~5%, there were ~30K IRQ/sec -and no additional SCST related context switches. Version 0.9.3 at the -same setup will usually have 1 CS/cmd for buffer allocation, so the will -be about 5-10K CS/sec. This will be fixed in the next version, when -sgv_pool is integrated. +and no additional SCST related context switches. Credits ------- Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/include/scsi_tgt.h 2006-10-20 18:18:46 UTC (rev 10) @@ -1388,6 +1388,9 @@ #define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0 #define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0 #define scst_sense_medium_changed_UA UNIT_ATTENTION, 0x28, 0 +#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 #ifndef smp_mb__after_set_bit /* There is no smp_mb__after_set_bit() in the kernel */ @@ -2055,5 +2058,11 @@ */ int scst_check_mem(struct scst_cmd *cmd); +/* + * Get/put global ref counter that prevents from entering into suspended + * activities stage, so protects from any global management operations. + */ +void scst_get(void); +void scst_put(void); #endif /* __SCST_H */ Modified: trunk/scst/src/dev_handlers/scst_dev_handler.h =================================================================== --- trunk/scst/src/dev_handlers/scst_dev_handler.h 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/src/dev_handlers/scst_dev_handler.h 2006-10-20 18:18:46 UTC (rev 10) @@ -11,7 +11,8 @@ #ifdef DEBUG #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \ - TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | TRACE_MGMT_DEBUG) + TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | TRACE_MGMT_DEBUG | \ + TRACE_SPECIAL) #else #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR) #endif Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-10-20 18:18:46 UTC (rev 10) @@ -31,6 +31,7 @@ #include <linux/proc_fs.h> #include <linux/list.h> #include <linux/ctype.h> +#include <linux/writeback.h> #include <asm/atomic.h> #define LOG_PREFIX "dev_fileio" @@ -57,6 +58,7 @@ #define MSENSE_BUF_SZ 256 #define DBD 0x08 /* disable block descriptor */ #define WP 0x80 /* write protect */ +#define DPOFUA 0x10 /* DPOFUA bit */ #define WCE 0x04 /* write cache enable */ #define PF 0x10 /* page format */ @@ -86,10 +88,12 @@ loff_t file_size; /* in bytes */ unsigned int rd_only_flag:1; unsigned int wt_flag:1; + unsigned int nv_cache:1; unsigned int o_direct_flag:1; unsigned int media_changed:1; unsigned int prevent_allow_medium_removal:1; unsigned int nullio:1; + unsigned int cdrom_empty:1; int virt_id; char name[16+1]; /* Name of virtual device, must be <= SCSI Model + 1 */ @@ -107,6 +111,7 @@ int iv_count; struct list_head fdev_cmd_list; wait_queue_head_t fdev_waitQ; + struct scst_fileio_dev *virt_dev; atomic_t threads_count; struct semaphore shutdown_mutex; struct list_head ftgt_list_entry; @@ -132,7 +137,8 @@ static void fileio_exec_mode_select(struct scst_cmd *cmd); static void fileio_exec_read_toc(struct scst_cmd *cmd); static void fileio_exec_prevent_allow_medium_removal(struct scst_cmd *cmd); -static int fileio_fsync(struct scst_cmd *cmd, uint64_t lba_start, uint32_t number_of_blocks); +static int fileio_fsync(struct scst_fileio_tgt_dev *ftgt_dev, + loff_t loff, loff_t len, struct scst_cmd *cmd); static int disk_fileio_proc(char *buffer, char **start, off_t offset, int length, int *eof, struct scst_dev_type *dev_type, int inout); static int cdrom_fileio_proc(char *buffer, char **start, off_t offset, @@ -180,9 +186,9 @@ static struct scst_dev_type cdrom_devtype_fileio = CDROM_TYPE_FILEIO; static char *disk_fileio_proc_help_string = - "echo \"open|close NAME [FILE_NAME [WRITE_THROUGH READ_ONLY " - "O_DIRECT NULLIO]]\" >/proc/scsi_tgt/" DISK_FILEIO_NAME "/" - DISK_FILEIO_NAME "\n"; + "echo \"open|close NAME [FILE_NAME [BLOCK_SIZE] [WRITE_THROUGH " + "READ_ONLY O_DIRECT NULLIO NV_CACHE]]\" >/proc/scsi_tgt/" + DISK_FILEIO_NAME "/" DISK_FILEIO_NAME "\n"; static char *cdrom_fileio_proc_help_string = "echo \"open|change|close NAME [FILE_NAME]\" " @@ -274,59 +280,66 @@ if (dev->handler->type == TYPE_ROM) virt_dev->rd_only_flag = 1; - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", - virt_dev->file_name, res); - goto out; - } + if (!virt_dev->cdrom_empty) { + fd = fileio_open(virt_dev); + if (IS_ERR(fd)) { + res = PTR_ERR(fd); + PRINT_ERROR_PR("filp_open(%s) returned an error %d", + virt_dev->file_name, res); + goto out; + } - if ((fd->f_op == NULL) || (fd->f_op->readv == NULL) || - (fd->f_op->writev == NULL)) - { - PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't have required " - "capabilities"); - res = -EINVAL; - goto out_close_file; - } + if ((fd->f_op == NULL) || (fd->f_op->readv == NULL) || + (fd->f_op->writev == NULL)) + { + PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't have " + "required capabilities"); + res = -EINVAL; + goto out_close_file; + } - /* seek to end */ - old_fs = get_fs(); - set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); - } else { - err = default_llseek(fd, 0, 2/*SEEK_END*/); - } - set_fs(old_fs); - if (err < 0) { - res = err; - PRINT_ERROR_PR("llseek %s returned an error %d", - virt_dev->file_name, res); - goto out_close_file; - } - virt_dev->file_size = err; - TRACE_DBG("size of file: %Ld", (uint64_t)err); + /* seek to end */ + old_fs = get_fs(); + set_fs(get_ds()); + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); + } else { + err = default_llseek(fd, 0, 2/*SEEK_END*/); + } + set_fs(old_fs); + if (err < 0) { + res = err; + PRINT_ERROR_PR("llseek %s returned an error %d", + virt_dev->file_name, res); + goto out_close_file; + } + virt_dev->file_size = err; + TRACE_DBG("size of file: %Ld", (uint64_t)err); - filp_close(fd, NULL); - + filp_close(fd, NULL); + } else + virt_dev->file_size = 0; + if (dev->handler->type == TYPE_DISK) { - virt_dev->block_size = DEF_DISK_BLOCKSIZE; - virt_dev->block_shift = DEF_DISK_BLOCKSIZE_SHIFT; - virt_dev->nblocks = virt_dev->file_size >> DEF_DISK_BLOCKSIZE_SHIFT; + virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift; } else { virt_dev->block_size = DEF_CDROM_BLOCKSIZE; virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT; virt_dev->nblocks = virt_dev->file_size >> DEF_CDROM_BLOCKSIZE_SHIFT; } - PRINT_INFO_PR("Attached SCSI target virtual %s %s " + + if (!virt_dev->cdrom_empty) { + PRINT_INFO_PR("Attached SCSI target virtual %s %s " "(file=\"%s\", fs=%LdMB, bs=%d, nblocks=%Ld, cyln=%Ld%s)", (dev->handler->type == TYPE_DISK) ? "disk" : "cdrom", virt_dev->name, virt_dev->file_name, virt_dev->file_size >> 20, virt_dev->block_size, virt_dev->nblocks, virt_dev->nblocks/64/32, virt_dev->nblocks < 64*32 ? " !WARNING! cyln less than 1" : ""); + } else { + PRINT_INFO_PR("Attached empty SCSI target virtual cdrom %s", + virt_dev->name); + } dev->tgt_dev_specific = virt_dev; @@ -369,13 +382,14 @@ static void fileio_do_job(struct scst_cmd *cmd) { - uint64_t lba_start = 0; - uint32_t number_of_blocks; + uint64_t lba_start; + loff_t data_len; int opcode = cmd->cdb[0]; loff_t loff; struct scst_device *dev = cmd->dev; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)dev->tgt_dev_specific; + int fua = 0; TRACE_ENTRY(); @@ -393,6 +407,7 @@ lba_start = (((cmd->cdb[1] & 0x1f) << (BYTE * 2)) + (cmd->cdb[2] << (BYTE * 1)) + (cmd->cdb[3] << (BYTE * 0))); + data_len = cmd->bufflen; break; case READ_10: case READ_12: @@ -402,31 +417,56 @@ case WRITE_VERIFY: case WRITE_VERIFY_12: case VERIFY_12: + lba_start = be32_to_cpu(*(u32 *)&cmd->cdb[2]); + data_len = cmd->bufflen; + break; case SYNCHRONIZE_CACHE: lba_start = be32_to_cpu(*(u32 *)&cmd->cdb[2]); + data_len = ((cmd->cdb[7] << (BYTE * 1)) + + (cmd->cdb[8] << (BYTE * 0))) << virt_dev->block_shift; + if (data_len == 0) + data_len = virt_dev->file_size - + ((loff_t)lba_start << virt_dev->block_shift); break; case READ_16: case WRITE_16: case WRITE_VERIFY_16: case VERIFY_16: - lba_start = be64_to_cpu(*(u64 *)&cmd->cdb[2]); + lba_start = be64_to_cpu(*(u64*)&cmd->cdb[2]); + data_len = cmd->bufflen; break; + default: + lba_start = 0; + data_len = 0; } loff = (loff_t)lba_start << virt_dev->block_shift; - TRACE_DBG("cmd %p, lba_start %Ld, loff %Ld", cmd, lba_start, - (uint64_t)loff); - if (unlikely(loff < 0) || - unlikely((loff + cmd->bufflen) > virt_dev->file_size)) { + TRACE_DBG("cmd %p, lba_start %Ld, loff %Ld, data_len %Ld", cmd, + lba_start, (uint64_t)loff, (uint64_t)data_len); + if (unlikely(loff < 0) || unlikely(data_len < 0) || + unlikely((loff + data_len) > virt_dev->file_size)) { PRINT_INFO_PR("Access beyond the end of the device " - "(%lld of %lld, len %zd)", (uint64_t)loff, - (uint64_t)virt_dev->file_size, cmd->bufflen); + "(%lld of %lld, len %Ld)", (uint64_t)loff, + (uint64_t)virt_dev->file_size, (uint64_t)data_len); scst_set_cmd_error(cmd, SCST_LOAD_SENSE( scst_sense_block_out_range_error)); goto done; } - + switch (opcode) { + case WRITE_10: + case WRITE_12: + case WRITE_16: + fua = (cmd->cdb[1] & 0x8) && !virt_dev->wt_flag; + if (cmd->cdb[1] & 0x8) { + TRACE(TRACE_SCSI, "FUA(%d): loff=%Ld, " + "data_len=%Ld", fua, (uint64_t)loff, + (uint64_t)data_len); + } + break; + } + + switch (opcode) { case READ_6: case READ_10: case READ_12: @@ -438,16 +478,24 @@ case WRITE_12: case WRITE_16: if (likely(!virt_dev->rd_only_flag)) { + int do_fsync = 0; + struct scst_fileio_tgt_dev *ftgt_dev = + (struct scst_fileio_tgt_dev*) + cmd->tgt_dev->tgt_dev_specific; + if ((cmd->queue_type == SCST_CMD_QUEUE_ORDERED) && + !virt_dev->wt_flag) { + TRACE(TRACE_SCSI/*|TRACE_SPECIAL*/, "ORDERED WRITE: " + "loff=%Ld, data_len=%Ld", (uint64_t)loff, + (uint64_t)data_len); + do_fsync = 1; + if (fileio_fsync(ftgt_dev, 0, 0, cmd) != 0) + goto done; + } fileio_exec_write(cmd, loff); -#if 0 /* instead, O_SYNC flag is used */ - if ((cmd->status == 0) && virt_dev->wt_flag) { - number_of_blocks = cmd->bufflen >> - virt_dev->block_shift; - fileio_fsync(cmd, lba_start, number_of_blocks); - } -#endif - } - else { + /* O_SYNC flag is used for wt_flag devices */ + if (do_fsync || fua) + fileio_fsync(ftgt_dev, loff, data_len, cmd); + } else { TRACE_DBG("%s", "Attempt to write to read-only device"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_data_protect)); @@ -457,29 +505,54 @@ case WRITE_VERIFY_12: case WRITE_VERIFY_16: if (likely(!virt_dev->rd_only_flag)) { + int do_fsync = 0; + struct scst_fileio_tgt_dev *ftgt_dev = + (struct scst_fileio_tgt_dev*) + cmd->tgt_dev->tgt_dev_specific; + if ((cmd->queue_type == SCST_CMD_QUEUE_ORDERED) && + !virt_dev->wt_flag) { + TRACE(TRACE_SCSI/*|TRACE_SPECIAL*/, "ORDERED " + "WRITE_VERIFY: loff=%Ld, data_len=%Ld", + (uint64_t)loff, (uint64_t)data_len); + do_fsync = 1; + if (fileio_fsync(ftgt_dev, 0, 0, cmd) != 0) + goto done; + } fileio_exec_write(cmd, loff); -#if 0 /* instead, O_SYNC flag is used */ - if ((cmd->status == 0) && virt_dev->wt_flag) { - number_of_blocks = cmd->bufflen >> - virt_dev->block_shift; - fileio_fsync(cmd, lba_start, number_of_blocks); - } -#endif + /* O_SYNC flag is used for wt_flag devices */ if (cmd->status == 0) fileio_exec_verify(cmd, loff); - } - else { + else if (do_fsync) + fileio_fsync(ftgt_dev, loff, data_len, cmd); + } else { TRACE_DBG("%s", "Attempt to write to read-only device"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_data_protect)); } break; case SYNCHRONIZE_CACHE: - /* ToDo: IMMED bit */ - number_of_blocks = ((cmd->cdb[7] << (BYTE * 1)) + - (cmd->cdb[8] << (BYTE * 0))); - fileio_fsync(cmd, lba_start, number_of_blocks); - break; + { + int immed = cmd->cdb[1] & 0x2; + struct scst_fileio_tgt_dev *ftgt_dev = + (struct scst_fileio_tgt_dev*) + cmd->tgt_dev->tgt_dev_specific; + TRACE(TRACE_SCSI, "SYNCHRONIZE_CACHE: " + "loff=%Ld, data_len=%Ld, immed=%d", (uint64_t)loff, + (uint64_t)data_len, immed); + if (immed) { + scst_get(); + cmd->completed = 1; + cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); + /* cmd is dead here */ + fileio_fsync(ftgt_dev, loff, data_len, NULL); + /* ToDo: fileio_fsync() error processing */ + scst_put(); + goto out; + } else { + fileio_fsync(ftgt_dev, loff, data_len, cmd); + break; + } + } case VERIFY_6: case VERIFY: case VERIFY_12: @@ -518,6 +591,7 @@ done_uncompl: cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); +out: TRACE_EXIT(); return; } @@ -611,14 +685,18 @@ init_waitqueue_head(&ftgt_dev->fdev_waitQ); atomic_set(&ftgt_dev->threads_count, 0); init_MUTEX_LOCKED(&ftgt_dev->shutdown_mutex); + ftgt_dev->virt_dev = virt_dev; - ftgt_dev->fd = fileio_open(virt_dev); - if (IS_ERR(ftgt_dev->fd)) { - res = PTR_ERR(ftgt_dev->fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", - virt_dev->file_name, res); - goto out_free; - } + if (!virt_dev->cdrom_empty) { + ftgt_dev->fd = fileio_open(virt_dev); + if (IS_ERR(ftgt_dev->fd)) { + res = PTR_ERR(ftgt_dev->fd); + PRINT_ERROR_PR("filp_open(%s) returned an error %d", + virt_dev->file_name, res); + goto out_free; + } + } else + ftgt_dev->fd = NULL; /* * Only ONE thread must be run here, otherwise the commands could @@ -644,7 +722,8 @@ return res; out_free_close: - filp_close(ftgt_dev->fd, NULL); + if (ftgt_dev->fd) + filp_close(ftgt_dev->fd, NULL); out_free: TRACE_MEM("kfree ftgt_dev: %p", ftgt_dev); @@ -669,7 +748,8 @@ wake_up_all(&ftgt_dev->fdev_waitQ); down(&ftgt_dev->shutdown_mutex); - filp_close(ftgt_dev->fd, NULL); + if (ftgt_dev->fd) + filp_close(ftgt_dev->fd, NULL); if (ftgt_dev->iv != NULL) { TRACE_MEM("kfree ftgt_dev->iv: %p", ftgt_dev->iv); @@ -852,7 +932,7 @@ case REPORT_LUNS: def: default: - TRACE_DBG("Wrong opcode 0x%02x", opcode); + TRACE_DBG("Invalid opcode 0x%02x", opcode); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); } @@ -959,6 +1039,13 @@ cmd->host_status = DID_OK; cmd->driver_status = 0; + if (virt_dev->cdrom_empty && (opcode != INQUIRY)) { + TRACE_DBG("%s", "CDROM empty"); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_not_ready)); + goto out; + } + /* * No protection is necessary, because media_changed set only * in suspended state and exec() is serialized @@ -966,8 +1053,9 @@ if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) && (cmd->cdb[0] != REQUEST_SENSE) && (cmd->cdb[0] != REPORT_LUNS)) { virt_dev->media_changed = 0; + TRACE_DBG("%s", "Reporting media changed"); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_medium_changed_UA)); + SCST_LOAD_SENSE(scst_sense_medium_changed_UA)); goto out; } @@ -1020,9 +1108,9 @@ break; case REPORT_LUNS: default: - TRACE_DBG("Wrong opcode 0x%02x", opcode); + TRACE_DBG("Invalid opcode 0x%02x", opcode); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); + SCST_LOAD_SENSE(scst_sense_invalid_opcode)); } out: @@ -1062,6 +1150,7 @@ length = scst_get_buf_first(cmd, &address); TRACE_DBG("length %d", length); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out_free; @@ -1073,6 +1162,7 @@ */ if (cmd->cdb[1] & CMDDT) { + TRACE_DBG("%s", "INQUIRY: CMDDT is unsupported"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; @@ -1135,13 +1225,15 @@ buf[3] = num + 12 - 4; } else { - /* Illegal request, invalid field in cdb */ + TRACE_DBG("INQUIRY: Unsupported EVPD page %x", + cmd->cdb[2]); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; } } else { if (cmd->cdb[2] != 0) { + TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; @@ -1187,8 +1279,8 @@ static int fileio_err_recov_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Read-Write Error Recovery page for mode_sense */ - unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, - 5, 0, 0xff, 0xff}; + const unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, + 5, 0, 0xff, 0xff}; memcpy(p, err_recov_pg, sizeof(err_recov_pg)); if (1 == pcontrol) @@ -1199,8 +1291,8 @@ static int fileio_disconnect_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Disconnect-Reconnect page for mode_sense */ - unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; + const unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; memcpy(p, disconnect_pg, sizeof(disconnect_pg)); if (1 == pcontrol) @@ -1211,9 +1303,9 @@ static int fileio_format_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Format device page for mode_sense */ - unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x40, 0, 0, 0}; + const unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x40, 0, 0, 0}; memcpy(p, format_pg, sizeof(format_pg)); p[10] = (DEF_SECTORS_PER >> 8) & 0xff; @@ -1228,11 +1320,11 @@ static int fileio_caching_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Caching page for mode_sense */ - unsigned char caching_pg[] = {0x8, 18, 0x10, 0, 0xff, 0xff, 0, 0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; + const unsigned char caching_pg[] = {0x8, 18, 0x10, 0, 0xff, 0xff, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; - caching_pg[2] |= !(virt_dev->wt_flag) ? WCE : 0; memcpy(p, caching_pg, sizeof(caching_pg)); + p[2] |= !(virt_dev->wt_flag) ? WCE : 0; if (1 == pcontrol) memset(p + 2, 0, sizeof(caching_pg) - 2); return sizeof(caching_pg); @@ -1241,10 +1333,12 @@ static int fileio_ctrl_m_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Control mode page for mode_sense */ - unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x22, 0, 0, 0x40, 0, 0, - 0, 0, 0x2, 0x4b}; + const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x22, 0, 0, 0x40, 0, 0, + 0, 0, 0x2, 0x4b}; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); + if (!virt_dev->wt_flag) + p[3] |= 0x10; /* Enable unrestricted reordering */ if (1 == pcontrol) memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); return sizeof(ctrl_m_pg); @@ -1253,8 +1347,8 @@ static int fileio_iec_m_pg(unsigned char *p, int pcontrol, struct scst_fileio_dev *virt_dev) { /* Informational Exceptions control mode page for mode_sense */ - unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; + const unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) memset(p + 2, 0, sizeof(iec_m_pg) - 2); @@ -1294,10 +1388,11 @@ pcode = cmd->cdb[2] & 0x3f; subpcode = cmd->cdb[3]; msense_6 = (MODE_SENSE == cmd->cdb[0]); - dev_spec = virt_dev->rd_only_flag ? WP : 0; + dev_spec = (virt_dev->rd_only_flag ? WP : 0) | DPOFUA; length = scst_get_buf_first(cmd, &address); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out_free; @@ -1305,7 +1400,8 @@ memset(buf, 0, sizeof(buf)); - if (0x3 == pcontrol) { /* Saving values not supported */ + if (0x3 == pcontrol) { + TRACE_DBG("%s", "MODE SENSE: Saving values not supported"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_saving_params_unsup)); goto out_put; @@ -1322,6 +1418,7 @@ } if (0 != subpcode) { /* TODO: Control Extension page */ + TRACE_DBG("%s", "MODE SENSE: Only subpage 0 is supported"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; @@ -1386,6 +1483,7 @@ offset += len; break; default: + TRACE_DBG("MODE SENSE: Unsupported page %x", pcode); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; @@ -1439,7 +1537,8 @@ res = 0; /* ?? ToDo */ goto out_resume; } - filp_close(ftgt_dev->fd, NULL); + if (ftgt_dev->fd) + filp_close(ftgt_dev->fd, NULL); ftgt_dev->fd = fd; } up(&virt_dev->ftgt_list_mutex); @@ -1466,12 +1565,15 @@ length = scst_get_buf_first(cmd, &address); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out; } if (!(cmd->cdb[1] & PF) || (cmd->cdb[1] & SP)) { + PRINT_ERROR_PR("MODE SELECT: PF and/or SP are wrongly set " + "(cdb[1]=%x)", cmd->cdb[1]); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_put; @@ -1486,6 +1588,8 @@ if (address[offset - 1] == 8) { offset += 8; } else if (address[offset - 1] != 0) { + PRINT_ERROR_PR("%s", "MODE SELECT: Wrong parameters list " + "lenght"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list)); goto out_put; @@ -1493,15 +1597,16 @@ while (length > offset + 2) { if (address[offset] & PS) { - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE( + PRINT_ERROR_PR("%s", "MODE SELECT: Illegal PS bit"); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE( scst_sense_invalid_field_in_parm_list)); goto out_put; } if ((address[offset] & 0x3f) == 0x8) { /* Caching page */ if (address[offset + 1] != 18) { - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE( + PRINT_ERROR_PR("%s", "MODE SELECT: Invalid " + "caching page request"); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE( scst_sense_invalid_field_in_parm_list)); goto out_put; } @@ -1559,6 +1664,7 @@ length = scst_get_buf_first(cmd, &address); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out; @@ -1599,6 +1705,7 @@ length = scst_get_buf_first(cmd, &address); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out; @@ -1626,22 +1733,31 @@ TRACE_ENTRY(); if (cmd->dev->handler->type != TYPE_ROM) { + PRINT_ERROR_PR("%s", "READ TOC for non-CDROM device"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); goto out; } - if ((cmd->cdb[1] & 0x02/*TIME*/) || - (cmd->cdb[2] & 0x0e/*Format*/) || - (cmd->cdb[6] != 0 && (cmd->cdb[2] & 0x01)) || + if (cmd->cdb[2] & 0x0e/*Format*/) { + PRINT_ERROR_PR("%s", "READ TOC: invalid requested data format"); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); + goto out; + } + + if ((cmd->cdb[6] != 0 && (cmd->cdb[2] & 0x01)) || (cmd->cdb[6] > 1 && cmd->cdb[6] != 0xAA)) { + PRINT_ERROR_PR("READ TOC: invalid requested track number %x", + cmd->cdb[6]); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; + SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); + goto out; } length = scst_get_buf_first(cmd, &address); if (unlikely(length <= 0)) { + PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out; @@ -1654,7 +1770,7 @@ /* Header */ memset(buffer, 0, sizeof(buffer)); buffer[2] = 0x01; /* First Track/Session */ - buffer[3] = 0x01; /* Last Track/Session */ + buffer[3] = 0x01; /* Last Track/Session */ off = 4; if (cmd->cdb[6] <= 1) { @@ -1666,7 +1782,7 @@ } if (!(cmd->cdb[2] & 0x01)) { - /* Lead-out area TOC Track Descriptor */ + /* Lead-out area TOC Track Descriptor */ buffer[off+1] = 0x14; buffer[off+2] = 0xAA; /* Track Number */ buffer[off+4] = (nblocks >> (BYTE * 3)) & 0xFF; /* Track Start Address */ @@ -1678,9 +1794,8 @@ buffer[1] = off - 2; /* Data Length */ - memcpy(address, buffer, length < off ? length : off); + memcpy(address, buffer, (length < off) ? length : off); -out_put: scst_put_buf(cmd, address); out: @@ -1702,62 +1817,43 @@ if (cmd->dev->handler->type == TYPE_ROM) virt_dev->prevent_allow_medium_removal = cmd->cdb[4] & 0x01 ? 1 : 0; - else + else { + PRINT_ERROR_PR("%s", "Prevent allow medium removal for " + "non-CDROM device"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); + } return; } -static int fileio_fsync(struct scst_cmd *cmd, uint64_t lba_start, uint32_t number_of_blocks) +static int fileio_fsync(struct scst_fileio_tgt_dev *ftgt_dev, + loff_t loff, loff_t len, struct scst_cmd *cmd) { - /* Mostly borrowed from sys_fsync() */ - struct address_space *mapping; - int ret = 0, err; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd->tgt_dev->tgt_dev_specific; + int res = 0; struct file *file = ftgt_dev->fd; + struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = file->f_mapping; TRACE_ENTRY(); - mapping = file->f_mapping; + if (ftgt_dev->virt_dev->nv_cache) + goto out; - ret = -EINVAL; - if (!file->f_op || !file->f_op->fsync) { - /* Why? We can still call filemap_fdatawrite */ - goto out; + res = sync_page_range(inode, mapping, loff, len); + if (unlikely(res != 0)) { + PRINT_ERROR_PR("sync_page_range() failed (%d)", res); + if (cmd != NULL) { + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_write_error)); + } } - /* We need to protect against concurrent writers.. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) - mutex_lock(&mapping->host->i_mutex); -#else - down(&mapping->host->i_sem); -#endif - current->flags |= PF_SYNCWRITE; - ret = filemap_fdatawrite(mapping); - err = file->f_op->fsync(file, file->f_dentry, 0); - if (!ret) - ret = err; - err = filemap_fdatawait(mapping); - if (!ret) - ret = err; - current->flags &= ~PF_SYNCWRITE; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) - mutex_unlock(&mapping->host->i_mutex); -#else - up(&mapping->host->i_sem); -#endif + /* ToDo: flush the device cache, if needed */ out: - if (ret != 0) - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - - /* ToDo: flush the device cache */ - - TRACE_EXIT_RES(ret); - return ret; + TRACE_EXIT_RES(res); + return res; } static struct iovec *fileio_alloc_iv(struct scst_cmd *cmd, @@ -1854,7 +1950,7 @@ scst_set_busy(cmd); else { scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_read_error)); } goto out_set_fs; } @@ -1942,7 +2038,7 @@ scst_set_busy(cmd); else { scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_write_error)); } goto out_set_fs; } else if (err < full_len) { @@ -1990,9 +2086,6 @@ static void fileio_exec_verify(struct scst_cmd *cmd, loff_t loff) { - uint32_t number_of_blocks; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->tgt_dev_specific; mm_segment_t old_fs; loff_t err; ssize_t length, len_mem = 0; @@ -2005,10 +2098,8 @@ TRACE_ENTRY(); - if (!virt_dev->wt_flag) { - number_of_blocks = cmd->bufflen >> virt_dev->block_shift; - fileio_fsync(cmd, loff, number_of_blocks); - } + if (fileio_fsync(ftgt_dev, loff, cmd->bufflen, cmd) != 0) + goto out; /* * Until the cache is cleared prior the verifying, there is not @@ -2063,7 +2154,7 @@ scst_set_busy(cmd); else { scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_read_error)); } scst_put_buf(cmd, address_sav); goto out_set_fs; @@ -2097,6 +2188,7 @@ if (mem_verify) vfree(mem_verify); +out: TRACE_EXIT(); return; } @@ -2192,7 +2284,7 @@ } if (inout == 0) { /* read */ - size = scnprintf(buffer, length, "%-17s %-9s %-8s %s\n", + size = scnprintf(buffer, length, "%-17s %-12s %-15s %s\n", "Name", "Size(MB)", "Options", "File name"); if (fileio_proc_update_size(size, &len, &begin, &pos, &offset)) { res = len; @@ -2204,7 +2296,7 @@ { int c; size = scnprintf(buffer + len, length - len, - "%-17s %-10d", virt_dev->name, + "%-17s %-13d", virt_dev->name, (uint32_t)(virt_dev->file_size >> 20)); if (fileio_proc_update_size(size, &len, &begin, &pos, &offset)) { @@ -2221,6 +2313,16 @@ goto out_up; } } + if (virt_dev->nv_cache) { + size = scnprintf(buffer + len, length - len, + c ? ",NV" : "NV"); + c += size; + if (fileio_proc_update_size(size, &len, &begin, + &pos, &offset)) { + res = len; + goto out_up; + } + } if (virt_dev->rd_only_flag) { size = scnprintf(buffer + len, length - len, c ? ",RO" : "RO"); @@ -2251,7 +2353,7 @@ goto out_up; } } - while (c < 9) { + while (c < 16) { size = scnprintf(buffer + len, length - len, " "); if (fileio_proc_update_size(size, &len, &begin, &pos, &offset)) { @@ -2276,12 +2378,8 @@ *eof = 1; } else { /* write */ - /* - * Usage: - * echo "open|close NAME FILE_NAME [WRITE_THROUGH \ - * READ_ONLY O_DIRECT NULLIO]" > - * /proc/scsi_tgt/DISK_FILEIO_NAME/DISK_FILEIO_NAME - */ + uint32_t block_size = DEF_DISK_BLOCKSIZE; + int block_shift = DEF_DISK_BLOCKSIZE_SHIFT; p = buffer; if (p[strlen(p) - 1] == '\n') { p[strlen(p) - 1] = '\0'; @@ -2359,12 +2457,47 @@ while (isspace(*p) && *p != '\0') p++; + + if (isdigit(*p)) { + char *pp; + uint32_t t; + block_size = simple_strtoul(p, &pp, 0); + p = pp; + if ((*p != '\0') && !isspace(*p)) { + PRINT_ERROR_PR("Parse error: \"%s\"", p); + res = -EINVAL; + goto out_free_vdev; + } + while (isspace(*p) && *p != '\0') + p++; + + t = block_size; + block_shift = 0; + while(1) { + if ((t & 1) != 0) + break; + t >>= 1; + block_shift++; + } + if (block_shift < 9) { + PRINT_ERROR_PR("Wrong block size %d", + block_size); + res = -EINVAL; + goto out_free_vdev; + } + } + virt_dev->block_size = block_size; + virt_dev->block_shift = block_shift; while (*p != '\0') { if (!strncmp("WRITE_THROUGH", p, 13)) { p += 13; virt_dev->wt_flag = 1; TRACE_DBG("%s", "WRITE_THROUGH"); + } else if (!strncmp("NV_CACHE", p, 8)) { + p += 8; + virt_dev->nv_cache = 1; + TRACE_DBG("%s", "NON-VOLATILE CACHE"); } else if (!strncmp("READ_ONLY", p, 9)) { p += 9; virt_dev->rd_only_flag = 1; @@ -2410,9 +2543,11 @@ res = virt_dev->virt_id; goto out_free_vpath; } - TRACE_DBG("Added virt_dev (name %s file name %s id %d) " - "to disk_fileio_dev_list", virt_dev->name, - virt_dev->file_name, virt_dev->virt_id); + TRACE_DBG("Added virt_dev (name %s, file name %s, " + "id %d, block size %d) to " + "disk_fileio_dev_list", virt_dev->name, + virt_dev->file_name, virt_dev->virt_id, + virt_dev->block_size); } else { /* close */ virt_dev = NULL; list_for_each_entry(vv, &disk_fileio_dev_list, @@ -2469,6 +2604,7 @@ char *file_name; int len; int res = 0; + int cdrom_empty; virt_dev = NULL; list_for_each_entry(vv, &cdrom_fileio_dev_list, @@ -2493,15 +2629,15 @@ p++; *p++ = '\0'; if (*file_name == '\0') { - PRINT_ERROR_PR("%s", "File name required"); - res = -EINVAL; - goto out; + cdrom_empty = 1; + TRACE_DBG("%s", "No media"); } else if (*file_name != '/') { PRINT_ERROR_PR("File path \"%s\" is not " "absolute", file_name); res = -EINVAL; goto out; - } + } else + cdrom_empty = 0; virt_dev = fileio_alloc_dev(); if (virt_dev == NULL) { @@ -2510,20 +2646,23 @@ res = -ENOMEM; goto out; } + virt_dev->cdrom_empty = cdrom_empty; strcpy(virt_dev->name, name); - len = strlen(file_name) + 1; - virt_dev->file_name = kmalloc(len, GFP_KERNEL); - TRACE_MEM("kmalloc(GFP_KERNEL) for file_name (%d): %p", - len, virt_dev->file_name); - if (virt_dev->file_name == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", - "Allocation of file_name failed"); - res = -ENOMEM; - goto out_free_vdev; + if (!virt_dev->cdrom_empty) { + len = strlen(file_name) + 1; + virt_dev->file_name = kmalloc(len, GFP_KERNEL); + TRACE_MEM("kmalloc(GFP_KERNEL) for file_name (%d): %p", + len, virt_dev->file_name); + if (virt_dev->file_name == NULL) { + TRACE(TRACE_OUT_OF_MEM, "%s", + "Allocation of file_name failed"); + res = -ENOMEM; + goto out_free_vdev; + } + strncpy(virt_dev->file_name, file_name, len); } - strncpy(virt_dev->file_name, file_name, len); list_add_tail(&virt_dev->fileio_dev_list_entry, &cdrom_fileio_dev_list); @@ -2582,8 +2721,10 @@ list_del(&virt_dev->fileio_dev_list_entry); - TRACE_MEM("kfree for file_name: %p", virt_dev->file_name); - kfree(virt_dev->file_name); + if (virt_dev->file_name) { + TRACE_MEM("kfree for file_name: %p", virt_dev->file_name); + kfree(virt_dev->file_name); + } TRACE_MEM("kfree for virt_dev: %p", virt_dev); kfree(virt_dev); @@ -2626,63 +2767,70 @@ p++; *p++ = '\0'; if (*file_name == '\0') { - PRINT_ERROR_PR("%s", "File name required"); - res = -EINVAL; - goto out; + virt_dev->cdrom_empty = 1; + TRACE_DBG("%s", "No media"); } else if (*file_name != '/') { PRINT_ERROR_PR("File path \"%s\" is not " "absolute", file_name); res = -EINVAL; goto out; - } + } else + virt_dev->cdrom_empty = 0; - len = strlen(file_name) + 1; - fn = kmalloc(len, GFP_KERNEL); - TRACE_MEM("kmalloc(GFP_KERNEL) for file_name (%d): %p", - len, fn); - if (fn == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", - "Allocation of file_name failed"); - res = -ENOMEM; - goto out; - } - old_fn = virt_dev->file_name; - virt_dev->file_name = fn; - strncpy(virt_dev->file_name, file_name, len); - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", - virt_dev->file_name, res); - goto out_free; - } - if ((fd->f_op == NULL) || (fd->f_op->readv == NULL)) - { - PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't" - " have required capabilities"); - res = -EINVAL; + if (!virt_dev->cdrom_empty) { + len = strlen(file_name) + 1; + fn = kmalloc(len, GFP_KERNEL); + TRACE_MEM("kmalloc(GFP_KERNEL) for file_name (%d): %p", + len, fn); + if (fn == NULL) { + TRACE(TRACE_OUT_OF_MEM, "%s", + "Allocation of file_name failed"); + res = -ENOMEM; + goto out; + } + + strncpy(fn, file_name, len); + virt_dev->file_name = fn; + + fd = fileio_open(virt_dev); + if (IS_ERR(fd)) { + res = PTR_ERR(fd); + PRINT_ERROR_PR("filp_open(%s) returned an error %d", + virt_dev->file_name, res); + goto out_free; + } + if ((fd->f_op == NULL) || (fd->f_op->readv == NULL)) { + PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't " + "have required capabilities"); + res = -EINVAL; + filp_close(fd, NULL); + goto out_free; + } + + /* seek to end */ + old_fs = get_fs(); + set_fs(get_ds()); + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); + } else { + err = default_llseek(fd, 0, 2/*SEEK_END*/); + } + set_fs(old_fs); filp_close(fd, NULL); - goto out_free; - } - - /* seek to end */ - old_fs = get_fs(); - set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); + if (err < 0) { + res = err; + PRINT_ERROR_PR("llseek %s returned an error %d", + virt_dev->file_name, res); + goto out_free; + } } else { - err = default_llseek(fd, 0, 2/*SEEK_END*/); + len = 0; + err = 0; + fn = NULL; + virt_dev->file_name = fn; } - set_fs(old_fs); - filp_close(fd, NULL); - if (err < 0) { - res = err; - PRINT_ERROR_PR("llseek %s returned an error %d", - virt_dev->file_name, res); - goto out_free; - } scst_suspend_activity(); @@ -2695,34 +2843,48 @@ virt_dev->file_size = err; virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift; - virt_dev->media_changed = 1; - PRINT_INFO_PR("Changed SCSI target virtual cdrom %s " - "(file=\"%s\", fs=%LdMB, bs=%d, nblocks=%Ld, cyln=%Ld%s)", - virt_dev->name, virt_dev->file_name, - virt_dev->file_size >> 20, virt_dev->block_size, - virt_dev->nblocks, virt_dev->nblocks/64/32, - virt_dev->nblocks < 64*32 ? " !WARNING! cyln less than 1" : ""); + if (!virt_dev->cdrom_empty) + virt_dev->media_changed = 1; down(&virt_dev->ftgt_list_mutex); list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, ftgt_list_entry) { - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d, " - "closing the device", virt_dev->file_name, res); - up(&virt_dev->ftgt_list_mutex); - goto out_err_resume; - } - filp_close(ftgt_dev->fd, NULL); + if (!virt_dev->cdrom_empty) { + fd = fileio_open(virt_dev); + if (IS_ERR(fd)) { + res = PTR_ERR(fd); + PRINT_ERROR_PR("filp_open(%s) returned an error %d, " + "closing the device", virt_dev->file_name, res); + up(&virt_dev->ftgt_list_mutex); + goto out_err_resume; + } + } else + fd = NULL; + if (ftgt_dev->fd) + filp_close(ftgt_dev->fd, NULL); ftgt_dev->fd = fd; } up(&virt_dev->ftgt_list_mutex); - TRACE_MEM("kfree for old_fn: %p", old_fn); - kfree(old_fn); + if (!virt_dev->cdrom_empty) { + PRINT_INFO_PR("Changed SCSI target virtual cdrom %s " + "(file=\"%s\", fs=%LdMB, bs=%d, nblocks=%Ld, cyln=%Ld%s)", + virt_dev->name, virt_dev->file_name, + virt_dev->file_size >> 20, virt_dev->block_size, + virt_dev->nblocks, virt_dev->nblocks/64/32, + virt_dev->nblocks < 64*32 ? " !WARNING! cyln less " + "than 1" : ""); + } else { + PRINT_INFO_PR("Removed media from SCSI target virtual cdrom %s", + virt_dev->name); + } + if (old_fn) { + TRACE_MEM("kfree for old_fn: %p", old_fn); + kfree(old_fn); + } + out_resume: scst_resume_activity(); @@ -2799,11 +2961,6 @@ res = len; } else { /* write */ - /* - * Usage: - * echo "open|change|close NAME [FILE_NAME SIZE_IN_MB]" > - * /proc/scsi_tgt/CDROM_FILEIO_NAME/CDROM_FILEIO_NAME - */ p = buffer; if (p[strlen(p) - 1] == '\n') { p[strlen(p) - 1] = '\0'; Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2006-10-17 09:22:31 UTC (rev 9) +++ trunk/scst/src/scst.c 2006-10-20 18:18:46 UTC (rev 10) @@ -881,6 +881,16 @@ return; } +void scst_get(void) +{ + scst_inc_cmd_count(); +} + +void scst_put(void) +{ + scst_dec_cmd_count(); +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) static int scst_add(struct class_device *cdev) #else @@ -1239,6 +1249,8 @@ EXPORT_SYMBOL(__scst_get_buf); EXPORT_SYMBOL(scst_check_mem); +EXPORT_SYMBOL(scst_get); +EXPORT_SYMBOL(scst_put); /* * Other Commands This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-26 16:08:53
|
Revision: 14 http://svn.sourceforge.net/scst/?rev=14&view=rev Author: vlnb Date: 2006-10-26 09:08:29 -0700 (Thu, 26 Oct 2006) Log Message: ----------- 1. Added support of 2.6.18 kernels 2. FILEIO_ONLY added Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/include/scsi_tgt.h trunk/scst/src/Makefile trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Added Paths: ----------- trunk/scst/kernel/26_scst-2.6.18.patch Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/ChangeLog 2006-10-26 16:08:29 UTC (rev 14) @@ -4,6 +4,12 @@ - Fixed many found task management related problems, especially in the RESETs area. DEBUG_TM compilation option added (see README). + - Updated to work on kernels version 2.6.18+. + + - FILEIO_ONLY added. If it's defined, there is no need to patch the + kernel, but pass-through modules (scst_disk, scst_tape, etc.) are not + supported). + - Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status implemented. Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/README 2006-10-26 16:08:29 UTC (rev 14) @@ -134,6 +134,11 @@ There are the following compilation options, that could be commented in/out in Makefile: + - FILEIO_ONLY - if defined, the pass-through device handlers + (scst_disk, scst_tape) will not work, but SCST will not require the + kernel patching. Defined by default to ease new people try SCST on + their kernels. + - DEBUG - turns on some debugging code, including some logging. Makes the driver considerably bigger and slower, producing large amount of log data. @@ -424,12 +429,18 @@ IMPORTANT: If you use on initiator some versions of Windows (at least W2K) ========= you can't get good write performance for FILEIO devices with - default 512 bytes block sizes. You could get about 10% of - the expected one. This is because of "unusual" write access + default 512 bytes block sizes. You could get about 10% of the + expected one. This is because of "unusual" write access pattern, with which Windows'es write data and which is - (simplifying) incompatible with how Linux page cache works. + (simplifying) incompatible with how Linux page cache works, + so for each write the corresponding block must be read first. With 4096 bytes block sizes for FILEIO devices the write - performance will be as expected. + performance will be as expected. Actually, any system on + initiator, not only Windows, will benefit from block size + max(PAGE_SIZE, BLOCK_SIZE_ON_UNDERLYING_FS), where PAGE_SIZE + is the page size, BLOCK_SIZE_ON_UNDERLYING_FS is block size on + the underlying FS, on which the device file located, or 0, if + a device node is used. Both values are on the target. Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x kernel, where we did carefull performance study, aggregate throuhput Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/include/scsi_tgt.h 2006-10-26 16:08:29 UTC (rev 14) @@ -1026,7 +1026,9 @@ struct scst_tgt_dev *tgt_dev; /* corresponding device for this cmd */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) struct scsi_request *scsi_req; /* SCSI request */ +#endif /* List entry for tgt_dev's SN related lists */ struct list_head sn_cmd_list_entry; Added: trunk/scst/kernel/26_scst-2.6.18.patch =================================================================== --- trunk/scst/kernel/26_scst-2.6.18.patch (rev 0) +++ trunk/scst/kernel/26_scst-2.6.18.patch 2006-10-26 16:08:29 UTC (rev 14) @@ -0,0 +1,106 @@ +--- linux-2.6.18.1-scst-dbg/drivers/scsi/scsi_lib.c_scst 2006-09-20 07:42:06.000000000 +0400 ++++ linux-2.6.18.1-scst-dbg/drivers/scsi/scsi_lib.c 2006-10-25 20:52:58.000000000 +0400 +@@ -367,7 +367,7 @@ + } + + /** +- * scsi_execute_async - insert request ++ * __scsi_execute_async - insert request + * @sdev: scsi device + * @cmd: scsi command + * @cmd_len: length of scsi cdb +@@ -378,11 +378,14 @@ + * @timeout: request timeout in seconds + * @retries: number of times to retry request + * @flags: or into request flags ++ * @at_head: insert request at head or tail of queue + **/ +-int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, ++static inline int __scsi_execute_async(struct scsi_device *sdev, ++ const unsigned char *cmd, + int cmd_len, int data_direction, void *buffer, unsigned bufflen, + int use_sg, int timeout, int retries, void *privdata, +- void (*done)(void *, char *, int, int), gfp_t gfp) ++ void (*done)(void *, char *, int, int), gfp_t gfp, ++ int at_head) + { + struct request *req; + struct scsi_io_context *sioc; +@@ -418,7 +421,7 @@ + sioc->data = privdata; + sioc->done = done; + +- blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async); ++ blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async); + return 0; + + free_req: +@@ -427,8 +430,53 @@ + kfree(sioc); + return DRIVER_ERROR << 24; + } ++ ++/** ++ * scsi_execute_async - insert request ++ * @sdev: scsi device ++ * @cmd: scsi command ++ * @cmd_len: length of scsi cdb ++ * @data_direction: data direction ++ * @buffer: data buffer (this can be a kernel buffer or scatterlist) ++ * @bufflen: len of buffer ++ * @use_sg: if buffer is a scatterlist this is the number of elements ++ * @timeout: request timeout in seconds ++ * @retries: number of times to retry request ++ * @flags: or into request flags ++ **/ ++int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, ++ int cmd_len, int data_direction, void *buffer, unsigned bufflen, ++ int use_sg, int timeout, int retries, void *privdata, ++ void (*done)(void *, char *, int, int), gfp_t gfp) ++{ ++ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, ++ bufflen, use_sg, timeout, retries, privdata, done, gfp, 1); ++} + EXPORT_SYMBOL_GPL(scsi_execute_async); + ++/** ++ * scsi_execute_async_fifi - insert request at tail, in FIFO order ++ * @sdev: scsi device ++ * @cmd: scsi command ++ * @cmd_len: length of scsi cdb ++ * @data_direction: data direction ++ * @buffer: data buffer (this can be a kernel buffer or scatterlist) ++ * @bufflen: len of buffer ++ * @use_sg: if buffer is a scatterlist this is the number of elements ++ * @timeout: request timeout in seconds ++ * @retries: number of times to retry request ++ * @flags: or into request flags ++ **/ ++int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd, ++ int cmd_len, int data_direction, void *buffer, unsigned bufflen, ++ int use_sg, int timeout, int retries, void *privdata, ++ void (*done)(void *, char *, int, int), gfp_t gfp) ++{ ++ return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, ++ bufflen, use_sg, timeout, retries, privdata, done, gfp, 0); ++} ++EXPORT_SYMBOL_GPL(scsi_execute_async_fifo); ++ + /* + * Function: scsi_init_cmd_errh() + * +--- linux-2.6.18.1-scst-dbg/include/scsi/scsi_device.h_scst 2006-09-20 07:42:06.000000000 +0400 ++++ linux-2.6.18.1-scst-dbg/include/scsi/scsi_device.h 2006-10-25 20:09:23.000000000 +0400 +@@ -297,6 +297,12 @@ + int timeout, int retries, void *privdata, + void (*done)(void *, char *, int, int), + gfp_t gfp); ++extern int scsi_execute_async_fifo(struct scsi_device *sdev, ++ const unsigned char *cmd, int cmd_len, int data_direction, ++ void *buffer, unsigned bufflen, int use_sg, ++ int timeout, int retries, void *privdata, ++ void (*done)(void *, char *, int, int), ++ gfp_t gfp); + + static inline void scsi_device_reprobe(struct scsi_device *sdev) + { Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/src/Makefile 2006-10-26 16:08:29 UTC (rev 14) @@ -75,7 +75,8 @@ #EXTRA_CFLAGS += -DSTRICT_SERIALIZING -EXTRA_CFLAGS += -DEXTRACHECKS +EXTRA_CFLAGS += -DEXTRACHECKS +#EXTRA_CFLAGS += -DFILEIO_ONLY #EXTRA_CFLAGS += -fno-inline Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/src/scst.c 2006-10-26 16:08:29 UTC (rev 14) @@ -631,6 +631,16 @@ goto out; } +#ifdef FILEIO_ONLY + if (dev_type->exec == NULL) { + PRINT_ERROR_PR("Pass-through dev handlers (handler %s) not " + "supported. Recompile SCST with undefined FILEIO_ONLY", + dev_type->name); + res = -EINVAL; + goto out; + } +#endif + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out; @@ -950,11 +960,22 @@ { int res = 0, i; struct scst_cmd *cmd; - struct scsi_request *req; TRACE_ENTRY(); - BUILD_BUG_ON(sizeof(cmd->sense_buffer) != sizeof(req->sr_sense_buffer)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + { + struct scsi_request *req; + BUILD_BUG_ON(sizeof(cmd->sense_buffer) != + sizeof(req->sr_sense_buffer)); + } +#else + { + struct scsi_sense_hdr *shdr; + BUILD_BUG_ON((sizeof(cmd->sense_buffer) < sizeof(*shdr)) && + (sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE)); + } +#endif scst_num_cpus = get_cpus_count(); @@ -1130,6 +1151,9 @@ static void __exit exit_scst(void) { +#ifdef CONFIG_LOCKDEP + static /* To hide the lockdep's warning about non-static key */ +#endif DECLARE_MUTEX_LOCKED(shm); TRACE_ENTRY(); Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/src/scst_lib.c 2006-10-26 16:08:29 UTC (rev 14) @@ -711,6 +711,7 @@ return res; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) static void scst_req_done(struct scsi_cmnd *scsi_cmd) { struct scsi_request *req; @@ -776,7 +777,42 @@ TRACE_EXIT(); return; } +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ +static void scst_send_release(struct scst_tgt_dev *tgt_dev) +{ + struct scsi_device *scsi_dev; + unsigned char cdb[6]; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; + int rc; + TRACE_ENTRY(); + + if (tgt_dev->acg_dev->dev->scsi_dev == NULL) + goto out; + + scsi_dev = tgt_dev->acg_dev->dev->scsi_dev; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = RELEASE; + cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ? + ((scsi_dev->lun << 5) & 0xe0) : 0; + + TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI " + "mid-level"); + rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0, + sense, SCST_DEFAULT_TIMEOUT, + 3, GFP_KERNEL); + if (rc) { + PRINT_INFO_PR("scsi_execute() failed: %d", rc); + goto out; + } + +out: + TRACE_EXIT(); + return; +} +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ + struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask, const char *initiator_name) { @@ -944,7 +980,7 @@ BUG_ON(cmd->blocking); -#ifdef EXTRACHECKS +#if defined(EXTRACHECKS) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) if (cmd->scsi_req) { PRINT_ERROR_PR("%s: %s", __FUNCTION__, "Cmd with unfreed " "scsi_req!"); @@ -1114,6 +1150,7 @@ return; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) int scst_alloc_request(struct scst_cmd *cmd) { int res = 0; @@ -1154,6 +1191,7 @@ scsi_release_request(cmd->scsi_req); cmd->scsi_req = NULL; } +#endif int scst_alloc_space(struct scst_cmd *cmd) { Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/src/scst_priv.h 2006-10-26 16:08:29 UTC (rev 14) @@ -24,9 +24,12 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_driver.h> #include <scsi/scsi_device.h> -#include <scsi/scsi_request.h> #include <scsi/scsi_host.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#include <scsi/scsi_request.h> +#endif + #define SCST_MAJOR 177 #define TRACE_RETRY 0x80000000 @@ -250,6 +253,7 @@ void scst_check_retries(struct scst_tgt *tgt, int processible_env); void scst_tgt_retry_timer_fn(unsigned long arg); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) int scst_alloc_request(struct scst_cmd *cmd); void scst_release_request(struct scst_cmd *cmd); @@ -257,12 +261,33 @@ const void *cmnd, void *buffer, unsigned bufflen, void (*done)(struct scsi_cmnd *), int timeout, int retries) { -#ifdef STRICT_SERIALIZING + #ifdef STRICT_SERIALIZING scsi_do_req(sreq, cmnd, buffer, bufflen, done, timeout, retries); + #elif defined(FILEIO_ONLY) + BUG(); + #else + scsi_do_req_fifo(sreq, cmnd, buffer, bufflen, done, timeout, retries); + #endif +} #else - scsi_do_req_fifo(sreq, cmnd, buffer, bufflen, done, timeout, retries); +static inline int scst_exec_req(struct scsi_device *sdev, + const unsigned char *cmd, int cmd_len, int data_direction, + void *buffer, unsigned bufflen, int use_sg, int timeout, int retries, + void *privdata, void (*done)(void *, char *, int, int), gfp_t gfp) +{ + #ifdef STRICT_SERIALIZING + return scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer, + bufflen, use_sg, timeout, retries, privdata, done, gfp); + #elif defined(FILEIO_ONLY) + BUG(); + return -1; + #else + return scsi_execute_async_fifo(sdev, cmd, cmd_len, data_direction, + buffer, bufflen, use_sg, timeout, retries, privdata, done, gfp); + #endif +} #endif -} + int scst_alloc_space(struct scst_cmd *cmd); void scst_release_space(struct scst_cmd *cmd); void scst_scsi_op_list_init(void); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-10-26 13:58:39 UTC (rev 13) +++ trunk/scst/src/scst_targ.c 2006-10-26 16:08:29 UTC (rev 14) @@ -823,8 +823,8 @@ } /* No locks supposed to be held */ -static void scst_check_sense(struct scst_cmd *cmd, struct scsi_request *req, - int *next_state) +static void scst_check_sense(struct scst_cmd *cmd, const uint8_t *rq_sense, + int rq_sense_len, int *next_state) { int sense_valid; struct scst_device *dev = cmd->dev; @@ -848,11 +848,15 @@ smp_mb(); } - if (req != NULL) { - sense_valid = SCST_SENSE_VALID(req->sr_sense_buffer); + if (rq_sense != NULL) { + sense_valid = SCST_SENSE_VALID(rq_sense); if (sense_valid) { - memcpy(cmd->sense_buffer, req->sr_sense_buffer, - sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + /* + * We checked that rq_sense_len < sizeof(cmd->sense_buffer) + * in init_scst() + */ + memcpy(cmd->sense_buffer, rq_sense, rq_sense_len); } } else sense_valid = SCST_SENSE_VALID(cmd->sense_buffer); @@ -971,38 +975,60 @@ return res; } -static void scst_do_cmd_done(struct scst_cmd *cmd, - struct scsi_request *req, int *next_state) +static void scst_do_cmd_done(struct scst_cmd *cmd, int result, + const uint8_t *rq_sense, int rq_sense_len, int *next_state) { + unsigned char type; + TRACE_ENTRY(); - cmd->status = req->sr_result & 0xff; - cmd->masked_status = status_byte(req->sr_result); - cmd->msg_status = msg_byte(req->sr_result); - cmd->host_status = host_byte(req->sr_result); - cmd->driver_status = driver_byte(req->sr_result); - TRACE(TRACE_SCSI, "req->sr_result=%x, cmd->status=%x, " + cmd->status = result & 0xff; + cmd->masked_status = status_byte(result); + cmd->msg_status = msg_byte(result); + cmd->host_status = host_byte(result); + cmd->driver_status = driver_byte(result); + TRACE(TRACE_SCSI, "result=%x, cmd->status=%x, " "cmd->masked_status=%x, cmd->msg_status=%x, cmd->host_status=%x, " - "cmd->driver_status=%x", req->sr_result, cmd->status, + "cmd->driver_status=%x", result, cmd->status, cmd->masked_status, cmd->msg_status, cmd->host_status, cmd->driver_status); - scst_check_sense(cmd, req, next_state); + cmd->completed = 1; - cmd->bufflen = req->sr_bufflen; //?? + scst_dec_on_dev_cmd(cmd); - /* Clear out request structure */ - req->sr_use_sg = 0; - req->sr_sglist_len = 0; - req->sr_bufflen = 0; - req->sr_buffer = NULL; - req->sr_underflow = 0; - req->sr_request->rq_disk = NULL; /* disown request blk */ ; + type = cmd->dev->handler->type; + if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) && + cmd->tgt_dev->acg_dev->rd_only_flag && + (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD || + type == TYPE_TAPE)) { + int32_t length; + uint8_t *address; + length = scst_get_buf_first(cmd, &address); + TRACE_DBG("length %d", length); + if (unlikely(length <= 0)) { + PRINT_ERROR_PR("%s: scst_get_buf_first() failed", + __func__); + goto next; + } + if (length > 2 && cmd->cdb[0] == MODE_SENSE) { + address[2] |= 0x80; /* Write Protect*/ + } + else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) { + address[3] |= 0x80; /* Write Protect*/ + } + scst_put_buf(cmd, address); + } + +next: + scst_check_sense(cmd, rq_sense, rq_sense_len, next_state); + TRACE_EXIT(); return; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) static inline struct scst_cmd *scst_get_cmd(struct scsi_cmnd *scsi_cmd, struct scsi_request **req) { @@ -1025,7 +1051,6 @@ struct scsi_request *req = NULL; struct scst_cmd *cmd; int next_state; - unsigned char type; TRACE_ENTRY(); @@ -1044,38 +1069,58 @@ if (cmd == NULL) goto out; - cmd->completed = 1; + next_state = SCST_CMD_STATE_DEV_DONE; + scst_do_cmd_done(cmd, req->sr_result, req->sr_sense_buffer, + sizeof(req->sr_sense_buffer), &next_state); - scst_dec_on_dev_cmd(cmd); + /* Clear out request structure */ + req->sr_use_sg = 0; + req->sr_sglist_len = 0; + req->sr_bufflen = 0; + req->sr_buffer = NULL; + req->sr_underflow = 0; + req->sr_request->rq_disk = NULL; /* disown request blk */ - type = cmd->dev->handler->type; - if ((cmd->cdb[0] == MODE_SENSE || cmd->cdb[0] == MODE_SENSE_10) && - cmd->tgt_dev->acg_dev->rd_only_flag && - (type == TYPE_DISK || type == TYPE_WORM || type == TYPE_MOD || - type == TYPE_TAPE)) { - int32_t length; - uint8_t *address; + cmd->bufflen = req->sr_bufflen; //?? - length = scst_get_buf_first(cmd, &address); - TRACE_DBG("length %d", length); - if (unlikely(length <= 0)) { - goto out; - } - if (length > 2 && cmd->cdb[0] == MODE_SENSE) { - address[2] |= 0x80; /* Write Protect*/ - } - else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) { - address[3] |= 0x80; /* Write Protect*/ - } - scst_put_buf(cmd, address); - } + scst_release_request(cmd); - next_state = SCST_CMD_STATE_DEV_DONE; + cmd->state = next_state; + cmd->non_atomic_only = 0; - scst_do_cmd_done(cmd, req, &next_state); + __scst_process_active_cmd(cmd, scst_get_context(), 0); - scst_release_request(cmd); +out: + TRACE_EXIT(); + return; +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ +static void scst_cmd_done(void *data, char *sense, int result, int resid) +{ + struct scst_cmd *cmd; + int next_state; + TRACE_ENTRY(); + + WARN_ON(in_irq()); + + /* + * We don't use resid, because: + * 1. Many low level initiator drivers don't use (set) this field + * 2. We determine the command's buffer size directly from CDB, + * so resid is not relevant for us, and target drivers + * should know the residual, if necessary, by comparing expected + * and actual transfer sizes. + */ + + cmd = (struct scst_cmd *)data; + if (cmd == NULL) + goto out; + + next_state = SCST_CMD_STATE_DEV_DONE; + scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, + &next_state); + cmd->state = next_state; cmd->non_atomic_only = 0; @@ -1085,6 +1130,7 @@ TRACE_EXIT(); return; } +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state) { @@ -1133,7 +1179,7 @@ } #endif - scst_check_sense(cmd, NULL, &next_state); + scst_check_sense(cmd, NULL, 0, &next_state); cmd->state = next_state; cmd->non_atomic_only = 0; @@ -1557,7 +1603,8 @@ (uint64_t)cmd->lun); goto out_error; } - + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) if (scst_alloc_request(cmd) != 0) { PRINT_INFO_PR("%s", "Unable to allocate request, " "sending BUSY status"); @@ -1568,6 +1615,16 @@ (void *)cmd->scsi_req->sr_buffer, cmd->scsi_req->sr_bufflen, scst_cmd_done, cmd->timeout, cmd->retries); +#else + rc = scst_exec_req(cmd->dev->scsi_dev, cmd->cdb, cmd->cdb_len, + cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, + cmd->timeout, cmd->retries, cmd, scst_cmd_done, + GFP_KERNEL); + if (rc) { + PRINT_INFO_PR("scst_exec_req() failed: %d", rc); + goto out_error; + } +#endif rc = SCST_EXEC_COMPLETED; @@ -1593,7 +1650,8 @@ rc = SCST_EXEC_COMPLETED; scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); goto out; - + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) out_busy: scst_set_busy(cmd); cmd->completed = 1; @@ -1601,6 +1659,7 @@ rc = SCST_EXEC_COMPLETED; scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); goto out; +#endif out_aborted: rc = SCST_EXEC_COMPLETED; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-11-02 18:39:04
|
Revision: 22 http://svn.sourceforge.net/scst/?rev=22&view=rev Author: vlnb Date: 2006-11-02 02:54:10 -0800 (Thu, 02 Nov 2006) Log Message: ----------- - Fixes wrongly set context in scst_tgt_cmd_done() - Fixes retries for stateful devices Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_changer.c trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/dev_handlers/scst_processor.c trunk/scst/src/dev_handlers/scst_raid.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/include/scsi_tgt.h 2006-11-02 10:54:10 UTC (rev 22) @@ -227,10 +227,9 @@ #define SCST_DEV_TM_NOT_COMPLETED 1 /************************************************************* - ** Default timeout and retries count for cmd's CDB execution - ** by SCSI mid-level (cmd's "timeout" and "retries" fields). + ** Default timeout for cmd's CDB execution + ** by SCSI mid-level (cmd's "timeout" field). *************************************************************/ -#define SCST_DEFAULT_RETRIES 5 #define SCST_DEFAULT_TIMEOUT (30*HZ) /************************************************************* Modified: trunk/scst/src/dev_handlers/scst_changer.c =================================================================== --- trunk/scst/src/dev_handlers/scst_changer.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_changer.c 2006-11-02 10:54:10 UTC (rev 22) @@ -141,6 +141,8 @@ * based on info_cdb, therefore change them only if necessary */ + cmd->retries = 1; + if (info_cdb->flags & SCST_LONG_TIMEOUT) { cmd->timeout = CHANGER_LONG_TIMEOUT; } else { Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_disk.c 2006-11-02 10:54:10 UTC (rev 22) @@ -58,7 +58,7 @@ exec: disk_exec, \ } -#define DISK_RETRIES 2 +#define DISK_RETRIES 5 #define DISK_SMALL_TIMEOUT (3 * HZ) #define DISK_REG_TIMEOUT (60 * HZ) #define DISK_LONG_TIMEOUT (3600 * HZ) @@ -294,6 +294,8 @@ * based on info_cdb, therefore change them only if necessary */ + cmd->retries = DISK_RETRIES; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = DISK_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-02 10:54:10 UTC (rev 22) @@ -1725,7 +1725,7 @@ nblocks = virt_dev->nblocks; memset(buffer, 0, sizeof(buffer)); - data64 = (uint64_t *)buffer; + data64 = (uint64_t*)buffer; data64[0] = cpu_to_be64(nblocks - 1); buffer[8] = (blocksize >> (BYTE * 3)) & 0xFF; buffer[9] = (blocksize >> (BYTE * 2)) & 0xFF; Modified: trunk/scst/src/dev_handlers/scst_processor.c =================================================================== --- trunk/scst/src/dev_handlers/scst_processor.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_processor.c 2006-11-02 10:54:10 UTC (rev 22) @@ -141,6 +141,8 @@ * based on info_cdb, therefore change them only if necessary */ + cmd->retries = 1; + if (info_cdb->flags & SCST_LONG_TIMEOUT) { cmd->timeout = PROCESSOR_LONG_TIMEOUT; } else { Modified: trunk/scst/src/dev_handlers/scst_raid.c =================================================================== --- trunk/scst/src/dev_handlers/scst_raid.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_raid.c 2006-11-02 10:54:10 UTC (rev 22) @@ -141,6 +141,8 @@ * based on info_cdb, therefore change them only if necessary */ + cmd->retries = 1; + if (info_cdb->flags & SCST_LONG_TIMEOUT) { cmd->timeout = RAID_LONG_TIMEOUT; } else { Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/dev_handlers/scst_tape.c 2006-11-02 10:54:10 UTC (rev 22) @@ -305,6 +305,8 @@ * based on info_cdb, therefore change them only if necessary */ + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = TAPE_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/scst_lib.c 2006-11-02 10:54:10 UTC (rev 22) @@ -949,7 +949,7 @@ cmd->queue_type = SCST_CMD_QUEUE_UNTAGGED; cmd->timeout = SCST_DEFAULT_TIMEOUT; - cmd->retries = SCST_DEFAULT_RETRIES; + cmd->retries = 1; cmd->data_len = -1; cmd->tgt_resp_flags = SCST_TSC_FLAG_STATUS; cmd->resp_data_len = -1; Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/scst_priv.h 2006-11-02 10:54:10 UTC (rev 22) @@ -102,9 +102,15 @@ #define SCST_CMD_MEM_TIMEOUT (120*HZ) static inline int scst_get_context(void) { - /* Be overinsured */ - return (in_atomic() || in_interrupt()) ? SCST_CONTEXT_DIRECT_ATOMIC : - SCST_CONTEXT_DIRECT; + if (in_irq()) + return SCST_CONTEXT_TASKLET; + if (in_softirq()) + return SCST_CONTEXT_DIRECT_ATOMIC; + if (in_interrupt()) /* Is it possible? */ + return SCST_CONTEXT_THREAD; + if (in_atomic()) + return SCST_CONTEXT_DIRECT_ATOMIC; + return SCST_CONTEXT_DIRECT; } #define SCST_MGMT_CMD_CACHE_STRING "scst_mgmt_cmd" @@ -250,6 +256,8 @@ return; } +void scst_proccess_redirect_cmd(struct scst_cmd *cmd, int context, + int check_retries); void scst_check_retries(struct scst_tgt *tgt, int processible_env); void scst_tgt_retry_timer_fn(unsigned long arg); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-11-02 10:43:29 UTC (rev 21) +++ trunk/scst/src/scst_targ.c 2006-11-02 10:54:10 UTC (rev 22) @@ -744,12 +744,65 @@ goto out; } -void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context) +void scst_proccess_redirect_cmd(struct scst_cmd *cmd, int context, + int check_retries) { unsigned long flags; + int rc; TRACE_ENTRY(); + TRACE_DBG("Context: %d", context); + + switch(context) { + case SCST_CONTEXT_DIRECT: + case SCST_CONTEXT_DIRECT_ATOMIC: + if (check_retries) + scst_check_retries(cmd->tgt, 0); + cmd->non_atomic_only = 0; + rc = __scst_process_active_cmd(cmd, context, 0); + if (rc == SCST_CMD_STATE_RES_NEED_THREAD) + goto out_thread; + break; + + default: + PRINT_ERROR_PR("Context %x is unknown, using the thread one", + context); + /* go through */ + case SCST_CONTEXT_THREAD: + if (check_retries) + scst_check_retries(cmd->tgt, 1); + goto out_thread; + + case SCST_CONTEXT_TASKLET: + if (check_retries) + scst_check_retries(cmd->tgt, 1); + cmd->non_atomic_only = 0; + spin_lock_irqsave(&scst_list_lock, flags); + TRACE_DBG("Moving cmd %p to active cmd list", cmd); + list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); + spin_unlock_irqrestore(&scst_list_lock, flags); + scst_schedule_tasklet(); + break; + } +out: + TRACE_EXIT(); + return; + +out_thread: + cmd->non_atomic_only = 1; + spin_lock_irqsave(&scst_list_lock, flags); + TRACE_DBG("Moving cmd %p to active cmd list", cmd); + list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); + spin_unlock_irqrestore(&scst_list_lock, flags); + wake_up(&scst_list_waitQ); + goto out; +} + +void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context) +{ + TRACE_ENTRY(); + TRACE_DBG("Preferred context: %d", pref_context); TRACE(TRACE_SCSI, "tag=%d status=%#x", scst_cmd_get_tag(cmd), status); cmd->non_atomic_only = 0; @@ -783,41 +836,13 @@ default: PRINT_ERROR_PR("scst_rx_data() received unknown status %x", - status); + status); + cmd->state = SCST_CMD_STATE_DEV_DONE; break; } - switch (pref_context) { - case SCST_CONTEXT_DIRECT: - case SCST_CONTEXT_DIRECT_ATOMIC: - scst_check_retries(cmd->tgt, 0); - __scst_process_active_cmd(cmd, pref_context, 0); - break; + scst_proccess_redirect_cmd(cmd, pref_context, 1); - default: - PRINT_ERROR_PR("Context %x is undefined, using thread one", - pref_context); - /* go through */ - case SCST_CONTEXT_THREAD: - spin_lock_irqsave(&scst_list_lock, flags); - TRACE_DBG("Moving cmd %p to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); - cmd->non_atomic_only = 1; - spin_unlock_irqrestore(&scst_list_lock, flags); - scst_check_retries(cmd->tgt, 1); - wake_up(&scst_list_waitQ); - break; - - case SCST_CONTEXT_TASKLET: - spin_lock_irqsave(&scst_list_lock, flags); - TRACE_DBG("Moving cmd %p to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irqrestore(&scst_list_lock, flags); - scst_schedule_tasklet(); - scst_check_retries(cmd->tgt, 0); - break; - } - TRACE_EXIT(); return; } @@ -1088,7 +1113,7 @@ cmd->state = next_state; cmd->non_atomic_only = 0; - __scst_process_active_cmd(cmd, scst_get_context(), 0); + scst_proccess_redirect_cmd(cmd, scst_get_context(), 0); out: TRACE_EXIT(); @@ -1124,7 +1149,7 @@ cmd->state = next_state; cmd->non_atomic_only = 0; - __scst_process_active_cmd(cmd, scst_get_context(), 0); + scst_proccess_redirect_cmd(cmd, scst_get_context(), 0); out: TRACE_EXIT(); @@ -1153,7 +1178,7 @@ cmd->sg_cnt, sg, (void*)sg[0].page); for(i = 0; i < cmd->sg_cnt; ++i) { TRACE_BUFF_FLAG(TRACE_RECV_TOP, - "Exec'd sg:", page_address(sg[i].page), + "Exec'd sg", page_address(sg[i].page), sg[i].length); } } @@ -1184,7 +1209,7 @@ cmd->state = next_state; cmd->non_atomic_only = 0; - __scst_process_active_cmd(cmd, scst_get_context(), 0); + scst_proccess_redirect_cmd(cmd, scst_get_context(), 0); TRACE_EXIT(); return; @@ -2175,7 +2200,7 @@ cmd->sg_cnt, sg, (void*)sg[0].page); for(i = 0; i < cmd->sg_cnt; ++i) { TRACE_BUFF_FLAG(TRACE_SEND_BOT, - "Xmitting sg:", page_address(sg[i].page), + "Xmitting sg", page_address(sg[i].page), sg[i].length); } } @@ -2277,48 +2302,13 @@ void scst_tgt_cmd_done(struct scst_cmd *cmd) { - int res = 0; - unsigned long flags; - int context; - TRACE_ENTRY(); BUG_ON(cmd->state != SCST_CMD_STATE_XMIT_WAIT); - if (in_irq()) - context = SCST_CONTEXT_TASKLET; - else - context = scst_get_context(); - - TRACE_DBG("Context: %d", context); - cmd->non_atomic_only = 0; cmd->state = SCST_CMD_STATE_FINISHED; + scst_proccess_redirect_cmd(cmd, scst_get_context(), 1); - switch (context) { - case SCST_CONTEXT_DIRECT: - case SCST_CONTEXT_DIRECT_ATOMIC: - flags = 0; - scst_check_retries(cmd->tgt, 0); - res = __scst_process_active_cmd(cmd, context, 0); - BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD); - break; - - case SCST_CONTEXT_TASKLET: - { - spin_lock_irqsave(&scst_list_lock, flags); - TRACE_DBG("Moving cmd %p to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irqrestore(&scst_list_lock, flags); - scst_schedule_tasklet(); - scst_check_retries(cmd->tgt, 0); - break; - } - - default: - BUG(); - break; - } - TRACE_EXIT(); return; } @@ -2577,6 +2567,14 @@ TRACE_ENTRY(); +#ifdef EXTRACHECKS + { + int c = (context & ~SCST_PROCESSIBLE_ENV); + WARN_ON((c != SCST_CONTEXT_DIRECT_ATOMIC) && + (c != SCST_CONTEXT_DIRECT)); + } +#endif + tm_dbg_check_released_cmds(); restart: @@ -2649,7 +2647,7 @@ scst_do_job_init(&scst_init_cmd_list); scst_do_job_active(&scst_active_cmd_list, - SCST_CONTEXT_THREAD|SCST_PROCESSIBLE_ENV); + SCST_CONTEXT_DIRECT|SCST_PROCESSIBLE_ENV); if (unlikely(test_bit(SCST_FLAG_SHUTDOWN, &scst_flags)) && list_empty(&scst_cmd_list) && This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-11-07 17:48:57
|
Revision: 28 http://svn.sourceforge.net/scst/?rev=28&view=rev Author: vlnb Date: 2006-11-07 02:48:12 -0800 (Tue, 07 Nov 2006) Log Message: ----------- - One more iteration of scst_get_context() related fixes - Locking cleanup while calling dev handlers' task_mgmt_fn() - STRICT_SERIALIZING mode fixes - Cleanups Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/include/scsi_tgt.h 2006-11-07 10:48:12 UTC (rev 28) @@ -774,7 +774,7 @@ * - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the command * should be done * - * NOTE: for SCST_ABORT_TASK called under spinlock + * Called with BH off. Might be called under a lock and IRQ off. */ int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, struct scst_tgt_dev *tgt_dev); Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-07 10:48:12 UTC (rev 28) @@ -2212,7 +2212,7 @@ return; } -/* Might be called under lock and IRQ off */ +/* Called with BH off. Might be called under lock and IRQ off */ static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd, struct scst_tgt_dev *tgt_dev) { @@ -2221,16 +2221,16 @@ TRACE_ENTRY(); if (mcmd->fn == SCST_ABORT_TASK) { - unsigned long flags; struct scst_cmd *cmd_to_abort = mcmd->cmd_to_abort; struct scst_fileio_tgt_dev *ftgt_dev = (struct scst_fileio_tgt_dev *)cmd_to_abort->tgt_dev->dh_priv; - /* - * Actually, _bh lock is enough here. But, since we - * could be called with IRQ off, the in-kernel debug check - * gives false alarm on using _bh lock. So, let's suppress it. + + /* + * It is safe relating to scst_list_lock despite of lockdep's + * warning. Just don't know how to tell it to lockdep. */ - spin_lock_irqsave(&ftgt_dev->fdev_lock, flags); + /* BH already off */ + spin_lock(&ftgt_dev->fdev_lock); if (cmd_to_abort->fileio_in_list) { TRACE(TRACE_MGMT, "Aborting cmd %p and moving it to " "the queue head", cmd_to_abort); @@ -2239,7 +2239,7 @@ &ftgt_dev->fdev_cmd_list); wake_up(&ftgt_dev->fdev_waitQ); } - spin_unlock_irqrestore(&ftgt_dev->fdev_lock, flags); + spin_unlock(&ftgt_dev->fdev_lock); } TRACE_EXIT_RES(res); @@ -2522,8 +2522,14 @@ TRACE_DBG("%s", "READ_ONLY"); } else if (!strncmp("O_DIRECT", p, 8)) { p += 8; + #if 0 + virt_dev->o_direct_flag = 1; TRACE_DBG("%s", "O_DIRECT"); + #else + PRINT_INFO_PR("%s flag doesn't currently" + " work, ignoring it", "O_DIRECT"); + #endif } else if (!strncmp("NULLIO", p, 6)) { p += 6; virt_dev->nullio = 1; Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/src/scst.c 2006-11-07 10:48:12 UTC (rev 28) @@ -34,10 +34,6 @@ #include "scst_debug.c" -#if defined(DEBUG) || defined(TRACING) -unsigned long trace_flag = SCST_DEFAULT_LOG_FLAGS; -#endif - /* * All targets, devices and dev_types management is done under * this mutex. @@ -73,6 +69,10 @@ LIST_HEAD(scst_cmd_list); DECLARE_WAIT_QUEUE_HEAD(scst_list_waitQ); +#if defined(DEBUG) || defined(TRACING) +unsigned long trace_flag = SCST_DEFAULT_LOG_FLAGS; +#endif + spinlock_t scst_cmd_mem_lock = SPIN_LOCK_UNLOCKED; unsigned long scst_cur_cmd_mem, scst_cur_max_cmd_mem; Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/src/scst_lib.c 2006-11-07 10:48:12 UTC (rev 28) @@ -1651,6 +1651,7 @@ { struct scst_session *sess = tgt_dev->sess; + local_bh_disable(); spin_lock_irq(&scst_list_lock); TRACE_DBG("Searching in search cmd list (sess=%p)", sess); @@ -1666,6 +1667,7 @@ } } spin_unlock_irq(&scst_list_lock); + local_bh_enable(); } list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, @@ -1980,37 +1982,43 @@ void scst_unblock_cmds(struct scst_device *dev) { #ifdef STRICT_SERIALIZING - struct scst_cmd *cmd; + struct scst_cmd *cmd, *t; int found = 0; TRACE_ENTRY(); - list_for_each_entry(cmd, &dev->blocked_cmd_list, + list_for_each_entry_safe(cmd, t, &dev->blocked_cmd_list, blocked_cmd_list_entry) { + unsigned long flags; + int brk = 0; /* * Since only one cmd per time is being executed, expected_sn * can't change behind us, if the corresponding cmd is in - * blocked_cmd_list + * blocked_cmd_list, but we could be called before + * __scst_inc_expected_sn(). */ - if ((cmd->tgt_dev && (cmd->sn == cmd->tgt_dev->expected_sn)) || - (unlikely(cmd->internal) || unlikely(cmd->retry))) { - unsigned long flags; - list_del(&cmd->blocked_cmd_list_entry); - TRACE_MGMT_DBG("Moving cmd %p to active cmd list", cmd); - spin_lock_irqsave(&scst_list_lock, flags); - list_move(&cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irqrestore(&scst_list_lock, flags); - wake_up(&scst_list_waitQ); - found = 1; + if (likely(!cmd->internal) && likely(!cmd->retry)) { + int expected_sn; + if (cmd->tgt_dev == NULL) + BUG(); + expected_sn = cmd->tgt_dev->expected_sn; + if (cmd->sn == expected_sn) + brk = 1; + else if (cmd->sn != (expected_sn+1)) + continue; + } + + list_del(&cmd->blocked_cmd_list_entry); + TRACE_MGMT_DBG("Moving cmd %p to active cmd list", cmd); + spin_lock_irqsave(&scst_list_lock, flags); + list_move(&cmd->cmd_list_entry, &scst_active_cmd_list); + spin_unlock_irqrestore(&scst_list_lock, flags); + found = 1; + if (brk) break; - } } -#ifdef EXTRACHECKS - if (!found && !list_empty(&dev->blocked_cmd_list)) { - TRACE(TRACE_MINOR, "%s", "No commands unblocked when " - "blocked cmd list is not empty"); - } -#endif + if (found) + wake_up(&scst_list_waitQ); #else /* STRICT_SERIALIZING */ struct scst_cmd *cmd, *tcmd; unsigned long flags; Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/src/scst_priv.h 2006-11-07 10:48:12 UTC (rev 28) @@ -104,11 +104,9 @@ static inline int scst_get_context(void) { if (in_irq()) return SCST_CONTEXT_TASKLET; - if (in_softirq()) - return SCST_CONTEXT_DIRECT_ATOMIC; - if (in_interrupt()) /* Is it possible? */ + if (irqs_disabled()) return SCST_CONTEXT_THREAD; - if (in_atomic()) + if (in_softirq() || in_atomic()) return SCST_CONTEXT_DIRECT_ATOMIC; return SCST_CONTEXT_DIRECT; } @@ -447,8 +445,11 @@ static inline void scst_sess_put(struct scst_session *sess) { - if (atomic_dec_and_test(&sess->refcnt)) + smp_mb__before_atomic_dec(); + if (atomic_dec_and_test(&sess->refcnt)) { + smp_mb__after_atomic_dec(); scst_sched_session_free(sess); + } } void __scst_suspend_activity(void); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-11-03 17:41:16 UTC (rev 27) +++ trunk/scst/src/scst_targ.c 2006-11-07 10:48:12 UTC (rev 28) @@ -2469,7 +2469,9 @@ TRACE_ENTRY(); +#ifdef EXTRACHECKS BUG_ON(in_irq()); +#endif cmd->atomic = ((context & ~SCST_PROCESSIBLE_ENV) == SCST_CONTEXT_DIRECT_ATOMIC); @@ -2788,10 +2790,18 @@ { int res = SCST_DEV_TM_NOT_COMPLETED; if (tgt_dev->acg_dev->dev->handler->task_mgmt_fn) { + int irq = irqs_disabled(); TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn(fn=%d)", - tgt_dev->acg_dev->dev->handler->name, mcmd->fn); + tgt_dev->acg_dev->dev->handler->name, mcmd->fn); +#ifdef EXTRACHECKS + BUG_ON(in_irq()); +#endif + if (!irq) + local_bh_disable(); res = tgt_dev->acg_dev->dev->handler->task_mgmt_fn(mcmd, tgt_dev); + if (!irq) + local_bh_enable(); TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn() returned %d", tgt_dev->acg_dev->dev->handler->name, res); if (set_status && (res != SCST_DEV_TM_NOT_COMPLETED)) { @@ -2817,7 +2827,7 @@ /* * Called under scst_list_lock and IRQ off (to protect cmd - * from being destroyed). + * from being destroyed) + BHs also off * Returns -1 if command is being executed (ABORT failed), 0 otherwise */ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd, @@ -2945,6 +2955,7 @@ TRACE_ENTRY(); + local_bh_disable(); spin_lock_irq(&scst_list_lock); TRACE_DBG("Searching in search cmd list (sess=%p)", sess); @@ -2958,6 +2969,7 @@ scst_abort_cmd(cmd, mcmd, other_ini, 0); } spin_unlock_irq(&scst_list_lock); + local_bh_enable(); scst_unblock_aborted_cmds(scst_mutex_held); @@ -3026,6 +3038,7 @@ struct scst_session *sess = mcmd->sess; struct scst_cmd *cmd; + local_bh_disable(); spin_lock_irq(&scst_list_lock); cmd = __scst_find_cmd_by_tag(sess, mcmd->tag); if (cmd == NULL) { @@ -3042,6 +3055,7 @@ mcmd->cmd_to_abort = NULL; /* just in case */ } spin_unlock_irq(&scst_list_lock); + local_bh_enable(); } else { int rc; rc = scst_mgmt_translate_lun(mcmd); @@ -3944,8 +3958,12 @@ scst_free_session_callback(sess); } else if (sess->init_phase == SCST_SESS_IPH_INITING) { scst_init_session(sess); - } else + } else { + PRINT_ERROR_PR("session %p is in " + "scst_sess_mgmt_list, but in unknown " + "phase %x", sess, sess->init_phase); BUG(); + } spin_lock_irq(&scst_mgmt_lock); goto restart; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-11-13 17:15:01
|
Revision: 32 http://svn.sourceforge.net/scst/?rev=32&view=rev Author: vlnb Date: 2006-11-13 09:14:19 -0800 (Mon, 13 Nov 2006) Log Message: ----------- - Fixed problems with big amount of LUNs. Tested on 1500 LUNS - Docs update Modified Paths: -------------- trunk/scst/README trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-11-10 12:39:12 UTC (rev 31) +++ trunk/scst/README 2006-11-13 17:14:19 UTC (rev 32) @@ -323,20 +323,20 @@ way as "*_perf" handlers. - NV_CACHE - enables "non-volatile cache" mode. In this mode it is - assumed that the target has GOOD uninterruptable power supply - and software/hardware bug free, i.e. all data from the target's - cache are guaranteed sooner or later to go to the media, hence - all data synchronization with media operations, like - SYNCHRONIZE_CACHE, are ignored (BTW, so violating SCSI standard) - in order to bring a bit more performance. Use with extreme - caution, since in this mode after a crash of the target - journaled file systems don't guarantee the consistency after - journal recovery, therefore manual fsck MUST be ran. The main - intent for it is to determine the performance impact caused by - the cache synchronization. Note, that since usually the journal - barrier protection (see "IMPORTANT" below) turned off, enabling - NV_CACHE could change nothing, since no data synchronization - with media operations will go from the initiator. + assumed that the target has GOOD UPS and software/hardware bug + free, i.e. all data from the target's cache are guaranteed + sooner or later to go to the media, hence all data + synchronization with media operations, like SYNCHRONIZE_CACHE, + are ignored (BTW, so violating SCSI standard) in order to bring + a bit more performance. Use with extreme caution, since in this + mode after a crash of the target journaled file systems don't + guarantee the consistency after journal recovery, therefore + manual fsck MUST be ran. The main intent for it is to determine + the performance impact caused by the cache synchronization. + Note, that since usually the journal barrier protection (see + "IMPORTANT" below) turned off, enabling NV_CACHE could change + nothing, since no data synchronization with media operations + will go from the initiator. * "close NAME" - closes device "NAME". @@ -349,32 +349,36 @@ ========= caching policy. This is generally safe from the consistence of journaled file systems, laying over them, point of view, but your unsaved cached data will be lost in case of - power/hardware/software faulure, so you must supply your + power/hardware/software failure, so you must supply your target server with some kind of UPS or disable write back caching using WRITE_THROUGH flag. You also should note, that the file systems journaling over write back caching enabled - devices works reliably *ONLY* if it uses some kind of data - protection barriers (i.e. after writing journaling data some - kind of synchronization with media operations will be used), - otherwise, because of possible reordering in the cache, even - after successful journal rollback you very much risk to loose - your data on the FS. On Linux initiators for EXT3 and - ReiserFS file systems the barrier protection could be turned - on using "barrier=1" and "barrier=flush" mount options - correspondingly. Note, that usually it turned off by default - and the status of barriers usage isn't reported anywhere in - the system logs as well as there is no way to know it on the - mounted file system (at least no known one). Also note - that on some real-life workloads write through caching might - perform better, than write back one with the barrier protection - turned on. + devices works reliably *ONLY* if the order of journal writes + is guaranteed or it uses some kind of data protection + barriers (i.e. after writing journal data some kind of + synchronization with media operations is used), otherwise, + because of possible reordering in the cache, even after + successful journal rollback, you very much risk to loose your + data on the FS. Currently, Linux IO subsystem guarantees + order of write operations only using data protection + barriers. Some info about it from the XFS point of view could + be found at http://oss.sgi.com/projects/xfs/faq.html#wcache. + On Linux initiators for EXT3 and ReiserFS file systems the + barrier protection could be turned on using "barrier=1" and + "barrier=flush" mount options correspondingly. Note, that + usually it turned off by default and the status of barriers + usage isn't reported anywhere in the system logs as well as + there is no way to know it on the mounted file system (at + least no known one). Also note that on some real-life + workloads write through caching might perform better, than + write back one with the barrier protection turned on. -IMPORTANT: Many disk and partition table mananagement utilities don't support +IMPORTANT: Many 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 - things like utilities hang up or other unexpected behaviour. + 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. @@ -384,10 +388,15 @@ Before doing any performance measurements note that: -I. Maximum performance is possible only with real SCSI devices or -performance handlers. If you have enough CPU power, FILEIO handler could -provide the same results, when aggregate throughput is close to -aggregate throuput locally on the target on the same disks. +I. Currently maximum performance is possible only with real SCSI devices +with several simultaneously executed commands (SCSI tagged queuing) or +performance handlers. If you have enough CPU power, FILEIO handler also +could provide the same results, when aggregate throughput is close to +the aggregate throughput locally on the target from the same disks. Also +note, that currently IO subsystem in Linux implemented on such way, so a +FILEIO device over a single file occupied entire formatted with some +file system device (eg /dev/hdc) could perform considerably better, than +a FILEIO device over /dev/hdc itself without the file system involved. II. In order to get the maximum performance you should: @@ -414,8 +423,8 @@ - The default kernel read-ahead and queuing settings are optimized for locally attached disks, therefore they are not optimal if they - attached remotly (our case), which sometimes could lead to unexpectedly - low throughput. You should increase read-ahead size + attached remotely (our case), which sometimes could lead to + unexpectedly low throughput. You should increase read-ahead size (/sys/block/device/queue/read_ahead_kb) to at least 256Kb or even more on all initiators and the target. Also experiment with other parameters in /sys/block/device directory, they also affect the @@ -448,7 +457,7 @@ a device node is used. Both values are on the target. Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x -kernel, where we did carefull performance study, aggregate throuhput +kernel, where we did careful performance study, aggregate throughput about 390 Mb/sec from 2 qla2300 cards sitting on different 64-bit PCI buses and working simultaneously for two different initiators with several simultaneously working load programs on each. From one card - Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-10 12:39:12 UTC (rev 31) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-13 17:14:19 UTC (rev 32) @@ -2066,7 +2066,7 @@ * value less, than requested. Let's restart. */ int i, e = eiv_count; - TRACE(TRACE_MINOR, "write() returned %d from %zd " + TRACE_MGMT_DBG("write() returned %d from %zd " "(iv_count=%d)", (int)err, full_len, eiv_count); if (err == 0) { @@ -2261,20 +2261,43 @@ return dev; } -static int fileio_proc_update_size(int size, int *len, - off_t *begin, off_t *pos, off_t *offset) +struct fileio_proc_update_struct { + int len, plen, pplen; + off_t begin, pbegin, ppbegin; + off_t pos; +}; + +static int fileio_proc_update_size(int size, off_t offset, int length, + struct fileio_proc_update_struct *p, int is_start) { int res; if (size > 0) { - *len += size; - *pos = *begin + *len; - if (*pos < *offset) { - *len = 0; - *begin = *pos; + p->len += size; + p->pos = p->begin + p->len; + if (p->pos < offset) { + p->len = 0; + p->begin = p->pos; } - res = 0; - } else + if (p->pos > offset + length) { + p->begin = p->pbegin; + p->len = p->plen; + res = 1; + goto out; + } else + res = 0; + } else { + p->begin = p->ppbegin; + p->len = p->pplen; res = 1; + goto out; + } + if (is_start) { + p->ppbegin = p->pbegin; + p->pplen = p->plen; + p->pbegin = p->begin; + p->plen = p->len; + } +out: return res; } @@ -2288,10 +2311,12 @@ int res = 0, action; char *p, *name, *file_name; struct scst_fileio_dev *virt_dev, *vv; - int size, len = 0; - off_t begin = 0, pos = 0; + int size; + struct fileio_proc_update_struct pu; TRACE_ENTRY(); + + memset(&pu, 0, sizeof(pu)); /* VERY UGLY code. You can rewrite it if you want */ @@ -2303,99 +2328,84 @@ if (inout == 0) { /* read */ size = scnprintf(buffer, length, "%-17s %-11s %-11s %-15s %s\n", "Name", "Size(MB)", "Block size", "Options", "File name"); - if (fileio_proc_update_size(size, &len, &begin, &pos, &offset)) { - res = len; - goto out_up; - } + if (fileio_proc_update_size(size, offset, length, &pu, 1)) + goto stop_output; list_for_each_entry(virt_dev, &disk_fileio_dev_list, fileio_dev_list_entry) { int c; - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, "%-17s %-11d %-12d", virt_dev->name, (uint32_t)(virt_dev->file_size >> 20), virt_dev->block_size); - if (fileio_proc_update_size(size, &len, &begin, &pos, - &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, length, &pu, + 1)) { + goto stop_output; } c = 0; if (virt_dev->wt_flag) { - size = scnprintf(buffer + len, length - len, "WT"); + size = scnprintf(buffer + pu.len, length - pu.len, "WT"); c += size; - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } } if (virt_dev->nv_cache) { - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, c ? ",NV" : "NV"); c += size; - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } } if (virt_dev->rd_only_flag) { - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, c ? ",RO" : "RO"); c += size; - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } } if (virt_dev->o_direct_flag) { - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, c ? ",DR" : "DR"); c += size; - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } } if (virt_dev->nullio) { - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, c ? ",NIO" : "NIO"); c += size; - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } } while (c < 16) { - size = scnprintf(buffer + len, length - len, " "); - if (fileio_proc_update_size(size, &len, &begin, &pos, - &offset)) { - res = len; - goto out_up; + size = scnprintf(buffer + pu.len, length - pu.len, " "); + if (fileio_proc_update_size(size, offset, + length, &pu, 0)) { + goto stop_output; } c++; } - size = scnprintf(buffer + len, length - len, "%s\n", + size = scnprintf(buffer + pu.len, length - pu.len, "%s\n", virt_dev->file_name); - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, length, &pu, + 0)) { + goto stop_output; } } - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - res = len; *eof = 1; - } - else { /* write */ + goto stop_output; + } else { /* write */ uint32_t block_size = DEF_DISK_BLOCKSIZE; int block_shift = DEF_DISK_BLOCKSIZE_SHIFT; p = buffer; @@ -2545,15 +2555,15 @@ strcpy(virt_dev->name, name); - len = strlen(file_name) + 1; - virt_dev->file_name = kmalloc(len, GFP_KERNEL); + pu.len = strlen(file_name) + 1; + virt_dev->file_name = kmalloc(pu.len, GFP_KERNEL); if (virt_dev->file_name == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of file_name failed"); res = -ENOMEM; goto out_free_vdev; } - strncpy(virt_dev->file_name, file_name, len); + strncpy(virt_dev->file_name, file_name, pu.len); list_add_tail(&virt_dev->fileio_dev_list_entry, &disk_fileio_dev_list); @@ -2605,6 +2615,14 @@ TRACE_EXIT_RES(res); return res; +stop_output: + *start = buffer + (offset - pu.begin); + pu.len -= (offset - pu.begin); + if (pu.len > length) + pu.len = length; + res = pu.len; + goto out_up; + out_free_vpath: list_del(&virt_dev->fileio_dev_list_entry); kfree(virt_dev->file_name); @@ -2924,11 +2942,13 @@ int res = 0, action; char *p, *name; struct scst_fileio_dev *virt_dev; - int size, len = 0; - off_t begin = 0, pos = 0; + int size; + struct fileio_proc_update_struct pu; TRACE_ENTRY(); + memset(&pu, 0, sizeof(pu)); + if (down_interruptible(&scst_fileio_mutex) != 0) { res = -EINTR; goto out; @@ -2937,32 +2957,24 @@ if (inout == 0) { /* read */ size = scnprintf(buffer, length, "%-17s %-9s %s\n", "Name", "Size(MB)", "File name"); - if (fileio_proc_update_size(size, &len, &begin, &pos, - &offset)) { - res = len; - goto out_up; - } + if (fileio_proc_update_size(size, offset, length, &pu, 1)) + goto stop_output; list_for_each_entry(virt_dev, &cdrom_fileio_dev_list, fileio_dev_list_entry) { - size = scnprintf(buffer + len, length - len, + size = scnprintf(buffer + pu.len, length - pu.len, "%-17s %-9d %s\n", virt_dev->name, (uint32_t)(virt_dev->file_size >> 20), virt_dev->file_name); - if (fileio_proc_update_size(size, &len, &begin, - &pos, &offset)) { - res = len; - goto out_up; + if (fileio_proc_update_size(size, offset, length, &pu, + 1)) { + goto stop_output; } } - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - res = len; - } - else { /* write */ + *eof = 1; + goto stop_output; + } else { /* write */ p = buffer; if (p[strlen(p) - 1] == '\n') { p[strlen(p) - 1] = '\0'; @@ -3022,6 +3034,13 @@ TRACE_EXIT_RES(res); return res; +stop_output: + *start = buffer + (offset - pu.begin); + pu.len -= (offset - pu.begin); + if (pu.len > length) + pu.len = length; + res = pu.len; + goto out_up; } static int fileio_proc_help_build(struct scst_dev_type *dev_type) Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-11-10 12:39:12 UTC (rev 31) +++ trunk/scst/src/scst_lib.c 2006-11-13 17:14:19 UTC (rev 32) @@ -341,7 +341,7 @@ dev->scsi_dev->lun, (uint64_t)tgt_dev->acg_dev->lun); } else { - TRACE(TRACE_MINOR, "Virtual device SCST lun=%Ld", + TRACE_MGMT_DBG("Virtual device SCST lun=%Ld", (uint64_t)tgt_dev->acg_dev->lun); } @@ -1562,6 +1562,7 @@ address_method = (*lun) >> 6; /* high 2 bits of byte 0 */ switch (address_method) { case 0: /* peripheral device addressing method */ +#if 0 /* At least QLA2300 Linux ini uses it as the flat space addressing method */ if (*lun) { PRINT_ERROR_PR("Illegal BUS INDENTIFIER in LUN " "peripheral device addressing method 0x%02x, " @@ -1570,6 +1571,9 @@ } res = *(lun + 1); break; +#else + /* go through */ +#endif case 1: /* flat space addressing method */ res = *(lun + 1) | (((*lun) & 0x3f) << 8); Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2006-11-10 12:39:12 UTC (rev 31) +++ trunk/scst/src/scst_proc.c 2006-11-13 17:14:19 UTC (rev 32) @@ -726,45 +726,62 @@ TRACE_EXIT(); } -static int scst_proc_update_size(int size, int *len, - off_t *begin, off_t *pos, off_t *offset, int length) +struct scst_proc_update_struct { + int len, plen, pplen; + off_t begin, pbegin, ppbegin; + off_t pos; +}; + +static int scst_proc_update_size(int size, off_t offset, int length, + struct scst_proc_update_struct *p) { int res; if (size > 0) { - *len += size; - *pos = *begin + *len; - if (*pos < *offset) { - *len = 0; - *begin = *pos; + p->len += size; + p->pos = p->begin + p->len; + if (p->pos < offset) { + p->len = 0; + p->begin = p->pos; } - if (pos > offset + length) + if (p->pos > offset + length) { + p->begin = p->pbegin; + p->len = p->plen; res = 1; - else + goto out; + } else res = 0; - } else + } else { + p->begin = p->ppbegin; + p->len = p->pplen; res = 1; + goto out; + } + p->ppbegin = p->pbegin; + p->pplen = p->plen; + p->pbegin = p->begin; + p->plen = p->len; +out: return res; } -static int scst_proc_sgv_read_1(char *buffer, int *len, - off_t *begin, off_t *pos, off_t *offset, int length, +static int scst_proc_sgv_read_1(char *buffer, off_t offset, int length, + struct scst_proc_update_struct *p, const struct sgv_pool *pool, const char *name) { int i, size; - size = scnprintf(buffer + *len, length - *len, "\n%-20s %-11d %-11d\n", + size = scnprintf(buffer + p->len, length - p->len, "\n%-20s %-11d %-11d\n", name, atomic_read(&pool->acc.hit_alloc), atomic_read(&pool->acc.total_alloc)); - if (scst_proc_update_size(size, len, begin, pos, offset, length)) + if (scst_proc_update_size(size, offset, length, p)) return 1; for(i = 0; i < SGV_POOL_ELEMENTS; i++) { - size = scnprintf(buffer + *len, length - *len, + size = scnprintf(buffer + p->len, length - p->len, " %-18s %-11d %-11d\n", pool->cache_names[i], atomic_read(&pool->cache_acc[i].hit_alloc), atomic_read(&pool->cache_acc[i].total_alloc)); - if (scst_proc_update_size(size, len, begin, pos, offset, - length)) + if (scst_proc_update_size(size, offset, length, p)) return 1; } return 0; @@ -774,48 +791,52 @@ off_t offset, int length, int *eof, void *data) { int res = 0; - int size, len = 0; - off_t begin = 0, pos = 0; + int size; + struct scst_proc_update_struct st; TRACE_ENTRY(); TRACE_DBG("offset: %d, length %d", (int) offset, length); - size = scnprintf(buffer + len, length - len, "%-20s %-11s %-11s", + memset(&st, 0, sizeof(st)); + + size = scnprintf(buffer + st.len, length - st.len, "%-20s %-11s %-11s", "Name", "Hit", "Total"); - if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length)) + if (scst_proc_update_size(size, offset, length, &st)) goto stop_output; - if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, - &scst_sgv.norm, "sgv")) + if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.norm, + "sgv")) goto stop_output; - if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, + if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.norm_clust, "sgv-clust")) goto stop_output; - if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, + if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.dma, "sgv-dma")) goto stop_output; #ifdef SCST_HIGHMEM - if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, + if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.highmem, "sgv-highmem")) goto stop_output; #endif - size = scnprintf(buffer + len, length - len, "\n%-32s %-11d\n", + size = scnprintf(buffer + st.len, length - st.len, "\n%-32s %-11d\n", "big", atomic_read(&sgv_big_total_alloc)); - if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length)) + if (scst_proc_update_size(size, offset, length, &st)) goto stop_output; + *eof = 1; + stop_output: - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - res = len; + *start = buffer + (offset - st.begin); + st.len -= (offset - st.begin); + if (st.len > length) + st.len = length; + res = st.len; TRACE_EXIT_RES(res); return res; @@ -979,8 +1000,8 @@ void *data) { int res = 0; - int size, len = 0; - off_t begin = 0, pos = 0; + int size, len = 0, plen, pplen; + off_t begin = 0, pos = 0, pbegin, ppbegin; struct scst_device *dev; TRACE_ENTRY(); @@ -1005,6 +1026,8 @@ } else goto stop_output; + ppbegin = pbegin = begin; + pplen = plen = len; list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { if (dev->virt_id == 0) { size = scnprintf(buffer + len, length - len, @@ -1027,12 +1050,24 @@ len = 0; begin = pos; } - if (pos > offset + length) + if (pos > offset + length) { + begin = pbegin; + len = plen; goto stop_output; - } else + } + } else { + begin = ppbegin; + len = pplen; goto stop_output; + } + ppbegin = pbegin; + pplen = plen; + pbegin = begin; + plen = len; } + *eof = 1; + stop_output: *start = buffer + (offset - begin); len -= (offset - begin); @@ -1771,8 +1806,8 @@ int res = 0; struct scst_acg *acg = (struct scst_acg *)data; struct scst_acg_dev *acg_dev; - int size, len = 0; - off_t begin = 0, pos = 0; + int size, len = 0, plen, pplen; + off_t begin = 0, pos = 0, pbegin, ppbegin; TRACE_ENTRY(); @@ -1796,6 +1831,8 @@ } else goto stop_output; + ppbegin = pbegin = begin; + pplen = plen = len; list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { if (acg_dev->dev->virt_id == 0) { size = scnprintf(buffer + len, length - len, @@ -1819,12 +1856,24 @@ len = 0; begin = pos; } - if (pos > offset + length) + if (pos > offset + length) { + begin = pbegin; + len = plen; goto stop_output; - } else + } + } else { + begin = ppbegin; + len = pplen; goto stop_output; + } + ppbegin = pbegin; + pplen = plen; + pbegin = begin; + plen = len; } + *eof = 1; + stop_output: *start = buffer + (offset - begin); len -= (offset - begin); @@ -2034,8 +2083,8 @@ int res = 0; struct scst_acg *acg; struct scst_session *sess; - int size, len = 0; - off_t begin = 0, pos = 0; + int size, len = 0, plen, pplen; + off_t begin = 0, pos = 0, pbegin, ppbegin; TRACE_ENTRY(); @@ -2059,6 +2108,8 @@ } else goto stop_output; + ppbegin = pbegin = begin; + pplen = plen = len; list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { size = scnprintf(buffer + len, length - len, @@ -2074,13 +2125,25 @@ len = 0; begin = pos; } - if (pos > offset + length) + if (pos > offset + length) { + begin = pbegin; + len = plen; goto stop_output; - } else + } + } else { + begin = ppbegin; + len = pplen; goto stop_output; + } + ppbegin = pbegin; + pplen = plen; + pbegin = begin; + plen = len; } } + *eof = 1; + stop_output: *start = buffer + (offset - begin); len -= (offset - begin); @@ -2102,8 +2165,8 @@ int res = 0; struct scst_acg *acg = (struct scst_acg *)data; struct scst_acn *name; - int size, len = 0; - off_t begin = 0, pos = 0; + int size, len = 0, plen, pplen; + off_t begin = 0, pos = 0, pbegin, ppbegin; TRACE_ENTRY(); @@ -2112,6 +2175,8 @@ goto out; } + ppbegin = pbegin = begin; + pplen = plen = len; list_for_each_entry(name, &acg->acn_list, acn_list_entry) { size = scnprintf(buffer + len, length - len, "%s\n", name->name); @@ -2122,12 +2187,24 @@ len = 0; begin = pos; } - if (pos > offset + length) + if (pos > offset + length) { + begin = pbegin; + len = plen; goto stop_output; - } else + } + } else { + begin = ppbegin; + len = pplen; goto stop_output; + } + ppbegin = pbegin; + pplen = plen; + pbegin = begin; + plen = len; } + *eof = 1; + stop_output: *start = buffer + (offset - begin); len -= (offset - begin); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-11-10 12:39:12 UTC (rev 31) +++ trunk/scst/src/scst_targ.c 2006-11-13 17:14:19 UTC (rev 32) @@ -306,7 +306,7 @@ cmd->cdb[0], dev->handler->name); } if (scst_cmd_is_expected_set(cmd)) { - TRACE(TRACE_MINOR, "Using initiator supplied values: " + TRACE(TRACE_SCSI, "Using initiator supplied values: " "direction %d, transfer_len %d", cmd->expected_data_direction, cmd->expected_transfer_len); @@ -1234,6 +1234,7 @@ int buffer_size; struct scst_tgt_dev *tgt_dev = NULL; uint8_t *buffer; + int offs, overflow = 0; TRACE_ENTRY(); @@ -1243,45 +1244,70 @@ cmd->host_status = DID_OK; cmd->driver_status = 0; - /* ToDo: use full SG buffer, not only the first entry */ + if (cmd->cdb[2] != 0) { + PRINT_ERROR_PR("Unsupported SELECT REPORT value %x in REPORT " + "LUNS command", cmd->cdb[2]); + goto out_err; + } + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) goto out_err; - if (buffer_size < 16) { + if (buffer_size < 16) goto out_put_err; - } memset(buffer, 0, buffer_size); + offs = 8; /* sess->sess_tgt_dev_list is protected by suspended activity */ list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list, sess_tgt_dev_list_entry) { - if (8 + 8 * dev_cnt + 2 <= buffer_size) { - buffer[8 + 8 * dev_cnt] = (tgt_dev->acg_dev->lun >> 8) & 0xff; - buffer[8 + 8 * dev_cnt + 1] = tgt_dev->acg_dev->lun & 0xff; + if (!overflow) { + if (offs >= buffer_size) { + scst_put_buf(cmd, buffer); + buffer_size = scst_get_buf_first(cmd, &buffer); + if (buffer_size > 0) { + memset(buffer, 0, buffer_size); + offs = 0; + } else { + overflow = 1; + goto inc_dev_cnt; + } + } + if ((buffer_size - offs) < 8) { + PRINT_ERROR_PR("Buffer allocated for REPORT " + "LUNS command doesn't allow to fit 8 " + "byte entry (buffer_size=%d)", + buffer_size); + goto out_put_hw_err; + } + buffer[offs] = (tgt_dev->acg_dev->lun >> 8) & 0xff; + buffer[offs + 1] = tgt_dev->acg_dev->lun & 0xff; + offs += 8; } +inc_dev_cnt: dev_cnt++; - /* Tmp, until ToDo above done */ - if (dev_cnt >= ((PAGE_SIZE >> 3) - 2)) - break; } + if (!overflow) + scst_put_buf(cmd, buffer); /* Set the response header */ + buffer_size = scst_get_buf_first(cmd, &buffer); + if (unlikely(buffer_size <= 0)) + goto out_err; dev_cnt *= 8; buffer[0] = (dev_cnt >> 24) & 0xff; buffer[1] = (dev_cnt >> 16) & 0xff; buffer[2] = (dev_cnt >> 8) & 0xff; buffer[3] = dev_cnt & 0xff; + scst_put_buf(cmd, buffer); dev_cnt += 8; + if (dev_cnt < cmd->resp_data_len) + scst_set_resp_data_len(cmd, dev_cnt); - scst_put_buf(cmd, buffer); - - if (buffer_size > dev_cnt) - scst_set_resp_data_len(cmd, dev_cnt); - out_done: cmd->completed = 1; @@ -1298,6 +1324,11 @@ scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); goto out_done; + +out_put_hw_err: + scst_put_buf(cmd, buffer); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_done; } static int scst_pre_select(struct scst_cmd *cmd) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-11-30 16:25:57
|
Revision: 36 http://svn.sourceforge.net/scst/?rev=36&view=rev Author: vlnb Date: 2006-11-30 08:24:09 -0800 (Thu, 30 Nov 2006) Log Message: ----------- A bunch of small fixes and cleanups before 0.9.5 Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/ChangeLog 2006-11-30 16:24:09 UTC (rev 36) @@ -10,6 +10,8 @@ kernel, but pass-through modules (scst_disk, scst_tape, etc.) are not supported). + - Fixed problems with big amount of LUNs (500+). + - Timer-based retries for targets after SCST_TGT_RES_QUEUE_FULL status implemented. Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/README 2006-11-30 16:24:09 UTC (rev 36) @@ -255,16 +255,16 @@ - "del_group GROUP" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP" - - "add H:C:I:L lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds + - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds device with host:channel:id:lun as LUN "lun" in group "GROUP". Optionally, the device could be marked as read only. - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with host:channel:id:lun from group "GROUP" - - "add V_NAME lun [RO]" to /proc/scsi_tgt/groups/GROUP/devices adds device with - virtual name "V_NAME" as LUN "lun" in group "GROUP". Optionally, the device - could be marked as read only. + - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds + device with virtual name "V_NAME" as LUN "lun" in group "GROUP". + Optionally, the device could be marked as read only. - "del V_NAME" to /proc/scsi_tgt/groups/GROUP/devices deletes device with virtual name "V_NAME" from group "GROUP" Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-11-30 16:24:09 UTC (rev 36) @@ -2274,13 +2274,10 @@ if (size > 0) { p->len += size; p->pos = p->begin + p->len; - if (p->pos < offset) { + if (p->pos <= offset) { p->len = 0; p->begin = p->pos; - } - if (p->pos > offset + length) { - p->begin = p->pbegin; - p->len = p->plen; + } else if (p->pos >= offset + length) { res = 1; goto out; } else @@ -2620,7 +2617,7 @@ pu.len -= (offset - pu.begin); if (pu.len > length) pu.len = length; - res = pu.len; + res = max(0, pu.len); goto out_up; out_free_vpath: Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/src/scst_lib.c 2006-11-30 16:24:09 UTC (rev 36) @@ -692,6 +692,128 @@ return res; } +struct scst_cmd *scst_create_prepare_internal_cmd( + struct scst_cmd *orig_cmd, int bufsize) +{ + struct scst_cmd *res; + int gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : GFP_KERNEL; + + TRACE_ENTRY(); + + res = scst_alloc_cmd(gfp_mask); + if (unlikely(res == NULL)) { + goto out; + } + + res->sess = orig_cmd->sess; + res->state = SCST_CMD_STATE_SEND_TO_MIDLEV; + res->atomic = scst_cmd_atomic(orig_cmd); + res->internal = 1; + res->tgtt = orig_cmd->tgtt; + res->tgt = orig_cmd->tgt; + res->dev = orig_cmd->dev; + res->tgt_dev = orig_cmd->tgt_dev; + res->lun = orig_cmd->lun; + res->queue_type = SCST_CMD_QUEUE_HEAD_OF_QUEUE; + res->data_direction = SCST_DATA_UNKNOWN; + res->orig_cmd = orig_cmd; + + res->bufflen = bufsize; + if (bufsize > 0) { + if (scst_alloc_space(res) != 0) + PRINT_ERROR("Unable to create buffer (size %d) for " + "internal cmd", bufsize); + goto out_free_res; + } + +out: + TRACE_EXIT_HRES((unsigned long)res); + return res; + +out_free_res: + scst_destroy_cmd(res); + res = NULL; + goto out; +} + +void scst_free_internal_cmd(struct scst_cmd *cmd) +{ + TRACE_ENTRY(); + + if (cmd->bufflen > 0) + scst_release_space(cmd); + scst_destroy_cmd(cmd); + + TRACE_EXIT(); + return; +} + +int scst_prepare_request_sense(struct scst_cmd *orig_cmd) +{ + int res = SCST_CMD_STATE_RES_RESTART; +#define sbuf_size 252 + static const unsigned char request_sense[6] = + { REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 }; + struct scst_cmd *rs_cmd; + + TRACE_ENTRY(); + + rs_cmd = scst_create_prepare_internal_cmd(orig_cmd, sbuf_size); + if (rs_cmd != 0) + goto out_error; + + memcpy(rs_cmd->cdb, request_sense, sizeof(request_sense)); + rs_cmd->cdb_len = sizeof(request_sense); + rs_cmd->data_direction = SCST_DATA_READ; + + spin_lock_irq(&scst_list_lock); + list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list); + spin_unlock_irq(&scst_list_lock); + +out: + TRACE_EXIT_RES(res); + return res; + +out_error: + res = -1; + goto out; +#undef sbuf_size +} + +struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd) +{ + struct scst_cmd *orig_cmd = cmd->orig_cmd; + uint8_t *buf; + int len; + + TRACE_ENTRY(); + + BUG_ON(orig_cmd); + + len = scst_get_buf_first(cmd, &buf); + + if ((cmd->status == 0) && SCST_SENSE_VALID(buf) && + (!SCST_NO_SENSE(buf))) + { + TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", + buf, len); + memcpy(orig_cmd->sense_buffer, buf, + (sizeof(orig_cmd->sense_buffer) > len) ? + len : sizeof(orig_cmd->sense_buffer)); + } else { + PRINT_ERROR_PR("%s", "Unable to get the sense via " + "REQUEST SENSE, returning HARDWARE ERROR"); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + } + + scst_put_buf(cmd, buf); + + scst_free_internal_cmd(cmd); + + TRACE_EXIT_HRES((unsigned long)orig_cmd); + return orig_cmd; +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) static void scst_req_done(struct scsi_cmnd *scsi_cmd) { @@ -1561,7 +1683,7 @@ address_method = (*lun) >> 6; /* high 2 bits of byte 0 */ switch (address_method) { case 0: /* peripheral device addressing method */ -#if 0 /* At least QLA2300 Linux ini uses it as the flat space addressing method */ +#if 0 /* Looks like it's legal to use it as flat space addressing method as well */ if (*lun) { PRINT_ERROR_PR("Illegal BUS INDENTIFIER in LUN " "peripheral device addressing method 0x%02x, " Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/src/scst_priv.h 2006-11-30 16:24:09 UTC (rev 36) @@ -237,6 +237,12 @@ int scst_acg_add_name(struct scst_acg *acg, const char *name); int scst_acg_remove_name(struct scst_acg *acg, const char *name); +struct scst_cmd *scst_create_prepare_internal_cmd( + struct scst_cmd *orig_cmd, int bufsize); +void scst_free_internal_cmd(struct scst_cmd *cmd); +int scst_prepare_request_sense(struct scst_cmd *orig_cmd); +struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd); + int scst_assign_dev_handler(struct scst_device *dev, struct scst_dev_type *handler); Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/src/scst_proc.c 2006-11-30 16:24:09 UTC (rev 36) @@ -228,11 +228,10 @@ if (*size > 0) { *len += *size; *pos = *begin + *len; - if (*pos < offset) { + if (*pos <= offset) { *len = 0; *begin = *pos; - } - if (*pos > offset + length) + } else if (*pos >= offset + length) goto out_end; } else goto out_end; @@ -278,11 +277,10 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -292,7 +290,7 @@ len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); TRACE_EXIT_RES(res); return res; } @@ -739,13 +737,10 @@ if (size > 0) { p->len += size; p->pos = p->begin + p->len; - if (p->pos < offset) { + if (p->pos <= offset) { p->len = 0; p->begin = p->pos; - } - if (p->pos > offset + length) { - p->begin = p->pbegin; - p->len = p->plen; + } else if (p->pos >= offset + length) { res = 1; goto out; } else @@ -836,7 +831,7 @@ st.len -= (offset - st.begin); if (st.len > length) st.len = length; - res = st.len; + res = max(0, st.len); TRACE_EXIT_RES(res); return res; @@ -1006,6 +1001,8 @@ TRACE_ENTRY(); +//TRACE(TRACE_SPECIAL, "offset=%ld, length=%d", offset, length); + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out; @@ -1014,14 +1011,17 @@ size = scnprintf(buffer + len, length - len, "%-60s%s\n", "Device (host:ch:id:lun or name)", "Device handler"); + +//TRACE(TRACE_SPECIAL, "size=%d, pos=%ld, begin=%ld, len=%d, buf %s", +// size, pos, begin, len, buffer+len); + if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -1030,31 +1030,35 @@ pplen = plen = len; list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { if (dev->virt_id == 0) { + char conv[12]; size = scnprintf(buffer + len, length - len, - "%d:%d:%d:%-54d%s\n", + "%d:%d:%d:", dev->scsi_dev->host->host_no, dev->scsi_dev->channel, - dev->scsi_dev->id, - dev->scsi_dev->lun, - dev->handler ? dev->handler->name : - "-"); + dev->scsi_dev->id); + sprintf(conv, "%%-%dd%%s\n", 60-size); + size += scnprintf(buffer + len + size, length - len - size, + conv, dev->scsi_dev->lun, + dev->handler ? dev->handler->name : "-"); } else { size = scnprintf(buffer + len, length - len, "%-60s%s\n", dev->virt_name, dev->handler->name); } + +//printk("size=%d, pbegin=%ld, plen=%d, ppbegin=%ld, pplen=%d, buf %s", +// size, pbegin, plen, ppbegin, pplen, buffer+len); + if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; } - if (pos > offset + length) { - begin = pbegin; - len = plen; +//TRACE(TRACE_SPECIAL, "pos=%ld, begin=%ld, len=%d", pos, begin, len); + if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -1073,8 +1077,10 @@ len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); +//TRACE(TRACE_SPECIAL, "res=%d, start=%ld, len=%d, begin=%ld, eof=%d", res, offset-begin, len, begin, *eof); + up(&scst_mutex); out: @@ -1822,11 +1828,10 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -1835,11 +1840,15 @@ pplen = plen = len; list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { if (acg_dev->dev->virt_id == 0) { + char conv[20]; size = scnprintf(buffer + len, length - len, - "%d:%d:%d:%-54d%4d%12s\n", + "%d:%d:%d:", acg_dev->dev->scsi_dev->host->host_no, acg_dev->dev->scsi_dev->channel, - acg_dev->dev->scsi_dev->id, + acg_dev->dev->scsi_dev->id); + sprintf(conv, "%%-%dd%%4d%%12s\n", 60-size); + size += scnprintf(buffer + len + size, + length - len - size, conv, acg_dev->dev->scsi_dev->lun, acg_dev->lun, acg_dev->rd_only_flag ? "RO" : ""); @@ -1852,15 +1861,11 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -1879,7 +1884,7 @@ len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); @@ -2099,11 +2104,10 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) + } else if (pos >= offset + length) goto stop_output; } else goto stop_output; @@ -2121,15 +2125,11 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -2149,7 +2149,7 @@ len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); @@ -2183,15 +2183,11 @@ if (size > 0) { len += size; pos = begin + len; - if (pos < offset) { + if (pos <= offset) { len = 0; begin = pos; - } - if (pos > offset + length) { - begin = pbegin; - len = plen; + } else if (pos >= offset + length) goto stop_output; - } } else { begin = ppbegin; len = pplen; @@ -2210,7 +2206,7 @@ len -= (offset - begin); if (len > length) len = length; - res = len; + res = max(0, len); up(&scst_mutex); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-11-15 12:13:57 UTC (rev 35) +++ trunk/scst/src/scst_targ.c 2006-11-30 16:24:09 UTC (rev 36) @@ -1141,15 +1141,6 @@ WARN_ON(in_irq()); - /* - * We don't use resid, because: - * 1. Many low level initiator drivers don't use (set) this field - * 2. We determine the command's buffer size directly from CDB, - * so resid is not relevant for us, and target drivers - * should know the residual, if necessary, by comparing expected - * and actual transfer sizes. - */ - cmd = (struct scst_cmd *)data; if (cmd == NULL) goto out; @@ -1180,8 +1171,8 @@ if (next_state == SCST_CMD_STATE_DEFAULT) next_state = SCST_CMD_STATE_DEV_DONE; - if (next_state == SCST_CMD_STATE_DEV_DONE) { #if defined(DEBUG) || defined(TRACING) + if (next_state == SCST_CMD_STATE_DEV_DONE) { if (cmd->sg) { int i; struct scatterlist *sg = cmd->sg; @@ -1194,8 +1185,8 @@ sg[i].length); } } -#endif } +#endif #ifdef EXTRACHECKS @@ -1244,7 +1235,7 @@ cmd->host_status = DID_OK; cmd->driver_status = 0; - if (cmd->cdb[2] != 0) { + if ((cmd->cdb[2] != 0) && (cmd->cdb[2] != 2)) { PRINT_ERROR_PR("Unsupported SELECT REPORT value %x in REPORT " "LUNS command", cmd->cdb[2]); goto out_err; @@ -1267,7 +1258,7 @@ if (!overflow) { if (offs >= buffer_size) { scst_put_buf(cmd, buffer); - buffer_size = scst_get_buf_first(cmd, &buffer); + buffer_size = scst_get_buf_next(cmd, &buffer); if (buffer_size > 0) { memset(buffer, 0, buffer_size); offs = 0; @@ -1284,7 +1275,7 @@ goto out_put_hw_err; } buffer[offs] = (tgt_dev->acg_dev->lun >> 8) & 0xff; - buffer[offs + 1] = tgt_dev->acg_dev->lun & 0xff; + buffer[offs+1] = tgt_dev->acg_dev->lun & 0xff; offs += 8; } inc_dev_cnt: @@ -1490,51 +1481,53 @@ TRACE_ENTRY(); /* Reserve check before Unit Attention */ - if (unlikely(test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) && - (cmd->cdb[0] != INQUIRY) && - (cmd->cdb[0] != REPORT_LUNS) && - (cmd->cdb[0] != RELEASE) && - (cmd->cdb[0] != RELEASE_10) && - (cmd->cdb[0] != REPORT_DEVICE_IDENTIFIER) && - (cmd->cdb[0] != ALLOW_MEDIUM_REMOVAL || (cmd->cdb[4] & 3)) && - (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE)) - { - scst_report_reserved(cmd); - res = SCST_EXEC_COMPLETED; - goto out; + if (unlikely(test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags))) { + if ((cmd->cdb[0] != INQUIRY) && (cmd->cdb[0] != REPORT_LUNS) && + (cmd->cdb[0] != RELEASE) && (cmd->cdb[0] != RELEASE_10) && + (cmd->cdb[0] != REPORT_DEVICE_IDENTIFIER) && + (cmd->cdb[0] != ALLOW_MEDIUM_REMOVAL || (cmd->cdb[4] & 3)) && + (cmd->cdb[0] != LOG_SENSE) && (cmd->cdb[0] != REQUEST_SENSE)) + { + scst_report_reserved(cmd); + res = SCST_EXEC_COMPLETED; + goto out; + } } /* If we had a internal bus reset, set the command error unit attention */ if ((cmd->dev->scsi_dev != NULL) && - unlikely(cmd->dev->scsi_dev->was_reset) && - scst_is_ua_command(cmd)) - { - struct scst_device *dev = cmd->dev; - int done = 0; - /* Prevent more than 1 cmd to be triggered by was_reset */ - spin_lock_bh(&dev->dev_lock); - barrier(); /* to reread was_reset */ - if (dev->scsi_dev->was_reset) { - TRACE(TRACE_MGMT, "was_reset is %d", 1); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_reset_UA)); - /* It looks like it is safe to clear was_reset here */ - dev->scsi_dev->was_reset = 0; - smp_mb(); - done = 1; - } - spin_unlock_bh(&dev->dev_lock); + unlikely(cmd->dev->scsi_dev->was_reset)) { + if (scst_is_ua_command(cmd)) + { + struct scst_device *dev = cmd->dev; + int done = 0; + /* Prevent more than 1 cmd to be triggered by was_reset */ + spin_lock_bh(&dev->dev_lock); + barrier(); /* to reread was_reset */ + if (dev->scsi_dev->was_reset) { + TRACE(TRACE_MGMT, "was_reset is %d", 1); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_reset_UA)); + /* It looks like it is safe to clear was_reset here */ + dev->scsi_dev->was_reset = 0; + smp_mb(); + done = 1; + } + spin_unlock_bh(&dev->dev_lock); - if (done) - goto out_done; + if (done) + goto out_done; + } } - if (test_bit(SCST_TGT_DEV_UA_PENDING, &cmd->tgt_dev->tgt_dev_flags) && - scst_is_ua_command(cmd)) - { - rc = scst_set_pending_UA(cmd); - if (rc == 0) - goto out_done; + if (unlikely(test_bit(SCST_TGT_DEV_UA_PENDING, + &cmd->tgt_dev->tgt_dev_flags))) { + if (scst_is_ua_command(cmd)) + { + rc = scst_set_pending_UA(cmd); + if (rc == 0) + goto out_done; + } } /* Check READ_ONLY device status */ @@ -1653,14 +1646,12 @@ /* !! At this point cmd, sess & tgt_dev can be already freed !! */ TRACE_DBG("Dev handler %s exec() returned %d", dev->handler->name, rc); - if (rc != SCST_EXEC_NOT_COMPLETED) { - if (rc == SCST_EXEC_COMPLETED) - goto out; - else if (rc == SCST_EXEC_NEED_THREAD) - goto out_clear; - else - goto out_rc_error; - } + if (rc == SCST_EXEC_COMPLETED) + goto out; + else if (rc == SCST_EXEC_NEED_THREAD) + goto out_clear; + else if (rc != SCST_EXEC_NOT_COMPLETED) + goto out_rc_error; } TRACE_DBG("Sending cmd %p to SCSI mid-level", cmd); @@ -1673,10 +1664,15 @@ } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) - if (scst_alloc_request(cmd) != 0) { - PRINT_INFO_PR("%s", "Unable to allocate request, " - "sending BUSY status"); - goto out_busy; + if (unlikely(scst_alloc_request(cmd) != 0)) { + if (scst_cmd_atomic(cmd)) { + rc = SCST_EXEC_NEED_THREAD; + goto out_clear; + } else { + PRINT_INFO_PR("%s", "Unable to allocate request, " + "sending BUSY status"); + goto out_busy; + } } scst_do_req(cmd->scsi_req, (void *)cmd->cdb, @@ -1687,10 +1683,15 @@ rc = scst_exec_req(cmd->dev->scsi_dev, cmd->cdb, cmd->cdb_len, cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, cmd->timeout, cmd->retries, cmd, scst_cmd_done, - GFP_KERNEL); - if (rc) { - PRINT_INFO_PR("scst_exec_req() failed: %d", rc); - goto out_error; + scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL); + if (unlikely(rc != 0)) { + if (scst_cmd_atomic(cmd)) { + rc = SCST_EXEC_NEED_THREAD; + goto out_clear; + } else { + PRINT_INFO_PR("scst_exec_req() failed: %d", rc); + goto out_error; + } } #endif @@ -1838,128 +1839,6 @@ return res; } -static struct scst_cmd *scst_create_prepare_internal_cmd( - struct scst_cmd *orig_cmd, int bufsize) -{ - struct scst_cmd *res; - int gfp_mask = scst_cmd_atomic(orig_cmd) ? GFP_ATOMIC : GFP_KERNEL; - - TRACE_ENTRY(); - - res = scst_alloc_cmd(gfp_mask); - if (unlikely(res == NULL)) { - goto out; - } - - res->sess = orig_cmd->sess; - res->state = SCST_CMD_STATE_SEND_TO_MIDLEV; - res->atomic = scst_cmd_atomic(orig_cmd); - res->internal = 1; - res->tgtt = orig_cmd->tgtt; - res->tgt = orig_cmd->tgt; - res->dev = orig_cmd->dev; - res->tgt_dev = orig_cmd->tgt_dev; - res->lun = orig_cmd->lun; - res->queue_type = SCST_CMD_QUEUE_HEAD_OF_QUEUE; - res->data_direction = SCST_DATA_UNKNOWN; - res->orig_cmd = orig_cmd; - - res->bufflen = bufsize; - if (bufsize > 0) { - if (scst_alloc_space(res) != 0) - PRINT_ERROR("Unable to create buffer (size %d) for " - "internal cmd", bufsize); - goto out_free_res; - } - -out: - TRACE_EXIT_HRES((unsigned long)res); - return res; - -out_free_res: - scst_destroy_cmd(res); - res = NULL; - goto out; -} - -static void scst_free_internal_cmd(struct scst_cmd *cmd) -{ - TRACE_ENTRY(); - - if (cmd->bufflen > 0) - scst_release_space(cmd); - scst_destroy_cmd(cmd); - - TRACE_EXIT(); - return; -} - -static int scst_prepare_request_sense(struct scst_cmd *orig_cmd) -{ - int res = SCST_CMD_STATE_RES_RESTART; -#define sbuf_size 252 - static const unsigned char request_sense[6] = - { REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 }; - struct scst_cmd *rs_cmd; - - TRACE_ENTRY(); - - rs_cmd = scst_create_prepare_internal_cmd(orig_cmd, sbuf_size); - if (rs_cmd != 0) - goto out_error; - - memcpy(rs_cmd->cdb, request_sense, sizeof(request_sense)); - rs_cmd->cdb_len = sizeof(request_sense); - rs_cmd->data_direction = SCST_DATA_READ; - - spin_lock_irq(&scst_list_lock); - list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irq(&scst_list_lock); - -out: - TRACE_EXIT_RES(res); - return res; - -out_error: - res = -1; - goto out; -#undef sbuf_size -} - -static struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd) -{ - struct scst_cmd *orig_cmd = cmd->orig_cmd; - uint8_t *buf; - int len; - - TRACE_ENTRY(); - - BUG_ON(orig_cmd); - - len = scst_get_buf_first(cmd, &buf); - - if ((cmd->status == 0) && SCST_SENSE_VALID(buf) && - (!SCST_NO_SENSE(buf))) - { - TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", - buf, len); - memcpy(orig_cmd->sense_buffer, buf, - (sizeof(orig_cmd->sense_buffer) > len) ? - len : sizeof(orig_cmd->sense_buffer)); - } else { - PRINT_ERROR_PR("%s", "Unable to get the sense via " - "REQUEST SENSE, returning HARDWARE ERROR"); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - } - - scst_put_buf(cmd, buf); - - scst_free_internal_cmd(cmd); - - TRACE_EXIT_HRES((unsigned long)orig_cmd); - return orig_cmd; -} - static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres) { int res = 0, rc; @@ -1967,10 +1846,10 @@ TRACE_ENTRY(); - if (cmd->cdb[0] == REQUEST_SENSE) { + if (unlikely(cmd->cdb[0] == REQUEST_SENSE)) { if (cmd->internal) cmd = scst_complete_request_sense(cmd); - } else if (scst_check_auto_sense(cmd)) { + } else if (unlikely(scst_check_auto_sense(cmd))) { PRINT_INFO_PR("Command finished with CHECK CONDITION, but " "without sense data (opcode 0x%x), issuing " "REQUEST SENSE", cmd->cdb[0]); @@ -2238,7 +2117,7 @@ if (cmd->sg) { int i; struct scatterlist *sg = cmd->sg; - TRACE(TRACE_SEND_BOT, + TRACE(TRACE_SEND_BOT, "Xmitting %d S/G(s) at %p sg[0].page at %p", cmd->sg_cnt, sg, (void*)sg[0].page); for(i = 0; i < cmd->sg_cnt; ++i) { @@ -2306,6 +2185,19 @@ goto out; } +void scst_tgt_cmd_done(struct scst_cmd *cmd) +{ + TRACE_ENTRY(); + + BUG_ON(cmd->state != SCST_CMD_STATE_XMIT_WAIT); + + cmd->state = SCST_CMD_STATE_FINISHED; + scst_proccess_redirect_cmd(cmd, scst_get_context(), 1); + + TRACE_EXIT(); + return; +} + static int scst_finish_cmd(struct scst_cmd *cmd) { int res; @@ -2343,19 +2235,6 @@ return res; } -void scst_tgt_cmd_done(struct scst_cmd *cmd) -{ - TRACE_ENTRY(); - - BUG_ON(cmd->state != SCST_CMD_STATE_XMIT_WAIT); - - cmd->state = SCST_CMD_STATE_FINISHED; - scst_proccess_redirect_cmd(cmd, scst_get_context(), 1); - - TRACE_EXIT(); - return; -} - /* * Returns 0 on success, > 0 when we need to wait for unblock, * < 0 if there is no device (lun) or device type handler. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-12-05 10:23:41
|
Revision: 44 http://svn.sourceforge.net/scst/?rev=44&view=rev Author: vlnb Date: 2006-12-05 02:22:53 -0800 (Tue, 05 Dec 2006) Log Message: ----------- - Fixed a race, which could lead to BUG() in scst_mgmt_thread() - Credits updated Modified Paths: -------------- trunk/scst/README trunk/scst/src/scst_targ.c Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2006-12-04 11:08:18 UTC (rev 43) +++ trunk/scst/README 2006-12-05 10:22:53 UTC (rev 44) @@ -486,4 +486,6 @@ * Calvin Morrow <cal...@co...> for testing and usful suggestions. + * Erik Habbinga <eri...@in...> for fixes. + Vladislav Bolkhovitin <vs...@vl...>, http://scst.sourceforge.net Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-12-04 11:08:18 UTC (rev 43) +++ trunk/scst/src/scst_targ.c 2006-12-05 10:22:53 UTC (rev 44) @@ -3861,11 +3861,13 @@ list_for_each_entry(sess, &scst_sess_mgmt_list, sess_mgmt_list_entry) { + int shutting_down; TRACE_DBG("Removing sess %p from scst_sess_mgmt_list", sess); list_del(&sess->sess_mgmt_list_entry); + shutting_down = sess->shutting_down; spin_unlock_irq(&scst_mgmt_lock); - if (sess->shutting_down) { + if (shutting_down) { BUG_ON(atomic_read(&sess->refcnt) != 0); scst_free_session_callback(sess); } else if (sess->init_phase == SCST_SESS_IPH_INITING) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-12-14 17:51:03
|
Revision: 58 http://svn.sourceforge.net/scst/?rev=58&view=rev Author: vlnb Date: 2006-12-14 09:50:57 -0800 (Thu, 14 Dec 2006) Log Message: ----------- Internal threads management reimplemented based on kthread*() API. Mostly done by Ming Zhang. Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/include/scsi_tgt.h 2006-12-14 17:50:57 UTC (rev 58) @@ -2190,8 +2190,8 @@ * Adds and deletes (stops) num SCST's threads. Returns 0 on success, * error code otherwise. */ -int scst_add_threads(int num); -void scst_del_threads(int num); +int scst_add_cmd_threads(int num); +void scst_del_cmd_threads(int num); void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense, unsigned int len); Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-14 17:50:57 UTC (rev 58) @@ -34,6 +34,7 @@ #include <linux/writeback.h> #include <linux/vmalloc.h> #include <asm/atomic.h> +#include <linux/kthread.h> #define LOG_PREFIX "dev_fileio" #include "scst_debug.h" @@ -107,15 +108,13 @@ struct scst_fileio_tgt_dev { spinlock_t fdev_lock; enum scst_cmd_queue_type last_write_cmd_queue_type; - int shutdown; struct file *fd; struct iovec *iv; int iv_count; struct list_head fdev_cmd_list; wait_queue_head_t fdev_waitQ; + struct task_struct *cmd_thread; struct scst_fileio_dev *virt_dev; - atomic_t threads_count; - struct semaphore shutdown_mutex; struct list_head ftgt_list_entry; }; @@ -198,8 +197,6 @@ "echo \"open|change|close NAME [FILE_NAME]\" " ">/proc/scsi_tgt/" CDROM_FILEIO_NAME "/" CDROM_FILEIO_NAME "\n"; -#define FILEIO_THREAD_FLAGS CLONE_KERNEL - /************************************************************** * Function: fileio_open * @@ -631,7 +628,7 @@ static inline int test_cmd_list(struct scst_fileio_tgt_dev *ftgt_dev) { int res = !list_empty(&ftgt_dev->fdev_cmd_list) || - unlikely(ftgt_dev->shutdown); + unlikely(kthread_should_stop()); return res; } @@ -641,13 +638,11 @@ TRACE_ENTRY(); - daemonize("scst_fileio"); - recalc_sigpending(); set_user_nice(current, 10); current->flags |= PF_NOFREEZE; spin_lock_bh(&ftgt_dev->fdev_lock); - while (1) { + while (!kthread_should_stop()) { wait_queue_t wait; struct scst_cmd *cmd; init_waitqueue_entry(&wait, current); @@ -674,20 +669,15 @@ spin_unlock_bh(&ftgt_dev->fdev_lock); fileio_do_job(cmd); spin_lock_bh(&ftgt_dev->fdev_lock); - if (unlikely(ftgt_dev->shutdown)) - break; } - - if (unlikely(ftgt_dev->shutdown)) - break; } spin_unlock_bh(&ftgt_dev->fdev_lock); - if (atomic_dec_and_test(&ftgt_dev->threads_count)) { - smp_mb__after_atomic_dec(); - TRACE_DBG("%s", "Releasing shutdown_mutex"); - up(&ftgt_dev->shutdown_mutex); - } + /* + * If kthread_should_stop() is true, we are guaranteed to be in + * suspended activity state, so fdev_cmd_list must be empty. + */ + sBUG_ON(!list_empty(&ftgt_dev->fdev_cmd_list)); TRACE_EXIT(); return 0; @@ -713,8 +703,6 @@ spin_lock_init(&ftgt_dev->fdev_lock); INIT_LIST_HEAD(&ftgt_dev->fdev_cmd_list); init_waitqueue_head(&ftgt_dev->fdev_waitQ); - atomic_set(&ftgt_dev->threads_count, 0); - init_MUTEX_LOCKED(&ftgt_dev->shutdown_mutex); ftgt_dev->virt_dev = virt_dev; if (!virt_dev->cdrom_empty) { @@ -732,13 +720,12 @@ * Only ONE thread must be run here, otherwise the commands could * be executed out of order !! */ - res = kernel_thread(fileio_cmd_thread, ftgt_dev, FILEIO_THREAD_FLAGS); - if (res < 0) { - PRINT_ERROR_PR("kernel_thread() failed: %d", res); + ftgt_dev->cmd_thread = kthread_run(fileio_cmd_thread, ftgt_dev, "scst_fileio"); + if (IS_ERR(ftgt_dev->cmd_thread)) { + PRINT_ERROR_PR("kthread_run failed to create %s", "scst_fileio"); + res = PTR_ERR(ftgt_dev->cmd_thread); goto out_free_close; } - res = 0; - atomic_inc(&ftgt_dev->threads_count); tgt_dev->dh_priv = ftgt_dev; @@ -773,9 +760,7 @@ list_del(&ftgt_dev->ftgt_list_entry); up(&virt_dev->ftgt_list_mutex); - ftgt_dev->shutdown = 1; - wake_up_all(&ftgt_dev->fdev_waitQ); - down(&ftgt_dev->shutdown_mutex); + kthread_stop(ftgt_dev->cmd_thread); if (ftgt_dev->fd) filp_close(ftgt_dev->fd, NULL); @@ -2800,9 +2785,7 @@ virt_dev->media_changed = 1; down(&virt_dev->ftgt_list_mutex); - list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, - ftgt_list_entry) - { + list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, ftgt_list_entry) { if (!virt_dev->cdrom_empty) { fd = fileio_open(virt_dev); if (IS_ERR(fd)) { @@ -3116,12 +3099,7 @@ * Wait for one sec. to allow the thread(s) actually exit, * otherwise we can get Oops. Any better way? */ - { - unsigned long t = jiffies; - TRACE_DBG("%s", "Waiting 1 sec..."); - while ((jiffies - t) < HZ) - schedule(); - } + schedule_timeout(HZ); } module_init(init_scst_fileio_driver); Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/src/scst.c 2006-12-14 17:50:57 UTC (rev 58) @@ -26,6 +26,7 @@ #include <linux/sched.h> #include <asm/unistd.h> #include <asm/string.h> +#include <linux/kthread.h> #include "scst_debug.h" #include "scsi_tgt.h" @@ -93,12 +94,9 @@ spinlock_t scst_mgmt_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(scst_sess_mgmt_list); -struct semaphore *scst_shutdown_mutex = NULL; +static int scst_threads; +struct scst_threads_info_t scst_threads_info; -int scst_threads; -atomic_t scst_threads_count = ATOMIC_INIT(0); -int scst_shut_threads_count; -int scst_thread_num; static int suspend_count; int scst_virt_dev_last_id = 1; /* protected by scst_mutex */ @@ -832,21 +830,87 @@ goto out_resume; } -int scst_add_threads(int num) +int scst_cmd_threads_count(void) { + int i; + + /* Just to lower the race window, when user can get just changed value */ + down(&scst_threads_info.cmd_threads_mutex); + i = scst_threads_info.nr_cmd_threads; + up(&scst_threads_info.cmd_threads_mutex); + return i; +} + +static void scst_threads_info_init(void) +{ + memset(&scst_threads_info, 0, sizeof(scst_threads_info)); + init_MUTEX(&scst_threads_info.cmd_threads_mutex); + INIT_LIST_HEAD(&scst_threads_info.cmd_threads_list); +} + +/* scst_threads_info.cmd_threads_mutex supposed to be held */ +void __scst_del_cmd_threads(int num) +{ + struct scst_cmd_thread_t *ct, *tmp; + int i; + + TRACE_ENTRY(); + + i = scst_threads_info.nr_cmd_threads; + if (num <= 0 || num > i) { + PRINT_ERROR_PR("can not del %d cmd threads from %d", num, i); + return; + } + + list_for_each_entry_safe(ct, tmp, &scst_threads_info.cmd_threads_list, + thread_list_entry) { + int res; + + res = kthread_stop(ct->cmd_thread); + if (res < 0) { + TRACE_MGMT_DBG("kthread_stop() failed: %d", res); + } + list_del(&ct->thread_list_entry); + kfree(ct); + scst_threads_info.nr_cmd_threads--; + --num; + if (num == 0) + break; + } + + TRACE_EXIT(); + return; +} + +/* scst_threads_info.cmd_threads_mutex supposed to be held */ +int __scst_add_cmd_threads(int num) +{ int res = 0, i; + static int scst_thread_num = 0; TRACE_ENTRY(); - + for (i = 0; i < num; i++) { - res = kernel_thread(scst_cmd_thread, 0, SCST_THREAD_FLAGS); - if (res < 0) { - PRINT_ERROR_PR("kernel_thread() failed: %d", res); + struct scst_cmd_thread_t *thr; + + thr = kmalloc(sizeof(*thr), GFP_KERNEL); + if (!thr) { + res = -ENOMEM; + PRINT_ERROR_PR("fail to allocate thr %d", res); goto out_error; } - atomic_inc(&scst_threads_count); + thr->cmd_thread = kthread_run(scst_cmd_thread, 0, "scsi_tgt%d", + scst_thread_num++); + if (IS_ERR(thr->cmd_thread)) { + res = PTR_ERR(thr->cmd_thread); + PRINT_ERROR_PR("kthread_create() failed: %d", res); + kfree(thr); + goto out_error; + } + list_add(&thr->thread_list_entry, + &scst_threads_info.cmd_threads_list); + scst_threads_info.nr_cmd_threads++; } - res = 0; out: @@ -855,24 +919,87 @@ out_error: if (i > 0) - scst_del_threads(i-1); + __scst_del_cmd_threads(i - 1); goto out; } -void scst_del_threads(int num) +int scst_add_cmd_threads(int num) { + int res; + TRACE_ENTRY(); - - spin_lock_irq(&scst_list_lock); - scst_shut_threads_count += num; - spin_unlock_irq(&scst_list_lock); - - wake_up_nr(&scst_list_waitQ, num); + down(&scst_threads_info.cmd_threads_mutex); + res = __scst_add_cmd_threads(num); + up(&scst_threads_info.cmd_threads_mutex); + + TRACE_EXIT_RES(res); + return res; +} + +void scst_del_cmd_threads(int num) +{ + TRACE_ENTRY(); + + down(&scst_threads_info.cmd_threads_mutex); + __scst_del_cmd_threads(num); + up(&scst_threads_info.cmd_threads_mutex); + TRACE_EXIT(); return; } +static void scst_stop_all_threads(void) +{ + TRACE_ENTRY(); + + down(&scst_threads_info.cmd_threads_mutex); + __scst_del_cmd_threads(scst_threads_info.nr_cmd_threads); + if (scst_threads_info.mgmt_cmd_thread) + kthread_stop(scst_threads_info.mgmt_cmd_thread); + if (scst_threads_info.mgmt_thread) + kthread_stop(scst_threads_info.mgmt_thread); + up(&scst_threads_info.cmd_threads_mutex); + + TRACE_EXIT(); + return; +} + +static int scst_start_all_threads(int num) +{ + int res; + + TRACE_ENTRY(); + + down(&scst_threads_info.cmd_threads_mutex); + res = __scst_add_cmd_threads(num); + if (res < 0) + goto out; + + scst_threads_info.mgmt_cmd_thread = kthread_run(scst_mgmt_cmd_thread, + NULL, "scsi_tgt_mc"); + if (IS_ERR(scst_threads_info.mgmt_cmd_thread)) { + res = PTR_ERR(scst_threads_info.mgmt_cmd_thread); + PRINT_ERROR_PR("kthread_create() for mcmd failed: %d", res); + scst_threads_info.mgmt_cmd_thread = NULL; + goto out; + } + + scst_threads_info.mgmt_thread = kthread_run(scst_mgmt_thread, + NULL, "scsi_tgt_mgmt"); + if (IS_ERR(scst_threads_info.mgmt_thread)) { + res = PTR_ERR(scst_threads_info.mgmt_thread); + PRINT_ERROR_PR("kthread_create() for mgmt failed: %d", res); + scst_threads_info.mgmt_thread = NULL; + goto out; + } + +out: + up(&scst_threads_info.cmd_threads_mutex); + TRACE_EXIT_RES(res); + return res; +} + void scst_get(void) { scst_inc_cmd_count(); @@ -969,10 +1096,11 @@ if (scst_threads < scst_num_cpus) { PRINT_ERROR_PR("%s", "scst_threads can not be less than " "CPUs count"); - res = -EFAULT; - goto out; + scst_threads = scst_num_cpus; } - + + scst_threads_info_init(); + #define INIT_CACHEP(p, s, t, o) do { \ p = kmem_cache_create(s, sizeof(struct t), 0, \ SCST_SLAB_FLAGS, NULL, NULL); \ @@ -1024,38 +1152,19 @@ scst_scsi_op_list_init(); - res = scst_proc_init_module(); - if (res != 0) - goto out_unreg_interface; + for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++) + tasklet_init(&scst_tasklets[i], (void *)scst_cmd_tasklet, 0); TRACE_DBG("%d CPUs found, starting %d threads", scst_num_cpus, scst_threads); - for (i = 0; i < scst_threads; i++) { - res = kernel_thread(scst_cmd_thread, NULL, SCST_THREAD_FLAGS); - if (res < 0) { - PRINT_ERROR_PR("kernel_thread() failed: %d", res); - goto out_thread_free; - } - atomic_inc(&scst_threads_count); - } - - for (i = 0; i < sizeof(scst_tasklets) / sizeof(scst_tasklets[0]); i++) - tasklet_init(&scst_tasklets[i], (void *)scst_cmd_tasklet, 0); - - res = kernel_thread(scst_mgmt_cmd_thread, NULL, SCST_THREAD_FLAGS); - if (res < 0) { - PRINT_ERROR_PR("kernel_thread() for mcmd failed: %d", res); + res = scst_start_all_threads(scst_threads); + if (res < 0) goto out_thread_free; - } - atomic_inc(&scst_threads_count); - res = kernel_thread(scst_mgmt_thread, NULL, SCST_THREAD_FLAGS); - if (res < 0) { - PRINT_ERROR_PR("kernel_thread() for mgmt failed: %d", res); + res = scst_proc_init_module(); + if (res != 0) goto out_thread_free; - } - atomic_inc(&scst_threads_count); if (scst_max_cmd_mem == 0) { struct sysinfo si; @@ -1079,24 +1188,8 @@ return res; out_thread_free: - if (atomic_read(&scst_threads_count)) { - DECLARE_MUTEX_LOCKED(shm); - scst_shutdown_mutex = &shm; - smp_mb(); - set_bit(SCST_FLAG_SHUTDOWN, &scst_flags); + scst_stop_all_threads(); - wake_up_all(&scst_list_waitQ); - wake_up_all(&scst_mgmt_cmd_list_waitQ); - wake_up_all(&scst_mgmt_waitQ); - - TRACE_DBG("Waiting for %d threads to complete", - atomic_read(&scst_threads_count)); - down(&shm); - } - - scst_proc_cleanup_module(); - -out_unreg_interface: scsi_unregister_interface(&scst_interface); out_free_acg: @@ -1142,37 +1235,15 @@ /* ToDo: unregister_cpu_notifier() */ - scst_shutdown_mutex = &shm; - smp_mb(); - set_bit(SCST_FLAG_SHUTDOWN, &scst_flags); - - wake_up_all(&scst_list_waitQ); - wake_up_all(&scst_mgmt_cmd_list_waitQ); - wake_up_all(&scst_mgmt_waitQ); - - if (atomic_read(&scst_threads_count)) { - TRACE_DBG("Waiting for %d threads to complete", - atomic_read(&scst_threads_count)); - down(&shm); - - /* - * Wait for one sec. to allow the thread(s) actually exit, - * otherwise we can get Oops. Any better way? - */ - { - unsigned long t = jiffies; - TRACE_DBG("%s", "Waiting 1 sec..."); - while((jiffies - t) < HZ) - schedule(); - } - } - if (test_bit(SCST_FLAG_CMD_MEM_WORK_SCHEDULED, &scst_flags)) { cancel_delayed_work(&scst_cmd_mem_work); flush_scheduled_work(); } scst_proc_cleanup_module(); + + scst_stop_all_threads(); + scsi_unregister_interface(&scst_interface); scst_destroy_acg(scst_default_acg); @@ -1246,8 +1317,8 @@ EXPORT_SYMBOL(scst_suspend_activity); EXPORT_SYMBOL(scst_resume_activity); -EXPORT_SYMBOL(scst_add_threads); -EXPORT_SYMBOL(scst_del_threads); +EXPORT_SYMBOL(scst_add_cmd_threads); +EXPORT_SYMBOL(scst_del_cmd_threads); #if defined(DEBUG) || defined(TRACING) EXPORT_SYMBOL(scst_proc_log_entry_read); Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/src/scst_priv.h 2006-12-14 17:50:57 UTC (rev 58) @@ -66,13 +66,6 @@ /* Set if new commands initialization should be suspended for a while */ #define SCST_FLAG_SUSPENDED 0 -/* - * If set, SCST's threads exit immediately not performing any - * sessions' shutdown tasks, therefore at this point all the sessions - * must be already down. - */ -#define SCST_FLAG_SHUTDOWN 1 - /* Set if a TM command is being performed */ #define SCST_FLAG_TM_ACTIVE 2 @@ -96,8 +89,6 @@ **/ #define SCST_MAX_DEVICE_COMMANDS 128 -#define SCST_THREAD_FLAGS CLONE_KERNEL - #define SCST_TGT_RETRY_TIMEOUT (3/2*HZ) #define SCST_CMD_MEM_TIMEOUT (120*HZ) @@ -170,13 +161,24 @@ extern spinlock_t scst_mgmt_lock; extern struct list_head scst_sess_mgmt_list; -extern int scst_threads; -extern int scst_shut_threads_count; -extern atomic_t scst_threads_count; -extern int scst_thread_num; +struct scst_cmd_thread_t { + struct task_struct *cmd_thread; + struct list_head thread_list_entry; +}; -extern struct semaphore *scst_shutdown_mutex; +struct scst_threads_info_t { + struct semaphore cmd_threads_mutex; + u32 nr_cmd_threads; + struct list_head cmd_threads_list; + struct task_struct *mgmt_thread; + struct task_struct *mgmt_cmd_thread; +}; +extern struct scst_threads_info_t scst_threads_info; +extern int scst_cmd_threads_count(void); +extern int __scst_add_cmd_threads(int num); +extern void __scst_del_cmd_threads(int num); + extern spinlock_t scst_temp_UA_lock; extern uint8_t scst_temp_UA[SCSI_SENSE_BUFFERSIZE]; Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/src/scst_proc.c 2006-12-14 17:50:57 UTC (rev 58) @@ -770,25 +770,26 @@ goto out_free; } - oldtn = atomic_read(&scst_threads_count); - newtn = simple_strtoul(buffer, NULL, 0) + 2; /* 2 mgmt threads */ + down(&scst_threads_info.cmd_threads_mutex); + + oldtn = scst_threads_info.nr_cmd_threads; + newtn = simple_strtoul(buffer, NULL, 0); if (newtn <= 0) { PRINT_ERROR_PR("Illegal threads num value %d", newtn); res = -EINVAL; - goto out_up_free; + goto out_up_thr_free; } delta = newtn - oldtn; - if (delta < 0) { - scst_del_threads(-delta); - } - else { - scst_add_threads(delta); - } + if (delta < 0) + __scst_del_cmd_threads(-delta); + else + __scst_add_cmd_threads(delta); - PRINT_INFO_PR("Changed threads num: old %d, new %d(%d)", oldtn, newtn, - atomic_read(&scst_threads_count)); + PRINT_INFO_PR("Changed cmd threads num: old %d, new %d", oldtn, newtn); -out_up_free: +out_up_thr_free: + up(&scst_threads_info.cmd_threads_mutex); + up(&scst_proc_mutex); out_free: @@ -1925,8 +1926,7 @@ { TRACE_ENTRY(); - /* 2 mgmt threads */ - seq_printf(seq, "%d\n", atomic_read(&scst_threads_count) - 2); + seq_printf(seq, "%d\n", scst_cmd_threads_count()); TRACE_EXIT(); return 0; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-12-14 17:08:46 UTC (rev 57) +++ trunk/scst/src/scst_targ.c 2006-12-14 17:50:57 UTC (rev 58) @@ -25,6 +25,7 @@ #include <linux/smp_lock.h> #include <asm/unistd.h> #include <asm/string.h> +#include <linux/kthread.h> #include "scst_debug.h" #include "scsi_tgt.h" @@ -80,21 +81,7 @@ { struct tasklet_struct *t = &scst_tasklets[smp_processor_id()]; -#if 0 /* Looks like #else is better for performance */ - if ((!test_bit(TASKLET_STATE_SCHED, &t->state)) || (scst_num_cpus == 1)) - tasklet_schedule(t); - else { - /* - * We suppose that other CPU(s) are rather idle, so we - * ask one of them to help - */ - TRACE_DBG("Tasklet on CPU %d busy, waking up the thread " - "instead", smp_processor_id()); - wake_up(&scst_list_waitQ); - } -#else tasklet_schedule(t); -#endif } /* @@ -2683,29 +2670,20 @@ int res = !list_empty(&scst_active_cmd_list) || (!list_empty(&scst_init_cmd_list) && !test_bit(SCST_FLAG_SUSPENDED, &scst_flags)) || - test_bit(SCST_FLAG_SHUTDOWN, &scst_flags) || - unlikely(scst_shut_threads_count > 0) || + unlikely(kthread_should_stop()) || tm_dbg_is_release(); return res; } int scst_cmd_thread(void *arg) { - static spinlock_t lock = SPIN_LOCK_UNLOCKED; - int n; - TRACE_ENTRY(); - spin_lock(&lock); - n = scst_thread_num++; - spin_unlock(&lock); - daemonize("scsi_tgt%d", n); - recalc_sigpending(); set_user_nice(current, 10); current->flags |= PF_NOFREEZE; spin_lock_irq(&scst_list_lock); - while (1) { + while (!kthread_should_stop()) { wait_queue_t wait; init_waitqueue_entry(&wait, current); @@ -2725,26 +2703,18 @@ scst_do_job_init(); scst_do_job_active(SCST_CONTEXT_DIRECT|SCST_PROCESSIBLE_ENV); - - if (unlikely(test_bit(SCST_FLAG_SHUTDOWN, &scst_flags)) && - list_empty(&scst_cmd_list) && - list_empty(&scst_active_cmd_list) && - list_empty(&scst_init_cmd_list)) { - break; - } - - if (unlikely(scst_shut_threads_count > 0)) { - scst_shut_threads_count--; - break; - } } spin_unlock_irq(&scst_list_lock); - if (atomic_dec_and_test(&scst_threads_count) && scst_shutdown_mutex) { - smp_mb__after_atomic_dec(); - TRACE_DBG("%s", "Releasing scst_shutdown_mutex"); - up(scst_shutdown_mutex); - } + /* + * If kthread_should_stop() is true, we are guaranteed to be either + * on the module unload, or there must be at least one other thread to + * process the commands lists. + */ + sBUG_ON((scst_threads_info.nr_cmd_threads == 1) && + (!list_empty(&scst_cmd_list) || + !list_empty(&scst_active_cmd_list) || + !list_empty(&scst_init_cmd_list))); TRACE_EXIT(); return 0; @@ -3548,7 +3518,7 @@ { int res = (!list_empty(&scst_active_mgmt_cmd_list) && !test_bit(SCST_FLAG_SUSPENDED, &scst_flags)) || - test_bit(SCST_FLAG_SHUTDOWN, &scst_flags); + unlikely(kthread_should_stop()); return res; } @@ -3558,12 +3528,10 @@ TRACE_ENTRY(); - daemonize("scsi_tgt_mc"); - recalc_sigpending(); current->flags |= PF_NOFREEZE; spin_lock_irq(&scst_list_lock); - while (1) { + while(!kthread_should_stop()) { wait_queue_t wait; init_waitqueue_entry(&wait, current); @@ -3602,20 +3570,14 @@ &scst_active_mgmt_cmd_list); } } - - if (test_bit(SCST_FLAG_SHUTDOWN, &scst_flags) && - list_empty(&scst_active_mgmt_cmd_list)) - { - break; - } } spin_unlock_irq(&scst_list_lock); - if (atomic_dec_and_test(&scst_threads_count) && scst_shutdown_mutex) { - smp_mb__after_atomic_dec(); - TRACE_DBG("%s", "Releasing scst_shutdown_mutex"); - up(scst_shutdown_mutex); - } + /* + * If kthread_should_stop() is true, we are guaranteed to be + * on the module unload, so scst_active_mgmt_cmd_list must be empty. + */ + sBUG_ON(!list_empty(&scst_active_mgmt_cmd_list)); TRACE_EXIT(); return 0; @@ -3977,7 +3939,7 @@ static inline int test_mgmt_list(void) { int res = !list_empty(&scst_sess_mgmt_list) || - test_bit(SCST_FLAG_SHUTDOWN, &scst_flags); + unlikely(kthread_should_stop()); return res; } @@ -3987,12 +3949,10 @@ TRACE_ENTRY(); - daemonize("scsi_tgt_mgmt"); - recalc_sigpending(); current->flags |= PF_NOFREEZE; spin_lock_irq(&scst_mgmt_lock); - while (1) { + while(!kthread_should_stop()) { wait_queue_t wait; init_waitqueue_entry(&wait, current); @@ -4032,20 +3992,14 @@ spin_lock_irq(&scst_mgmt_lock); goto restart; } - - if (test_bit(SCST_FLAG_SHUTDOWN, &scst_flags) && - list_empty(&scst_sess_mgmt_list)) - { - break; - } } spin_unlock_irq(&scst_mgmt_lock); - if (atomic_dec_and_test(&scst_threads_count) && scst_shutdown_mutex) { - smp_mb__after_atomic_dec(); - TRACE_DBG("%s", "Releasing scst_shutdown_mutex"); - up(scst_shutdown_mutex); - } + /* + * If kthread_should_stop() is true, we are guaranteed to be + * on the module unload, so scst_sess_mgmt_list must be empty. + */ + sBUG_ON(!list_empty(&scst_sess_mgmt_list)); TRACE_EXIT(); return 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-12-15 11:45:50
|
Revision: 61 http://svn.sourceforge.net/scst/?rev=61&view=rev Author: vlnb Date: 2006-12-15 03:45:24 -0800 (Fri, 15 Dec 2006) Log Message: ----------- - Minor cleanup - Corrected definition PERSISTENT_RESERV_IN and PERSISTENT_RESERV_OUT Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst_cdbprobe.h trunk/scst/src/scst_lib.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/include/scsi_tgt.h 2006-12-15 11:45:24 UTC (rev 61) @@ -701,7 +701,8 @@ /* * Those functions can be used to export the driver's statistics and - * other infos to the world outside the kernel. + * other infos to the world outside the kernel as well as to get some + * management commands from it. * * OPTIONAL */ @@ -844,7 +845,8 @@ /* * Those functions can be used to export the handler's statistics and - * other infos to the world outside the kernel. + * other infos to the world outside the kernel as well as to get some + * management commands from it. * * OPTIONAL */ @@ -1077,13 +1079,6 @@ unsigned int mem_checked:1; /* - * Set if target driver may need to call dma_sync_sg() or similar - * function before transferring cmd' data to the target device - * via DMA. - */ - unsigned int may_need_dma_sync:1; - - /* * Set if scst_cmd_init_stage1_done() called and the target * want that preprocessing_done() will be called */ @@ -1098,6 +1093,13 @@ /* Set if the cmd's must not use sgv cache for data buffer */ unsigned int no_sgv:1; + /* + * Set if target driver may need to call dma_sync_sg() or similar + * function before transferring cmd' data to the target device + * via DMA. + */ + unsigned int may_need_dma_sync:1; + /**************************************************************/ unsigned long cmd_flags; /* cmd's async flags */ Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-15 11:45:24 UTC (rev 61) @@ -2642,7 +2642,6 @@ goto out_up; } - /* scst_fileio_mutex supposed to be held */ static int cdrom_fileio_open(char *p, char *name) { Modified: trunk/scst/src/scst_cdbprobe.h =================================================================== --- trunk/scst/src/scst_cdbprobe.h 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/src/scst_cdbprobe.h 2006-12-15 11:45:24 UTC (rev 61) @@ -351,10 +351,10 @@ SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2}, {0x5D, " O ", "SEND CUE SHEET", SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_3}, - {0x5E, " ", "PERSISTENT_RESERV_IN", - SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, - {0x5F, " ", "PERSISTENT_RESERV_OUT", - SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, + {0x5E, "OOOOO OOOO ", "PERSISTENT_RESERV_IN", + SCST_DATA_READ, FLAG_NONE, 5, get_trans_len_4}, + {0x5F, "OOOOO OOOO ", "PERSISTENT_RESERV_OUT", + SCST_DATA_WRITE, FLAG_NONE, 5, get_trans_len_4}, /* 16-bytes length CDB */ {0x80, "O OO O ", "XDWRITE EXTENDED", Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/src/scst_lib.c 2006-12-15 11:45:24 UTC (rev 61) @@ -209,7 +209,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) memset(res, 0, sizeof(*res)); #endif - + res->dev = dev; res->acg = acg; res->lun = lun; Modified: trunk/scst/src/scst_mem.c =================================================================== --- trunk/scst/src/scst_mem.c 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/src/scst_mem.c 2006-12-15 11:45:24 UTC (rev 61) @@ -410,7 +410,7 @@ memset(pool, 0, sizeof(*pool)); pool->clustered = clustered; - TRACE_MEM("sizeof(*obj)=%d, clustered=%d, sizeof(obj->trans_tbl[0])=%d", + TRACE_MEM("sizeof(*obj)=%zd, clustered=%d, sizeof(obj->trans_tbl[0])=%zd", sizeof(*obj), clustered, sizeof(obj->trans_tbl[0])); for(i = 0; i < SGV_POOL_ELEMENTS; i++) { Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-12-14 18:10:39 UTC (rev 60) +++ trunk/scst/src/scst_targ.c 2006-12-15 11:45:24 UTC (rev 61) @@ -395,7 +395,7 @@ 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 " + "cmd->bufflen(%zd), using expected_transfer_len " "instead", cmd->expected_transfer_len, cmd->bufflen); cmd->bufflen = cmd->expected_transfer_len; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-12-21 11:04:53
|
Revision: 69 http://svn.sourceforge.net/scst/?rev=69&view=rev Author: vlnb Date: 2006-12-21 03:04:34 -0800 (Thu, 21 Dec 2006) Log Message: ----------- - Cleanup: masked_status deleted, use status instead - In FILEIO report in MODE SENSE if NV_CACHE enabled that no commands reordering is possible Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_cdrom.c trunk/scst/src/dev_handlers/scst_changer.c trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_processor.c trunk/scst/src/dev_handlers/scst_raid.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/include/scsi_tgt.h 2006-12-21 11:04:34 UTC (rev 69) @@ -1175,10 +1175,9 @@ int resp_data_len; uint8_t status; /* status byte from target device */ - uint8_t masked_status; /* set from host device by status_byte() */ uint8_t msg_status; /* return status from host adapter itself */ - uint16_t host_status; /* set by low-level driver to indicate status */ - uint16_t driver_status; /* set by mid-level */ + uint8_t host_status; /* set by low-level driver to indicate status */ + uint8_t driver_status; /* set by mid-level */ /* Used for storage of target driver private stuff */ void *tgt_priv; @@ -1872,12 +1871,6 @@ return cmd->status; } -/* Returns cmd's status byte set from host device by status_byte() */ -static inline uint8_t scst_cmd_get_masked_status(struct scst_cmd *cmd) -{ - return cmd->masked_status; -} - /* Returns cmd's status from host adapter itself */ static inline uint8_t scst_cmd_get_msg_status(struct scst_cmd *cmd) { @@ -1885,13 +1878,13 @@ } /* Returns cmd's status set by low-level driver to indicate its status */ -static inline uint16_t scst_cmd_get_host_status(struct scst_cmd *cmd) +static inline uint8_t scst_cmd_get_host_status(struct scst_cmd *cmd) { return cmd->host_status; } /* Returns cmd's status set by SCSI mid-level */ -static inline uint16_t scst_cmd_get_driver_status(struct scst_cmd *cmd) +static inline uint8_t scst_cmd_get_driver_status(struct scst_cmd *cmd) { return cmd->driver_status; } Modified: trunk/scst/src/dev_handlers/scst_cdrom.c =================================================================== --- trunk/scst/src/dev_handlers/scst_cdrom.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_cdrom.c 2006-12-21 11:04:34 UTC (rev 69) @@ -288,7 +288,7 @@ int cdrom_done(struct scst_cmd *cmd) { int opcode = cmd->cdb[0]; - int masked_status = cmd->masked_status; + int status = cmd->status; struct cdrom_params *cdrom; int res = SCST_CMD_STATE_DEFAULT; @@ -299,11 +299,11 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ - if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) { + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { switch (opcode) { case READ_CAPACITY: { Modified: trunk/scst/src/dev_handlers/scst_changer.c =================================================================== --- trunk/scst/src/dev_handlers/scst_changer.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_changer.c 2006-12-21 11:04:34 UTC (rev 69) @@ -183,7 +183,7 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_disk.c 2006-12-21 11:04:34 UTC (rev 69) @@ -351,7 +351,7 @@ int disk_done(struct scst_cmd *cmd) { int opcode = cmd->cdb[0]; - int masked_status = cmd->masked_status; + int status = cmd->status; struct disk_params *disk; int res = SCST_CMD_STATE_DEFAULT; @@ -362,11 +362,11 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ - if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) { + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { switch (opcode) { case READ_CAPACITY: { @@ -444,7 +444,6 @@ case READ_16: res = SCST_EXEC_COMPLETED; cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2006-12-21 11:04:34 UTC (rev 69) @@ -893,7 +893,6 @@ TRACE_ENTRY(); cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; @@ -1056,7 +1055,6 @@ TRACE_ENTRY(); cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; @@ -1380,7 +1378,7 @@ 0, 0, 0x2, 0x4b}; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); - if (!virt_dev->wt_flag) + if (!virt_dev->wt_flag && !virt_dev->nv_cache) p[3] |= 0x10; /* Enable unrestricted reordering */ if (1 == pcontrol) memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2006-12-21 11:04:34 UTC (rev 69) @@ -375,7 +375,7 @@ int modisk_done(struct scst_cmd *cmd) { int opcode = cmd->cdb[0]; - int masked_status = cmd->masked_status; + int status = cmd->status; struct modisk_params *modisk; int res = SCST_CMD_STATE_DEFAULT; @@ -386,11 +386,11 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ - if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) { + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { switch (opcode) { case READ_CAPACITY: { @@ -468,7 +468,6 @@ case READ_16: res = SCST_EXEC_COMPLETED; cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; Modified: trunk/scst/src/dev_handlers/scst_processor.c =================================================================== --- trunk/scst/src/dev_handlers/scst_processor.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_processor.c 2006-12-21 11:04:34 UTC (rev 69) @@ -183,7 +183,7 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ Modified: trunk/scst/src/dev_handlers/scst_raid.c =================================================================== --- trunk/scst/src/dev_handlers/scst_raid.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_raid.c 2006-12-21 11:04:34 UTC (rev 69) @@ -183,7 +183,7 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/dev_handlers/scst_tape.c 2006-12-21 11:04:34 UTC (rev 69) @@ -348,7 +348,7 @@ int tape_done(struct scst_cmd *cmd) { int opcode = cmd->cdb[0]; - int masked_status = cmd->masked_status; + int status = cmd->status; struct tape_params *tape; int res = SCST_CMD_STATE_DEFAULT; @@ -359,11 +359,11 @@ /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->masked_status and cmd->data_direction, therefore change + * based on cmd->status and cmd->data_direction, therefore change * them only if necessary */ - if ((masked_status == GOOD) || (masked_status == CONDITION_GOOD)) { + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { int buffer_size; uint8_t *buffer = NULL; @@ -434,7 +434,7 @@ break; } } - else if ((masked_status == CHECK_CONDITION) && + else if ((status == SAM_STAT_CHECK_CONDITION) && SCST_SENSE_VALID(cmd->sense_buffer)) { TRACE_DBG("%s", "Extended sense"); @@ -504,7 +504,6 @@ case READ_6: res = SCST_EXEC_COMPLETED; cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/scst_lib.c 2006-12-21 11:04:34 UTC (rev 69) @@ -43,7 +43,6 @@ TRACE_ENTRY(); cmd->status = status; - cmd->masked_status = status >> 1; cmd->host_status = DID_OK; cmd->data_direction = SCST_DATA_NONE; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-12-20 17:53:41 UTC (rev 68) +++ trunk/scst/src/scst_targ.c 2006-12-21 11:04:34 UTC (rev 69) @@ -1062,7 +1062,6 @@ TRACE(TRACE_MGMT, "Retrying cmd %p " "(tag %d)", cmd, cmd->tag); cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; @@ -1127,9 +1126,8 @@ SCST_NO_SENSE(cmd->sense_buffer))) { TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: " - "cmd->status=%x, cmd->masked_status=%x, " - "cmd->msg_status=%x, cmd->host_status=%x, " - "cmd->driver_status=%x", cmd->status, cmd->masked_status, + "cmd->status=%x, cmd->msg_status=%x, " + "cmd->host_status=%x, cmd->driver_status=%x", cmd->status, cmd->msg_status, cmd->host_status, cmd->driver_status); res = 1; } else if (unlikely(cmd->host_status)) { @@ -1158,7 +1156,6 @@ TRACE_ENTRY(); cmd->status = result & 0xff; - cmd->masked_status = status_byte(result); cmd->msg_status = msg_byte(result); cmd->host_status = host_byte(result); cmd->driver_status = driver_byte(result); @@ -1173,10 +1170,9 @@ } TRACE(TRACE_SCSI, "result=%x, cmd->status=%x, resid=%d, " - "cmd->masked_status=%x, cmd->msg_status=%x, cmd->host_status=%x, " + "cmd->msg_status=%x, cmd->host_status=%x, " "cmd->driver_status=%x", result, cmd->status, resid, - cmd->masked_status, cmd->msg_status, cmd->host_status, - cmd->driver_status); + cmd->msg_status, cmd->host_status, cmd->driver_status); cmd->completed = 1; @@ -1369,7 +1365,6 @@ TRACE_ENTRY(); cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; @@ -1581,7 +1576,6 @@ if (test_bit(SCST_TGT_DEV_RESERVED, &cmd->tgt_dev->tgt_dev_flags)) { res = SCST_EXEC_COMPLETED; cmd->status = 0; - cmd->masked_status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; @@ -2062,7 +2056,7 @@ &cmd->tgt_dev->tgt_dev_flags)) { struct scst_tgt_dev *tgt_dev_tmp; TRACE(TRACE_SCSI, "Real RESERVE failed lun=%Ld, status=%x", - (uint64_t)cmd->lun, cmd->masked_status); + (uint64_t)cmd->lun, cmd->status); TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer, sizeof(cmd->sense_buffer)); /* Clearing the reservation */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-01-18 11:30:07
|
Revision: 82 http://svn.sourceforge.net/scst/?rev=82&view=rev Author: vlnb Date: 2007-01-18 03:30:05 -0800 (Thu, 18 Jan 2007) Log Message: ----------- - shutdown_mutex was replaced by shutdown_compl in hope that it will remove the lockdep's warning about "trying to register - Ability to trace SYNCHRONIZE_CACHE, FUA and ORDERED commands added to FILEIO - NULLIO for FILEIO doesn't require anymore path to a real file/device Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_dev_handler.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-01-18 10:59:48 UTC (rev 81) +++ trunk/scst/include/scsi_tgt.h 2007-01-18 11:30:05 UTC (rev 82) @@ -957,7 +957,7 @@ const char *initiator_name; /* Used if scst_unregister_session() called in wait mode */ - struct semaphore *shutdown_mutex; + struct completion *shutdown_compl; /* List entry of sessions per target */ struct list_head sess_list_entry; Modified: trunk/scst/src/dev_handlers/scst_dev_handler.h =================================================================== --- trunk/scst/src/dev_handlers/scst_dev_handler.h 2007-01-18 10:59:48 UTC (rev 81) +++ trunk/scst/src/dev_handlers/scst_dev_handler.h 2007-01-18 11:30:05 UTC (rev 82) @@ -24,6 +24,10 @@ static unsigned long dh_trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS; #define trace_flag dh_trace_flag +#ifndef trace_log_tbl +#define trace_log_tbl NULL +#endif + static struct scst_proc_data dev_handler_log_proc_data; static int dev_handler_log_info_show(struct seq_file *seq, void *v) @@ -32,21 +36,21 @@ TRACE_ENTRY(); - res = scst_proc_log_entry_read(seq, trace_flag, NULL); + res = scst_proc_log_entry_read(seq, trace_flag, trace_log_tbl); TRACE_EXIT_RES(res); return res; } -static int scst_dev_handler_proc_log_entry_write(struct file *file, const char __user *buf, - size_t length, loff_t *off) +static int scst_dev_handler_proc_log_entry_write(struct file *file, + const char __user *buf, size_t length, loff_t *off) { int res = 0; TRACE_ENTRY(); res = scst_proc_log_entry_write(file, buf, length, &trace_flag, - SCST_DEFAULT_DEV_LOG_FLAGS, NULL); + SCST_DEFAULT_DEV_LOG_FLAGS, trace_log_tbl); TRACE_EXIT_RES(res); return res; Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2007-01-18 10:59:48 UTC (rev 81) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2007-01-18 11:30:05 UTC (rev 82) @@ -39,6 +39,16 @@ #define LOG_PREFIX "dev_fileio" #include "scsi_tgt.h" + +#define TRACE_ORDER 0x80000000 + +static struct scst_proc_log fileio_proc_local_trace_tbl[] = +{ + { TRACE_ORDER, "order" }, + { 0, NULL } +}; +#define trace_log_tbl fileio_proc_local_trace_tbl + #include "scst_dev_handler.h" /* 8 byte ASCII Vendor of the FILE IO target */ @@ -279,47 +289,51 @@ virt_dev->rd_only_flag = 1; if (!virt_dev->cdrom_empty) { - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", + if (virt_dev->nullio) + err = 3LL*1024*1024*1024*1024/2; + else { + fd = fileio_open(virt_dev); + if (IS_ERR(fd)) { + res = PTR_ERR(fd); + PRINT_ERROR_PR("filp_open(%s) returned an error %d", virt_dev->file_name, res); - goto out; - } + goto out; + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - if ((fd->f_op == NULL) || (fd->f_op->readv == NULL) || - (fd->f_op->writev == NULL)) + if ((fd->f_op == NULL) || (fd->f_op->readv == NULL) || + (fd->f_op->writev == NULL)) #else - if ((fd->f_op == NULL) || (fd->f_op->aio_read == NULL) || - (fd->f_op->aio_write == NULL)) + if ((fd->f_op == NULL) || (fd->f_op->aio_read == NULL) || + (fd->f_op->aio_write == NULL)) #endif - { - PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't have " - "required capabilities"); - res = -EINVAL; - goto out_close_file; - } - - /* seek to end */ - old_fs = get_fs(); - set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); - } else { - err = default_llseek(fd, 0, 2/*SEEK_END*/); - } - set_fs(old_fs); - if (err < 0) { - res = err; - PRINT_ERROR_PR("llseek %s returned an error %d", + { + PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't have " + "required capabilities"); + res = -EINVAL; + filp_close(fd, NULL); + goto out; + } + + /* seek to end */ + old_fs = get_fs(); + set_fs(get_ds()); + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); + } else { + err = default_llseek(fd, 0, 2/*SEEK_END*/); + } + set_fs(old_fs); + filp_close(fd, NULL); + if (err < 0) { + res = err; + PRINT_ERROR_PR("llseek %s returned an error %d", virt_dev->file_name, res); - goto out_close_file; + goto out; + } } virt_dev->file_size = err; TRACE_DBG("size of file: %Ld", (uint64_t)err); - - filp_close(fd, NULL); } else virt_dev->file_size = 0; @@ -349,10 +363,6 @@ out: TRACE_EXIT(); return res; - -out_close_file: - filp_close(fd, NULL); - goto out; } /************************************************************ @@ -492,7 +502,7 @@ case WRITE_16: fua = (cdb[1] & 0x8) && !virt_dev->wt_flag; if (cdb[1] & 0x8) { - TRACE(TRACE_SCSI, "FUA(%d): loff=%Ld, " + TRACE(TRACE_ORDER, "FUA(%d): loff=%Ld, " "data_len=%Ld", fua, (uint64_t)loff, (uint64_t)data_len); } @@ -520,7 +530,7 @@ ftgt_dev->last_write_cmd_queue_type = cmd->queue_type; if (fileio_need_pre_sync(cmd->queue_type, last_queue_type) && !virt_dev->wt_flag) { - TRACE(TRACE_SCSI/*|TRACE_SPECIAL*/, "ORDERED " + TRACE(TRACE_ORDER, "ORDERED " "WRITE(%d): loff=%Ld, data_len=%Ld", cmd->queue_type, (uint64_t)loff, (uint64_t)data_len); @@ -551,7 +561,7 @@ ftgt_dev->last_write_cmd_queue_type = cmd->queue_type; if (fileio_need_pre_sync(cmd->queue_type, last_queue_type) && !virt_dev->wt_flag) { - TRACE(TRACE_SCSI/*|TRACE_SPECIAL*/, "ORDERED " + TRACE(TRACE_ORDER, "ORDERED " "WRITE_VERIFY(%d): loff=%Ld, data_len=%Ld", cmd->queue_type, (uint64_t)loff, (uint64_t)data_len); @@ -577,7 +587,7 @@ struct scst_fileio_tgt_dev *ftgt_dev = (struct scst_fileio_tgt_dev*) cmd->tgt_dev->dh_priv; - TRACE(TRACE_SCSI, "SYNCHRONIZE_CACHE: " + TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: " "loff=%Ld, data_len=%Ld, immed=%d", (uint64_t)loff, (uint64_t)data_len, immed); if (immed) { @@ -717,7 +727,7 @@ init_waitqueue_head(&ftgt_dev->fdev_waitQ); ftgt_dev->virt_dev = virt_dev; - if (!virt_dev->cdrom_empty) { + if (!virt_dev->cdrom_empty && !virt_dev->nullio) { ftgt_dev->fd = fileio_open(virt_dev); if (IS_ERR(ftgt_dev->fd)) { res = PTR_ERR(ftgt_dev->fd); @@ -1561,7 +1571,7 @@ TRACE_ENTRY(); - if (virt_dev->wt_flag == wt) + if ((virt_dev->wt_flag == wt) || virt_dev->nullio) goto out; virt_dev->wt_flag = wt; @@ -2023,33 +2033,33 @@ SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out_put; } - + old_fs = get_fs(); set_fs(get_ds()); - - /* SEEK */ - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/); - } else { - err = default_llseek(fd, loff, 0/*SEEK_SET*/); - } - if (err != loff) { - PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, - (uint64_t)loff); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_set_fs; - } - - /* READ */ + TRACE_DBG("reading(iv_count %d, full_len %zd)", iv_count, full_len); if (virt_dev->nullio) err = full_len; - else + else { + /* SEEK */ + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/); + } else { + err = default_llseek(fd, loff, 0/*SEEK_SET*/); + } + if (err != loff) { + PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, + (uint64_t)loff); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_set_fs; + } + /* READ */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) err = fd->f_op->readv(fd, iv, iv_count, &fd->f_pos); #else err = do_sync_readv_writev(fd, iv, iv_count, full_len, &fd->f_pos, fd->f_op->aio_read); #endif + } if ((err < 0) || (err < full_len)) { PRINT_ERROR_PR("readv() returned %Ld from %zd", (uint64_t)err, @@ -2111,25 +2121,10 @@ SCST_LOAD_SENSE(scst_sense_hardw_error)); goto out_put; } - + old_fs = get_fs(); set_fs(get_ds()); - - /* SEEK */ - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, loff, 0 /*SEEK_SET */ ); - } else { - err = default_llseek(fd, loff, 0 /*SEEK_SET */ ); - } - if (err != loff) { - PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, - (uint64_t)loff); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_set_fs; - } - - /* WRITE */ + eiv = iv; eiv_count = iv_count; restart: @@ -2137,13 +2132,29 @@ if (virt_dev->nullio) err = full_len; - else + else { + /* SEEK */ + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, loff, 0 /*SEEK_SET */ ); + } else { + err = default_llseek(fd, loff, 0 /*SEEK_SET */ ); + } + if (err != loff) { + PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, + (uint64_t)loff); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_set_fs; + } + + /* WRITE */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) err = fd->f_op->writev(fd, eiv, eiv_count, &fd->f_pos); #else err = do_sync_readv_writev(fd, iv, iv_count, full_len, &fd->f_pos, fd->f_op->aio_write); #endif + } if (err < 0) { PRINT_ERROR_PR("write() returned %Ld from %zd", @@ -2205,6 +2216,8 @@ ssize_t length, len_mem = 0; uint8_t *address_sav, *address; int compare; + struct scst_fileio_dev *virt_dev = + (struct scst_fileio_dev *)cmd->dev->dh_priv; struct scst_fileio_tgt_dev *ftgt_dev = (struct scst_fileio_tgt_dev *)cmd->tgt_dev->dh_priv; struct file *fd = ftgt_dev->fd; @@ -2227,17 +2240,19 @@ old_fs = get_fs(); set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/); - } else { - err = default_llseek(fd, loff, 0/*SEEK_SET*/); + if (!virt_dev->nullio) { + if (fd->f_op->llseek) { + err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/); + } else { + err = default_llseek(fd, loff, 0/*SEEK_SET*/); + } + if (err != loff) { + PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, + (uint64_t)loff); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_set_fs; + } } - if (err != loff) { - PRINT_ERROR_PR("lseek trouble %Ld != %Ld", (uint64_t)err, - (uint64_t)loff); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_set_fs; - } mem_verify = vmalloc(LEN_MEM); if (mem_verify == NULL) { @@ -2260,7 +2275,10 @@ len_mem = length > LEN_MEM ? LEN_MEM : length; TRACE_DBG("Verify: length %zd - len_mem %zd", length, len_mem); - err = fd->f_op->read(fd, (char*)mem_verify, len_mem, &fd->f_pos); + if (!virt_dev->nullio) + err = fd->f_op->read(fd, (char*)mem_verify, len_mem, &fd->f_pos); + else + err = len_mem; if ((err < 0) || (err < len_mem)) { PRINT_ERROR_PR("verify() returned %Ld from %zd", (uint64_t)err, len_mem); @@ -2497,11 +2515,6 @@ PRINT_ERROR_PR("%s", "File name required"); res = -EINVAL; goto out_up; - } else if (*file_name != '/') { - PRINT_ERROR_PR("File path \"%s\" is not " - "absolute", file_name); - res = -EINVAL; - goto out_up; } virt_dev = fileio_alloc_dev(); @@ -2581,7 +2594,14 @@ while (isspace(*p) && *p != '\0') p++; } - + + if (!virt_dev->nullio && (*file_name != '/')) { + PRINT_ERROR_PR("File path \"%s\" is not " + "absolute", file_name); + res = -EINVAL; + goto out_up; + } + strcpy(virt_dev->name, name); len = strlen(file_name) + 1; @@ -2825,7 +2845,7 @@ old_fn = virt_dev->file_name; - if (!virt_dev->cdrom_empty) { + if (!virt_dev->cdrom_empty && !virt_dev->nullio) { len = strlen(file_name) + 1; fn = kmalloc(len, GFP_KERNEL); if (fn == NULL) { @@ -2895,7 +2915,7 @@ down(&virt_dev->ftgt_list_mutex); list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, ftgt_list_entry) { - if (!virt_dev->cdrom_empty) { + if (!virt_dev->cdrom_empty && !virt_dev->nullio) { fd = fileio_open(virt_dev); if (IS_ERR(fd)) { res = PTR_ERR(fd); Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-01-18 10:59:48 UTC (rev 81) +++ trunk/scst/src/scst_lib.c 2007-01-18 11:30:05 UTC (rev 82) @@ -1001,13 +1001,13 @@ void scst_free_session_callback(struct scst_session *sess) { - struct semaphore *shm; + struct completion *c; TRACE_ENTRY(); TRACE_DBG("Freeing session %p", sess); - shm = sess->shutdown_mutex; + c = sess->shutdown_compl; if (sess->unreg_done_fn) { TRACE_DBG("Calling unreg_done_fn(%p)", sess); @@ -1016,8 +1016,8 @@ } scst_free_session(sess); - if (shm) - up(shm); + if (c) + complete_all(c); TRACE_EXIT(); return; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-01-18 10:59:48 UTC (rev 81) +++ trunk/scst/src/scst_targ.c 2007-01-18 11:30:05 UTC (rev 82) @@ -3900,7 +3900,7 @@ void (*unreg_done_fn) (struct scst_session *sess)) { unsigned long flags; - DECLARE_MUTEX_LOCKED(shm); + DECLARE_COMPLETION(c); TRACE_ENTRY(); @@ -3909,7 +3909,7 @@ sess->shutting_down = 1; sess->unreg_done_fn = unreg_done_fn; if (wait) { - sess->shutdown_mutex = &shm; + sess->shutdown_compl = &c; smp_mb(); } @@ -3919,7 +3919,7 @@ if (wait) { TRACE_DBG("Waiting for session %p to complete", sess); - down(&shm); + wait_for_completion(&c); } TRACE_EXIT(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-01-22 10:58:16
|
Revision: 83 http://svn.sourceforge.net/scst/?rev=83&view=rev Author: vlnb Date: 2007-01-22 02:38:18 -0800 (Mon, 22 Jan 2007) Log Message: ----------- Bugfix for Fedora 6 kernel where GFP_ATOMIC constant is redefined, which lead to massive commands data buffers memory allocations failures. Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/src/scst_lib.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_mem.h Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2007-01-18 11:30:05 UTC (rev 82) +++ trunk/scst/ChangeLog 2007-01-22 10:38:18 UTC (rev 83) @@ -13,7 +13,7 @@ - Support for CPU cache flushing before doing DMA to target devices added. - - Various cleanups and bug fixes. + - Various cleanups, bug fixes and improvements. Summary of changes between versions 0.9.4 and 0.9.5 --------------------------------------------------- Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-01-18 11:30:05 UTC (rev 82) +++ trunk/scst/src/scst_lib.c 2007-01-22 10:38:18 UTC (rev 83) @@ -1313,6 +1313,7 @@ int ini_unchecked_isa_dma, ini_use_clustering; int use_clustering = 0; struct sgv_pool *pool; + int atomic = scst_cmd_atomic(cmd); TRACE_ENTRY(); @@ -1324,7 +1325,7 @@ } gfp_mask = __GFP_NOWARN; - gfp_mask |= (scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL); + gfp_mask |= (atomic ? GFP_ATOMIC : GFP_KERNEL); pool = &scst_sgv.norm; if (cmd->dev->scsi_dev != NULL) { @@ -1364,7 +1365,7 @@ cmd->sg = scst_alloc(cmd->bufflen, gfp_mask, use_clustering, &cmd->sg_cnt); } else { - cmd->sg = sgv_pool_alloc(pool, cmd->bufflen, gfp_mask, + cmd->sg = sgv_pool_alloc(pool, cmd->bufflen, gfp_mask, atomic, &cmd->sg_cnt, &cmd->sgv); } if (cmd->sg == NULL) Modified: trunk/scst/src/scst_mem.c =================================================================== --- trunk/scst/src/scst_mem.c 2007-01-18 11:30:05 UTC (rev 82) +++ trunk/scst/src/scst_mem.c 2007-01-22 10:38:18 UTC (rev 83) @@ -211,7 +211,8 @@ } struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, int size, - unsigned long gfp_mask, int *count, struct sgv_pool_obj **sgv) + unsigned long gfp_mask, int atomic, int *count, + struct sgv_pool_obj **sgv) { struct sgv_pool_obj *obj; int order, pages, cnt, sg; @@ -227,7 +228,7 @@ if (order >= SGV_POOL_ELEMENTS) { obj = NULL; - if (gfp_mask & GFP_ATOMIC) + if (atomic) goto out; atomic_inc(&sgv_big_total_alloc); atomic_dec(&sgv_other_total_alloc); @@ -238,7 +239,7 @@ obj = kmem_cache_alloc(pool->caches[order], gfp_mask & ~(__GFP_HIGHMEM|GFP_DMA)); if (obj == NULL) { - if (!(gfp_mask & GFP_ATOMIC)) { + if (!atomic) { TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj " "failed (size %d)", size); } @@ -248,7 +249,7 @@ if (obj->owner_cache != pool->caches[order]) { int esz, epg, eorder; - if (gfp_mask & GFP_ATOMIC) + if (atomic) goto out_free; esz = (1 << order) * sizeof(obj->entries[0]); Modified: trunk/scst/src/scst_mem.h =================================================================== --- trunk/scst/src/scst_mem.h 2007-01-18 11:30:05 UTC (rev 82) +++ trunk/scst/src/scst_mem.h 2007-01-22 10:38:18 UTC (rev 83) @@ -80,7 +80,8 @@ extern void sgv_pool_deinit(struct sgv_pool *pool); extern struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, int size, - unsigned long gfp_mask, int *count, struct sgv_pool_obj **sgv); + unsigned long gfp_mask, int atomic, int *count, + struct sgv_pool_obj **sgv); static inline void sgv_pool_free(struct sgv_pool_obj *sgv) { TRACE_MEM("Freeing sgv_obj %p", sgv); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-02-21 11:43:25
|
Revision: 90 http://svn.sourceforge.net/scst/?rev=90&view=rev Author: vlnb Date: 2007-02-21 03:43:22 -0800 (Wed, 21 Feb 2007) Log Message: ----------- A major locking and general code cleanup Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/include/scsi_tgt.h 2007-02-21 11:43:22 UTC (rev 90) @@ -150,12 +150,6 @@ /* Thread context required for cmd's processing */ #define SCST_CONTEXT_THREAD 3 -/* - * Additional bit to set processible environment. - * Private for SCST, ie must not be used target drivers. - */ -#define SCST_PROCESSIBLE_ENV 0x10000000 - /************************************************************* ** Values for status parameter of scst_rx_data() *************************************************************/ @@ -365,24 +359,30 @@ */ #define SCST_CMD_XMITTING 4 -/* Set if the cmd was done or aborted out of its SN */ -#define SCST_CMD_OUT_OF_SN 5 - /* Set if the cmd is dead and can be destroyed at any time */ -#define SCST_CMD_CAN_BE_DESTROYED 6 +#define SCST_CMD_CAN_BE_DESTROYED 5 /************************************************************* - ** Tgt_dev's flags + ** Tgt_dev's flags (tgt_dev_flags) *************************************************************/ /* Set if tgt_dev has Unit Attention sense */ -#define SCST_TGT_DEV_UA_PENDING 0 +#define SCST_TGT_DEV_UA_PENDING 0 /* Set if tgt_dev is RESERVED by another session */ -#define SCST_TGT_DEV_RESERVED 1 +#define SCST_TGT_DEV_RESERVED 1 +/* Set if the corresponding context is atomic */ +#define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC 5 +#define SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC 6 +#define SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC 7 +#define SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC 8 +#define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9 +#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10 + + #ifdef DEBUG_TM -#define SCST_TGT_DEV_UNDER_TM_DBG 10 +#define SCST_TGT_DEV_UNDER_TM_DBG 20 #endif /************************************************************* @@ -657,9 +657,7 @@ * level driver. No return value expected. * This function is expected to be NON-BLOCKING * - * Pay attention to "atomic" attribute of the cmd, which can be get - * by scst_cmd_atomic(): it is true if the function called in the - * atomic (non-sleeping) context. + * Called without any locks held from a thread context. * * MUST HAVE if the target supports ABORTs */ @@ -838,7 +836,7 @@ * - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the command * should be done * - * Called with BH off. Might be called under a lock and IRQ off. + * Called without any locks held from a thread context. */ int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, struct scst_tgt_dev *tgt_dev); @@ -907,19 +905,13 @@ atomic_t refcnt; /* get/put counter */ - /* Alive commands for this session. Serialized by scst_list_lock */ - int sess_cmd_count; - /************************************************************* - ** Session's flags. Serialized by scst_list_lock + ** Session's flags. Serialized by scst_mgmt_lock *************************************************************/ /* Set if the session is shutting down */ unsigned int shutting_down:1; - /* Set if the session is waiting in suspended state */ - unsigned int waiting:1; - /**************************************************************/ /* @@ -937,28 +929,22 @@ /* Used for storage of target driver private stuff */ void *tgt_priv; + /* Alive commands for this session, protected by sess_list_lock */ + int sess_cmd_count; + + spinlock_t sess_list_lock; /* protects search_cmd_list, etc */ + /* * List of cmds in this session. Used to find a cmd in the - * session. Protected by scst_list_lock. - * - * ToDo: make it protected by own lock. + * session. Protected by sess_list_lock. */ struct list_head search_cmd_list; struct scst_tgt *tgt; /* corresponding target */ - /* - * List entry for the list that keeps all sessions, which were - * stopped due to device block - */ - struct list_head dev_wait_sess_list_entry; - /* Name of attached initiator */ const char *initiator_name; - /* Used if scst_unregister_session() called in wait mode */ - struct completion *shutdown_compl; - /* List entry of sessions per target */ struct list_head sess_list_entry; @@ -967,11 +953,14 @@ /* * Lists of deffered during session initialization commands. - * Protected by scst_list_lock. + * Protected by sess_list_lock. */ struct list_head init_deferred_cmd_list; struct list_head init_deferred_mcmd_list; + /* Used if scst_unregister_session() called in wait mode */ + struct completion *shutdown_compl; + /* * Functions and data for user callbacks from scst_register_session() * and scst_unregister_session() @@ -991,11 +980,24 @@ SCST_CMD_QUEUE_ACA }; +struct scst_cmd_lists +{ + spinlock_t cmd_list_lock; + struct list_head active_cmd_list; + wait_queue_head_t cmd_list_waitQ; + struct list_head lists_list_entry; +}; + struct scst_cmd { - /* List entry for global *_cmd_list */ + /* List entry for below *_cmd_lists */ struct list_head cmd_list_entry; + /* Pointer to lists of commands with the lock */ + struct scst_cmd_lists *cmd_lists; + + atomic_t cmd_ref; + struct scst_session *sess; /* corresponding session */ /* Cmd state, one of SCST_CMD_STATE_* constants */ @@ -1019,9 +1021,6 @@ /* Set if cmd is being processed in atomic context */ unsigned int atomic:1; - /* Set if cmd must be processed only in non-atomic context */ - unsigned int non_atomic_only:1; - /* Set if cmd is internally generated */ unsigned int internal:1; @@ -1048,14 +1047,6 @@ unsigned int expected_values_set:1; /* - * Set if the cmd is being processed from the thread/tasklet, - * i.e. if another cmd is moved to the active list during processing - * of the current one, then another cmd will be processed after - * the current. Helps to save some context switches. - */ - unsigned int processible_env:1; - - /* * Set if the cmd was delayed by task management debugging code. * Used only if DEBUG_TM is on. */ @@ -1100,9 +1091,12 @@ */ unsigned int may_need_dma_sync:1; + /* Set if the cmd was done or aborted out of its SN */ + unsigned long out_of_sn:1; + /**************************************************************/ - unsigned long cmd_flags; /* cmd's async flags */ + unsigned long cmd_flags; /* cmd's async flags */ struct scst_tgt_template *tgtt; /* to save extra dereferences */ struct scst_tgt *tgt; /* to save extra dereferences */ @@ -1190,7 +1184,7 @@ uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* sense buffer */ - /* The corresponding mgmt cmd, if any. Protected by scst_list_lock */ + /* The corresponding mgmt cmd, if any, protected by sess_list_lock */ struct scst_mgmt_cmd *mgmt_cmnd; /* List entry for dev's blocked_cmd_list */ @@ -1227,11 +1221,15 @@ int fn; unsigned int completed:1; /* set, if the mcmd is completed */ + unsigned int active:1; /* set, if the mcmd is active */ - /* Number of commands to complete before sending response */ + /* + * Number of commands to complete before sending response, + * protected by scst_mcmd_lock + */ int cmd_wait_count; - /* Number of completed commands */ + /* Number of completed commands, protected by scst_mcmd_lock */ int completed_cmd_count; lun_t lun; /* LUN for this mgmt cmd */ @@ -1334,11 +1332,8 @@ struct scst_acg_dev *acg_dev; /* corresponding acg_dev */ - /* - * How many cmds alive on this dev in this session. - * Protected by scst_list_lock. - */ - int cmd_count; + /* How many cmds alive on this dev in this session */ + atomic_t cmd_count; spinlock_t tgt_dev_lock; /* per-session device lock */ @@ -1350,16 +1345,19 @@ /* Used for storage of dev handler private stuff */ void *dh_priv; + /* Pointer to lists of commands with the lock */ + struct scst_cmd_lists *p_cmd_lists; + /* * Used to execute cmd's in order of arrival. * - * Protected by sn_lock, except next_sn and expected_sn. + * Protected by sn_lock, except curr_sn and expected_sn. * Expected_sn protected by itself, since only one thread, which * processes SN matching command, can increment it at any time. - * Next_sn must be the same type as expected_sn to overflow + * Next_sn must have the same size as expected_sn to overflow * simultaneously. */ - int next_sn; /* protected by scst_list_lock */ + atomic_t curr_sn; int expected_sn; spinlock_t sn_lock; int def_cmd_count; Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-21 11:43:22 UTC (rev 90) @@ -2325,7 +2325,7 @@ return; } -/* Called with BH off. Might be called under lock and IRQ off */ +/* No locks supposed to be held, thread context */ static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd, struct scst_tgt_dev *tgt_dev) { @@ -2338,12 +2338,7 @@ struct scst_fileio_tgt_dev *ftgt_dev = (struct scst_fileio_tgt_dev *)cmd_to_abort->tgt_dev->dh_priv; - /* - * It is safe relating to scst_list_lock despite of lockdep's - * warning. Just don't know how to tell it to lockdep. - */ - /* BH already off */ - spin_lock(&ftgt_dev->fdev_lock); + spin_lock_bh(&ftgt_dev->fdev_lock); if (cmd_to_abort->fileio_in_list) { TRACE(TRACE_MGMT, "Aborting cmd %p and moving it to " "the queue head", cmd_to_abort); @@ -2352,7 +2347,7 @@ &ftgt_dev->fdev_cmd_list); wake_up(&ftgt_dev->fdev_waitQ); } - spin_unlock(&ftgt_dev->fdev_lock); + spin_unlock_bh(&ftgt_dev->fdev_lock); } TRACE_EXIT_RES(res); Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/src/scst.c 2007-02-21 11:43:22 UTC (rev 90) @@ -32,23 +32,18 @@ #include "scst_priv.h" #include "scst_mem.h" -#if defined(DEBUG) || defined(TRACING) -unsigned long scst_trace_flag = SCST_DEFAULT_LOG_FLAGS; -#endif - /* * All targets, devices and dev_types management is done under * this mutex. */ DECLARE_MUTEX(scst_mutex); -DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ); -LIST_HEAD(scst_dev_wait_sess_list); - LIST_HEAD(scst_template_list); LIST_HEAD(scst_dev_list); LIST_HEAD(scst_dev_type_list); +spinlock_t scst_main_lock = SPIN_LOCK_UNLOCKED; + struct kmem_cache *scst_mgmt_cachep; mempool_t *scst_mgmt_mempool; struct kmem_cache *scst_ua_cachep; @@ -60,32 +55,37 @@ LIST_HEAD(scst_acg_list); struct scst_acg *scst_default_acg; +spinlock_t scst_init_lock = SPIN_LOCK_UNLOCKED; +DECLARE_WAIT_QUEUE_HEAD(scst_init_cmd_list_waitQ); +LIST_HEAD(scst_init_cmd_list); +unsigned int scst_init_poll_cnt; + struct kmem_cache *scst_cmd_cachep; +#if defined(DEBUG) || defined(TRACING) +unsigned long scst_trace_flag = SCST_DEFAULT_LOG_FLAGS; +#endif + unsigned long scst_flags; atomic_t scst_cmd_count = ATOMIC_INIT(0); -spinlock_t scst_list_lock = SPIN_LOCK_UNLOCKED; -LIST_HEAD(scst_active_cmd_list); -LIST_HEAD(scst_init_cmd_list); -LIST_HEAD(scst_cmd_list); -DECLARE_WAIT_QUEUE_HEAD(scst_list_waitQ); spinlock_t scst_cmd_mem_lock = SPIN_LOCK_UNLOCKED; unsigned long scst_cur_cmd_mem, scst_cur_max_cmd_mem; +unsigned long scst_max_cmd_mem; -struct tasklet_struct scst_tasklets[NR_CPUS]; - struct scst_sgv_pools scst_sgv; +struct scst_cmd_lists scst_main_cmd_lists; + +struct scst_tasklet scst_tasklets[NR_CPUS]; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) DECLARE_WORK(scst_cmd_mem_work, scst_cmd_mem_work_fn, 0); #else DECLARE_DELAYED_WORK(scst_cmd_mem_work, scst_cmd_mem_work_fn); #endif -unsigned long scst_max_cmd_mem; - -LIST_HEAD(scst_mgmt_cmd_list); +spinlock_t scst_mcmd_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(scst_active_mgmt_cmd_list); LIST_HEAD(scst_delayed_mgmt_cmd_list); DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_cmd_list_waitQ); @@ -94,6 +94,11 @@ spinlock_t scst_mgmt_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(scst_sess_mgmt_list); +DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ); + +DECLARE_MUTEX(scst_suspend_mutex);; +LIST_HEAD(scst_cmd_lists_list); /* protected by scst_suspend_mutex */ + static int scst_threads; struct scst_threads_info_t scst_threads_info; @@ -152,6 +157,9 @@ goto out_err; } + if (vtt->preprocessing_done == NULL) + vtt->preprocessing_done_atomic = 1; + if (down_interruptible(&m) != 0) goto out_err; @@ -265,6 +273,7 @@ tgt->retry_timer.data = (unsigned long)tgt; tgt->retry_timer.function = scst_tgt_retry_timer_fn; + scst_suspend_activity(); down(&scst_mutex); if (scst_build_proc_target_entries(tgt) < 0) { @@ -275,6 +284,7 @@ list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list); up(&scst_mutex); + scst_resume_activity(); PRINT_INFO_PR("Target for template %s registered successfully", vtt->name); @@ -285,6 +295,7 @@ out_up: up(&scst_mutex); + scst_resume_activity(); out_err: PRINT_ERROR_PR("Failed to register target for template %s", vtt->name); @@ -321,12 +332,16 @@ wait_event(tgt->unreg_waitQ, test_sess_list(tgt)); TRACE_DBG("%s", "wait_event() returned"); + scst_suspend_activity(); down(&scst_mutex); + list_del(&tgt->tgt_list_entry); - up(&scst_mutex); scst_cleanup_proc_target_entries(tgt); + up(&scst_mutex); + scst_resume_activity(); + del_timer_sync(&tgt->retry_timer); kfree(tgt); @@ -338,72 +353,81 @@ return; } -/* scst_mutex supposed to be held */ -void __scst_suspend_activity(void) +void scst_suspend_activity(void) { TRACE_ENTRY(); + down(&scst_suspend_mutex); + + TRACE_MGMT_DBG("suspend_count %d", suspend_count); suspend_count++; if (suspend_count > 1) - goto out; + goto out_up; + set_bit(SCST_FLAG_SUSPENDING, &scst_flags); set_bit(SCST_FLAG_SUSPENDED, &scst_flags); smp_mb__after_set_bit(); - TRACE_DBG("Waiting for all %d active commands to complete", + TRACE_MGMT_DBG("Waiting for %d active commands to complete", atomic_read(&scst_cmd_count)); wait_event(scst_dev_cmd_waitQ, atomic_read(&scst_cmd_count) == 0); - TRACE_DBG("%s", "wait_event() returned"); + TRACE_MGMT_DBG("%s", "wait_event() returned"); -out: + clear_bit(SCST_FLAG_SUSPENDING, &scst_flags); + smp_mb__after_clear_bit(); + + TRACE_MGMT_DBG("Waiting for %d active commands finally to complete", + atomic_read(&scst_cmd_count)); + wait_event(scst_dev_cmd_waitQ, atomic_read(&scst_cmd_count) == 0); + TRACE_MGMT_DBG("%s", "wait_event() returned"); + +out_up: + up(&scst_suspend_mutex); + TRACE_EXIT(); return; } -void scst_suspend_activity(void) +void scst_resume_activity(void) { - down(&scst_mutex); - __scst_suspend_activity(); -} + struct scst_cmd_lists *l; -/* scst_mutex supposed to be held */ -void __scst_resume_activity(void) -{ - struct scst_session *sess, *tsess; - TRACE_ENTRY(); + down(&scst_suspend_mutex); + + TRACE_MGMT_DBG("suspend_count %d", suspend_count); suspend_count--; if (suspend_count > 0) - goto out; + goto out_up; clear_bit(SCST_FLAG_SUSPENDED, &scst_flags); smp_mb__after_clear_bit(); - spin_lock_irq(&scst_list_lock); - list_for_each_entry_safe(sess, tsess, &scst_dev_wait_sess_list, - dev_wait_sess_list_entry) - { - sess->waiting = 0; - list_del(&sess->dev_wait_sess_list_entry); + list_for_each_entry(l, &scst_cmd_lists_list, lists_list_entry) { + wake_up_all(&l->cmd_list_waitQ); } - spin_unlock_irq(&scst_list_lock); + wake_up_all(&scst_init_cmd_list_waitQ); - wake_up_all(&scst_list_waitQ); + spin_lock_irq(&scst_mcmd_lock); + if (!list_empty(&scst_delayed_mgmt_cmd_list)) { + struct scst_mgmt_cmd *m; + m = list_entry(scst_delayed_mgmt_cmd_list.next, typeof(*m), + mgmt_cmd_list_entry); + TRACE_MGMT_DBG("Moving delayed mgmt cmd %p to head of active " + "mgmt cmd list", m); + list_move(&m->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list); + } + spin_unlock_irq(&scst_mcmd_lock); wake_up_all(&scst_mgmt_cmd_list_waitQ); -out: +out_up: + up(&scst_suspend_mutex); + TRACE_EXIT(); return; } -void scst_resume_activity(void) -{ - __scst_resume_activity(); - up(&scst_mutex); -} - -/* Called under scst_mutex */ static int scst_register_device(struct scsi_device *scsidp) { int res = 0; @@ -412,12 +436,15 @@ TRACE_ENTRY(); + scst_suspend_activity(); + down(&scst_mutex); + dev = scst_alloc_device(GFP_KERNEL); if (dev == NULL) { res = -ENOMEM; - goto out; + goto out_up; } - + dev->rq_disk = alloc_disk(1); if (dev->rq_disk == NULL) { res = -ENOMEM; @@ -438,7 +465,10 @@ } } -out: +out_up: + up(&scst_mutex); + scst_resume_activity(); + if (res == 0) { PRINT_INFO_PR("Attached SCSI target mid-level at " "scsi%d, channel %d, id %d, lun %d, type %d", @@ -461,10 +491,9 @@ out_free_dev: scst_free_device(dev); - goto out; + goto out_up; } -/* Called under scst_mutex */ static void scst_unregister_device(struct scsi_device *scsidp) { struct scst_device *d, *dev = NULL; @@ -472,7 +501,8 @@ TRACE_ENTRY(); - __scst_suspend_activity(); + scst_suspend_activity(); + down(&scst_mutex); list_for_each_entry(d, &scst_dev_list, dev_list_entry) { if (d->scsi_dev == scsidp) { @@ -504,16 +534,39 @@ scsidp->channel, scsidp->id, scsidp->lun, scsidp->type); out_unblock: - __scst_resume_activity(); + up(&scst_mutex); + scst_resume_activity(); TRACE_EXIT(); return; } +static int scst_dev_handler_check(struct scst_dev_type *dev_handler) +{ + int res = 0; + + if (dev_handler->parse == NULL) { + PRINT_ERROR_PR("scst dev_type driver %s doesn't have a " + "parse() method.", dev_handler->name); + res = -EINVAL; + goto out; + } + + if (dev_handler->exec == NULL) + dev_handler->exec_atomic = 1; + + if (dev_handler->dev_done == NULL) + dev_handler->dev_done_atomic = 1; + +out: + TRACE_EXIT_RES(res); + return res; +} + int scst_register_virtual_device(struct scst_dev_type *dev_handler, const char *dev_name) { - int res = -EINVAL, rc; + int res, rc; struct scst_device *dev = NULL; TRACE_ENTRY(); @@ -531,6 +584,10 @@ goto out; } + res = scst_dev_handler_check(dev_handler); + if (res != 0) + goto out; + dev = scst_alloc_device(GFP_KERNEL); if (dev == NULL) { res = -ENOMEM; @@ -540,6 +597,8 @@ dev->scsi_dev = NULL; dev->virt_name = dev_name; + scst_suspend_activity(); + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out_free_dev; @@ -559,6 +618,9 @@ up(&scst_mutex); +out_resume: + scst_resume_activity(); + out: if (res > 0) { PRINT_INFO_PR("Attached SCSI target mid-level to virtual " @@ -578,7 +640,7 @@ out_free_dev: scst_free_device(dev); - goto out; + goto out_resume; } void scst_unregister_virtual_device(int id) @@ -588,10 +650,9 @@ TRACE_ENTRY(); + scst_suspend_activity(); down(&scst_mutex); - __scst_suspend_activity(); - list_for_each_entry(d, &scst_dev_list, dev_list_entry) { if (d->virt_id == id) { dev = d; @@ -620,9 +681,8 @@ scst_free_device(dev); out_unblock: - __scst_resume_activity(); - up(&scst_mutex); + scst_resume_activity(); TRACE_EXIT(); return; @@ -632,17 +692,14 @@ { struct scst_dev_type *dt; struct scst_device *dev; - int res = 0; + int res; int exist; TRACE_ENTRY(); - if (dev_type->parse == NULL) { - PRINT_ERROR_PR("scst dev_type driver %s doesn't have a " - "parse() method.", dev_type->name); - res = -EINVAL; + res = scst_dev_handler_check(dev_type); + if (res != 0) goto out_err; - } #ifdef FILEIO_ONLY if (dev_type->exec == NULL) { @@ -654,6 +711,8 @@ } #endif + scst_suspend_activity(); + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out_err; @@ -678,16 +737,15 @@ list_add_tail(&dev_type->dev_type_list_entry, &scst_dev_type_list); - __scst_suspend_activity(); list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { if ((dev->scsi_dev == NULL) || (dev->handler != NULL)) continue; if (dev->scsi_dev->type == dev_type->type) scst_assign_dev_handler(dev, dev_type); } - __scst_resume_activity(); up(&scst_mutex); + scst_resume_activity(); if (res == 0) { PRINT_INFO_PR("Device handler %s for type %d registered " @@ -702,6 +760,7 @@ up(&scst_mutex); out_err: + scst_resume_activity(); PRINT_ERROR_PR("Failed to register device handler %s for type %d", dev_type->name, dev_type->type); goto out; @@ -715,6 +774,7 @@ TRACE_ENTRY(); + scst_suspend_activity(); down(&scst_mutex); list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) { @@ -729,18 +789,17 @@ goto out_up; } - __scst_suspend_activity(); list_for_each_entry(dev, &scst_dev_list, dev_list_entry) { if (dev->handler == dev_type) { scst_assign_dev_handler(dev, NULL); TRACE_DBG("Dev handler removed from device %p", dev); } } - __scst_resume_activity(); list_del(&dev_type->dev_type_list_entry); up(&scst_mutex); + scst_resume_activity(); scst_cleanup_proc_dev_handler_dir_entries(dev_type); @@ -753,21 +812,19 @@ out_up: up(&scst_mutex); + scst_resume_activity(); goto out; } int scst_register_virtual_dev_driver(struct scst_dev_type *dev_type) { - int res = 0; + int res; TRACE_ENTRY(); - if (dev_type->parse == NULL) { - PRINT_ERROR_PR("scst dev_type driver %s doesn't have a " - "parse() method.", dev_type->name); - res = -EINVAL; + res = scst_dev_handler_check(dev_type); + if (res != 0) goto out_err; - } res = scst_build_proc_dev_handler_dir_entries(dev_type); if (res < 0) @@ -799,7 +856,7 @@ return; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_assign_dev_handler(struct scst_device *dev, struct scst_dev_type *handler) { @@ -812,8 +869,6 @@ if (dev->handler == handler) goto out; - __scst_suspend_activity(); - if (dev->handler && dev->handler->detach_tgt) { list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) @@ -841,7 +896,7 @@ PRINT_ERROR_PR("New device handler's %s attach() " "failed: %d", handler->name, res); } - goto out_resume; + goto out_null; } if (handler && handler->attach_tgt) { @@ -862,10 +917,9 @@ } } -out_resume: +out_null: if (res != 0) dev->handler = NULL; - __scst_resume_activity(); out: TRACE_EXIT_RES(res); @@ -885,9 +939,9 @@ if (handler && handler->detach) { TRACE_DBG("%s", "Calling handler's detach()"); handler->detach(dev); - TRACE_DBG("%s", "Hhandler's detach() returned"); + TRACE_DBG("%s", "Handler's detach() returned"); } - goto out_resume; + goto out_null; } int scst_cmd_threads_count(void) @@ -959,7 +1013,8 @@ PRINT_ERROR_PR("fail to allocate thr %d", res); goto out_error; } - thr->cmd_thread = kthread_run(scst_cmd_thread, 0, "scsi_tgt%d", + thr->cmd_thread = kthread_run(scst_cmd_thread, + &scst_main_cmd_lists, "scsi_tgt%d", scst_thread_num++); if (IS_ERR(thr->cmd_thread)) { res = PTR_ERR(thr->cmd_thread); @@ -1019,6 +1074,8 @@ kthread_stop(scst_threads_info.mgmt_cmd_thread); if (scst_threads_info.mgmt_thread) kthread_stop(scst_threads_info.mgmt_thread); + if (scst_threads_info.init_cmd_thread) + kthread_stop(scst_threads_info.init_cmd_thread); up(&scst_threads_info.cmd_threads_mutex); TRACE_EXIT(); @@ -1036,6 +1093,15 @@ if (res < 0) goto out; + scst_threads_info.init_cmd_thread = kthread_run(scst_init_cmd_thread, + NULL, "scsi_tgt_init"); + if (IS_ERR(scst_threads_info.init_cmd_thread)) { + res = PTR_ERR(scst_threads_info.init_cmd_thread); + PRINT_ERROR_PR("kthread_create() for init cmd failed: %d", res); + scst_threads_info.init_cmd_thread = NULL; + goto out; + } + scst_threads_info.mgmt_cmd_thread = kthread_run(scst_mgmt_cmd_thread, NULL, "scsi_tgt_mc"); if (IS_ERR(scst_threads_info.mgmt_cmd_thread)) { @@ -1062,12 +1128,12 @@ void scst_get(void) { - scst_inc_cmd_count(); + __scst_get(0); } void scst_put(void) { - scst_dec_cmd_count(); + __scst_put(); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) @@ -1082,10 +1148,7 @@ TRACE_ENTRY(); scsidp = to_scsi_device(cdev->dev); - - down(&scst_mutex); res = scst_register_device(scsidp); - up(&scst_mutex); TRACE_EXIT(); return res; @@ -1102,10 +1165,7 @@ TRACE_ENTRY(); scsidp = to_scsi_device(cdev->dev); - - down(&scst_mutex); scst_unregister_device(scsidp); - up(&scst_mutex); TRACE_EXIT(); return; @@ -1137,7 +1197,17 @@ (sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE)); } #endif + { + struct scst_tgt_dev *t; + BUILD_BUG_ON(sizeof(t->curr_sn) != sizeof(t->expected_sn)); + } + spin_lock_init(&scst_main_cmd_lists.cmd_list_lock); + INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list); + init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ); + list_add_tail(&scst_main_cmd_lists.lists_list_entry, + &scst_cmd_lists_list); + scst_num_cpus = num_online_cpus(); /* ToDo: register_cpu_notifier() */ @@ -1204,8 +1274,12 @@ scst_scsi_op_list_init(); - for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++) - tasklet_init(&scst_tasklets[i], (void *)scst_cmd_tasklet, 0); + for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++) { + spin_lock_init(&scst_tasklets[i].tasklet_lock); + INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list); + tasklet_init(&scst_tasklets[i].tasklet, (void*)scst_cmd_tasklet, + (unsigned long)&scst_tasklets[i]); + } TRACE_DBG("%d CPUs found, starting %d threads", scst_num_cpus, scst_threads); Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/src/scst_lib.c 2007-02-21 11:43:22 UTC (rev 90) @@ -84,21 +84,22 @@ void scst_set_busy(struct scst_cmd *cmd) { + int c = cmd->sess->sess_cmd_count; + TRACE_ENTRY(); - if ((cmd->sess->sess_cmd_count <= 1) || - (cmd->sess->init_phase != SCST_SESS_IPH_READY)) + if ((c <= 1) || (cmd->sess->init_phase != SCST_SESS_IPH_READY)) { scst_set_cmd_error_status(cmd, SAM_STAT_BUSY); TRACE_MGMT_DBG("Sending BUSY status to initiator %s " "(cmds count %d, queue_type %x, sess->init_phase %d)", - cmd->sess->initiator_name, cmd->sess->sess_cmd_count, + cmd->sess->initiator_name, c, cmd->queue_type, cmd->sess->init_phase); } else { scst_set_cmd_error_status(cmd, SAM_STAT_TASK_SET_FULL); TRACE_MGMT_DBG("Sending QUEUE_FULL status to initiator %s " "(cmds count %d, queue_type %x, sess->init_phase %d)", - cmd->sess->initiator_name, cmd->sess->sess_cmd_count, + cmd->sess->initiator_name, c, cmd->queue_type, cmd->sess->init_phase); } @@ -218,7 +219,7 @@ return res; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ void scst_free_acg_dev(struct scst_acg_dev *acg_dev) { TRACE_ENTRY(); @@ -234,7 +235,7 @@ return; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ struct scst_acg *scst_alloc_add_acg(const char *acg_name) { struct scst_acg *acg; @@ -260,7 +261,7 @@ return acg; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_destroy_acg(struct scst_acg *acg) { struct scst_acn *n, *nn; @@ -275,8 +276,6 @@ goto out; } - __scst_suspend_activity(); - TRACE_DBG("Removing acg %s from scst_acg_list", acg->acg_name); list_del(&acg->scst_acg_list_entry); @@ -295,8 +294,6 @@ scst_free_acg_dev(acg_dev); } - __scst_resume_activity(); - /* Freeing names */ list_for_each_entry_safe(n, nn, &acg->acn_list, acn_list_entry) @@ -342,8 +339,12 @@ tgt_dev->acg_dev = acg_dev; tgt_dev->sess = sess; - tgt_dev->cmd_count = 0; + atomic_set(&tgt_dev->cmd_count, 0); + atomic_set(&tgt_dev->curr_sn, 0); + tgt_dev->expected_sn = 1; + tgt_dev->p_cmd_lists = &scst_main_cmd_lists; + if (dev->scsi_dev != NULL) { TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, " "SCST lun=%Ld", dev->scsi_dev->host->host_no, @@ -361,6 +362,30 @@ INIT_LIST_HEAD(&tgt_dev->deferred_cmd_list); INIT_LIST_HEAD(&tgt_dev->skipped_sn_list); + if (dev->handler->parse_atomic && + sess->tgt->tgtt->preprocessing_done_atomic) { + if (sess->tgt->tgtt->rdy_to_xfer_atomic) + __set_bit(SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC, + &tgt_dev->tgt_dev_flags); + if (dev->handler->exec_atomic) + __set_bit(SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC, + &tgt_dev->tgt_dev_flags); + } + if (dev->handler->exec_atomic) { + if (sess->tgt->tgtt->rdy_to_xfer_atomic) + __set_bit(SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC, + &tgt_dev->tgt_dev_flags); + __set_bit(SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC, + &tgt_dev->tgt_dev_flags); + __set_bit(SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC, + &tgt_dev->tgt_dev_flags); + } + if (dev->handler->dev_done_atomic && + sess->tgt->tgtt->xmit_response_atomic) { + __set_bit(SCST_TGT_DEV_AFTER_EXEC_ATOMIC, + &tgt_dev->tgt_dev_flags); + } + spin_lock_bh(&scst_temp_UA_lock); scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA), SCST_LOAD_SENSE(scst_sense_reset_UA)); @@ -467,7 +492,7 @@ return; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_sess_alloc_tgt_devs(struct scst_session *sess) { int res = 0; @@ -476,8 +501,6 @@ TRACE_ENTRY(); - __scst_suspend_activity(); - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); list_for_each_entry(acg_dev, &sess->acg->acg_dev_list, acg_dev_list_entry) @@ -489,15 +512,13 @@ } } -out_resume: - __scst_resume_activity(); - +out: TRACE_EXIT(); return res; out_free: scst_sess_free_tgt_devs(sess); - goto out_resume; + goto out; } /* scst_mutex supposed to be held and activity suspended */ @@ -519,7 +540,7 @@ return; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun, int read_only) { @@ -551,8 +572,6 @@ } acg_dev->rd_only_flag = read_only; - __scst_suspend_activity(); - TRACE_DBG("Adding acg_dev %p to acg_dev_list and dev_acg_dev_list", acg_dev); list_add_tail(&acg_dev->acg_dev_list_entry, &acg->acg_dev_list); @@ -569,9 +588,6 @@ &tmp_tgt_dev_list); } -out_resume: - __scst_resume_activity(); - out: TRACE_EXIT_RES(res); return res; @@ -583,10 +599,10 @@ scst_free_tgt_dev(tgt_dev); } scst_free_acg_dev(acg_dev); - goto out_resume; + goto out; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev) { int res = 0; @@ -608,8 +624,6 @@ goto out; } - __scst_suspend_activity(); - list_for_each_entry_safe(tgt_dev, tt, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { @@ -618,8 +632,6 @@ } scst_free_acg_dev(acg_dev); - __scst_resume_activity(); - out: TRACE_EXIT_RES(res); return res; @@ -715,6 +727,7 @@ goto out; } + res->cmd_lists = orig_cmd->cmd_lists; res->sess = orig_cmd->sess; res->state = SCST_CMD_STATE_SEND_TO_MIDLEV; res->atomic = scst_cmd_atomic(orig_cmd); @@ -750,9 +763,7 @@ { TRACE_ENTRY(); - if (cmd->bufflen > 0) - scst_release_space(cmd); - scst_destroy_cmd(cmd); + scst_cmd_put(cmd); TRACE_EXIT(); return; @@ -760,7 +771,7 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd) { - int res = SCST_CMD_STATE_RES_RESTART; + int res = SCST_CMD_STATE_RES_CONT_NEXT; #define sbuf_size 252 static const unsigned char request_sense[6] = { REQUEST_SENSE, 0, 0, 0, sbuf_size, 0 }; @@ -776,9 +787,11 @@ rs_cmd->cdb_len = sizeof(request_sense); rs_cmd->data_direction = SCST_DATA_READ; - spin_lock_irq(&scst_list_lock); - list_add(&rs_cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irq(&scst_list_lock); + TRACE(TRACE_RETRY, "Adding REQUEST SENSE cmd %p to head of active " + "cmd list ", rs_cmd); + spin_lock_irq(&rs_cmd->cmd_lists->cmd_list_lock); + list_add(&rs_cmd->cmd_list_entry, &rs_cmd->cmd_lists->active_cmd_list); + spin_unlock_irq(&rs_cmd->cmd_lists->cmd_list_lock); out: TRACE_EXIT_RES(res); @@ -949,11 +962,12 @@ sess->init_phase = SCST_SESS_IPH_INITING; atomic_set(&sess->refcnt, 0); INIT_LIST_HEAD(&sess->sess_tgt_dev_list); + spin_lock_init(&sess->sess_list_lock); INIT_LIST_HEAD(&sess->search_cmd_list); sess->tgt = tgt; INIT_LIST_HEAD(&sess->init_deferred_cmd_list); INIT_LIST_HEAD(&sess->init_deferred_mcmd_list); - + len = strlen(initiator_name); nm = kmalloc(len + 1, gfp_mask); if (nm == NULL) { @@ -978,19 +992,20 @@ { TRACE_ENTRY(); + scst_suspend_activity(); down(&scst_mutex); + TRACE_DBG("Removing sess %p from the list", sess); list_del(&sess->sess_list_entry); TRACE_DBG("Removing session %p from acg %s", sess, sess->acg->acg_name); list_del(&sess->acg_sess_list_entry); - - __scst_suspend_activity(); + scst_sess_free_tgt_devs(sess); - __scst_resume_activity(); wake_up_all(&sess->tgt->unreg_waitQ); up(&scst_mutex); + scst_resume_activity(); kfree(sess->initiator_name); kmem_cache_free(scst_sess_cachep, sess); @@ -1059,6 +1074,8 @@ memset(cmd, 0, sizeof(*cmd)); #endif + atomic_set(&cmd->cmd_ref, 1); + cmd->cmd_lists = &scst_main_cmd_lists; cmd->queue_type = SCST_CMD_QUEUE_UNTAGGED; cmd->timeout = SCST_DEFAULT_TIMEOUT; cmd->retries = 1; @@ -1071,19 +1088,19 @@ return cmd; } -static void scst_destroy_put_cmd(struct scst_cmd *cmd) +void scst_destroy_put_cmd(struct scst_cmd *cmd) { scst_sess_put(cmd->sess); /* At this point tgt_dev can be dead, but the pointer remains not-NULL */ if (likely(cmd->tgt_dev != NULL)) - scst_dec_cmd_count(); + __scst_put(); scst_destroy_cmd(cmd); return; } -/* No locks supposed to be held. Must be called only from scst_finish_cmd()! */ +/* No locks supposed to be held */ void scst_free_cmd(struct scst_cmd *cmd) { int destroy = 1; @@ -1100,6 +1117,24 @@ } #endif + if (likely(cmd->tgt_dev != NULL)) + atomic_dec(&cmd->tgt_dev->cmd_count); + + /* + * cmd->mgmt_cmnd can't being changed here, since for that it either + * must be on search_cmd_list, or cmd_ref must be taken. Both are + * false here. + */ + if (unlikely(cmd->mgmt_cmnd)) + scst_complete_cmd_mgmt(cmd, cmd->mgmt_cmnd); + + if (unlikely(cmd->internal)) { + if (cmd->bufflen > 0) + scst_release_space(cmd); + scst_destroy_cmd(cmd); + goto out; + } + if (cmd->tgtt->on_free_cmd != NULL) { TRACE_DBG("Calling target's on_free_cmd(%p)", cmd); cmd->tgtt->on_free_cmd(cmd); @@ -1126,34 +1161,29 @@ "target %s, lun %Ld, sn %d, expected_sn %d)", cmd->cdb[0], cmd->tgtt->name, (uint64_t)cmd->lun, cmd->sn, cmd->tgt_dev->expected_sn); - scst_inc_expected_sn_unblock(cmd->tgt_dev, cmd, 0); + scst_inc_expected_sn_unblock(cmd->tgt_dev, cmd); } #endif - if (unlikely(test_bit(SCST_CMD_OUT_OF_SN, - &cmd->cmd_flags))) - { - spin_lock_bh(&cmd->tgt_dev->sn_lock); - set_bit(SCST_CMD_CAN_BE_DESTROYED, - &cmd->cmd_flags); - barrier(); /* to reread SCST_CMD_OUT_OF_SN */ - destroy = !test_bit(SCST_CMD_OUT_OF_SN, - &cmd->cmd_flags); + + if (unlikely(cmd->out_of_sn)) { TRACE(TRACE_SCSI_SERIALIZING, "Out of SN " "cmd %p (tag %d, sn %d), destroy=%d", cmd, cmd->tag, cmd->sn, destroy); - spin_unlock_bh(&cmd->tgt_dev->sn_lock); + destroy = test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED, + &cmd->cmd_flags); } } if (likely(destroy)) scst_destroy_put_cmd(cmd); +out: TRACE_EXIT(); return; } /* No locks supposed to be held. */ -void scst_check_retries(struct scst_tgt *tgt, int processible_env) +void scst_check_retries(struct scst_tgt *tgt) { int need_wake_up = 0; @@ -1174,29 +1204,25 @@ tgt->retry_cmds); spin_lock_irqsave(&tgt->tgt_lock, flags); - spin_lock(&scst_list_lock); - list_for_each_entry_safe(c, tc, &tgt->retry_cmd_list, cmd_list_entry) { tgt->retry_cmds--; - TRACE(TRACE_RETRY, "Moving retry cmd %p to active cmd " - "list (retry_cmds left %d)", c, tgt->retry_cmds); - list_move(&c->cmd_list_entry, &scst_active_cmd_list); + TRACE(TRACE_RETRY, "Moving retry cmd %p to head of active " + "cmd list (retry_cmds left %d)", c, tgt->retry_cmds); + spin_lock(&c->cmd_lists->cmd_list_lock); + list_move(&c->cmd_list_entry, &c->cmd_lists->active_cmd_list); + wake_up(&c->cmd_lists->cmd_list_waitQ); + spin_unlock(&c->cmd_lists->cmd_list_lock); need_wake_up++; if (need_wake_up >= 2) /* "slow start" */ break; } - - spin_unlock(&scst_list_lock); spin_unlock_irqrestore(&tgt->tgt_lock, flags); } - if (need_wake_up && !processible_env) - wake_up(&scst_list_waitQ); - TRACE_EXIT(); return; } @@ -1213,7 +1239,7 @@ tgt->retry_timer_active = 0; spin_unlock_irqrestore(&tgt->tgt_lock, flags); - scst_check_retries(tgt, 0); + scst_check_retries(tgt); TRACE_EXIT(); return; @@ -1238,22 +1264,20 @@ return mcmd; } -void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del) +void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd) { unsigned long flags; TRACE_ENTRY(); - spin_lock_irqsave(&scst_list_lock, flags); - if (del) - list_del(&mcmd->mgmt_cmd_list_entry); + spin_lock_irqsave(&mcmd->sess->sess_list_lock, flags); mcmd->sess->sess_cmd_count--; - spin_unlock_irqrestore(&scst_list_lock, flags); + spin_unlock_irqrestore(&mcmd->sess->sess_list_lock, flags); scst_sess_put(mcmd->sess); if (mcmd->mcmd_tgt_dev != NULL) - scst_dec_cmd_count(); + __scst_put(); mempool_free(mcmd, scst_mgmt_mempool); @@ -1722,7 +1746,6 @@ { struct scst_tgt_dev *tgt_dev; struct scst_cmd *cmd, *tcmd; - int wake = 0; TRACE_ENTRY(); @@ -1759,8 +1782,7 @@ { struct scst_session *sess = tgt_dev->sess; - local_bh_disable(); - spin_lock_irq(&scst_list_lock); + spin_lock_irq(&sess->sess_list_lock); TRACE_DBG("Searching in search cmd list (sess=%p)", sess); list_for_each_entry(cmd, &sess->search_cmd_list, @@ -1774,27 +1796,23 @@ (tgt_dev->sess != originator), 0); } } - spin_unlock_irq(&scst_list_lock); - local_bh_enable(); + spin_unlock_irq(&sess->sess_list_lock); } list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) { list_del(&cmd->blocked_cmd_list_entry); - TRACE_MGMT_DBG("Moving aborted blocked cmd %p " + TRACE_MGMT_DBG("Adding aborted blocked cmd %p " "to active cmd list", cmd); - spin_lock_irq(&scst_list_lock); - list_move_tail(&cmd->cmd_list_entry, - &scst_active_cmd_list); - spin_unlock_irq(&scst_list_lock); - wake = 1; + spin_lock_irq(&cmd->cmd_lists->cmd_list_lock); + list_add_tail(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); + wake_up(&cmd->cmd_lists->cmd_list_waitQ); + spin_unlock_irq(&cmd->cmd_lists->cmd_list_lock); } } - if (wake) - wake_up(&scst_list_waitQ); - TRACE_EXIT(); return; } @@ -1992,12 +2010,9 @@ tcmd->tag, tcmd->sn); tgt_dev->def_cmd_count--; list_del(&tcmd->sn_cmd_list_entry); - if (test_bit(SCST_CMD_CAN_BE_DESTROYED, + if (test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED, &tcmd->cmd_flags)) { scst_destroy_put_cmd(tcmd); - } else { - smp_mb__before_clear_bit(); - clear_bit(SCST_CMD_OUT_OF_SN, &tcmd->cmd_flags); } expected_sn = __scst_inc_expected_sn(tgt_dev); goto restart; @@ -2091,10 +2106,10 @@ { #ifdef STRICT_SERIALIZING struct scst_cmd *cmd, *t; - int found = 0; TRACE_ENTRY(); + local_irq_save(flags); list_for_each_entry_safe(cmd, t, &dev->blocked_cmd_list, blocked_cmd_list_entry) { unsigned long flags; @@ -2117,62 +2132,64 @@ } list_del(&cmd->blocked_cmd_list_entry); - TRACE_MGMT_DBG("Moving cmd %p to active cmd list", cmd); - spin_lock_irqsave(&scst_list_lock, flags); - list_move(&cmd->cmd_list_entry, &scst_active_cmd_list); - spin_unlock_irqrestore(&scst_list_lock, flags); - found = 1; + TRACE_MGMT_DBG("Adding cmd %p to head of active cmd list", cmd); + spin_lock(&cmd->cmd_lists->cmd_list_lock); + list_add(&cmd->cmd_list_entry, &cmd->cmd_lists->active_cmd_list); + wake_up(&cmd->cmd_lists->cmd_list_waitQ); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); if (brk) break; } - if (found) - wake_up(&scst_list_waitQ); + local_irq_restore(, flags); #else /* STRICT_SERIALIZING */ struct scst_cmd *cmd, *tcmd; unsigned long flags; TRACE_ENTRY(); - spin_lock_irqsave(&scst_list_lock, flags); + local_irq_save(flags); list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { list_del(&cmd->blocked_cmd_list_entry); - TRACE_MGMT_DBG("Moving blocked cmd %p to active cmd list", cmd); - list_move_tail(&cmd->cmd_list_entry, &scst_active_cmd_list); - wake_up(&scst_list_waitQ); + TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd); + spin_lock(&cmd->cmd_lists->cmd_list_lock); + list_add_tail(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); + wake_up(&cmd->cmd_lists->cmd_list_waitQ); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); } - spin_unlock_irqrestore(&scst_list_lock, flags); + local_irq_restore(flags); #endif /* STRICT_SERIALIZING */ TRACE_EXIT(); return; } -static struct scst_cmd *scst_inc_expected_sn( +static struct scst_cmd *__scst_inc_expected_sn_unblock( struct scst_tgt_dev *tgt_dev, struct scst_cmd *out_of_sn_cmd) { struct scst_cmd *res = NULL; if (out_of_sn_cmd->sn == tgt_dev->expected_sn) { __scst_inc_expected_sn(tgt_dev); + res = scst_check_deferred_commands(tgt_dev, + tgt_dev->expected_sn); } else { + out_of_sn_cmd->out_of_sn = 1; spin_lock_bh(&tgt_dev->sn_lock); tgt_dev->def_cmd_count++; - set_bit(SCST_CMD_OUT_OF_SN, &out_of_sn_cmd->cmd_flags); list_add_tail(&out_of_sn_cmd->sn_cmd_list_entry, &tgt_dev->skipped_sn_list); TRACE(TRACE_SCSI_SERIALIZING, "out_of_sn_cmd %p with sn %d " "added to skipped_sn_list (expected_sn %d)", out_of_sn_cmd, out_of_sn_cmd->sn, tgt_dev->expected_sn); spin_unlock_bh(&tgt_dev->sn_lock); - smp_mb(); /* just in case, we need new value of tgt_dev->expected_sn */ } - res = scst_check_deferred_commands(tgt_dev, tgt_dev->expected_sn); return res; } void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev, - struct scst_cmd *out_of_sn_cmd, int locked) + struct scst_cmd *out_of_sn_cmd) { struct scst_cmd *cmd; @@ -2183,18 +2200,15 @@ goto out; } - cmd = scst_inc_expected_sn(tgt_dev, out_of_sn_cmd); + cmd = __scst_inc_expected_sn_unblock(tgt_dev, out_of_sn_cmd); if (cmd != NULL) { - unsigned long flags = 0; - if (!locked) - spin_lock_irqsave(&scst_list_lock, flags); + unsigned long flags; + spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags); TRACE(TRACE_SCSI_SERIALIZING, "cmd %p with sn %d " - "moved to active cmd list", cmd, cmd->sn); - list_move(&cmd->cmd_list_entry, &scst_active_cmd_list); - if (!locked) - spin_unlock_irqrestore(&scst_list_lock, flags); - if (!out_of_sn_cmd->processible_env) - wake_up(&scst_list_waitQ); + "added to the head of active cmd list", cmd, cmd->sn); + list_add(&cmd->cmd_list_entry, &cmd->cmd_lists->active_cmd_list); + wake_up(&cmd->cmd_lists->cmd_list_waitQ); + spin_unlock_irqrestore(&cmd->cmd_lists->cmd_list_lock, flags); } out: @@ -2223,7 +2237,6 @@ return; } - #ifdef DEBUG /* Original taken from the XFS code */ unsigned long scst_random(void) @@ -2263,111 +2276,140 @@ static void tm_dbg_timer_fn(unsigned long arg); -/* All serialized by scst_list_lock */ -static int tm_dbg_release; -static int tm_dbg_blocked; +static spinlock_t scst_tm_dbg_lock = SPIN_LOCK_UNLOCKED; +/* All serialized by scst_tm_dbg_lock */ +struct +{ + unsigned int tm_dbg_active:1; + unsigned int tm_dbg_release:1; + unsigned int tm_dbg_blocked:1; +} tm_dbg_flags; static LIST_HEAD(tm_dbg_delayed_cmd_list); static int tm_dbg_delayed_cmds_count; static int tm_dbg_passed_cmds_count; static int tm_dbg_state; static int tm_dbg_on_state_passes; static DEFINE_TIMER(tm_dbg_timer, tm_dbg_timer_fn, 0, 0); +static wait_queue_head_t *tm_dbg_p_cmd_list_waitQ; static const int tm_dbg_on_state_num_passes[] = { 5, 1, 0x7ffffff }; void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev, struct scst_acg_dev *acg_dev) { - if ((acg_dev->acg == scst_default_acg) && (acg_dev->lun == 0)) { - /* Do TM debugging only for LUN 0 */ - tm_dbg_state = INIT_TM_DBG_STATE; - tm_dbg_on_state_passes = - tm_dbg_on_state_num_passes[tm_dbg_state]; - __set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags); - PRINT_INFO("LUN 0 connected from initiator %s is under " - "TM debugging", tgt_dev->sess->tgt->tgtt->name); + if (((acg_dev->acg == scst_default_acg) || + (acg_dev->acg == tgt_dev->sess->tgt->default_acg)) && + (acg_dev->lun == 0)) { + unsigned long flags; + spin_lock_irqsave(&scst_tm_dbg_lock, flags); + if (!tm_dbg_flags.tm_dbg_active) { + /* Do TM debugging only for LUN 0 */ + tm_dbg_p_cmd_list_waitQ = + &tgt_dev->p_cmd_lists->cmd_list_waitQ; + tm_dbg_state = INIT_TM_DBG_STATE; + tm_dbg_on_state_passes = + tm_dbg_on_state_num_passes[tm_dbg_state]; + __set_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags); + PRINT_INFO("LUN 0 connected from initiator %s is under " + "TM debugging", tgt_dev->sess->tgt->tgtt->name); + tm_dbg_flags.tm_dbg_active = 1; + } + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); } } void tm_dbg_deinit_tgt_dev(struct scst_tgt_dev *tgt_dev) { - if (test_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags)) + if (test_bit(SCST_TGT_DEV_UNDER_TM_DBG, &tgt_dev->tgt_dev_flags)) { + unsigned long flags; del_timer_sync(&tm_dbg_timer); + spin_lock_irqsave(&scst_tm_dbg_lock, flags); + tm_dbg_p_cmd_list_waitQ = NULL; + tm_dbg_flags.tm_dbg_active = 0; + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); + } } static void tm_dbg_timer_fn(unsigned long arg) { - TRACE_MGMT_DBG("%s: delayed cmd timer expired", __func__); - tm_dbg_release = 1; + TRACE_MGMT_DBG("%s", "delayed cmd timer expired"); + tm_dbg_flags.tm_dbg_release = 1; smp_mb(); - wake_up_all(&scst_list_waitQ); + wake_up_all(tm_dbg_p_cmd_list_waitQ); } -/* Called under scst_list_lock */ +/* Called under scst_tm_dbg_lock and IRQs off */ static void tm_dbg_delay_cmd(struct scst_cmd *cmd) { switch(tm_dbg_state) { case TM_DBG_STATE_ABORT: if (tm_dbg_delayed_cmds_count == 0) { unsigned long d = 58*HZ + (scst_random() % (4*HZ)); - TRACE_MGMT_DBG("%s: delaying timed cmd %p (tag %d) " + TRACE_MGMT_DBG("STATE ABORT: delaying cmd %p (tag %d) " "for %ld.%ld seconds (%ld HZ), " - "tm_dbg_on_state_passes=%d", __func__, cmd, - cmd->tag, d/HZ, (d%HZ)*100/HZ, d, - tm_dbg_on_state_passes); + "tm_dbg_on_state_passes=%d", cmd, cmd->tag, + d/HZ, (d%HZ)*100/HZ, d, tm_dbg_on_state_passes); mod_timer(&tm_dbg_timer, jiffies + d); #if 0 - tm_dbg_blocked = 1; + tm_dbg_flags.tm_dbg_blocked = 1; #endif } else { - TRACE_MGMT_DBG("%s: delaying another timed cmd %p " + TRACE_MGMT_DBG("Delaying another timed cmd %p " "(tag %d), delayed_cmds_count=%d, " - "tm_dbg_on_state_passes=%d", __func__, cmd, - cmd->tag, tm_dbg_delayed_cmds_count, + "tm_dbg_on_state_passes=%d", cmd, cmd->tag, + tm_dbg_delayed_cmds_count, tm_dbg_on_state_passes); if (tm_dbg_delayed_cmds_count == 2) - tm_dbg_blocked = 0; + tm_dbg_flags.tm_dbg_blocked = 0; } break; case TM_DBG_STATE_RESET: case TM_DBG_STATE_OFFLINE: - TRACE_MGMT_DBG("%s: delaying cmd %p " + TRACE_MGMT_DBG("STATE RESET/OFFLINE: delaying cmd %p " "(tag %d), delayed_cmds_count=%d, " - "tm_dbg_on_state_passes=%d", __func__, cmd, - cmd->tag, tm_dbg_delayed_cmds_count, - tm_dbg_on_state_passes); - tm_dbg_blocked = 1; + "tm_dbg_on_state_passes=%d", cmd, cmd->tag, + tm_dbg_delayed_cmds_count, tm_dbg_on_state_passes); + tm_dbg_flags.tm_dbg_blocked = 1; break; default: sBUG(); } - list_move_tail(&cmd->cmd_list_entry, &tm_dbg_delayed_cmd_list); + /* IRQs already off */ + spin_lock(&cmd->cmd_lists->cmd_list_lock); + list_add_tail(&cmd->cmd_list_entry, &tm_dbg_delayed_cmd_list); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); cmd->tm_dbg_delayed = 1; tm_dbg_delayed_cmds_count++; return; } -/* Called under scst_list_lock */ +/* No locks */ void tm_dbg_check_released_cmds(void) { - if (tm_dbg_release) { + if (tm_dbg_flags.tm_dbg_release) { struct scst_cmd *cmd, *tc; + spin_lock_irq(&scst_tm_dbg_lock); list_for_each_entry_safe_reverse(cmd, tc, &tm_dbg_delayed_cmd_list, cmd_list_entry) { - TRACE_MGMT_DBG("%s: Releasing timed cmd %p " - "(tag %d), delayed_cmds_count=%d", __func__, - cmd, cmd->tag, tm_dbg_delayed_cmds_count); - list_move(&cmd->cmd_list_entry, &scst_active_cmd_list); + TRACE_MGMT_DBG("Releasing timed cmd %p (tag %d), " + "delayed_cmds_count=%d", cmd, cmd->tag, + tm_dbg_delayed_cmds_count); + spin_lock(&cmd->cmd_lists->cmd_list_lock); + list_move(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); } - tm_dbg_release = 0; + tm_dbg_flags.tm_dbg_release = 0; + spin_unlock_irq(&scst_tm_dbg_lock); } } +/* Called under scst_tm_dbg_lock */ static void tm_dbg_change_state(void) { - tm_dbg_blocked = 0; + tm_dbg_flags.tm_dbg_blocked = 0; if (--tm_dbg_on_state_passes == 0) { switch(tm_dbg_state) { case TM_DBG_STATE_ABORT: @@ -2375,7 +2417,7 @@ "tm_dbg_state to RESET"); tm_dbg_state = TM_DBG_STATE_RESET; - tm_dbg_blocked = 0; + tm_dbg_flags.tm_dbg_blocked = 0; break; case TM_DBG_STATE_RESET: case TM_DBG_STATE_OFFLINE: @@ -2402,15 +2444,17 @@ del_timer(&tm_dbg_timer); } -/* Called under scst_list_lock */ +/* No locks */ int tm_dbg_check_cmd(struct scst_cmd *cmd) { int res = 0; + unsigned long flags; if (cmd->tm_dbg_immut) goto out; if (cmd->tm_dbg_delayed) { + spin_lock_irqsave(&scst_tm_dbg_lock, flags); TRACE_MGMT_DBG("Processing delayed cmd %p (tag %d), " "delayed_cmds_count=%d", cmd, cmd->tag, tm_dbg_delayed_cmds_count); @@ -2420,25 +2464,31 @@ if ((tm_dbg_delayed_cmds_count == 0) && (tm_dbg_state == TM_DBG_STATE_ABORT)) tm_dbg_change_state(); - + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); } else if (cmd->tgt_dev && test_bit(SCST_TGT_DEV_UNDER_TM_DBG, &cmd->tgt_dev->tgt_dev_flags)) { /* Delay 50th command */ - if (tm_dbg_blocked || (++tm_dbg_passed_cmds_count % 50) == 0) { + spin_lock_irqsave(&scst_tm_dbg_lock, flags); + if (tm_dbg_flags.tm_dbg_blocked || + (++tm_dbg_passed_cmds_count % 50) == 0) { tm_dbg_delay_cmd(cmd); res = 1; } else cmd->tm_dbg_immut = 1; + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); } out: return res; } -/* Called under scst_list_lock */ +/* No locks */ void tm_dbg_release_cmd(struct scst_cmd *cmd) { struct scst_cmd *c; + unsigned long flags; + + spin_lock_irqsave(&scst_tm_dbg_lock, flags); list_for_each_entry(c, &tm_dbg_delayed_cmd_list, cmd_list_entry) { if (c == cmd) { @@ -2446,30 +2496,38 @@ "delayed cmd %p (tag=%d), moving it to " "active cmd list (delayed_cmds_count=%d)", c, c->tag, tm_dbg_delayed_cmds_count); - list_move(&c->cmd_list_entry, &scst_active_cmd_list); - wake_up_all(&scst_list_waitQ); + spin_lock(&cmd->cmd_lists->cmd_list_lock); + list_move(&c->cmd_list_entry, + &c->cmd_lists->active_cmd_list); + wake_up(&c->cmd_lists->cmd_list_waitQ); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); break; } } + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); } -/* Called under scst_list_lock */ -void tm_dbg_task_mgmt(const char *fn) +/* No locks */ +void tm_dbg_task_mgmt(const char *fn, int force) { - if (tm_dbg_state != TM_DBG_STATE_OFFLINE) { + unsigned long flags; + + spin_lock_irqsave(&scst_tm_dbg_lock, flags); + if ((tm_dbg_state != TM_DBG_STATE_OFFLINE) || force) { TRACE_MGMT_DBG("%s: freeing %d delayed cmds", fn, tm_dbg_delayed_cmds_count); tm_dbg_change_state(); - tm_dbg_release = 1; + tm_dbg_flags.tm_dbg_release = 1; smp_mb(); - wake_up_all(&scst_list_waitQ); + wake_up_all(tm_dbg_p_cmd_list_waitQ); } else { TRACE_MGMT_DBG("%s: while OFFLINE state, doing nothing", fn); } + spin_unlock_irqrestore(&scst_tm_dbg_lock, flags); } int tm_dbg_is_release(void) { - return tm_dbg_release; + return tm_dbg_flags.tm_dbg_release; } #endif /* DEBUG_TM */ Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/src/scst_priv.h 2007-02-21 11:43:22 UTC (rev 90) @@ -70,9 +70,16 @@ ** Bits for scst_flags **/ -/* Set if new commands initialization should be suspended for a while */ -#define SCST_FLAG_SUSPENDED 0 +/* + * Set if new commands initialization is being suspended for a while. + * Used to let TM commands execute while preparing the suspend, since + * RESET or ABORT could be necessary to free SCSI commands. + */ +#define SCST_FLAG_SUSPENDING 0 +/* Set if new commands initialization is suspended for a while */ +#define SCST_FLAG_SUSPENDED 1 + /* Set if a TM command is being performed */ #define SCST_FLAG_TM_ACTIVE 2 @@ -129,13 +136,13 @@ #define SCST_ACG_DEV_CACHE_STRING "scst_acg_dev" extern struct kmem_cache *scst_acgd_cachep; +extern spinlock_t scst_main_lock; + extern struct scst_sgv_pools scst_sgv; extern unsigned long scst_flags; extern struct semaphore scst_mutex; extern atomic_t scst_cmd_count; -extern spinlock_t scst_list_lock; -extern struct list_head scst_dev_wait_sess_list; /* protected by scst_list_lock */ extern struct list_head scst_template_list; /* protected by scst_mutex */ extern struct list_head scst_dev_list; /* protected by scst_mutex */ extern struct list_head scst_dev_type_list; /* protected by scst_mutex */ @@ -144,11 +151,13 @@ extern struct list_head scst_acg_list; extern struct scst_acg *scst_default_acg; -/* The following lists protected by scst_list_lock */ -extern struct list_head scst_active_cmd_list; +extern spinlock_t scst_init_lock; extern struct list_head scst_init_cmd_list; -extern struct list_head scst_cmd_list; +extern wait_queue_head_t scst_init_cmd_list_waitQ; +extern unsigned int scst_init_poll_cnt; +extern struct scst_cmd_lists scst_main_cmd_lists; + extern spinlock_t scst_cmd_mem_lock; extern unsigned long scst_max_cmd_mem, scst_cur_max_cmd_mem, scst_cur_cmd_mem; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) @@ -157,16 +166,21 @@ extern struct delayed_work scst_cmd_mem_work; #endif -/* The following lists protected by scst_list_lock as well */ -extern struct list_head scst_mgmt_cmd_list; +extern spinlock_t scst_mcmd_lock; +/* The following lists protected by scst_mcmd_lock */ extern struct list_head scst_active_mgmt_cmd_list; extern struct list_head scst_delayed_mgmt_cmd_list; -extern struct tasklet_struct scst_tasklets[NR_CPUS]; -extern wait_queue_head_t scst_list_waitQ; - extern wait_queue_head_t scst_mgmt_cmd_list_waitQ; +struct scst_tasklet +{ + spinlock_t tasklet_lock; + struct list_head tasklet_cmd_list; + struct tasklet_struct tasklet; +}; +extern struct scst_tasklet scst_tasklets[NR_CPUS]; + extern wait_queue_head_t scst_mgmt_waitQ; extern spinlock_t scst_mgmt_lock; extern struct list_head scst_sess_mgmt_list; @@ -180,6 +194,7 @@ struct semaphore cmd_threads_mutex; u32 nr_cmd_threads; struct list_head cmd_threads_list; + struct task_struct *init_cmd_thread; struct task_struct *mgmt_thread; struct task_struct *mgmt_cmd_thread; }; @@ -223,10 +238,11 @@ } void scst_inc_expected_sn_unblock(struct scst_tgt_dev *tgt_dev, - struct scst_cmd *cmd_sn, int locked); + struct scst_cmd *cmd_sn); int scst_cmd_thread(void *arg); void scst_cmd_tasklet(long p); +int scst_init_cmd_thread(void *arg); int scst_mgmt_cmd_thread(void *arg); int scst_mgmt_thread(void *arg); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) @@ -276,7 +292,7 @@ void scst_proccess_redirect_cmd(struct scst_cmd *cmd, int context, int check_retries); -void scst_check_retries(struct scst_tgt *tgt, int processible_env); +void scst_check_retries(struct scst_tgt *tgt); void scst_tgt_retry_timer_fn(unsigned long arg); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) @@ -324,7 +340,8 @@ uint32_t tag); struct scst_mgmt_cmd *scst_alloc_mgmt_cmd(int gfp_mask); -void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd, int del); +void scst_free_mgmt_cmd(struct scst_mgmt_cmd *mcmd); +void scst_complete_cmd_mgmt(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd); /* /proc support */ int scst_proc_init_module(void); @@ -438,21 +455,24 @@ wake_up_all(&cmd->dev->on_dev_waitQ); } -static inline void scst_inc_cmd_count(void) +static inline void __scst_get(int barrier) { atomic_inc(&scst_cmd_count); - /* It's needed to be before test_bit(SCST_FLAG_SUSPENDED) */ - smp_mb__after_atomic_inc(); TRACE_DBG("Incrementing scst_cmd_count(%d)", - atomic_read(&scst_cmd_count)); + atomic_read(&scst_cmd_count)); + + if (barrier) + smp_mb__after_atomic_inc(); } -static inline void scst_dec_cmd_count(void) +static inline void __scst_put(void) { int f; f = atomic_dec_and_test(&scst_cmd_count); - if (f && unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) + if (f && unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) { + TRACE_MGMT_DBG("%s", "Waking up scst_dev_cmd_waitQ"); wake_up_all(&scst_dev_cmd_waitQ); + } TRACE_DBG("Decrementing scst_cmd_count(%d)", atomic_read(&scst_cmd_count)); } @@ -470,9 +490,17 @@ scst_sched_session_free(sess); } -void __scst_suspend_activity(void); -void __scst_resume_activity(void); +static inline void scst_cmd_get(struct scst_cmd *cmd) +{ + atomic_inc(&cmd->cmd_ref); +} +static inline void scst_cmd_put(struct scst_cmd *cmd) +{ + if (atomic_dec_and_test(&cmd->cmd_ref)) + scst_free_cmd(cmd); +} + extern void scst_throttle_cmd(struct scst_cmd *cmd); extern void scst_unthrottle_cmd(struct scst_cmd *cmd); @@ -504,7 +532,7 @@ extern void tm_dbg_check_released_cmds(void); extern int tm_dbg_check_cmd(struct scst_cmd *cmd); extern void tm_dbg_release_cmd(struct scst_cmd *cmd); -extern void tm_dbg_task_mgmt(const char *fn); +extern void tm_dbg_task_mgmt(const char *fn, int force); extern int tm_dbg_is_release(void); #else static inline void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev, @@ -516,7 +544,7 @@ return 0; } static inline void tm_dbg_release_cmd(struct scst_cmd *cmd) {} -static inline void tm_dbg_task_mgmt(const char *fn) {} +static inline void tm_dbg_task_mgmt(const char *fn, int force) {} static inline int tm_dbg_is_release(void) { return 0; Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2007-02-19 12:55:54 UTC (rev 89) +++ trunk/scst/src/scst_proc.c 2007-02-21 11:43:22 UTC (rev 90) @@ -474,7 +474,7 @@ return; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ static int scst_proc_group_add(const char *p) { int res = 0, len = strlen(p) + 1; @@ -515,7 +515,7 @@ goto out; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc) { const char *name; @@ -1136,9 +1136,11 @@ goto out_free; } + scst_suspend_activity(); + if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; - goto out_free; + goto out_free_resume; } switch (action) { @@ -1188,14 +1190,18 @@ out... [truncated message content] |
From: <vl...@us...> - 2007-02-21 12:51:07
|
Revision: 91 http://svn.sourceforge.net/scst/?rev=91&view=rev Author: vlnb Date: 2007-02-21 04:50:48 -0800 (Wed, 21 Feb 2007) Log Message: ----------- Execution context cleanup. Completed full support for SCSI task attributes (SIMPLE, ORDERED, etc.) + minor cleanups Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/include/scsi_tgt.h trunk/scst/src/Makefile trunk/scst/src/dev_handlers/scst_fileio.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/ChangeLog 2007-02-21 12:50:48 UTC (rev 91) @@ -1,6 +1,12 @@ Summary of changes between versions 0.9.5 and 0.9.6 --------------------------------------------------- + - Internal locking and execution context were reimplemnted. Particularly, + implemented full support for SCSI task attributes (SIMPLE, ORDERED, + etc.). + + - Updated to work on 2.6.20.x + - Updated to work on 2.6.19.x, thanks to Ming Zhang. - Internal threads management reimplemented based on kthread*() API, Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/include/scsi_tgt.h 2007-02-21 12:50:48 UTC (rev 91) @@ -49,12 +49,6 @@ /* LUN translation (cmd->tgt_dev assignment) */ #define SCST_CMD_STATE_INIT 2 -/* - * Again LUN translation (cmd->tgt_dev assignment), used if dev handler - * wants to restart cmd on another LUN - */ -#define SCST_CMD_STATE_REINIT 3 - /* Dev handler's parse() is going to be called */ #define SCST_CMD_STATE_DEV_PARSE 4 @@ -380,6 +374,8 @@ #define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9 #define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10 +/* Set HEAD OF QUEUE cmd is being executed */ +#define SCST_TGT_DEV_HQ_ACTIVE 12 #ifdef DEBUG_TM #define SCST_TGT_DEV_UNDER_TM_DBG 20 @@ -734,12 +730,6 @@ struct scst_dev_type { - /* Name of the dev handler. Must be unique. MUST HAVE */ - char name[15]; - - /* SCSI type of the supported device. MUST HAVE */ - int type; - /* * True, if corresponding function supports execution in * the atomic (non-sleeping) context @@ -747,26 +737,9 @@ unsigned parse_atomic:1; unsigned exec_atomic:1; unsigned dev_done_atomic:1; + unsigned dedicated_thread:1; /* - * Called when new device is attaching to the dev handler - * Returns 0 on success, error code otherwise. - */ - int (*attach) (struct scst_device *dev); - - /* Called when new device is detaching from the dev handler */ - void (*detach) (struct scst_device *dev); - - /* - * Called when new tgt_dev (session) is attaching to the dev handler. - * Returns 0 on success, error code otherwise. - */ - int (*attach_tgt) (struct scst_tgt_dev *tgt_dev); - - /* Called when tgt_dev (session) is detaching from the dev handler */ - void (*detach_tgt) (struct scst_tgt_dev *tgt_dev); - - /* * Called to parse CDB from the cmd and initialize * cmd->bufflen and cmd->data_direction (both - REQUIRED). * Returns the command's next state or SCST_CMD_STATE_DEFAULT, @@ -841,6 +814,24 @@ int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, struct scst_tgt_dev *tgt_dev); + /* + * Called when new device is attaching to the dev handler + * Returns 0 on success, error code otherwise. + */ + int (*attach) (struct scst_device *dev); + + /* Called when new device is detaching from the dev handler */ + void (*detach) (struct scst_device *dev); + + /* + * Called when new tgt_dev (session) is attaching to the dev handler. + * Returns 0 on success, error code otherwise. + */ + int (*attach_tgt) (struct scst_tgt_dev *tgt_dev); + + /* Called when tgt_dev (session) is detaching from the dev handler */ + void (*detach_tgt) (struct scst_tgt_dev *tgt_dev); + /* * Those functions can be used to export the handler's statistics and * other infos to the world outside the kernel as well as to get some @@ -852,6 +843,12 @@ int (*write_proc) (char *buffer, char **start, off_t offset, int length, int *eof, struct scst_dev_type *dev_type); + /* Name of the dev handler. Must be unique. MUST HAVE */ + char name[15]; + + /* SCSI type of the supported device. MUST HAVE */ + int type; + struct module *module; /* private: */ @@ -1094,6 +1091,12 @@ /* Set if the cmd was done or aborted out of its SN */ unsigned long out_of_sn:1; + /* Set if the cmd is HEAD OF QUEUE */ + unsigned long head_of_queue:1; + + /* Set if the cmd is deferred HEAD OF QUEUE */ + unsigned long hq_deferred:1; + /**************************************************************/ unsigned long cmd_flags; /* cmd's async flags */ @@ -1116,6 +1119,9 @@ /* Cmd's serial number, used to execute cmd's in order of arrival */ unsigned int sn; + /* The corresponding sn_slot in tgt_dev->sn_slots */ + atomic_t *sn_slot; + /* List entry for session's search_cmd_list */ struct list_head search_cmd_list_entry; @@ -1193,18 +1199,6 @@ /* Used for storage of dev handler private stuff */ void *dh_priv; - /* - * Fileio private fields - */ - struct list_head fileio_cmd_list_entry; - int fileio_in_list; - - /* - * Used to store previous tgt_dev if dev handler returns - * SCST_CMD_STATE_REINIT state - */ - struct scst_tgt_dev *tgt_dev_saved; - struct scst_cmd *orig_cmd; /* Used to issue REQUEST SENSE */ }; @@ -1253,8 +1247,7 @@ { struct scst_dev_type *handler; /* corresponding dev handler */ - /* Used to translate SCSI's cmd to SCST's cmd */ - struct gendisk *rq_disk; + unsigned short type; /* SCSI type of the device */ /************************************************************* ** Dev's flags. Updates serialized by dev_lock or suspended @@ -1262,16 +1255,16 @@ *************************************************************/ /* Set if dev is RESERVED */ - unsigned int dev_reserved:1; + unsigned short dev_reserved:1; /* Set if dev accepts only one command at time */ - unsigned int dev_serialized:1; + unsigned short dev_serialized:1; /* Set if double reset UA is possible */ - unsigned int dev_double_ua_possible:1; + unsigned short dev_double_ua_possible:1; /* Set if reset UA sent (to avoid double reset UAs) */ - unsigned int dev_reset_ua_sent:1; + unsigned short dev_reset_ua_sent:1; /**************************************************************/ @@ -1290,13 +1283,16 @@ atomic_t on_dev_count; struct list_head blocked_cmd_list; /* protected by dev_lock */ - - /* Corresponding real SCSI device, could be NULL for virtual devices */ - struct scsi_device *scsi_dev; - + /* Used for storage of dev handler private stuff */ void *dh_priv; + /* Used to translate SCSI's cmd to SCST's cmd */ + struct gendisk *rq_disk; + + /* Corresponding real SCSI device, could be NULL for virtual devices */ + struct scsi_device *scsi_dev; + /* Used to wait for requested amount of "on_dev" commands */ wait_queue_head_t on_dev_waitQ; @@ -1322,6 +1318,19 @@ struct list_head dev_acg_dev_list; }; +/* + * Used to store threads local tgt_dev specific data + */ +struct scst_thr_data_hdr +{ + /* List entry in tgt_dev->thr_data_list */ + struct list_head thr_data_list_entry; + pid_t pid; /* PID of the owner thread */ + atomic_t ref; + /* Function that will be called on the tgt_dev destruction */ + void (*free_fn) (struct scst_thr_data_hdr *data); +}; + /* * Used to store per-session specific device information */ @@ -1329,48 +1338,64 @@ { /* List entry in sess->sess_tgt_dev_list */ struct list_head sess_tgt_dev_list_entry; - - struct scst_acg_dev *acg_dev; /* corresponding acg_dev */ + struct scst_device *dev; /* to save extra dereferences */ + lun_t lun; /* to save extra dereferences */ + + /* Pointer to lists of commands with the lock */ + struct scst_cmd_lists *p_cmd_lists; + /* How many cmds alive on this dev in this session */ atomic_t cmd_count; - spinlock_t tgt_dev_lock; /* per-session device lock */ + unsigned long tgt_dev_flags; /* tgt_dev's async flags */ - /* List of UA's for this device, protected by tgt_dev_lock */ - struct list_head UA_list; - - unsigned long tgt_dev_flags; /* tgt_dev's flags */ - - /* Used for storage of dev handler private stuff */ - void *dh_priv; - - /* Pointer to lists of commands with the lock */ - struct scst_cmd_lists *p_cmd_lists; - /* - * Used to execute cmd's in order of arrival. + * Used to execute cmd's in order of arrival, honoring SCSI task + * attributes. * - * Protected by sn_lock, except curr_sn and expected_sn. - * Expected_sn protected by itself, since only one thread, which - * processes SN matching command, can increment it at any time. - * Next_sn must have the same size as expected_sn to overflow - * simultaneously. + * Protected by sn_lock, except expected_sn, which is protected by + * itself. Curr_sn must have the same size as expected_sn to + * overflow simultaneously. */ - atomic_t curr_sn; + int def_cmd_count; + spinlock_t sn_lock; int expected_sn; - spinlock_t sn_lock; - int def_cmd_count; + int curr_sn; struct list_head deferred_cmd_list; struct list_head skipped_sn_list; - + struct list_head hq_cmd_list; + unsigned short prev_cmd_ordered; /* Set if the prev cmd was ORDERED */ + short num_free_sn_slots; + atomic_t *cur_sn_slot; + atomic_t sn_slots[10]; + + /* Lists of commands with the lock, if dedicated threads are used */ + struct scst_cmd_lists cmd_lists; + + /* Used for storage of dev handler private stuff */ + void *dh_priv; + + /* List of scst_thr_data_hdr and lock */ + spinlock_t thr_data_lock; + struct list_head thr_data_list; + + spinlock_t tgt_dev_lock; /* per-session device lock */ + + /* List of UA's for this device, protected by tgt_dev_lock */ + struct list_head UA_list; + struct scst_session *sess; /* corresponding session */ - + struct scst_acg_dev *acg_dev; /* corresponding acg_dev */ + /* list entry in dev->dev_tgt_dev_list */ struct list_head dev_tgt_dev_list_entry; /* internal tmp list entry */ struct list_head extra_tgt_dev_list_entry; + + /* Dedicated thread. Doesn't need any protection. */ + struct task_struct *thread; }; /* @@ -1609,7 +1634,18 @@ * Notifies SCST that the driver finished its part of the command * initialization, and the command is ready for execution. * The second argument sets preferred command execition context. - * See SCST_CONTEXT_* constants for details + * See SCST_CONTEXT_* constants for details. + * + * !!IMPORTANT!! + * + * If cmd->no_sn not set, this function, as well as scst_cmd_init_stage1_done() + * and scst_restart_cmd() must not be called simultaneously for the same session + * (more precisely, for the same session/LUN, i.e. tgt_dev), i.e. they must be + * somehow externally serialized. This is needed to have lock free fast path in + * scst_cmd_set_sn(). For majority of targets those functions are naturally + * serialized by the single source of commands. Only iSCSI immediate commands + * with multiple connections per session seems to be an exception. For it, some + * mutex/lock shall be used for the serialization. */ void scst_cmd_init_done(struct scst_cmd *cmd, int pref_context); @@ -1619,6 +1655,8 @@ * SCST done the command's preprocessing preprocessing_done() function * should be called. The second argument sets preferred command execition * context. See SCST_CONTEXT_* constants for details. + * + * See also scst_cmd_init_done() comment for the serialization requirements. */ static inline void scst_cmd_init_stage1_done(struct scst_cmd *cmd, int pref_context, int set_sn) @@ -1634,7 +1672,9 @@ * The second argument sets data receiving completion status * (see SCST_PREPROCESS_STATUS_* constants for details) * The third argument sets preferred command execition context - * (see SCST_CONTEXT_* constants for details) + * (see SCST_CONTEXT_* constants for details). + * + * See also scst_cmd_init_done() comment for the serialization requirements. */ void scst_restart_cmd(struct scst_cmd *cmd, int status, int pref_context); @@ -2231,4 +2271,32 @@ /* Frees SG vector returned by scst_alloc() */ void scst_free(struct scatterlist *sg, int count); +/* + * Adds local to the current thread data to tgt_dev + * (they will be local for the tgt_dev and current thread). + */ +void scst_add_thr_data(struct scst_tgt_dev *tgt_dev, + struct scst_thr_data_hdr *data, + void (*free_fn) (struct scst_thr_data_hdr *data)); + +/* Deletes all local to threads data from tgt_dev */ +void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev); + +/* Deletes all local to threads data from all tgt_dev's of the dev */ +void scst_dev_del_all_thr_data(struct scst_device *dev); + +/* Finds local to the current thread data. Returns NULL, if they not found. */ +struct scst_thr_data_hdr *scst_find_thr_data(struct scst_tgt_dev *tgt_dev); + +static inline void scst_thr_data_get(struct scst_thr_data_hdr *data) +{ + atomic_inc(&data->ref); +} + +static inline void scst_thr_data_put(struct scst_thr_data_hdr *data) +{ + if (atomic_dec_and_test(&data->ref)) + data->free_fn(data); +} + #endif /* __SCST_H */ Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/src/Makefile 2007-02-21 12:50:48 UTC (rev 91) @@ -105,6 +105,7 @@ #EXTRA_CFLAGS += -DDEBUG_TM -DTM_DBG_GO_OFFLINE=0 #EXTRA_CFLAGS += -DDEBUG_RETRY #EXTRA_CFLAGS += -DDEBUG_OOM +#EXTRA_CFLAGS += -DDEBUG_SN # If defined, makes SCST zero allocated data buffers. # Undefining it considerably improves performance and eases CPU load, Modified: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-21 12:50:48 UTC (rev 91) @@ -51,6 +51,12 @@ #include "scst_dev_handler.h" +#if defined(DEBUG) && defined(CONFIG_DEBUG_SLAB) +#define FILEIO_SLAB_FLAGS ( SLAB_RED_ZONE | SLAB_POISON ) +#else +#define FILEIO_SLAB_FLAGS 0L +#endif + /* 8 byte ASCII Vendor of the FILE IO target */ #define SCST_FIO_VENDOR "SCST_FIO" /* 4 byte ASCII Product Revision Level of the FILE IO target - left aligned */ @@ -94,6 +100,11 @@ uint64_t nblocks; int block_shift; loff_t file_size; /* in bytes */ + spinlock_t flags_lock; + /* + * Below flags are protected by flags_lock or suspended activity + * with scst_fileio_mutex. + */ unsigned int rd_only_flag:1; unsigned int wt_flag:1; unsigned int nv_cache:1; @@ -107,37 +118,38 @@ must be <= SCSI Model + 1 */ char *file_name; /* File name */ char *usn; + struct scst_device *dev; struct list_head fileio_dev_list_entry; - struct list_head ftgt_list; - struct semaphore ftgt_list_mutex; }; struct scst_fileio_tgt_dev { - spinlock_t fdev_lock; enum scst_cmd_queue_type last_write_cmd_queue_type; +}; + +struct scst_fileio_thr { + struct scst_thr_data_hdr hdr; struct file *fd; struct iovec *iv; int iv_count; - struct list_head fdev_cmd_list; - wait_queue_head_t fdev_waitQ; - struct task_struct *cmd_thread; struct scst_fileio_dev *virt_dev; - struct list_head ftgt_list_entry; }; +static struct kmem_cache *fileio_thr_cachep; + static int fileio_attach(struct scst_device *dev); static void fileio_detach(struct scst_device *dev); static int fileio_attach_tgt(struct scst_tgt_dev *tgt_dev); static void fileio_detach_tgt(struct scst_tgt_dev *tgt_dev); static int disk_fileio_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); -static int disk_fileio_exec(struct scst_cmd *cmd); +static int fileio_do_job(struct scst_cmd *cmd); static int cdrom_fileio_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); static int cdrom_fileio_exec(struct scst_cmd *cmd); -static void fileio_exec_read(struct scst_cmd *cmd, loff_t loff); -static void fileio_exec_write(struct scst_cmd *cmd, loff_t loff); -static void fileio_exec_verify(struct scst_cmd *cmd, loff_t loff); -static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd, - struct scst_tgt_dev *tgt_dev); +static void fileio_exec_read(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff); +static void fileio_exec_write(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff); +static void fileio_exec_verify(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff); static void fileio_exec_read_capacity(struct scst_cmd *cmd); static void fileio_exec_read_capacity16(struct scst_cmd *cmd); static void fileio_exec_inquiry(struct scst_cmd *cmd); @@ -145,7 +157,7 @@ static void fileio_exec_mode_select(struct scst_cmd *cmd); static void fileio_exec_read_toc(struct scst_cmd *cmd); static void fileio_exec_prevent_allow_medium_removal(struct scst_cmd *cmd); -static int fileio_fsync(struct scst_fileio_tgt_dev *ftgt_dev, +static int fileio_fsync(struct scst_fileio_thr *thr, loff_t loff, loff_t len, struct scst_cmd *cmd); static int disk_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type); static int disk_fileio_write_proc(char *buffer, char **start, off_t offset, @@ -158,15 +170,15 @@ name: DISK_FILEIO_NAME, \ type: TYPE_DISK, \ parse_atomic: 1, \ - exec_atomic: 1, \ + exec_atomic: 0, \ dev_done_atomic: 1, \ + dedicated_thread: 1, \ attach: fileio_attach, \ detach: fileio_detach, \ attach_tgt: fileio_attach_tgt, \ detach_tgt: fileio_detach_tgt, \ parse: disk_fileio_parse, \ - exec: disk_fileio_exec, \ - task_mgmt_fn: fileio_task_mgmt_fn, \ + exec: fileio_do_job, \ read_proc: disk_fileio_read_proc, \ write_proc: disk_fileio_write_proc, \ } @@ -175,15 +187,15 @@ name: CDROM_FILEIO_NAME, \ type: TYPE_ROM, \ parse_atomic: 1, \ - exec_atomic: 1, \ + exec_atomic: 0, \ dev_done_atomic: 1, \ + dedicated_thread: 1, \ attach: fileio_attach, \ detach: fileio_detach, \ attach_tgt: fileio_attach_tgt, \ detach_tgt: fileio_detach_tgt, \ parse: cdrom_fileio_parse, \ exec: cdrom_fileio_exec, \ - task_mgmt_fn: fileio_task_mgmt_fn, \ read_proc: cdrom_fileio_read_proc, \ write_proc: cdrom_fileio_write_proc,\ } @@ -271,8 +283,7 @@ * scst_fileio_mutex must be already taken before * scst_register_virtual_device() */ - list_for_each_entry(vv, fileio_dev_list, fileio_dev_list_entry) - { + list_for_each_entry(vv, fileio_dev_list, fileio_dev_list_entry) { if (strcmp(vv->name, dev->virt_name) == 0) { virt_dev = vv; break; @@ -284,7 +295,9 @@ res = -EINVAL; goto out; } - + + virt_dev->dev = dev; + if (dev->handler->type == TYPE_ROM) virt_dev->rd_only_flag = 1; @@ -393,6 +406,109 @@ return; } +static void fileio_free_thr_data(struct scst_thr_data_hdr *d) +{ + struct scst_fileio_thr *thr = container_of(d, struct scst_fileio_thr, + hdr); + + TRACE_ENTRY(); + + if (thr->fd) + filp_close(thr->fd, NULL); + + if (thr->iv != NULL) + kfree(thr->iv); + + kmem_cache_free(fileio_thr_cachep, thr); + + TRACE_EXIT(); + return; +} + +static struct scst_fileio_thr *fileio_init_thr_data( + struct scst_tgt_dev *tgt_dev) +{ + struct scst_fileio_thr *res; + struct scst_fileio_dev *virt_dev = + (struct scst_fileio_dev *)tgt_dev->dev->dh_priv; + + TRACE_ENTRY(); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) + res = kmem_cache_alloc(fileio_thr_cachep, GFP_KERNEL); + if (res != NULL) + memset(thr, 0, sizeof(*thr)); +#else + res = kmem_cache_zalloc(fileio_thr_cachep, GFP_KERNEL); +#endif + if (res == NULL) { + TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct " + "scst_fileio_thr"); + goto out; + } + + res->virt_dev = virt_dev; + + if (!virt_dev->cdrom_empty && !virt_dev->nullio) { + res->fd = fileio_open(virt_dev); + if (IS_ERR(res->fd)) { + PRINT_ERROR_PR("filp_open(%s) returned an error %ld", + virt_dev->file_name, PTR_ERR(res->fd)); + goto out_free; + } + } else + res->fd = NULL; + + scst_add_thr_data(tgt_dev, &res->hdr, fileio_free_thr_data); + +out: + TRACE_EXIT_HRES((unsigned long)res); + return res; + +out_free: + kmem_cache_free(fileio_thr_cachep, res); + res = NULL; + goto out; +} + +static int fileio_attach_tgt(struct scst_tgt_dev *tgt_dev) +{ + struct scst_fileio_tgt_dev *ftgt_dev; + int res = 0; + + TRACE_ENTRY(); + + ftgt_dev = kzalloc(sizeof(*ftgt_dev), GFP_KERNEL); + if (ftgt_dev == NULL) { + TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of per-session " + "virtual device failed"); + res = -ENOMEM; + goto out; + } + + tgt_dev->dh_priv = ftgt_dev; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static void fileio_detach_tgt(struct scst_tgt_dev *tgt_dev) +{ + struct scst_fileio_tgt_dev *ftgt_dev = + (struct scst_fileio_tgt_dev *)tgt_dev->dh_priv; + + TRACE_ENTRY(); + + scst_del_all_thr_data(tgt_dev); + + kfree(ftgt_dev); + tgt_dev->dh_priv = NULL; + + TRACE_EXIT(); + return; +} + static inline int fileio_sync_queue_type(enum scst_cmd_queue_type qt) { switch(qt) { @@ -413,7 +529,7 @@ return 0; } -static void fileio_do_job(struct scst_cmd *cmd) +static int fileio_do_job(struct scst_cmd *cmd) { uint64_t lba_start = 0; loff_t data_len = 0; @@ -423,17 +539,34 @@ struct scst_device *dev = cmd->dev; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)dev->dh_priv; + struct scst_thr_data_hdr *d; + struct scst_fileio_thr *thr = NULL; int fua = 0; TRACE_ENTRY(); + cmd->status = 0; + cmd->msg_status = 0; + cmd->host_status = DID_OK; + cmd->driver_status = 0; + if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) { TRACE_MGMT_DBG("Flag ABORTED set for " "cmd %p (tag %d), skipping", cmd, cmd->tag); goto done_uncompl; } - + d = scst_find_thr_data(cmd->tgt_dev); + if (unlikely(d == NULL)) { + thr = fileio_init_thr_data(cmd->tgt_dev); + if (thr == NULL) { + scst_set_busy(cmd); + goto done; + } + scst_thr_data_get(&thr->hdr); + } else + thr = container_of(d, struct scst_fileio_thr, hdr); + switch (opcode) { case READ_6: case WRITE_6: @@ -514,7 +647,7 @@ case READ_10: case READ_12: case READ_16: - fileio_exec_read(cmd, loff); + fileio_exec_read(cmd, thr, loff); break; case WRITE_6: case WRITE_10: @@ -535,13 +668,13 @@ cmd->queue_type, (uint64_t)loff, (uint64_t)data_len); do_fsync = 1; - if (fileio_fsync(ftgt_dev, 0, 0, cmd) != 0) + if (fileio_fsync(thr, 0, 0, cmd) != 0) goto done; } - fileio_exec_write(cmd, loff); + fileio_exec_write(cmd, thr, loff); /* O_SYNC flag is used for wt_flag devices */ if (do_fsync || fua) - fileio_fsync(ftgt_dev, loff, data_len, cmd); + fileio_fsync(thr, loff, data_len, cmd); } else { TRACE_DBG("%s", "Attempt to write to read-only device"); scst_set_cmd_error(cmd, @@ -566,15 +699,15 @@ cmd->queue_type, (uint64_t)loff, (uint64_t)data_len); do_fsync = 1; - if (fileio_fsync(ftgt_dev, 0, 0, cmd) != 0) + if (fileio_fsync(thr, 0, 0, cmd) != 0) goto done; } - fileio_exec_write(cmd, loff); + fileio_exec_write(cmd, thr, loff); /* O_SYNC flag is used for wt_flag devices */ if (cmd->status == 0) - fileio_exec_verify(cmd, loff); + fileio_exec_verify(cmd, thr, loff); else if (do_fsync) - fileio_fsync(ftgt_dev, loff, data_len, cmd); + fileio_fsync(thr, loff, data_len, cmd); } else { TRACE_DBG("%s", "Attempt to write to read-only device"); scst_set_cmd_error(cmd, @@ -584,9 +717,6 @@ case SYNCHRONIZE_CACHE: { int immed = cdb[1] & 0x2; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev*) - cmd->tgt_dev->dh_priv; TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: " "loff=%Ld, data_len=%Ld, immed=%d", (uint64_t)loff, (uint64_t)data_len, immed); @@ -595,12 +725,12 @@ cmd->completed = 1; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); /* cmd is dead here */ - fileio_fsync(ftgt_dev, loff, data_len, NULL); + fileio_fsync(thr, loff, data_len, NULL); /* ToDo: fileio_fsync() error processing */ scst_put(); goto out; } else { - fileio_fsync(ftgt_dev, loff, data_len, cmd); + fileio_fsync(thr, loff, data_len, cmd); break; } } @@ -608,7 +738,7 @@ case VERIFY: case VERIFY_12: case VERIFY_16: - fileio_exec_verify(cmd, loff); + fileio_exec_verify(cmd, thr, loff); break; case MODE_SENSE: case MODE_SENSE_10: @@ -629,7 +759,21 @@ case RESERVE_10: case RELEASE: case RELEASE_10: + case TEST_UNIT_READY: break; + case INQUIRY: + fileio_exec_inquiry(cmd); + break; + case READ_CAPACITY: + fileio_exec_read_capacity(cmd); + break; + case SERVICE_ACTION_IN: + if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) { + fileio_exec_read_capacity16(cmd); + break; + } + /* else go through */ + case REPORT_LUNS: default: TRACE_DBG("Invalid opcode %d", opcode); scst_set_cmd_error(cmd, @@ -643,160 +787,13 @@ cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); out: - TRACE_EXIT(); - return; -} + if (likely(thr != NULL)) + scst_thr_data_put(&thr->hdr); -static inline int test_cmd_list(struct scst_fileio_tgt_dev *ftgt_dev) -{ - int res = !list_empty(&ftgt_dev->fdev_cmd_list) || - unlikely(kthread_should_stop()); - return res; -} - -static int fileio_cmd_thread(void *arg) -{ - struct scst_fileio_tgt_dev *ftgt_dev = (struct scst_fileio_tgt_dev*)arg; - - TRACE_ENTRY(); - - set_user_nice(current, 10); - current->flags |= PF_NOFREEZE; - - spin_lock_bh(&ftgt_dev->fdev_lock); - while (!kthread_should_stop()) { - wait_queue_t wait; - struct scst_cmd *cmd; - init_waitqueue_entry(&wait, current); - - if (!test_cmd_list(ftgt_dev)) { - add_wait_queue_exclusive(&ftgt_dev->fdev_waitQ, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (test_cmd_list(ftgt_dev)) - break; - spin_unlock_bh(&ftgt_dev->fdev_lock); - schedule(); - spin_lock_bh(&ftgt_dev->fdev_lock); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&ftgt_dev->fdev_waitQ, &wait); - } - - while (!list_empty(&ftgt_dev->fdev_cmd_list)) { - cmd = list_entry(ftgt_dev->fdev_cmd_list.next, - typeof(*cmd), fileio_cmd_list_entry); - cmd->fileio_in_list = 0; - list_del(&cmd->fileio_cmd_list_entry); - spin_unlock_bh(&ftgt_dev->fdev_lock); - fileio_do_job(cmd); - spin_lock_bh(&ftgt_dev->fdev_lock); - } - } - spin_unlock_bh(&ftgt_dev->fdev_lock); - - /* - * If kthread_should_stop() is true, we are guaranteed to be in - * suspended activity state, so fdev_cmd_list must be empty. - */ - sBUG_ON(!list_empty(&ftgt_dev->fdev_cmd_list)); - TRACE_EXIT(); - return 0; + return SCST_EXEC_COMPLETED; } -static int fileio_attach_tgt(struct scst_tgt_dev *tgt_dev) -{ - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)tgt_dev->acg_dev->dev->dh_priv; - struct scst_fileio_tgt_dev *ftgt_dev; - int res = 0; - - TRACE_ENTRY(); - - ftgt_dev = kzalloc(sizeof(*ftgt_dev), GFP_KERNEL); - if (ftgt_dev == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of per-session " - "virtual device failed"); - res = -ENOMEM; - goto out; - } - - spin_lock_init(&ftgt_dev->fdev_lock); - INIT_LIST_HEAD(&ftgt_dev->fdev_cmd_list); - init_waitqueue_head(&ftgt_dev->fdev_waitQ); - ftgt_dev->virt_dev = virt_dev; - - if (!virt_dev->cdrom_empty && !virt_dev->nullio) { - ftgt_dev->fd = fileio_open(virt_dev); - if (IS_ERR(ftgt_dev->fd)) { - res = PTR_ERR(ftgt_dev->fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", - virt_dev->file_name, res); - goto out_free; - } - } else - ftgt_dev->fd = NULL; - - /* - * Only ONE thread must be run here, otherwise the commands could - * be executed out of order !! - */ - ftgt_dev->cmd_thread = kthread_run(fileio_cmd_thread, ftgt_dev, "scst_fileio"); - if (IS_ERR(ftgt_dev->cmd_thread)) { - PRINT_ERROR_PR("kthread_run failed to create %s", "scst_fileio"); - res = PTR_ERR(ftgt_dev->cmd_thread); - goto out_free_close; - } - - tgt_dev->dh_priv = ftgt_dev; - - down(&virt_dev->ftgt_list_mutex); - list_add_tail(&ftgt_dev->ftgt_list_entry, - &virt_dev->ftgt_list); - up(&virt_dev->ftgt_list_mutex); - -out: - TRACE_EXIT_RES(res); - return res; - -out_free_close: - if (ftgt_dev->fd) - filp_close(ftgt_dev->fd, NULL); - -out_free: - kfree(ftgt_dev); - goto out; -} - -static void fileio_detach_tgt(struct scst_tgt_dev *tgt_dev) -{ - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)tgt_dev->dh_priv; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)tgt_dev->acg_dev->dev->dh_priv; - - TRACE_ENTRY(); - - down(&virt_dev->ftgt_list_mutex); - list_del(&ftgt_dev->ftgt_list_entry); - up(&virt_dev->ftgt_list_mutex); - - kthread_stop(ftgt_dev->cmd_thread); - - if (ftgt_dev->fd) - filp_close(ftgt_dev->fd, NULL); - - if (ftgt_dev->iv != NULL) - kfree(ftgt_dev->iv); - - kfree(ftgt_dev); - - tgt_dev->dh_priv = NULL; - - TRACE_EXIT(); -} - /******************************************************************** * Function: disk_fileio_parse * @@ -872,112 +869,7 @@ return res; } -static inline void fileio_queue_cmd(struct scst_cmd *cmd) -{ - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd->tgt_dev->dh_priv; - spin_lock_bh(&ftgt_dev->fdev_lock); - TRACE_DBG("Pushing cmd %p to IO thread", cmd); - list_add_tail(&cmd->fileio_cmd_list_entry, - &ftgt_dev->fdev_cmd_list); - cmd->fileio_in_list = 1; - spin_unlock_bh(&ftgt_dev->fdev_lock); - wake_up(&ftgt_dev->fdev_waitQ); -} - /******************************************************************** - * Function: disk_fileio_exec - * - * Argument: - * - * Returns : always SCST_EXEC_COMPLETED, real status is in error condition - * in command - * - * Description: - ********************************************************************/ -static int disk_fileio_exec(struct scst_cmd *cmd) -{ - int delayed = 0; - int opcode = cmd->cdb[0]; - - TRACE_ENTRY(); - - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - - /* - * !! - * Only commands that unsensible to the execution order could be - * performed here, in place. Other ones must be passed to the - * thread. - * !! - */ - switch (opcode) { - case INQUIRY: - fileio_exec_inquiry(cmd); - break; - case READ_CAPACITY: - fileio_exec_read_capacity(cmd); - break; - case SERVICE_ACTION_IN: - if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) - fileio_exec_read_capacity16(cmd); - else - goto def; - break; - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case WRITE_VERIFY_16: - /* fall through */ - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - /* could move READ ONLY check up to here (currenlty in do_job()) */ - /* fall through */ - case MODE_SENSE: - case MODE_SENSE_10: - case MODE_SELECT: - case MODE_SELECT_10: - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case SYNCHRONIZE_CACHE: - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - case START_STOP: - case RESERVE: - case RESERVE_10: - case RELEASE: - case RELEASE_10: - fileio_queue_cmd(cmd); - delayed = 1; - break; - case TEST_UNIT_READY: - break; - case REPORT_LUNS: -def: - default: - TRACE_DBG("Invalid opcode 0x%02x", opcode); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); - } - - if (!delayed) { - cmd->completed = 1; - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - } - - TRACE_EXIT(); - return SCST_EXEC_COMPLETED; -} - -/******************************************************************** * Function: cdrom_fileio_parse * * Argument: @@ -1057,7 +949,6 @@ ********************************************************************/ static int cdrom_fileio_exec(struct scst_cmd *cmd) { - int delayed = 0; int opcode = cmd->cdb[0]; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; @@ -1073,84 +964,33 @@ TRACE_DBG("%s", "CDROM empty"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_not_ready)); - goto out; + goto out_complete; } - /* - * No protection is necessary, because media_changed set only - * in suspended state and exec() is serialized - */ if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) && (cmd->cdb[0] != REQUEST_SENSE) && (cmd->cdb[0] != REPORT_LUNS)) { - virt_dev->media_changed = 0; - TRACE_DBG("%s", "Reporting media changed"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_medium_changed_UA)); - goto out; + spin_lock(&virt_dev->flags_lock); + if (virt_dev->media_changed) { + virt_dev->media_changed = 0; + TRACE_DBG("%s", "Reporting media changed"); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_medium_changed_UA)); + spin_unlock(&virt_dev->flags_lock); + goto out_complete; + } + spin_unlock(&virt_dev->flags_lock); } - /* - * !! - * Only commands that unsensible to the execution order could be - * performed here, in place. Other ones must be passed to the - * thread. - * !! - */ + fileio_do_job(cmd); - switch (opcode) { - case INQUIRY: - fileio_exec_inquiry(cmd); - break; - case READ_CAPACITY: - fileio_exec_read_capacity(cmd); - break; - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case WRITE_VERIFY_16: - /* fall through */ - case MODE_SENSE: - case MODE_SENSE_10: - case MODE_SELECT: - case MODE_SELECT_10: - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - case START_STOP: - case RESERVE: - case RESERVE_10: - case RELEASE: - case RELEASE_10: - case ALLOW_MEDIUM_REMOVAL: - case READ_TOC: - fileio_queue_cmd(cmd); - delayed = 1; - break; - case TEST_UNIT_READY: - break; - case REPORT_LUNS: - default: - TRACE_DBG("Invalid opcode 0x%02x", opcode); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); - } - out: - if (!delayed) { - cmd->completed = 1; - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - } - TRACE_EXIT(); return SCST_EXEC_COMPLETED; + +out_complete: + cmd->completed = 1; + cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); + goto out; } static void fileio_exec_inquiry(struct scst_cmd *cmd) @@ -1566,41 +1406,18 @@ static int fileio_set_wt(struct scst_fileio_dev *virt_dev, int wt) { int res = 0; - struct scst_fileio_tgt_dev *ftgt_dev; - struct file *fd; TRACE_ENTRY(); if ((virt_dev->wt_flag == wt) || virt_dev->nullio) goto out; + spin_lock(&virt_dev->flags_lock); virt_dev->wt_flag = wt; + spin_unlock(&virt_dev->flags_lock); - scst_suspend_activity(); + scst_dev_del_all_thr_data(virt_dev->dev); - down(&virt_dev->ftgt_list_mutex); - list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, - ftgt_list_entry) - { - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d, " - "unable to change the cache mode", - virt_dev->file_name, res); - up(&virt_dev->ftgt_list_mutex); - res = 0; /* ?? ToDo */ - goto out_resume; - } - if (ftgt_dev->fd) - filp_close(ftgt_dev->fd, NULL); - ftgt_dev->fd = fd; - } - up(&virt_dev->ftgt_list_mutex); - -out_resume: - scst_resume_activity(); - out: TRACE_EXIT_RES(res); return res; @@ -1885,10 +1702,7 @@ TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]); - /* - * No protection here, because in cdrom_fileio_change() the - * activity is suspended and exec() is serialized - */ + spin_lock(&virt_dev->flags_lock); if (cmd->dev->handler->type == TYPE_ROM) virt_dev->prevent_allow_medium_removal = cmd->cdb[4] & 0x01 ? 1 : 0; @@ -1898,21 +1712,22 @@ scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); } + spin_unlock(&virt_dev->flags_lock); return; } -static int fileio_fsync(struct scst_fileio_tgt_dev *ftgt_dev, +static int fileio_fsync(struct scst_fileio_thr *thr, loff_t loff, loff_t len, struct scst_cmd *cmd) { int res = 0; - struct file *file = ftgt_dev->fd; + struct file *file = thr->fd; struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = file->f_mapping; TRACE_ENTRY(); - if (ftgt_dev->virt_dev->nv_cache) + if (thr->virt_dev->nv_cache) goto out; res = sync_page_range(inode, mapping, loff, len); @@ -1932,25 +1747,25 @@ } static struct iovec *fileio_alloc_iv(struct scst_cmd *cmd, - struct scst_fileio_tgt_dev *ftgt_dev) + struct scst_fileio_thr *thr) { int iv_count; iv_count = scst_get_buf_count(cmd); - if (iv_count > ftgt_dev->iv_count) { - if (ftgt_dev->iv != NULL) - kfree(ftgt_dev->iv); - ftgt_dev->iv = kmalloc(sizeof(*ftgt_dev->iv) * iv_count, GFP_KERNEL); - if (ftgt_dev->iv == NULL) { + if (iv_count > thr->iv_count) { + if (thr->iv != NULL) + kfree(thr->iv); + thr->iv = kmalloc(sizeof(*thr->iv) * iv_count, GFP_KERNEL); + if (thr->iv == NULL) { PRINT_ERROR_PR("Unable to allocate iv (%d)", iv_count); scst_set_busy(cmd); goto out; } - ftgt_dev->iv_count = iv_count; + thr->iv_count = iv_count; } out: - return ftgt_dev->iv; + return thr->iv; } /* @@ -1995,7 +1810,8 @@ } #endif -static void fileio_exec_read(struct scst_cmd *cmd, loff_t loff) +static void fileio_exec_read(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff) { mm_segment_t old_fs; loff_t err; @@ -2003,15 +1819,13 @@ uint8_t *address; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd->tgt_dev->dh_priv; - struct file *fd = ftgt_dev->fd; + struct file *fd = thr->fd; struct iovec *iv; int iv_count, i; TRACE_ENTRY(); - iv = fileio_alloc_iv(cmd, ftgt_dev); + iv = fileio_alloc_iv(cmd, thr); if (iv == NULL) goto out; @@ -2085,7 +1899,8 @@ return; } -static void fileio_exec_write(struct scst_cmd *cmd, loff_t loff) +static void fileio_exec_write(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff) { mm_segment_t old_fs; loff_t err; @@ -2093,15 +1908,13 @@ uint8_t *address; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd->tgt_dev->dh_priv; - struct file *fd = ftgt_dev->fd; + struct file *fd = thr->fd; struct iovec *iv, *eiv; int iv_count, eiv_count; TRACE_ENTRY(); - iv = fileio_alloc_iv(cmd, ftgt_dev); + iv = fileio_alloc_iv(cmd, thr); if (iv == NULL) goto out; @@ -2209,7 +2022,8 @@ return; } -static void fileio_exec_verify(struct scst_cmd *cmd, loff_t loff) +static void fileio_exec_verify(struct scst_cmd *cmd, + struct scst_fileio_thr *thr, loff_t loff) { mm_segment_t old_fs; loff_t err; @@ -2218,14 +2032,12 @@ int compare; struct scst_fileio_dev *virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd->tgt_dev->dh_priv; - struct file *fd = ftgt_dev->fd; + struct file *fd = thr->fd; uint8_t *mem_verify = NULL; TRACE_ENTRY(); - if (fileio_fsync(ftgt_dev, loff, cmd->bufflen, cmd) != 0) + if (fileio_fsync(thr, loff, cmd->bufflen, cmd) != 0) goto out; /* @@ -2325,35 +2137,6 @@ return; } -/* No locks supposed to be held, thread context */ -static int fileio_task_mgmt_fn(struct scst_mgmt_cmd *mcmd, - struct scst_tgt_dev *tgt_dev) -{ - int res = SCST_DEV_TM_NOT_COMPLETED; - - TRACE_ENTRY(); - - if (mcmd->fn == SCST_ABORT_TASK) { - struct scst_cmd *cmd_to_abort = mcmd->cmd_to_abort; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)cmd_to_abort->tgt_dev->dh_priv; - - spin_lock_bh(&ftgt_dev->fdev_lock); - if (cmd_to_abort->fileio_in_list) { - TRACE(TRACE_MGMT, "Aborting cmd %p and moving it to " - "the queue head", cmd_to_abort); - list_del(&cmd_to_abort->fileio_cmd_list_entry); - list_add(&cmd_to_abort->fileio_cmd_list_entry, - &ftgt_dev->fdev_cmd_list); - wake_up(&ftgt_dev->fdev_waitQ); - } - spin_unlock_bh(&ftgt_dev->fdev_lock); - } - - TRACE_EXIT_RES(res); - return res; -} - static inline struct scst_fileio_dev *fileio_alloc_dev(void) { struct scst_fileio_dev *dev; @@ -2363,8 +2146,7 @@ "device failed"); goto out; } - INIT_LIST_HEAD(&dev->ftgt_list); - init_MUTEX(&dev->ftgt_list_mutex); + spin_lock_init(&dev->flags_lock); out: return dev; } @@ -2797,7 +2579,6 @@ static int cdrom_fileio_change(char *p, char *name) { struct file *fd; - struct scst_fileio_tgt_dev *ftgt_dev; loff_t err; mm_segment_t old_fs; struct scst_fileio_dev *virt_dev, *vv; @@ -2908,24 +2689,7 @@ if (!virt_dev->cdrom_empty) virt_dev->media_changed = 1; - down(&virt_dev->ftgt_list_mutex); - list_for_each_entry(ftgt_dev, &virt_dev->ftgt_list, ftgt_list_entry) { - if (!virt_dev->cdrom_empty && !virt_dev->nullio) { - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d, " - "closing the device", virt_dev->file_name, res); - up(&virt_dev->ftgt_list_mutex); - goto out_err_resume; - } - } else - fd = NULL; - if (ftgt_dev->fd) - filp_close(ftgt_dev->fd, NULL); - ftgt_dev->fd = fd; - } - up(&virt_dev->ftgt_list_mutex); + scst_dev_del_all_thr_data(virt_dev->dev); if (!virt_dev->cdrom_empty) { PRINT_INFO_PR("Changed SCSI target virtual cdrom %s " @@ -2958,13 +2722,6 @@ virt_dev->file_name = old_fn; kfree(fn); goto out_resume; - -out_err_resume: - virt_dev->file_name = old_fn; - kfree(fn); - scst_resume_activity(); - cdrom_fileio_close(name); - goto out; } /* @@ -3134,6 +2891,7 @@ TRACE_ENTRY(); devtype->module = THIS_MODULE; + res = scst_register_virtual_dev_driver(devtype); if (res < 0) goto out; @@ -3197,9 +2955,18 @@ static int __init init_scst_fileio_driver(void) { int res; + + fileio_thr_cachep = kmem_cache_create("fileio_thr_data", + sizeof(struct scst_fileio_thr), 0, FILEIO_SLAB_FLAGS, NULL, + NULL); + if (fileio_thr_cachep == NULL) { + res = -ENOMEM; + goto out; + } + res = init_scst_fileio(&disk_devtype_fileio); if (res != 0) - goto out; + goto out_free_slab; res = init_scst_fileio(&cdrom_devtype_fileio); if (res != 0) @@ -3210,6 +2977,9 @@ out_err: exit_scst_fileio(&disk_devtype_fileio, &disk_fileio_dev_list); + +out_free_slab: + kmem_cache_destroy(fileio_thr_cachep); goto out; } @@ -3217,6 +2987,7 @@ { exit_scst_fileio(&disk_devtype_fileio, &disk_fileio_dev_list); exit_scst_fileio(&cdrom_devtype_fileio, &cdrom_fileio_dev_list); + kmem_cache_destroy(fileio_thr_cachep); } module_init(init_scst_fileio_driver); Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/src/scst.c 2007-02-21 12:50:48 UTC (rev 91) @@ -445,6 +445,8 @@ goto out_up; } + dev->type = scsidp->type; + dev->rq_disk = alloc_disk(1); if (dev->rq_disk == NULL) { res = -ENOMEM; @@ -594,6 +596,7 @@ goto out; } + dev->type = dev_handler->type; dev->scsi_dev = NULL; dev->virt_name = dev_name; @@ -1274,7 +1277,7 @@ scst_scsi_op_list_init(); - for (i = 0; i < sizeof(scst_tasklets)/sizeof(scst_tasklets[0]); i++) { + for (i = 0; i < ARRAY_SIZE(scst_tasklets); i++) { spin_lock_init(&scst_tasklets[i].tasklet_lock); INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list); tasklet_init(&scst_tasklets[i].tasklet, (void*)scst_cmd_tasklet, @@ -1469,6 +1472,12 @@ EXPORT_SYMBOL(scst_alloc); EXPORT_SYMBOL(scst_free); +/* Tgt_dev's threads local storage */ +EXPORT_SYMBOL(scst_add_thr_data); +EXPORT_SYMBOL(scst_del_all_thr_data); +EXPORT_SYMBOL(scst_dev_del_all_thr_data); +EXPORT_SYMBOL(scst_find_thr_data); + /* * Other Commands */ Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-02-21 11:43:22 UTC (rev 90) +++ trunk/scst/src/scst_lib.c 2007-02-21 12:50:48 UTC (rev 91) @@ -22,6 +22,7 @@ #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/sched.h> +#include <linux/kthread.h> #include <asm/unistd.h> #include <asm/string.h> @@ -310,6 +311,74 @@ return res; } +static int scst_create_tgt_threads(struct scst_tgt_dev *tgt_dev) +{ + int res = 0; + static atomic_t major = ATOMIC_INIT(0); + char nm[12]; + + TRACE_ENTRY(); + + if ( !tgt_dev->dev->handler->dedicated_thread) + goto out; + + spin_lock_init(&tgt_dev->cmd_lists.cmd_list_lock); + INIT_LIST_HEAD(&tgt_dev->cmd_lists.active_cmd_list); + init_waitqueue_head(&tgt_dev->cmd_lists.cmd_list_waitQ); + + /* + * Only ONE thread must be run here, otherwise the commands could + * be executed out of order !! + */ + + strncpy(nm, tgt_dev->dev->handler->name, ARRAY_SIZE(nm)-1); + nm[ARRAY_SIZE(nm)-1] = '\0'; + tgt_dev->thread = kthread_run(scst_cmd_thread, &tgt_dev->cmd_lists, + "%sd%d", nm, atomic_inc_return(&major)); + if (IS_ERR(tgt_dev->thread)) { + res = PTR_ERR(tgt_dev->thread); + PRINT_ERROR_PR("kthread_create() failed: %d", res); + tgt_dev->thread = NULL; + goto out; + } + + down(&scst_suspend_mutex); + list_add_tail(&tgt_dev->cmd_lists.lists_list_entry, + &scst_cmd_lists_list); + up(&scst_suspend_mutex); + + tgt_dev->p_cmd_lists = &tgt_dev->cmd_lists; + +out: + TRACE_EXIT(); + return res; +} + +static void scst_stop_tgt_threads(struct scst_tgt_dev *tgt_dev) +{ + int rc; + + TRACE_ENTRY(); + + if (tgt_dev->thread == NULL) + goto out; + + rc = kthread_stop(tgt_dev->thread); + if (rc < 0) { + TRACE_MGMT_DBG("kthread_stop() failed: %d", rc); + } + + if (tgt_dev->p_cmd_lists == &tgt_dev->cmd_lists) { + down(&scst_suspend_mutex); + list_del(&tgt_dev->cmd_lists.lists_list_entry); + up(&scst_suspend_mutex); + } + +out: + TRACE_EXIT(); + return; +} + /* * No spin locks supposed to be held, scst_mutex - held. * The activity is suspended. @@ -319,7 +388,7 @@ { struct scst_tgt_dev *tgt_dev; struct scst_device *dev = acg_dev->dev; - int res; + int rc, i; TRACE_ENTRY(); @@ -337,11 +406,11 @@ memset(tgt_dev, 0, sizeof(*tgt_dev)); #endif + tgt_dev->dev = acg_dev->dev; + tgt_dev->lun = acg_dev->lun; tgt_dev->acg_dev = acg_dev; tgt_dev->sess = sess; atomic_set(&tgt_dev->cmd_count, 0); - atomic_set(&tgt_dev->curr_sn, 0); - tgt_dev->expected_sn = 1; tgt_dev->p_cmd_lists = &scst_main_cmd_lists; @@ -349,18 +418,26 @@ TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, " "SCST lun=%Ld", dev->scsi_dev->host->host_no, dev->scsi_dev->channel, dev->scsi_dev->id, - dev->scsi_dev->lun, (uint64_t)tgt_dev->acg_dev->lun); + dev->scsi_dev->lun, (uint64_t)tgt_dev->lun); } else { TRACE_MGMT_DBG("Virtual device SCST lun=%Ld", - (uint64_t)tgt_dev->acg_dev->lun); + (uint64_t)tgt_dev->lun); } spin_lock_init(&tgt_dev->tgt_dev_lock); INIT_LIST_HEAD(&tgt_dev->UA_list); + spin_lock_init(&tgt_dev->thr_data_lock); + INIT_LIST_HEAD(&tgt_dev->thr_data_list); spin_lock_init(&tgt_dev->sn_lock); INIT_LIST_HEAD(&tgt_dev->deferred_cmd_list); INIT_LIST_HEAD(&tgt_dev->skipped_sn_list); + INIT_LIST_HEAD(&tgt_dev->hq_cmd_list); + tgt_dev->expected_sn = 1; + tgt_dev->num_free_sn_slots = ARRAY_SIZE(tgt_dev->sn_slots); + tgt_dev->cur_sn_slot = &tgt_dev->sn_slots[0]; + for(i = 0; i < ARRAY_SIZE(tgt_dev->sn_slots); i++) + atomic_set(&tgt_dev->sn_slots[i], 0); if (dev->handler->parse_atomic && sess->tgt->tgtt->preprocessing_done_atomic) { @@ -394,15 +471,19 @@ tm_dbg_init_tgt_dev(tgt_dev, acg_dev); + rc = scst_create_tgt_threads(tgt_dev); + if (rc != 0) + goto out_free; + if (dev->handler && dev->handler->attach_tgt) { TRACE_DBG("Calling dev handler's attach_tgt(%p)", tgt_dev); - res = dev->handler->attach_tgt(tgt_dev); + rc = dev->handler->attach_tgt(tgt_dev); TRACE_DBG("%s", "Dev handler's attach_tgt() returned"); - if (res != 0) { + if (rc != 0) { PRINT_ERROR_PR("Device handler's %s attach_tgt() " - "failed: %d", dev->handler->name, res); - goto out_free; + "failed: %d", dev->handler->name, rc); + goto out_stop_free; } } @@ -417,6 +498,9 @@ TRACE_EXIT(); return tgt_dev; +out_stop_free: + scst_stop_tgt_threads(tgt_dev); + out_free: kmem_cache_free(scst_tgtd_cachep, tgt_dev); tgt_dev = NULL; @@ -431,7 +515,7 @@ */ void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss) { - struct scst_device *dev = tgt_dev->acg_dev->dev; + struct scst_device *dev = tgt_dev->dev; if (dev->dev_reserved && !test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags)) @@ -467,7 +551,7 @@ */ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev) { - struct scst_device *dev = tgt_dev->acg_dev->dev; + struct scst_device *dev = tgt_dev->dev; TRACE_ENTRY(); @@ -486,6 +570,8 @@ TRACE_DBG("%s", "Dev handler's detach_tgt() returned"); } + scst_stop_tgt_threads(tgt_dev); + kmem_cache_free(scst_tgtd_cachep, tgt_dev); TRACE_EXIT(); @@ -864,10 +950,10 @@ TRACE_ENTRY(); - if (tgt_dev->acg_dev->dev->scsi_dev == NULL) + if (tgt_dev->dev->scsi_dev == NULL) goto out; - scsi_dev = tgt_dev->acg_dev->dev->scsi_dev; + scsi_dev = tgt_dev->dev->scsi_dev; req = scsi_allocate_request(scsi_dev, GFP_KERNEL); if (req == NULL) { @@ -888,7 +974,7 @@ req->sr_use_sg = 0; req->sr_bufflen = 0; req->sr_buffer = NULL; - req->sr_request->rq_disk = tgt_dev->acg_dev->dev->rq_disk; + req->sr_request->rq_disk = tgt_dev->dev->rq_disk; req->sr_sense_buffer[0] = 0; TRACE(TRACE_DEBUG | TRACE_SCSI, "Sending RELEASE req %p to SCSI " @@ -910,10 +996,10 @@ TRACE_ENTRY(); - if (tgt_dev->acg_dev->dev->scsi_dev == NULL) + if (tgt_dev->dev->scsi_dev == NULL) goto out; - scsi_dev = tgt_dev->acg_dev->dev->scsi_dev; + scsi_dev = tgt_dev->dev->scsi_dev; memset(cdb, 0, sizeof(cdb)); cdb[0] = RELEASE; @@ -1076,7 +1162,7 @@ atomic_set(&cmd->cmd_ref, 1); cmd->cmd_lists = &scst_main_cmd_lists; - cmd->queue_type = SCST_CMD_QUEUE_UNTAGGED; + cmd->queue_type = SCST_CMD_QUEUE_SIMPLE; cmd->timeout = SCST_DEFAULT_TIMEOUT; cmd->retries = 1; cmd->data_len = -1; @@ -1156,19 +1242,18 @@ if (likely(cmd->tgt_dev != NULL)) { #ifdef EXTRACHECKS - if (cmd->sent_to_midlev == 0) { - PRINT_ERROR_PR("Finishing not executed cmd (opcode %d, " - "target %s, lun %Ld, sn %d, expected_sn %d)", - cmd->cdb[0], cmd->tgtt->name, (uint64_t)cmd->lun, + if (unlikely(!cmd->sent_to_midlev)) { + PRINT_ERROR_PR("Finishing not executed cmd %p (opcode " + "%d, target %s, lun %Ld, sn %d, expected_sn %d)", + cmd, cmd->cdb[0], cmd->tgtt->name, (uint64_t)cmd->lun, cmd->sn, cmd->tgt_dev->expected_sn); - scst_inc_expected_sn_unblock(cmd->tgt_dev, cmd); + scst_unblock_deferred(cmd->tgt_dev, cmd); } #endif if (unlikely(cmd->out_of_sn)) { - TRACE(TRACE_SCSI_SERIALIZING, "Out of SN " - "cmd %p (tag %d, sn %d), destroy=%d", cmd, - cmd->tag, cmd->sn, destroy); + TRACE_SN("Out of SN cmd %p (tag %d, sn %d), " + "destroy=%d", cmd, cmd->tag, cmd->sn, destroy); destroy = test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED, &cmd->cmd_flags); } @@ -1751,11 +1836,12 @@ /* Clear RESERVE'ation, if necessary */ if (dev->dev_reserved) { + /* Either scst_mutex held or exclude_cmd non-NULL */ list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { TRACE(TRACE_MGMT, "Clearing RESERVE'ation for tgt_dev " - "lun %d", tgt_dev->acg_dev->lun); + "lun %d", tgt_dev->lun); clear_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags); } @@ -1791,7 +1877,7 @@ continue; if ((cmd->tgt_dev == tgt_dev) || ((cmd->tgt_dev == NULL) && - (cmd->lun == tgt_dev->acg_dev->lun))) { + (cmd->lun == tgt_dev->lun))) { scst_abort_cmd(cmd, mcmd, (tgt_dev->sess != originator), 0); } @@ -1964,7 +2050,7 @@ list_for_each_entry_safe(UA_entry, t, &tgt_dev->UA_list, UA_list_entry) { TRACE_MGMT_DBG("Clearing UA for tgt_dev lun %d", - tgt_dev->acg_dev->lun); + tgt_dev->lun); list_del(&UA_entry->UA_list_entry); kfree(UA_entry); } @@ -1975,57 +2061,205 @@ return; } -struct scst_cmd *__scst_check_deferred_commands(struct scst_tgt_dev *tgt_dev, - int expected_sn) +/* sn_lock supposed to be held and IRQ off */ +static inline int __scst_check_hq_cmd(struct scst_cmd *cmd) { - struct scst_cmd *cmd = NULL, *tcmd; + struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; + struct scst_cmd *hq; + int res; - if (tgt_dev->def_cmd_count == 0) - goto out; + TRACE_ENTRY(); - spin_lock_bh(&tgt_dev->sn_lock); + /* According to SAM, the latest HQ cmd shall pass first */ + hq = list_entry(tgt_dev->hq_cmd_list.next, typeof(*hq), + sn_cmd_list_entry); + if ((cmd == hq) && !test_bit(SCST_TGT_DEV_HQ_ACTIVE, + &tgt_dev->tgt_dev_flags)) { + TRACE_SN("Passing HQ cmd %p", cmd); + res = 1; + list_del(&cmd->sn_cmd_list_entry); + set_bit(SCST_TGT_DEV_HQ_ACTIVE, &tgt_dev->tgt_dev_flags); + } else { + TRACE_SN("Defer HQ cmd %p", cmd); + res = 0; + cmd->hq_deferred = 1; + tgt_dev->def_cmd_count++; + } + TRACE_EXIT_RES(res); + return res; +} + +int scst_check_hq_cmd(struct scst_cmd *cmd) +{ + struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; + int res; + + spin_lock_irq(&tgt_dev->sn_lock); + res = __scst_check_hq_cmd(cmd); + spin_unlock_irq(&tgt_dev->sn_lock); + + return res; +} + +/* No locks */ +struct scst_cmd *__scst_check_deferred_commands(struct scst_tgt_dev *tgt_dev) +{ + struct scst_cmd *res = NULL, *cmd, *t; + int expected_sn = tgt_dev->expected_sn; + + spin_lock_irq(&tgt_dev->sn_lock); + + if (unlikely(test_bit(SCST_TGT_DEV_HQ_ACTIVE, &tgt_dev->tgt_dev_flags))) { + if (!list_empty(&tgt_dev->hq_cmd_list)) { + int rc; + cmd = list_entry(tgt_dev->hq_cmd_list.next, + typeof(*cmd), sn_cmd_list_entry); + if (cmd->hq_deferred) { + TRACE_SN("Releasing deferred HQ cmd %p", cmd); + tgt_dev->def_cmd_count--; + cmd->hq_deferred = 0; + res = cmd; + /* + * Since __scst_check_hq_cmd() is inline, a lot + * of code should be optimized out + */ + clear_bit(SCST_TGT_DEV_HQ_ACTIVE, + &tgt_dev->tgt_dev_flags); + rc = __scst_check_hq_cmd(res); + EXTRACHECKS_BUG_ON(rc != 1); + goto out_unlock; + } + } + TRACE_SN("Turning OFF hq_cmd_active (tgt_dev %p)", + tgt_dev); + clear_bit(SCST_TGT_DEV_HQ_ACTIVE, &tgt_dev->tgt_dev_flags); + } + restart: - list_for_each_entry(tcmd, &tgt_dev->deferred_cmd_list, + list_for_each_entry_safe(cmd, t, &tgt_dev->deferred_cmd_list, sn_cmd_list_entry) { - if (tcmd->sn == expected_sn) { - TRACE(TRACE_SCSI_SERIALIZING, - "Deferred command sn %d found", tcmd->sn); + if (cmd->sn == expected_sn) { + TRACE_SN("Deferred command %p (sn %d) found", + cmd, cmd->sn); tgt_dev->def_cmd_count--; - list_del(&tcmd->sn_cmd_list_entry); - cmd = tcmd; - goto out_unlock; + list_del(&cmd->sn_cmd_list_entry); + if (res == NULL) + res = cmd; + else { + spin_lock(&cmd->cmd_lists->cmd_list_lock); + TRACE_SN("Adding cmd %p to active cmd list", + cmd); + list_add_tail(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); + wake_up(&cmd->cmd_lists->cmd_list_waitQ); + spin_unlock(&cmd->cmd_lists->cmd_list_lock); + } } } + if (res != NULL) + goto out_unlock; - list_for_each_entry(tcmd, &tgt_dev->skipped_sn_list, + list_for_each_entry(cmd, &tgt_dev->skipped_sn_list, sn_cmd_list_entry) { - if (tcmd->sn == expected_sn) { + if (cmd->sn == expected_sn) { + atomic_t *slot = cmd->sn_slot; /* - * !! At this point any pointer in tcmd, except !! - * !! sn_cmd_list_entry, could be already destroyed !! + * !! At this point any pointer in cmd, except !! + * !! sn_slot and sn_cmd_list_entry, could be !! + * !! already destroyed !! */ - TRACE(TRACE_SCSI_SERIALIZING, - "cmd %p (tag %d) with skipped sn %d found", tcmd, - tcmd->tag, tcmd->sn); + TRACE_SN("cmd %p (tag %d) with skipped sn %d found", + cmd, cmd->tag, cmd->sn); tgt_dev->def_cmd_count--; - list_del(&tcmd->sn_cmd_list_entry); + list_del(&cmd->sn_cmd_list_entry); + spin_unlock_irq(&tgt_dev->sn_lock); + EXTRACHECKS_BUG_ON(cmd->head_of_queue); if (test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED, - &tcmd->cmd_flags)) { - scst_destroy_put_cmd(tcmd); + &cmd->cmd_flags)) { + scst_destroy_put_cmd(cmd); } - expected_sn = __scst_inc_expected_sn(tgt_dev); + scst_inc_expected_sn(tgt_dev, slot); + expected_sn = tgt_dev->expected_sn; + spin_lock_irq(&tgt_dev->sn_lock); goto restart; } } out_unlock: - spin_unlock_bh(&tgt_dev->sn_lock); + spin_unlock_irq(&tgt_dev->sn_lock); + return res; +} -out: - return cmd; +void scst_add_thr_data(struct scst_tgt_dev *tgt_dev, + struct scst_thr_data_hdr *data, + void (*free_fn) (struct scst_thr_data_hdr *data)) +{ + data->pid = current->pid; + atomic_set(&data->ref, 1); + EXTRACHECKS_BUG_ON(free_fn == NULL); + data->free_fn = free_fn; + spin_lock(&tgt_dev->thr_data_lock); + list_add_tail(&data->thr_data_list_entry, &tgt_dev->thr_data_list); + spin_unlock(&tgt_dev->thr_data_lock); } +void scst_del_all_thr_data(struct scst_tgt_dev *tgt_dev) +{ + spin_lock(&tgt_dev->thr_data_lock); + while (!list_empty(&tgt_dev->thr_data_list)) { + struct scst_thr_data_hdr *d = list_entry( + tgt_dev->thr_data_list.next, typeof(*d), + thr_data_list_entry); + list_del(&d->thr_data_list_entry); + spin_unlock(&tgt_dev->thr_data_lock); + scst_thr_data_put(d); + spin_lock(&tgt_dev->thr_data_lock); + } + spin_unlock(&tgt_dev->thr_data_lock); + return; +} + +void scst_dev_del_all_thr_data(struct scst_device *dev) +{ + struct scst_tgt_dev *tgt_dev; + + TRACE_ENTRY(); + + /* + * This is read-only function for dev->dev_tgt_dev_list, so + * suspending the activity isn't necessary. + */ + + down(&scst_mutex); + + list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, + dev_tgt_dev_list_entry) { + scst_del_all_thr_data(tgt_dev); + } + + up(&scst_mutex); + + TRACE_EXIT(); + return; +} + +struct scst_thr_data_hdr *scst_find_thr_data(struct scst_tgt_dev *tgt_dev) +{ + struct scst_thr_data_hdr *res = NULL, *d; + + spin_lock(&tgt_dev->thr_data_lock); + list_for_each_entry(d, &tgt_dev->thr_data_list, thr_data_list_entry) { + if (d->pid == current->pid) { + res = d; + scst_thr_data_get(res); + break; + } + } + spin_unlock(&tgt_dev->thr_data_lock); + return res; +} + /* No locks */ int scst_inc_on_dev_cmd(struct scst_cmd *cmd) { @@ -2041,7 +2275,7 @@ if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) goto out_unlock; if (dev->block_count > 0) { - scst_dec_on_dev_cmd(cmd); + scst_dec_on_dev_cmd(cmd, 0); TRACE_MGMT_DBG("Delaying cmd %p due to blocking or serializing" "(tag %d, dev %p)", cmd, cmd->tag, dev); list_add_tail(&cmd->blocked_cmd_list_entry, @@ -2061,7 +2295,7 @@ goto out_unlock; barrier(); /* to reread block_count */ if (dev->block_count > 0) { - scst_dec_on_dev_cmd(cmd); + scst_dec_on_dev_cmd(cmd, 0); TRACE_MGMT_DBG("Delaying cmd %p due to blocking or " "serializing (tag %d, dev %p)", cmd, cmd->tag, dev); @@ -2118,7 +2352,7 @@ * Since only one cmd per time is being executed, expected_sn * can't change behind us, if the corresponding cmd is in * blocked_cmd_list, but we could be called before - * __scst_inc_expected_sn(). + * scst_inc_expected_sn(). */ if (likely(!cmd->internal) && likely(!cmd->retry)) { int expected_sn; @@ -2153,8 +2387,12 @@ list_del(&cmd->blocked_cmd_list_entry); TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd); spin_lock(&cmd->cmd_lists->cmd_list_lock); - list_add_tail(&cmd->cmd_list_entry, - &cmd->cmd_lists->active_cmd_list); + if (unlikely(cmd->head_of_queue)) + list_add(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); + else + list_add_tail(&cmd->cmd_list_entry, + &cmd->cmd_lists->active_cmd_list); wake_up(&cmd->cmd_lists->cmd_list_waitQ); spin_unlock(&cmd->cmd_lists->cmd_list_lock); } @@ -2165,30 +2403,36 @@ return; } -static struct scst_cmd *__scst_inc_expected_sn_unblock( +stat... [truncated message content] |
From: <vl...@us...> - 2007-02-21 15:49:01
|
Revision: 93 http://svn.sourceforge.net/scst/?rev=93&view=rev Author: vlnb Date: 2007-02-21 07:48:58 -0800 (Wed, 21 Feb 2007) Log Message: ----------- Rename FILEIO -> VDISK, part 1 Modified Paths: -------------- trunk/scst/README trunk/scst/ToDo trunk/scst/include/scsi_tgt.h trunk/scst/kernel/in-tree/Kconfig.scsi_tgt trunk/scst/kernel/in-tree/Makefile.scsi_tgt trunk/scst/src/Makefile trunk/scst/src/dev_handlers/Makefile trunk/scst/src/scst.c trunk/scst/src/scst_priv.h Added Paths: ----------- trunk/scst/src/dev_handlers/scst_vdisk.c Removed Paths: ------------- trunk/scst/src/dev_handlers/scst_fileio.c Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/README 2007-02-21 15:48:58 UTC (rev 93) @@ -13,7 +13,7 @@ SCST looks to be quite stable (for beta) and useful. It supports disks (SCSI type 0), tapes (type 1), processor (type 3), CDROM's (type 5), MO disks (type 7), medium changers (type 8) and RAID controller (type 0xC) -as well as FILEIO and "performance" device handlers. In addition, it +as well as VDISK and "performance" device handlers. In addition, it supports advanced per-initiator access and devices visibility management, so different initiators could see different set of devices with different access permissions. See below for details. @@ -34,7 +34,7 @@ in the kernel. Patch 26_scst-2.6.X.patch from "kernel" directory does that. If it doesn't apply to your kernel, apply it manually, it only adds one of those functions and nothing more. You may not patch the -kernel if STRICT_SERIALIZING or FILEIO_ONLY are defined during the +kernel if STRICT_SERIALIZING or VDISK_ONLY are defined during the compilation (see their description below). To compile SCST type 'make'. It will build SCST itself and its device @@ -55,7 +55,7 @@ - scst_modisk - device handler for MO disks (type 7) - scst_changer - device handler for medium changers (type 8) - scst_raid - device handler for storage array controller (e.g. raid) (type C) - - scst_fileio - device handler for FILE IO (disk or ISO CD image). + - scst_vdisk - device handler for virtual disks (disk or ISO CD image). Then, to see your devices remotely, you need to add them to at least "Default" security group (see below how). By default, no local devices @@ -97,10 +97,10 @@ devices of this type, so they will be invisible for remote initiators (more precisely, "LUN not supported" sense code will be returned). -In addition to device handlers for real devices, there are FILEIO and +In addition to device handlers for real devices, there are VDISK and "performance" ones. -FILEIO device handler works over files on file systems and makes from +VDISK device handler works over files on file systems and makes from them virtual remotely available SCSI disks or CDROM's. In addition, it allows to work directly over a block device, e.g. local IDE or SCSI disk or ever disk partition, where there is no file systems overhead. Using @@ -111,7 +111,7 @@ disadvantage here that there is superfluous data copying between the cache and SCST's buffers. This issue is going to be addressed in the next release. Virtual CDROM's are useful for remote installation. See -below for details how to setup and use FILEIO device handler. +below for details how to setup and use VDISK device handler. "Performance" device handlers for disks, MO disks and tapes in their exec() method skip (pretend to execute) all READ and WRITE operations @@ -129,7 +129,7 @@ There are the following compilation options, that could be commented in/out in Makefile: - - FILEIO_ONLY - if defined, the pass-through device handlers + - VDISK_ONLY - if defined, the pass-through device handlers (scst_disk, scst_tape) will not work, but SCST will not require the kernel patching. Defined by default to ease new people try SCST on their kernels. @@ -288,27 +288,27 @@ group with LUN 0. - "echo "add disk1 1" >/proc/scsi_tgt/groups/Default/devices" will - add virtual FILEIO device with name "disk1" to "Default" group + add virtual VDISK device with name "disk1" to "Default" group with LUN 1. -FILEIO device handler ---------------------- +VDISK device handler +-------------------- -After loading FILEIO device handler creates in "/proc/scsi_tgt/" -subdirectories "disk_fileio" and "cdrom_fileio". They have similar layout: +After loading VDISK device handler creates in "/proc/scsi_tgt/" +subdirectories "vdisk" and "vcdrom". They have similar layout: - "trace_level" and "type" files as described for other dev handlers - - "help" file, which provides online help for FILEIO commands + - "help" file, which provides online help for VDISK commands - - "disk_fileio"/"cdrom_fileio" files, which on read provides - information of currently open device files. On write it supports the - following command: + - "vdisk"/"vcdrom" files, which on read provides information of + currently open device files. On write it supports the following + command: * "open NAME [PATH] [BLOCK_SIZE] [FLAGS]" - opens file "PATH" as device "NAME" with block size "BLOCK_SIZE" bytes with flags - "FLAGS". "PATH" could be empty only for FILEIO CDROM. "BLOCK_SIZE" - and "FLAGS" are valid only for disk FILEIO. The block size must be + "FLAGS". "PATH" could be empty only for VDISK CDROM. "BLOCK_SIZE" + and "FLAGS" are valid only for disk VDISK. The block size must be power of 2 and >= 512 bytes Default is 512. Possible flags: - WRITE_THROUGH - write back caching disabled @@ -340,12 +340,12 @@ * "close NAME" - closes device "NAME". - * "change NAME [PATH]" - changes a virtual CD in the FILEIO CDROM. + * "change NAME [PATH]" - changes a virtual CD in the VDISK CDROM. -For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/disk_fileio/disk_fileio" -will open file /vdisks/disk1 as virtual FILEIO disk with name "disk1". +For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/vdisk/vdisk" +will open file /vdisks/disk1 as virtual VDISK disk with name "disk1". -IMPORTANT: By default for performance reasons FILEIO devices use write back +IMPORTANT: By default for performance reasons VDISK devices use write back ========= caching policy. This is generally safe from the consistence of journaled file systems, laying over them, point of view, but your unsaved cached data will be lost in case of @@ -390,13 +390,13 @@ I. Currently maximum performance is possible only with real SCSI devices with several simultaneously executed commands (SCSI tagged queuing) or -performance handlers. If you have enough CPU power, FILEIO handler also +performance handlers. If you have enough CPU power, VDISK handler also could provide the same results, when aggregate throughput is close to the aggregate throughput locally on the target from the same disks. Also note, that currently IO subsystem in Linux implemented on such way, so a -FILEIO device over a single file occupied entire formatted with some +VDISK device over a single file occupied entire formatted with some file system device (eg /dev/hdc) could perform considerably better, than -a FILEIO device over /dev/hdc itself without the file system involved. +a VDISK device over /dev/hdc itself without the file system involved. II. In order to get the maximum performance you should: @@ -409,7 +409,7 @@ - Disable in Makefile EXTRACHECKS, TRACING, DEBUG_TGT, DEBUG_WORK_IN_THREAD -3. For device handlers, including FILEIO: +3. For device handlers, including VDISK: - Disable in Makefile TRACING, DEBUG @@ -445,13 +445,13 @@ expected. IMPORTANT: If you use on initiator some versions of Windows (at least W2K) -========= you can't get good write performance for FILEIO devices with +========= you can't get good write performance for VDISK devices with default 512 bytes block sizes. You could get about 10% of the expected one. This is because of "unusual" write access pattern, with which Windows'es write data and which is (simplifying) incompatible with how Linux page cache works, so for each write the corresponding block must be read first. - With 4096 bytes block sizes for FILEIO devices the write + With 4096 bytes block sizes for VDISK devices the write performance will be as expected. Actually, any system on initiator, not only Windows, will benefit from block size max(PAGE_SIZE, BLOCK_SIZE_ON_UNDERLYING_FS), where PAGE_SIZE Modified: trunk/scst/ToDo =================================================================== --- trunk/scst/ToDo 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/ToDo 2007-02-21 15:48:58 UTC (rev 93) @@ -3,7 +3,7 @@ - Kernel build integration (patch). - - Reimplement FILEIO handler with usage of async. read/write operations + - Reimplement VDISK handler with usage of async. read/write operations (in order to avoid unnecessary context switches) and direct access to the page cache (in order to avoid data copy between it and internal buffers). Requires modifications of the kernel. @@ -27,7 +27,7 @@ - Redone some semaphores with completion interface. - HIGHMEM cleanup. Looks like HIGHMEM usage doesn't worth the effort and - performance hit, at least until FILEIO handler doesn't use the page + performance hit, at least until VDISK handler doesn't use the page cache directly, so disable it for now, although the code looks ready. To enable it, set SCST_HIGHMEM in 1 in scst_priv.h. HIGHMEM is not supported on 2.4 and is not going to be. Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/include/scsi_tgt.h 2007-02-21 15:48:58 UTC (rev 93) @@ -1611,7 +1611,7 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type); /* - * Registers dev handler driver for virtual devices (eg FILEIO) + * Registers dev handler driver for virtual devices (eg VDISK) * Returns 0 on success or appropriate error code otherwise */ int scst_register_virtual_dev_driver(struct scst_dev_type *dev_type); Modified: trunk/scst/kernel/in-tree/Kconfig.scsi_tgt =================================================================== --- trunk/scst/kernel/in-tree/Kconfig.scsi_tgt 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/kernel/in-tree/Kconfig.scsi_tgt 2007-02-21 15:48:58 UTC (rev 93) @@ -56,7 +56,7 @@ ---help--- SCSI TARGET handler for raid storage array controller (raid) device. -config SCSI_TARGET_FILEIO +config SCSI_TARGET_VDISK tristate "SCSI target virtual disk and/or cdrom support" default SCSI_TARGET depends on SCSI && PROC_FS && SCSI_TARGET Modified: trunk/scst/kernel/in-tree/Makefile.scsi_tgt =================================================================== --- trunk/scst/kernel/in-tree/Makefile.scsi_tgt 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/kernel/in-tree/Makefile.scsi_tgt 2007-02-21 15:48:58 UTC (rev 93) @@ -15,4 +15,4 @@ obj-$(CONFIG_SCSI_TARGET_CHANGER) += scst_changer.o obj-$(CONFIG_SCSI_TARGET_RAID) += scst_raid.o obj-$(CONFIG_SCSI_TARGET_PROCESSOR) += scst_processor.o -obj-$(CONFIG_SCSI_TARGET_FILEIO) += scst_fileio.o +obj-$(CONFIG_SCSI_TARGET_VDISK ) += scst_vdisk.o Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/src/Makefile 2007-02-21 15:48:58 UTC (rev 93) @@ -95,7 +95,7 @@ #EXTRA_CFLAGS += -DSTRICT_SERIALIZING EXTRA_CFLAGS += -DEXTRACHECKS -#EXTRA_CFLAGS += -DFILEIO_ONLY +#EXTRA_CFLAGS += -DVDISK_ONLY #EXTRA_CFLAGS += -fno-inline Modified: trunk/scst/src/dev_handlers/Makefile =================================================================== --- trunk/scst/src/dev_handlers/Makefile 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/src/dev_handlers/Makefile 2007-02-21 15:48:58 UTC (rev 93) @@ -30,7 +30,7 @@ SCST_INC_DIR := $(SUBDIRS)/../include obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \ - scst_fileio.o scst_raid.o scst_processor.o + scst_vdisk.o scst_raid.o scst_processor.o obj-$(CONFIG_SCSI_TARGET_DISK) += scst_disk.o obj-$(CONFIG_SCSI_TARGET_TAPE) += scst_tape.o @@ -39,7 +39,7 @@ obj-$(CONFIG_SCSI_TARGET_CHANGER) += scst_changer.o obj-$(CONFIG_SCSI_TARGET_RAID) += scst_raid.o obj-$(CONFIG_SCSI_TARGET_PROCESSOR) += scst_processor.o -obj-$(CONFIG_SCSI_TARGET_FILEIO) += scst_fileio.o +obj-$(CONFIG_SCSI_TARGET_VDISK) += scst_vdisk.o else ifeq ($(KDIR),) Deleted: trunk/scst/src/dev_handlers/scst_fileio.c =================================================================== --- trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-21 15:09:25 UTC (rev 92) +++ trunk/scst/src/dev_handlers/scst_fileio.c 2007-02-21 15:48:58 UTC (rev 93) @@ -1,2996 +0,0 @@ -/* - * scst_fileio.c - * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> - * and Leonid Stoljar - * - * SCSI disk (type 0) and CDROM (type 5) dev handler using files - * on file systems (FILEIO) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2 - * of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <asm/uaccess.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/unistd.h> -#include <linux/smp_lock.h> -#include <linux/spinlock.h> -#include <linux/init.h> -#include <linux/uio.h> -#include <linux/proc_fs.h> -#include <linux/list.h> -#include <linux/ctype.h> -#include <linux/writeback.h> -#include <linux/vmalloc.h> -#include <asm/atomic.h> -#include <linux/kthread.h> - -#define LOG_PREFIX "dev_fileio" - -#include "scsi_tgt.h" - -#define TRACE_ORDER 0x80000000 - -static struct scst_proc_log fileio_proc_local_trace_tbl[] = -{ - { TRACE_ORDER, "order" }, - { 0, NULL } -}; -#define trace_log_tbl fileio_proc_local_trace_tbl - -#include "scst_dev_handler.h" - -#if defined(DEBUG) && defined(CONFIG_DEBUG_SLAB) -#define FILEIO_SLAB_FLAGS ( SLAB_RED_ZONE | SLAB_POISON ) -#else -#define FILEIO_SLAB_FLAGS 0L -#endif - -/* 8 byte ASCII Vendor of the FILE IO target */ -#define SCST_FIO_VENDOR "SCST_FIO" -/* 4 byte ASCII Product Revision Level of the FILE IO target - left aligned */ -#define SCST_FIO_REV " 096" - -#define READ_CAP_LEN 8 -#define READ_CAP16_LEN 12 - -#define MAX_USN_LEN 20 - -#define BYTCHK 0x02 - -#define INQ_BUF_SZ 128 -#define EVPD 0x01 -#define CMDDT 0x02 - -#define MSENSE_BUF_SZ 256 -#define DBD 0x08 /* disable block descriptor */ -#define WP 0x80 /* write protect */ -#define DPOFUA 0x10 /* DPOFUA bit */ -#define WCE 0x04 /* write cache enable */ - -#define PF 0x10 /* page format */ -#define SP 0x01 /* save pages */ -#define PS 0x80 /* parameter saveable */ - -#define BYTE 8 -#define DEF_DISK_BLOCKSIZE 512 -#define DEF_DISK_BLOCKSIZE_SHIFT 9 -#define DEF_CDROM_BLOCKSIZE 2048 -#define DEF_CDROM_BLOCKSIZE_SHIFT 11 -#define DEF_SECTORS_PER 63 -#define LEN_MEM (32 * 1024) -#define DISK_FILEIO_NAME "disk_fileio" -#define CDROM_FILEIO_NAME "cdrom_fileio" - -#define FILEIO_PROC_HELP "help" - -struct scst_fileio_dev { - uint32_t block_size; - uint64_t nblocks; - int block_shift; - loff_t file_size; /* in bytes */ - spinlock_t flags_lock; - /* - * Below flags are protected by flags_lock or suspended activity - * with scst_fileio_mutex. - */ - unsigned int rd_only_flag:1; - unsigned int wt_flag:1; - unsigned int nv_cache:1; - unsigned int o_direct_flag:1; - unsigned int media_changed:1; - unsigned int prevent_allow_medium_removal:1; - unsigned int nullio:1; - unsigned int cdrom_empty:1; - int virt_id; - char name[16+1]; /* Name of virtual device, - must be <= SCSI Model + 1 */ - char *file_name; /* File name */ - char *usn; - struct scst_device *dev; - struct list_head fileio_dev_list_entry; -}; - -struct scst_fileio_tgt_dev { - enum scst_cmd_queue_type last_write_cmd_queue_type; -}; - -struct scst_fileio_thr { - struct scst_thr_data_hdr hdr; - struct file *fd; - struct iovec *iv; - int iv_count; - struct scst_fileio_dev *virt_dev; -}; - -static struct kmem_cache *fileio_thr_cachep; - -static int fileio_attach(struct scst_device *dev); -static void fileio_detach(struct scst_device *dev); -static int fileio_attach_tgt(struct scst_tgt_dev *tgt_dev); -static void fileio_detach_tgt(struct scst_tgt_dev *tgt_dev); -static int disk_fileio_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); -static int fileio_do_job(struct scst_cmd *cmd); -static int cdrom_fileio_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); -static int cdrom_fileio_exec(struct scst_cmd *cmd); -static void fileio_exec_read(struct scst_cmd *cmd, - struct scst_fileio_thr *thr, loff_t loff); -static void fileio_exec_write(struct scst_cmd *cmd, - struct scst_fileio_thr *thr, loff_t loff); -static void fileio_exec_verify(struct scst_cmd *cmd, - struct scst_fileio_thr *thr, loff_t loff); -static void fileio_exec_read_capacity(struct scst_cmd *cmd); -static void fileio_exec_read_capacity16(struct scst_cmd *cmd); -static void fileio_exec_inquiry(struct scst_cmd *cmd); -static void fileio_exec_mode_sense(struct scst_cmd *cmd); -static void fileio_exec_mode_select(struct scst_cmd *cmd); -static void fileio_exec_read_toc(struct scst_cmd *cmd); -static void fileio_exec_prevent_allow_medium_removal(struct scst_cmd *cmd); -static int fileio_fsync(struct scst_fileio_thr *thr, - loff_t loff, loff_t len, struct scst_cmd *cmd); -static int disk_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type); -static int disk_fileio_write_proc(char *buffer, char **start, off_t offset, - int length, int *eof, struct scst_dev_type *dev_type); -static int cdrom_fileio_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type); -static int cdrom_fileio_write_proc(char *buffer, char **start, off_t offset, - int length, int *eof, struct scst_dev_type *dev_type); - -#define DISK_TYPE_FILEIO { \ - name: DISK_FILEIO_NAME, \ - type: TYPE_DISK, \ - parse_atomic: 1, \ - exec_atomic: 0, \ - dev_done_atomic: 1, \ - dedicated_thread: 1, \ - attach: fileio_attach, \ - detach: fileio_detach, \ - attach_tgt: fileio_attach_tgt, \ - detach_tgt: fileio_detach_tgt, \ - parse: disk_fileio_parse, \ - exec: fileio_do_job, \ - read_proc: disk_fileio_read_proc, \ - write_proc: disk_fileio_write_proc, \ -} - -#define CDROM_TYPE_FILEIO { \ - name: CDROM_FILEIO_NAME, \ - type: TYPE_ROM, \ - parse_atomic: 1, \ - exec_atomic: 0, \ - dev_done_atomic: 1, \ - dedicated_thread: 1, \ - attach: fileio_attach, \ - detach: fileio_detach, \ - attach_tgt: fileio_attach_tgt, \ - detach_tgt: fileio_detach_tgt, \ - parse: cdrom_fileio_parse, \ - exec: cdrom_fileio_exec, \ - read_proc: cdrom_fileio_read_proc, \ - write_proc: cdrom_fileio_write_proc,\ -} - -static DECLARE_MUTEX(scst_fileio_mutex); -static LIST_HEAD(disk_fileio_dev_list); -static LIST_HEAD(cdrom_fileio_dev_list); - -static struct scst_dev_type disk_devtype_fileio = DISK_TYPE_FILEIO; -static struct scst_dev_type cdrom_devtype_fileio = CDROM_TYPE_FILEIO; - -static char *disk_fileio_proc_help_string = - "echo \"open|close NAME [FILE_NAME [BLOCK_SIZE] [WRITE_THROUGH " - "READ_ONLY O_DIRECT NULLIO NV_CACHE]]\" >/proc/scsi_tgt/" - DISK_FILEIO_NAME "/" DISK_FILEIO_NAME "\n"; - -static char *cdrom_fileio_proc_help_string = - "echo \"open|change|close NAME [FILE_NAME]\" " - ">/proc/scsi_tgt/" CDROM_FILEIO_NAME "/" CDROM_FILEIO_NAME "\n"; - -/************************************************************** - * Function: fileio_open - * - * Argument: - * - * Returns : fd, use IS_ERR(fd) to get error status - * - * Description: - *************************************************************/ -static struct file *fileio_open(const struct scst_fileio_dev *virt_dev) -{ - int open_flags = 0; - struct file *fd; - - TRACE_ENTRY(); - - if (virt_dev->rd_only_flag) - open_flags |= O_RDONLY; - else - open_flags |= O_RDWR; - if (virt_dev->o_direct_flag) - open_flags |= O_DIRECT; - if (virt_dev->wt_flag) - open_flags |= O_SYNC; - TRACE_DBG("Opening file %s, flags 0x%x", virt_dev->file_name, open_flags); - fd = filp_open(virt_dev->file_name, O_LARGEFILE | open_flags, 0600); - - TRACE_EXIT(); - return fd; -} - -/************************************************************** - * Function: fileio_attach - * - * Argument: - * - * Returns : 1 if attached, error code otherwise - * - * Description: - *************************************************************/ -static int fileio_attach(struct scst_device *dev) -{ - int res = 0; - loff_t err; - mm_segment_t old_fs; - struct file *fd; - struct scst_fileio_dev *virt_dev = NULL, *vv; - struct list_head *fileio_dev_list; - - TRACE_ENTRY(); - - TRACE_DBG("virt_id %d (%s)", dev->virt_id, dev->virt_name); - - if (dev->virt_id == 0) { - PRINT_ERROR_PR("%s", "Not a virtual device"); - res = -EINVAL; - goto out; - } - - fileio_dev_list = (dev->handler->type == TYPE_DISK) ? - &disk_fileio_dev_list : - &cdrom_fileio_dev_list; - - /* - * scst_fileio_mutex must be already taken before - * scst_register_virtual_device() - */ - list_for_each_entry(vv, fileio_dev_list, fileio_dev_list_entry) { - if (strcmp(vv->name, dev->virt_name) == 0) { - virt_dev = vv; - break; - } - } - - if (virt_dev == NULL) { - PRINT_ERROR_PR("Device %s not found", dev->virt_name); - res = -EINVAL; - goto out; - } - - virt_dev->dev = dev; - - if (dev->handler->type == TYPE_ROM) - virt_dev->rd_only_flag = 1; - - if (!virt_dev->cdrom_empty) { - if (virt_dev->nullio) - err = 3LL*1024*1024*1024*1024/2; - else { - fd = fileio_open(virt_dev); - if (IS_ERR(fd)) { - res = PTR_ERR(fd); - PRINT_ERROR_PR("filp_open(%s) returned an error %d", - virt_dev->file_name, res); - goto out; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - if ((fd->f_op == NULL) || (fd->f_op->readv == NULL) || - (fd->f_op->writev == NULL)) -#else - if ((fd->f_op == NULL) || (fd->f_op->aio_read == NULL) || - (fd->f_op->aio_write == NULL)) -#endif - { - PRINT_ERROR_PR("%s", "Wrong f_op or FS doesn't have " - "required capabilities"); - res = -EINVAL; - filp_close(fd, NULL); - goto out; - } - - /* seek to end */ - old_fs = get_fs(); - set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); - } else { - err = default_llseek(fd, 0, 2/*SEEK_END*/); - } - set_fs(old_fs); - filp_close(fd, NULL); - if (err < 0) { - res = err; - PRINT_ERROR_PR("llseek %s returned an error %d", - virt_dev->file_name, res); - goto out; - } - } - virt_dev->file_size = err; - TRACE_DBG("size of file: %Ld", (uint64_t)err); - } else - virt_dev->file_size = 0; - - if (dev->handler->type == TYPE_DISK) { - virt_dev->nblocks = virt_dev->file_size >> virt_dev->block_shift; - } else { - virt_dev->block_size = DEF_CDROM_BLOCKSIZE; - virt_dev->block_shift = DEF_CDROM_BLOCKSIZE_SHIFT; - virt_dev->nblocks = virt_dev->file_size >> DEF_CDROM_BLOCKSIZE_SHIFT; - } - - if (!virt_dev->cdrom_empty) { - PRINT_INFO_PR("Attached SCSI target virtual %s %s " - "(file=\"%s\", fs=%LdMB, bs=%d, nblocks=%Ld, cyln=%Ld%s)", - (dev->handler->type == TYPE_DISK) ? "disk" : "cdrom", - virt_dev->name, virt_dev->file_name, - virt_dev->file_size >> 20, virt_dev->block_size, - virt_dev->nblocks, virt_dev->nblocks/64/32, - virt_dev->nblocks < 64*32 ? " !WARNING! cyln less than 1" : ""); - } else { - PRINT_INFO_PR("Attached empty SCSI target virtual cdrom %s", - virt_dev->name); - } - - dev->dh_priv = virt_dev; - -out: - TRACE_EXIT(); - return res; -} - -/************************************************************ - * Function: fileio_detach - * - * Argument: - * - * Returns : None - * - * Description: Called to detach this device type driver - ************************************************************/ -static void fileio_detach(struct scst_device *dev) -{ - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)dev->dh_priv; - - TRACE_ENTRY(); - - TRACE_DBG("virt_id %d", dev->virt_id); - - PRINT_INFO_PR("Detached SCSI target virtual device %s (\"%s\")", - virt_dev->name, virt_dev->file_name); - - /* virt_dev will be freed by the caller */ - dev->dh_priv = NULL; - - TRACE_EXIT(); - return; -} - -static void fileio_free_thr_data(struct scst_thr_data_hdr *d) -{ - struct scst_fileio_thr *thr = container_of(d, struct scst_fileio_thr, - hdr); - - TRACE_ENTRY(); - - if (thr->fd) - filp_close(thr->fd, NULL); - - if (thr->iv != NULL) - kfree(thr->iv); - - kmem_cache_free(fileio_thr_cachep, thr); - - TRACE_EXIT(); - return; -} - -static struct scst_fileio_thr *fileio_init_thr_data( - struct scst_tgt_dev *tgt_dev) -{ - struct scst_fileio_thr *res; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)tgt_dev->dev->dh_priv; - - TRACE_ENTRY(); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) - res = kmem_cache_alloc(fileio_thr_cachep, GFP_KERNEL); - if (res != NULL) - memset(thr, 0, sizeof(*thr)); -#else - res = kmem_cache_zalloc(fileio_thr_cachep, GFP_KERNEL); -#endif - if (res == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct " - "scst_fileio_thr"); - goto out; - } - - res->virt_dev = virt_dev; - - if (!virt_dev->cdrom_empty && !virt_dev->nullio) { - res->fd = fileio_open(virt_dev); - if (IS_ERR(res->fd)) { - PRINT_ERROR_PR("filp_open(%s) returned an error %ld", - virt_dev->file_name, PTR_ERR(res->fd)); - goto out_free; - } - } else - res->fd = NULL; - - scst_add_thr_data(tgt_dev, &res->hdr, fileio_free_thr_data); - -out: - TRACE_EXIT_HRES((unsigned long)res); - return res; - -out_free: - kmem_cache_free(fileio_thr_cachep, res); - res = NULL; - goto out; -} - -static int fileio_attach_tgt(struct scst_tgt_dev *tgt_dev) -{ - struct scst_fileio_tgt_dev *ftgt_dev; - int res = 0; - - TRACE_ENTRY(); - - ftgt_dev = kzalloc(sizeof(*ftgt_dev), GFP_KERNEL); - if (ftgt_dev == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of per-session " - "virtual device failed"); - res = -ENOMEM; - goto out; - } - - tgt_dev->dh_priv = ftgt_dev; - -out: - TRACE_EXIT_RES(res); - return res; -} - -static void fileio_detach_tgt(struct scst_tgt_dev *tgt_dev) -{ - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev *)tgt_dev->dh_priv; - - TRACE_ENTRY(); - - scst_del_all_thr_data(tgt_dev); - - kfree(ftgt_dev); - tgt_dev->dh_priv = NULL; - - TRACE_EXIT(); - return; -} - -static inline int fileio_sync_queue_type(enum scst_cmd_queue_type qt) -{ - switch(qt) { - case SCST_CMD_QUEUE_ORDERED: - case SCST_CMD_QUEUE_HEAD_OF_QUEUE: - return 1; - default: - return 0; - } -} - -static inline int fileio_need_pre_sync(enum scst_cmd_queue_type cwqt, - enum scst_cmd_queue_type lwqt) -{ - if (fileio_sync_queue_type(cwqt)) - if (!fileio_sync_queue_type(lwqt)) - return 1; - return 0; -} - -static int fileio_do_job(struct scst_cmd *cmd) -{ - uint64_t lba_start = 0; - loff_t data_len = 0; - uint8_t *cdb = cmd->cdb; - int opcode = cdb[0]; - loff_t loff; - struct scst_device *dev = cmd->dev; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)dev->dh_priv; - struct scst_thr_data_hdr *d; - struct scst_fileio_thr *thr = NULL; - int fua = 0; - - TRACE_ENTRY(); - - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - - if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) { - TRACE_MGMT_DBG("Flag ABORTED set for " - "cmd %p (tag %d), skipping", cmd, cmd->tag); - goto done_uncompl; - } - - d = scst_find_thr_data(cmd->tgt_dev); - if (unlikely(d == NULL)) { - thr = fileio_init_thr_data(cmd->tgt_dev); - if (thr == NULL) { - scst_set_busy(cmd); - goto done; - } - scst_thr_data_get(&thr->hdr); - } else - thr = container_of(d, struct scst_fileio_thr, hdr); - - switch (opcode) { - case READ_6: - case WRITE_6: - case VERIFY_6: - lba_start = (((cdb[1] & 0x1f) << (BYTE * 2)) + - (cdb[2] << (BYTE * 1)) + - (cdb[3] << (BYTE * 0))); - data_len = cmd->bufflen; - break; - case READ_10: - case READ_12: - case WRITE_10: - case WRITE_12: - case VERIFY: - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case VERIFY_12: - lba_start |= ((u64)cdb[2]) << 24; - lba_start |= ((u64)cdb[3]) << 16; - lba_start |= ((u64)cdb[4]) << 8; - lba_start |= ((u64)cdb[5]); - data_len = cmd->bufflen; - break; - case SYNCHRONIZE_CACHE: - lba_start |= ((u64)cdb[2]) << 24; - lba_start |= ((u64)cdb[3]) << 16; - lba_start |= ((u64)cdb[4]) << 8; - lba_start |= ((u64)cdb[5]); - data_len = ((cdb[7] << (BYTE * 1)) + (cdb[8] << (BYTE * 0))) - << virt_dev->block_shift; - if (data_len == 0) - data_len = virt_dev->file_size - - ((loff_t)lba_start << virt_dev->block_shift); - break; - case READ_16: - case WRITE_16: - case WRITE_VERIFY_16: - case VERIFY_16: - lba_start |= ((u64)cdb[2]) << 56; - lba_start |= ((u64)cdb[3]) << 48; - lba_start |= ((u64)cdb[4]) << 40; - lba_start |= ((u64)cdb[5]) << 32; - lba_start |= ((u64)cdb[6]) << 16; - lba_start |= ((u64)cdb[7]) << 8; - lba_start |= ((u64)cdb[8]); - data_len = cmd->bufflen; - break; - } - - loff = (loff_t)lba_start << virt_dev->block_shift; - TRACE_DBG("cmd %p, lba_start %Ld, loff %Ld, data_len %Ld", cmd, - lba_start, (uint64_t)loff, (uint64_t)data_len); - if (unlikely(loff < 0) || unlikely(data_len < 0) || - unlikely((loff + data_len) > virt_dev->file_size)) { - PRINT_INFO_PR("Access beyond the end of the device " - "(%lld of %lld, len %Ld)", (uint64_t)loff, - (uint64_t)virt_dev->file_size, (uint64_t)data_len); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE( - scst_sense_block_out_range_error)); - goto done; - } - - switch (opcode) { - case WRITE_10: - case WRITE_12: - case WRITE_16: - fua = (cdb[1] & 0x8) && !virt_dev->wt_flag; - if (cdb[1] & 0x8) { - TRACE(TRACE_ORDER, "FUA(%d): loff=%Ld, " - "data_len=%Ld", fua, (uint64_t)loff, - (uint64_t)data_len); - } - break; - } - - switch (opcode) { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - fileio_exec_read(cmd, thr, loff); - break; - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - if (likely(!virt_dev->rd_only_flag)) { - int do_fsync = 0; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev*) - cmd->tgt_dev->dh_priv; - enum scst_cmd_queue_type last_queue_type = - ftgt_dev->last_write_cmd_queue_type; - ftgt_dev->last_write_cmd_queue_type = cmd->queue_type; - if (fileio_need_pre_sync(cmd->queue_type, last_queue_type) && - !virt_dev->wt_flag) { - TRACE(TRACE_ORDER, "ORDERED " - "WRITE(%d): loff=%Ld, data_len=%Ld", - cmd->queue_type, (uint64_t)loff, - (uint64_t)data_len); - do_fsync = 1; - if (fileio_fsync(thr, 0, 0, cmd) != 0) - goto done; - } - fileio_exec_write(cmd, thr, loff); - /* O_SYNC flag is used for wt_flag devices */ - if (do_fsync || fua) - fileio_fsync(thr, loff, data_len, cmd); - } else { - TRACE_DBG("%s", "Attempt to write to read-only device"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_data_protect)); - } - break; - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case WRITE_VERIFY_16: - if (likely(!virt_dev->rd_only_flag)) { - int do_fsync = 0; - struct scst_fileio_tgt_dev *ftgt_dev = - (struct scst_fileio_tgt_dev*) - cmd->tgt_dev->dh_priv; - enum scst_cmd_queue_type last_queue_type = - ftgt_dev->last_write_cmd_queue_type; - ftgt_dev->last_write_cmd_queue_type = cmd->queue_type; - if (fileio_need_pre_sync(cmd->queue_type, last_queue_type) && - !virt_dev->wt_flag) { - TRACE(TRACE_ORDER, "ORDERED " - "WRITE_VERIFY(%d): loff=%Ld, data_len=%Ld", - cmd->queue_type, (uint64_t)loff, - (uint64_t)data_len); - do_fsync = 1; - if (fileio_fsync(thr, 0, 0, cmd) != 0) - goto done; - } - fileio_exec_write(cmd, thr, loff); - /* O_SYNC flag is used for wt_flag devices */ - if (cmd->status == 0) - fileio_exec_verify(cmd, thr, loff); - else if (do_fsync) - fileio_fsync(thr, loff, data_len, cmd); - } else { - TRACE_DBG("%s", "Attempt to write to read-only device"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_data_protect)); - } - break; - case SYNCHRONIZE_CACHE: - { - int immed = cdb[1] & 0x2; - TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: " - "loff=%Ld, data_len=%Ld, immed=%d", (uint64_t)loff, - (uint64_t)data_len, immed); - if (immed) { - scst_get(); - cmd->completed = 1; - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - /* cmd is dead here */ - fileio_fsync(thr, loff, data_len, NULL); - /* ToDo: fileio_fsync() error processing */ - scst_put(); - goto out; - } else { - fileio_fsync(thr, loff, data_len, cmd); - break; - } - } - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - fileio_exec_verify(cmd, thr, loff); - break; - case MODE_SENSE: - case MODE_SENSE_10: - fileio_exec_mode_sense(cmd); - break; - case MODE_SELECT: - case MODE_SELECT_10: - fileio_exec_mode_select(cmd); - break; - case ALLOW_MEDIUM_REMOVAL: - fileio_exec_prevent_allow_medium_removal(cmd); - break; - case READ_TOC: - fileio_exec_read_toc(cmd); - break; - case START_STOP: - case RESERVE: - case RESERVE_10: - case RELEASE: - case RELEASE_10: - case TEST_UNIT_READY: - break; - case INQUIRY: - fileio_exec_inquiry(cmd); - break; - case READ_CAPACITY: - fileio_exec_read_capacity(cmd); - break; - case SERVICE_ACTION_IN: - if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) { - fileio_exec_read_capacity16(cmd); - break; - } - /* else go through */ - case REPORT_LUNS: - default: - TRACE_DBG("Invalid opcode %d", opcode); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); - } - -done: - cmd->completed = 1; - -done_uncompl: - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - -out: - if (likely(thr != NULL)) - scst_thr_data_put(&thr->hdr); - - TRACE_EXIT(); - return SCST_EXEC_COMPLETED; -} - -/******************************************************************** - * Function: disk_fileio_parse - * - * Argument: - * - * Returns : The state of the command - * - * Description: This does the parsing of the command - * - * Note: Not all states are allowed on return - ********************************************************************/ -static int disk_fileio_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) -{ - int res = SCST_CMD_STATE_DEFAULT; - int fixed; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->dh_priv; - - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - 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; - cmd->data_direction = SCST_DATA_READ; - } - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT(); - return res; -} - -/******************************************************************** - * Function: cdrom_fileio_parse - * - * Argument: - * - * Returns : The state of the command - * - * Description: This does the parsing of the command - * - * Note: Not all states are allowed on return - ********************************************************************/ -static int cdrom_fileio_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) -{ - int res = SCST_CMD_STATE_DEFAULT; - int fixed; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->dh_priv; - - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT_HRES(res); - return res; -} - -/******************************************************************** - * Function: cdrom_fileio_exec - * - * Argument: - * - * Returns : - * - * Description: - ********************************************************************/ -static int cdrom_fileio_exec(struct scst_cmd *cmd) -{ - int opcode = cmd->cdb[0]; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->dh_priv; - - TRACE_ENTRY(); - - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - - if (virt_dev->cdrom_empty && (opcode != INQUIRY)) { - TRACE_DBG("%s", "CDROM empty"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_not_ready)); - goto out_complete; - } - - if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) && - (cmd->cdb[0] != REQUEST_SENSE) && (cmd->cdb[0] != REPORT_LUNS)) { - spin_lock(&virt_dev->flags_lock); - if (virt_dev->media_changed) { - virt_dev->media_changed = 0; - TRACE_DBG("%s", "Reporting media changed"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_medium_changed_UA)); - spin_unlock(&virt_dev->flags_lock); - goto out_complete; - } - spin_unlock(&virt_dev->flags_lock); - } - - fileio_do_job(cmd); - -out: - TRACE_EXIT(); - return SCST_EXEC_COMPLETED; - -out_complete: - cmd->completed = 1; - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - goto out; -} - -static void fileio_exec_inquiry(struct scst_cmd *cmd) -{ - int32_t length, len, i, resp_len = 0; - uint8_t *address; - uint8_t *buf; - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->dh_priv; - - /* ToDo: Performance Boost: - * 1. remove kzalloc, buf - * 2. do all checks before touching *address - * 3. zero *address - * 4. write directly to *address - */ - - TRACE_ENTRY(); - - buf = kzalloc(INQ_BUF_SZ, - scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL); - if (buf == NULL) { - scst_set_busy(cmd); - goto out; - } - - length = scst_get_buf_first(cmd, &address); - TRACE_DBG("length %d", length); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_free; - } - - /* - * ToDo: write through/back flags as well as read only one. - */ - - if (cmd->cdb[1] & CMDDT) { - TRACE_DBG("%s", "INQUIRY: CMDDT is unsupported"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - - memset(buf, 0, sizeof(buf)); - buf[0] = cmd->dev->handler->type; /* type dev */ - if (buf[0] == TYPE_ROM) - buf[1] = 0x80; /* removable */ - /* Vital Product */ - if (cmd->cdb[1] & EVPD) { - int dev_id_num; - char dev_id_str[6]; - - for (dev_id_num = 0, i = 0; i < strlen(virt_dev->name); i++) { - dev_id_num += virt_dev->name[i]; - } - len = scnprintf(dev_id_str, 6, "%d", dev_id_num); - TRACE_DBG("num %d, str <%s>, len %d", - dev_id_num, dev_id_str, len); - if (0 == cmd->cdb[2]) { /* supported vital product data pages */ - buf[3] = 3; - buf[4] = 0x0; /* this page */ - buf[5] = 0x80; /* unit serial number */ - buf[6] = 0x83; /* device identification */ - resp_len = buf[3] + 4; - } else if (0x80 == cmd->cdb[2]) { /* unit serial number */ - buf[1] = 0x80; - if (virt_dev->usn == NULL) { - buf[3] = MAX_USN_LEN; - memset(&buf[4], 0x20, MAX_USN_LEN); - } else { - int usn_len; - - if (strlen(virt_dev->usn) > MAX_USN_LEN) - usn_len = MAX_USN_LEN; - else - usn_len = len; - buf[3] = usn_len; - strncpy(&buf[4], virt_dev->usn, usn_len); - } - resp_len = buf[3] + 4; - } else if (0x83 == cmd->cdb[2]) { /* device identification */ - int num = 4; - - buf[1] = 0x83; - /* Two identification descriptors: */ - /* T10 vendor identifier field format (faked) */ - buf[num + 0] = 0x2; /* ASCII */ - buf[num + 1] = 0x1; - buf[num + 2] = 0x0; - memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8); - memset(&buf[num + 12], ' ', 16); - i = strlen(virt_dev->name); - i = i < 16 ? i : 16; - memcpy(&buf[num + 12], virt_dev->name, len); - memcpy(&buf[num + 28], dev_id_str, len); - buf[num + 3] = 8 + 16 + len; - num += buf[num + 3] + 4; - /* NAA IEEE registered identifier (faked) */ - buf[num] = 0x1; /* binary */ - buf[num + 1] = 0x3; - buf[num + 2] = 0x0; - buf[num + 3] = 0x8; - buf[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ - buf[num + 5] = 0x23; - buf[num + 6] = 0x45; - buf[num + 7] = 0x60; - buf[num + 8] = (dev_id_num >> 24); - buf[num + 9] = (dev_id_num >> 16) & 0xff; - buf[num + 10] = (dev_id_num >> 8) & 0xff; - buf[num + 11] = dev_id_num & 0xff; - - resp_len = num + 12 - 4; - buf[2] = (resp_len >> 8) & 0xFF; - buf[3] = resp_len & 0xFF; - resp_len += 4; - } else { - TRACE_DBG("INQUIRY: Unsupported EVPD page %x", - cmd->cdb[2]); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - } else { - if (cmd->cdb[2] != 0) { - TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - - buf[2] = 4; /* Device complies to this standard - SPC-2 */ - buf[3] = 2; /* data in format specified in this standard */ - buf[4] = 31; /* n - 4 = 35 - 4 = 31 for full 36 byte data */ - buf[6] = 0; buf[7] = 2; /* BQue = 0, CMDQUE = 1 commands queuing supported */ - - /* 8 byte ASCII Vendor Identification of the target - left aligned */ - memcpy(&buf[8], SCST_FIO_VENDOR, 8); - - /* 16 byte ASCII Product Identification of the target - left aligned */ - memset(&buf[16], ' ', 16); - len = strlen(virt_dev->name); - len = len < 16 ? len : 16; - memcpy(&buf[16], virt_dev->name, len); - - /* 4 byte ASCII Product Revision Level of the target - left aligned */ - memcpy(&buf[32], SCST_FIO_REV, 4); - resp_len = buf[4] + 5; - } - - sBUG_ON(resp_len >= INQ_BUF_SZ); - if (length > resp_len) - length = resp_len; - memcpy(address, buf, length); - -out_put: - scst_put_buf(cmd, address); - if (length < cmd->resp_data_len) - scst_set_resp_data_len(cmd, length); - -out_free: - kfree(buf); - -out: - TRACE_EXIT(); - return; -} - -/* - * <<Following mode pages info copied from ST318451LW with some corrections>> - * - * ToDo: revise them - */ - -static int fileio_err_recov_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Read-Write Error Recovery page for mode_sense */ - const unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, - 5, 0, 0xff, 0xff}; - - memcpy(p, err_recov_pg, sizeof(err_recov_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(err_recov_pg) - 2); - return sizeof(err_recov_pg); -} - -static int fileio_disconnect_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Disconnect-Reconnect page for mode_sense */ - const unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - - memcpy(p, disconnect_pg, sizeof(disconnect_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(disconnect_pg) - 2); - return sizeof(disconnect_pg); -} - -static int fileio_format_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Format device page for mode_sense */ - const unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x40, 0, 0, 0}; - - memcpy(p, format_pg, sizeof(format_pg)); - p[10] = (DEF_SECTORS_PER >> 8) & 0xff; - p[11] = DEF_SECTORS_PER & 0xff; - p[12] = (virt_dev->block_size >> 8) & 0xff; - p[13] = virt_dev->block_size & 0xff; - if (1 == pcontrol) - memset(p + 2, 0, sizeof(format_pg) - 2); - return sizeof(format_pg); -} - -static int fileio_caching_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Caching page for mode_sense */ - const unsigned char caching_pg[] = {0x8, 18, 0x10, 0, 0xff, 0xff, 0, 0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; - - memcpy(p, caching_pg, sizeof(caching_pg)); - p[2] |= !(virt_dev->wt_flag) ? WCE : 0; - if (1 == pcontrol) - memset(p + 2, 0, sizeof(caching_pg) - 2); - return sizeof(caching_pg); -} - -static int fileio_ctrl_m_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Control mode page for mode_sense */ - const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x22, 0, 0, 0x40, 0, 0, - 0, 0, 0x2, 0x4b}; - - memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); - if (!virt_dev->wt_flag && !virt_dev->nv_cache) - p[3] |= 0x10; /* Enable unrestricted reordering */ - if (1 == pcontrol) - memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); - return sizeof(ctrl_m_pg); -} - -static int fileio_iec_m_pg(unsigned char *p, int pcontrol, - struct scst_fileio_dev *virt_dev) -{ /* Informational Exceptions control mode page for mode_sense */ - const unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; - memcpy(p, iec_m_pg, sizeof(iec_m_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(iec_m_pg) - 2); - return sizeof(iec_m_pg); -} - -static void fileio_exec_mode_sense(struct scst_cmd *cmd) -{ - int32_t length; - uint8_t *address; - uint8_t *buf; - struct scst_fileio_dev *virt_dev; - uint32_t blocksize; - uint64_t nblocks; - unsigned char dbd, type; - int pcontrol, pcode, subpcode; - unsigned char dev_spec; - int msense_6, offset = 0, len; - unsigned char *bp; - - TRACE_ENTRY(); - - buf = kzalloc(MSENSE_BUF_SZ, - scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL); - if (buf == NULL) { - scst_set_busy(cmd); - goto out; - } - - virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - blocksize = virt_dev->block_size; - nblocks = virt_dev->nblocks; - - type = cmd->dev->handler->type; /* type dev */ - dbd = cmd->cdb[1] & DBD; - pcontrol = (cmd->cdb[2] & 0xc0) >> 6; - pcode = cmd->cdb[2] & 0x3f; - subpcode = cmd->cdb[3]; - msense_6 = (MODE_SENSE == cmd->cdb[0]); - dev_spec = (virt_dev->rd_only_flag ? WP : 0) | DPOFUA; - - length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_free; - } - - memset(buf, 0, sizeof(buf)); - - if (0x3 == pcontrol) { - TRACE_DBG("%s", "MODE SENSE: Saving values not supported"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_saving_params_unsup)); - goto out_put; - } - - if (msense_6) { - buf[1] = type; - buf[2] = dev_spec; - offset = 4; - } else { - buf[2] = type; - buf[3] = dev_spec; - offset = 8; - } - - if (0 != subpcode) { /* TODO: Control Extension page */ - TRACE_DBG("%s", "MODE SENSE: Only subpage 0 is supported"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - - if (!dbd) { - /* Create block descriptor */ - buf[offset - 1] = 0x08; /* block descriptor length */ - if (nblocks >> 32) { - buf[offset + 0] = 0xFF; - buf[offset + 1] = 0xFF; - buf[offset + 2] = 0xFF; - buf[offset + 3] = 0xFF; - } else { - buf[offset + 0] = (nblocks >> (BYTE * 3)) & 0xFF;/* num blks */ - buf[offset + 1] = (nblocks >> (BYTE * 2)) & 0xFF; - buf[offset + 2] = (nblocks >> (BYTE * 1)) & 0xFF; - buf[offset + 3] = (nblocks >> (BYTE * 0)) & 0xFF; - } - buf[offset + 4] = 0; /* density code */ - buf[offset + 5] = (blocksize >> (BYTE * 2)) & 0xFF;/* blklen */ - buf[offset + 6] = (blocksize >> (BYTE * 1)) & 0xFF; - buf[offset + 7] = (blocksize >> (BYTE * 0)) & 0xFF; - - offset += 8; /* increment offset */ - } - - bp = buf + offset; - - switch (pcode) { - case 0x1: /* Read-Write error recovery page, direct access */ - len = fileio_err_recov_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0x2: /* Disconnect-Reconnect page, all devices */ - len = fileio_disconnect_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0x3: /* Format device page, direct access */ - len = fileio_format_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0x8: /* Caching page, direct access */ - len = fileio_caching_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0xa: /* Control Mode page, all devices */ - len = fileio_ctrl_m_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0x1c: /* Informational Exceptions Mode page, all devices */ - len = fileio_iec_m_pg(bp, pcontrol, virt_dev); - offset += len; - break; - case 0x3f: /* Read all Mode pages */ - len = fileio_err_recov_pg(bp, pcontrol, virt_dev); - len += fileio_disconnect_pg(bp + len, pcontrol, virt_dev); - len += fileio_format_pg(bp + len, pcontrol, virt_dev); - len += fileio_caching_pg(bp + len, pcontrol, virt_dev); - len += fileio_ctrl_m_pg(bp + len, pcontrol, virt_dev); - len += fileio_iec_m_pg(bp + len, pcontrol, virt_dev); - offset += len; - break; - default: - TRACE_DBG("MODE SENSE: Unsupported page %x", pcode); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - if (msense_6) - buf[0] = offset - 1; - else { - buf[0] = ((offset - 2) >> 8) & 0xff; - buf[1] = (offset - 2) & 0xff; - } - - if (offset > length) - offset = length; - memcpy(address, buf, offset); - -out_put: - scst_put_buf(cmd, address); - if (offset < cmd->resp_data_len) - scst_set_resp_data_len(cmd, offset); - -out_free: - kfree(buf); - -out: - TRACE_EXIT(); - return; -} - -static int fileio_set_wt(struct scst_fileio_dev *virt_dev, int wt) -{ - int res = 0; - - TRACE_ENTRY(); - - if ((virt_dev->wt_flag == wt) || virt_dev->nullio) - goto out; - - spin_lock(&virt_dev->flags_lock); - virt_dev->wt_flag = wt; - spin_unlock(&virt_dev->flags_lock); - - scst_dev_del_all_thr_data(virt_dev->dev); - -out: - TRACE_EXIT_RES(res); - return res; -} - -static void fileio_exec_mode_select(struct scst_cmd *cmd) -{ - int32_t length; - uint8_t *address; - struct scst_fileio_dev *virt_dev; - int mselect_6, offset; - - TRACE_ENTRY(); - - virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - mselect_6 = (MODE_SELECT == cmd->cdb[0]); - - length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out; - } - - if (!(cmd->cdb[1] & PF) || (cmd->cdb[1] & SP)) { - PRINT_ERROR_PR("MODE SELECT: PF and/or SP are wrongly set " - "(cdb[1]=%x)", cmd->cdb[1]); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put; - } - - if (mselect_6) { - offset = 4; - } else { - offset = 8; - } - - if (address[offset - 1] == 8) { - offset += 8; - } else if (address[offset - 1] != 0) { - PRINT_ERROR_PR("%s", "MODE SELECT: Wrong parameters list " - "lenght"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list)); - goto out_put; - } - - while (length > offset + 2) { - if (address[offset] & PS) { - PRINT_ERROR_PR("%s", "MODE SELECT: Illegal PS bit"); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE( - scst_sense_invalid_field_in_parm_list)); - goto out_put; - } - if ((address[offset] & 0x3f) == 0x8) { /* Caching page */ - if (address[offset + 1] != 18) { - PRINT_ERROR_PR("%s", "MODE SELECT: Invalid " - "caching page request"); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE( - scst_sense_invalid_field_in_parm_list)); - goto out_put; - } - if (fileio_set_wt(virt_dev, - (address[offset + 2] & WCE) ? 0 : 1) != 0) { - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_put; - } - break; - } - offset += address[offset + 1]; - } - -out_put: - scst_put_buf(cmd, address); - -out: - TRACE_EXIT(); - return; -} - -static void fileio_exec_read_capacity(struct scst_cmd *cmd) -{ - int32_t length; - uint8_t *address; - struct scst_fileio_dev *virt_dev; - uint32_t blocksize; - uint64_t nblocks; - uint8_t buffer[READ_CAP_LEN]; - - TRACE_ENTRY(); - - virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - blocksize = virt_dev->block_size; - nblocks = virt_dev->nblocks; - - /* last block on the virt_dev is (nblocks-1) */ - memset(buffer, 0, sizeof(buffer)); - if (nblocks >> 32) { - buffer[0] = 0xFF; - buffer[1] = 0xFF; - buffer[2] = 0xFF; - buffer[3] = 0xFF; - } else { - buffer[0] = ((nblocks - 1) >> (BYTE * 3)) & 0xFF; - buffer[1] = ((nblocks - 1) >> (BYTE * 2)) & 0xFF; - buffer[2] = ((nblocks - 1) >> (BYTE * 1)) & 0xFF; - buffer[3] = ((nblocks - 1) >> (BYTE * 0)) & 0xFF; - } - buffer[4] = (blocksize >> (BYTE * 3)) & 0xFF; - buffer[5] = (blocksize >> (BYTE * 2)) & 0xFF; - buffer[6] = (blocksize >> (BYTE * 1)) & 0xFF; - buffer[7] = (blocksize >> (BYTE * 0)) & 0xFF; - - length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out; - } - - if (length > READ_CAP_LEN) - length = READ_CAP_LEN; - memcpy(address, buffer, length); - - scst_put_buf(cmd, address); - - if (length < cmd->resp_data_len) - scst_set_resp_data_len(cmd, length); - -out: - TRACE_EXIT(); - return; -} - -static void fileio_exec_read_capacity16(struct scst_cmd *cmd) -{ - int32_t length; - uint8_t *address; - struct scst_fileio_dev *virt_dev; - uint32_t blocksize; - uint64_t nblocks; - uint8_t buffer[READ_CAP16_LEN]; - - TRACE_ENTRY(); - - virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - blocksize = virt_dev->block_size; - nblocks = virt_dev->nblocks - 1; - - memset(buffer, 0, sizeof(buffer)); - buffer[0] = nblocks >> 56; - buffer[1] = (nblocks >> 48) & 0xFF; - buffer[2] = (nblocks >> 40) & 0xFF; - buffer[3] = (nblocks >> 32) & 0xFF; - buffer[4] = (nblocks >> 24) & 0xFF; - buffer[5] = (nblocks >> 16) & 0xFF; - buffer[6] = (nblocks >> 8) & 0xFF; - buffer[7] = nblocks& 0xFF; - - buffer[8] = (blocksize >> (BYTE * 3)) & 0xFF; - buffer[9] = (blocksize >> (BYTE * 2)) & 0xFF; - buffer[10] = (blocksize >> (BYTE * 1)) & 0xFF; - buffer[11] = (blocksize >> (BYTE * 0)) & 0xFF; - - length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out; - } - - if (length > READ_CAP16_LEN) - length = READ_CAP16_LEN; - memcpy(address, buffer, length); - - scst_put_buf(cmd, address); - - if (length < cmd->resp_data_len) - scst_set_resp_data_len(cmd, length); - -out: - TRACE_EXIT(); - return; -} - -static void fileio_exec_read_toc(struct scst_cmd *cmd) -{ - int32_t length, off = 0; - uint8_t *address; - struct scst_fileio_dev *virt_dev; - uint32_t nblocks; - uint8_t buffer[4+8+8] = { 0x00, 0x0a, 0x01, 0x01, 0x00, 0x14, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - TRACE_ENTRY(); - - if (cmd->dev->handler->type != TYPE_ROM) { - PRINT_ERROR_PR("%s", "READ TOC for non-CDROM device"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); - goto out; - } - - if (cmd->cdb[2] & 0x0e/*Format*/) { - PRINT_ERROR_PR("%s", "READ TOC: invalid requested data format"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out; - } - - if ((cmd->cdb[6] != 0 && (cmd->cdb[2] & 0x01)) || - (cmd->cdb[6] > 1 && cmd->cdb[6] != 0xAA)) { - PRINT_ERROR_PR("READ TOC: invalid requested track number %x", - cmd->cdb[6]); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out; - } - - length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { - PRINT_ERROR_PR("scst_get_buf_first() failed: %d", length); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out; - } - - virt_dev = (struct scst_fileio_dev *)cmd->dev->dh_priv; - /* FIXME when you have > 8TB ROM device. */ - nblocks = (uint32_t)virt_dev->nblocks; - - /* Header */ - memset(buffer, 0, sizeof(buffer)); - buffer[2] = 0x01; /* First Track/Session */ - buffer[3] = 0x01; /* Last Track/Session */ - off = 4; - if (cmd->cdb[6] <= 1) - { - /* Fistr TOC Track Descriptor */ - buffer[off+1] = 0x14; /* ADDR 0x10 - Q Sub-channel encodes current position data - CONTROL 0x04 - Data track, recoreded uninterrupted */ - buffer[off+2] = 0x01; /* Track Number */ - off += 8; - } - if (!(cmd->cdb[2] & 0x01)) - { - /* Lead-out area TOC Track Descriptor */ - buffer[off+1] = 0x14; - buffer[off+2] = 0xAA; /* Track Number */ - buffer[off+4] = (nblocks >> (BYTE * 3)) & 0xFF; /* Track Start Address */ - buffer[off+5] = (nblocks >> (BYTE * 2)) & 0xFF; - buffer[off+6] = (nblocks >> (BYTE * 1)) & 0xFF; - buffer[off+7] = (nblocks >> (BYTE * 0)) & 0xFF; - off += 8; - } - - buffer[1] = off - 2; /* Data Length */ - - if (off > length) - off = length; - memcpy(address, buffer, off); - - scst_put_buf(cmd, address); - - if (off < cmd->resp_data_len) - scst_set_resp_data_len(cmd, off); - -out: - TRACE_EXIT(); - return; -} - -static void fileio_exec_prevent_allow_medium_removal(struct scst_cmd *cmd) -{ - struct scst_fileio_dev *virt_dev = - (struct scst_fileio_dev *)cmd->dev->dh_priv; - - TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]); - - spin_lock(&virt_dev->flags_lock); - if (cmd->dev->handler->type == TYPE_ROM) - virt_dev->prevent_allow_medium_removal = - cmd->cdb[4] & 0x01 ? 1 : 0; - else { - PRINT_ERROR_PR("%s", "Prevent allow medium removal for " - "non-CDROM device"); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_opcode)); - } - spin_unlock(&virt_dev->flags_lock); - - return; -} - -static int fileio_f... [truncated message content] |
From: <vl...@us...> - 2007-02-21 18:15:24
|
Revision: 95 http://svn.sourceforge.net/scst/?rev=95&view=rev Author: vlnb Date: 2007-02-21 10:15:19 -0800 (Wed, 21 Feb 2007) Log Message: ----------- Adding blockio mode support to scst_vdisk Signed-of-by: Vu Pham <hu...@ya...> Merged by me. Don't use it, currently it corrupts transferred data Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/src/dev_handlers/scst_vdisk.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2007-02-21 16:44:59 UTC (rev 94) +++ trunk/scst/ChangeLog 2007-02-21 18:15:19 UTC (rev 95) @@ -1,6 +1,9 @@ Summary of changes between versions 0.9.5 and 0.9.6 --------------------------------------------------- + - FILEIO was renamed to VDISK. BLOCK IO added to it, thanks to Ross S. W. + Walker and Vu Pham. + - Internal locking and execution context were reimplemnted. Particularly, implemented full support for SCSI task attributes (SIMPLE, ORDERED, etc.). Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-02-21 16:44:59 UTC (rev 94) +++ trunk/scst/README 2007-02-21 18:15:19 UTC (rev 95) @@ -486,6 +486,14 @@ * Calvin Morrow <cal...@co...> for testing and usful suggestions. - * Erik Habbinga <eri...@in...> for fixes. + * Hu Gang <hu...@so...> for the original version of the + LSI target driver. + * Erik Habbinga <eri...@in...> for fixes and support + of the LSI target driver. + + * Ross S. W. Walker <rsw...@ho...> for the original block IO + code and Vu Pham <hu...@ya...> who updated it for the VDISK dev + handler. + Vladislav Bolkhovitin <vs...@vl...>, http://scst.sourceforge.net Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-02-21 16:44:59 UTC (rev 94) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-02-21 18:15:19 UTC (rev 95) @@ -3,9 +3,11 @@ * * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar + * (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com> + * (C) 2007 Ross Walker <rswwalker at hotmail dot com> * * SCSI disk (type 0) and CDROM (type 5) dev handler using files - * on file systems (VDISK) + * on file systems or block devices (VDISK) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -57,9 +59,10 @@ #define VDISK_SLAB_FLAGS 0L #endif -/* 8 byte ASCII Vendor of the FILE IO target */ +/* 8 byte ASCII Vendor */ #define SCST_FIO_VENDOR "SCST_FIO" -/* 4 byte ASCII Product Revision Level of the FILE IO target - left aligned */ +#define SCST_BIO_VENDOR "SCST_BIO" +/* 4 byte ASCII Product Revision Level - left aligned */ #define SCST_FIO_REV " 096" #define READ_CAP_LEN 8 @@ -112,6 +115,7 @@ unsigned int media_changed:1; unsigned int prevent_allow_medium_removal:1; unsigned int nullio:1; + unsigned int blockio:1; unsigned int cdrom_empty:1; int virt_id; char name[16+1]; /* Name of virtual device, @@ -129,6 +133,7 @@ struct scst_vdisk_thr { struct scst_thr_data_hdr hdr; struct file *fd; + struct block_device *bdev; struct iovec *iv; int iv_count; struct scst_vdisk_dev *virt_dev; @@ -148,6 +153,8 @@ struct scst_vdisk_thr *thr, loff_t loff); static void vdisk_exec_write(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, loff_t loff); +static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, + u64 lba_start, int write); static void vdisk_exec_verify(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, loff_t loff); static void vdisk_exec_read_capacity(struct scst_cmd *cmd); @@ -209,7 +216,7 @@ static char *vdisk_proc_help_string = "echo \"open|close NAME [FILE_NAME [BLOCK_SIZE] [WRITE_THROUGH " - "READ_ONLY O_DIRECT NULLIO NV_CACHE]]\" >/proc/scsi_tgt/" + "READ_ONLY O_DIRECT NULLIO NV_CACHE BLOCKIO]]\" >/proc/scsi_tgt/" VDISK_NAME "/" VDISK_NAME "\n"; static char *vcdrom_proc_help_string = @@ -260,7 +267,6 @@ { int res = 0; loff_t err; - mm_segment_t old_fs; struct file *fd; struct scst_vdisk_dev *virt_dev = NULL, *vv; struct list_head *vd; @@ -305,6 +311,8 @@ if (virt_dev->nullio) err = 3LL*1024*1024*1024*1024/2; else { + struct inode *inode; + fd = vdisk_open(virt_dev); if (IS_ERR(fd)) { res = PTR_ERR(fd); @@ -328,22 +336,28 @@ goto out; } - /* seek to end */ - old_fs = get_fs(); - set_fs(get_ds()); - if (fd->f_op->llseek) { - err = fd->f_op->llseek(fd, 0, 2/*SEEK_END*/); - } else { - err = default_llseek(fd, 0, 2/*SEEK_END*/); + inode = fd->f_dentry->d_inode; + + if (virt_dev->blockio && !S_ISBLK(inode->i_mode)) { + PRINT_ERROR_PR("File %s is NOT a block device", + virt_dev->file_name); + res = -EINVAL; + filp_close(fd, NULL); + goto out; } - set_fs(old_fs); + + if (S_ISREG(inode->i_mode)) + ; + else if (S_ISBLK(inode->i_mode)) + inode = inode->i_bdev->bd_inode; + else { + res = -EINVAL; + filp_close(fd, NULL); + goto out; + } + err = inode->i_size; + filp_close(fd, NULL); - if (err < 0) { - res = err; - PRINT_ERROR_PR("llseek %s returned an error %d", - virt_dev->file_name, res); - goto out; - } } virt_dev->file_size = err; TRACE_DBG("size of file: %Ld", (uint64_t)err); @@ -456,6 +470,10 @@ virt_dev->file_name, PTR_ERR(res->fd)); goto out_free; } + if (virt_dev->blockio) + res->bdev = res->fd->f_dentry->d_inode->i_bdev; + else + res->bdev = NULL; } else res->fd = NULL; @@ -647,7 +665,10 @@ case READ_10: case READ_12: case READ_16: - vdisk_exec_read(cmd, thr, loff); + if (virt_dev->blockio) + blockio_exec_rw(cmd, thr, lba_start, 0); + else + vdisk_exec_read(cmd, thr, loff); break; case WRITE_6: case WRITE_10: @@ -671,7 +692,10 @@ if (vdisk_fsync(thr, 0, 0, cmd) != 0) goto done; } - vdisk_exec_write(cmd, thr, loff); + if (virt_dev->blockio) + blockio_exec_rw(cmd, thr, lba_start, 1); + else + vdisk_exec_write(cmd, thr, loff); /* O_SYNC flag is used for wt_flag devices */ if (do_fsync || fua) vdisk_fsync(thr, loff, data_len, cmd); @@ -702,6 +726,7 @@ if (vdisk_fsync(thr, 0, 0, cmd) != 0) goto done; } + /* ToDo: BLOCKIO VERIFY */ vdisk_exec_write(cmd, thr, loff); /* O_SYNC flag is used for wt_flag devices */ if (cmd->status == 0) @@ -1083,7 +1108,10 @@ buf[num + 0] = 0x2; /* ASCII */ buf[num + 1] = 0x1; buf[num + 2] = 0x0; - memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8); + if (virt_dev->blockio) + memcpy(&buf[num + 4], SCST_BIO_VENDOR, 8); + else + memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8); memset(&buf[num + 12], ' ', 16); i = strlen(virt_dev->name); i = i < 16 ? i : 16; @@ -1130,7 +1158,10 @@ buf[6] = 0; buf[7] = 2; /* BQue = 0, CMDQUE = 1 commands queuing supported */ /* 8 byte ASCII Vendor Identification of the target - left aligned */ - memcpy(&buf[8], SCST_FIO_VENDOR, 8); + if (virt_dev->blockio) + memcpy(&buf[8], SCST_BIO_VENDOR, 8); + else + memcpy(&buf[8], SCST_FIO_VENDOR, 8); /* 16 byte ASCII Product Identification of the target - left aligned */ memset(&buf[16], ' ', 16); @@ -1727,7 +1758,8 @@ TRACE_ENTRY(); - if (thr->virt_dev->nv_cache) + /* ToDo: BLOCKIO fsync() */ + if (thr->virt_dev->nv_cache || thr->virt_dev->blockio) goto out; res = sync_page_range(inode, mapping, loff, len); @@ -2022,6 +2054,156 @@ return; } +struct blockio_work { + atomic_t bios_inflight; + struct scst_cmd *cmd; + struct completion complete; +}; + +static int blockio_endio(struct bio *bio, unsigned int bytes_done, int error) +{ + struct blockio_work *blockio_work = bio->bi_private; + + if (bio->bi_size) + return 1; + + error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? error : -EIO; + + if (unlikely(error != 0)) { + PRINT_ERROR_PR("cmd %p returned error %d", blockio_work->cmd, + error); + if (bio->bi_rw & WRITE) + scst_set_cmd_error(blockio_work->cmd, + SCST_LOAD_SENSE(scst_sense_write_error)); + else + scst_set_cmd_error(blockio_work->cmd, + SCST_LOAD_SENSE(scst_sense_read_error)); + } + + /* Decrement the bios in processing, and if zero signal completion */ + if (atomic_dec_and_test(&blockio_work->bios_inflight)) + complete(&blockio_work->complete); + + bio_put(bio); + return 0; +} + +static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, + u64 lba_start, int write) +{ + struct scst_vdisk_dev *virt_dev = thr->virt_dev; + struct block_device *bdev = thr->bdev; + struct request_queue *q = bdev_get_queue(bdev); + int j, max_nr_vecs = 0; + struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; + int need_new_bio; + struct scatterlist *sgl = cmd->sg; + struct blockio_work *blockio_work; + + TRACE_ENTRY(); + + if (virt_dev->nullio) + goto out; + + /* Allocate and initialize blockio_work struct */ + blockio_work = kmalloc(sizeof (*blockio_work), GFP_KERNEL); + if (blockio_work == NULL) + goto out_no_mem; + + atomic_set(&blockio_work->bios_inflight, 0); + blockio_work->cmd = cmd; + init_completion(&blockio_work->complete); + + if (q) + max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES); + else + max_nr_vecs = 1; + + need_new_bio = 1; + for (j = 0; j < cmd->sg_cnt; ++j) { + unsigned int len, bytes, off, thislen; + struct page *page; + + page = sgl[j].page; + off = sgl[j].offset; + len = sgl[j].length; + thislen = 0; + + while (len > 0) { + if (need_new_bio) { + bio = bio_alloc(GFP_KERNEL, max_nr_vecs); + if (!bio) { + PRINT_ERROR_PR("Failed to create bio" + "for data segment= %d" + " cmd %p", j, cmd); + goto out_no_bio; + } + + atomic_inc(&blockio_work->bios_inflight); + need_new_bio = 0; + bio->bi_end_io = blockio_endio; + bio->bi_sector = lba_start; + bio->bi_bdev = bdev; + bio->bi_private = blockio_work; + bio->bi_rw |= write; + if (write && virt_dev->wt_flag) + bio->bi_rw |= 1 << BIO_RW_SYNC; + + if (!hbio) + hbio = tbio = bio; + else + tbio = tbio->bi_next = bio; + } + + bytes = min_t(unsigned int, len, PAGE_SIZE - off); + + if (bio_add_page(bio, page, bytes, off) < bytes) { + need_new_bio = 1; + lba_start += thislen >> virt_dev->block_shift; + continue; + } + + page++; + thislen += bytes; + len -= bytes; + off = 0; + } + + lba_start += sgl[j].length >> virt_dev->block_shift; + } + + while (hbio) { + bio = hbio; + hbio = hbio->bi_next; + bio->bi_next = NULL; + + generic_make_request(bio); + } + + if (q && q->unplug_fn) + q->unplug_fn(q); + + wait_for_completion(&blockio_work->complete); + + kfree(blockio_work); + +out: + TRACE_EXIT(); + return; + +out_no_bio: + while (hbio) { + bio = hbio; + hbio = hbio->bi_next; + bio_put(bio); + } + kfree(blockio_work); + +out_no_mem: + scst_set_busy(cmd); + goto out; +} + static void vdisk_exec_verify(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, loff_t loff) { @@ -2195,6 +2377,10 @@ seq_printf(seq, "NIO "); c += 4; } + if (virt_dev->blockio) { + seq_printf(seq, "BIO "); + c += 4; + } while (c < 16) { seq_printf(seq, " "); c++; @@ -2363,6 +2549,10 @@ p += 6; virt_dev->nullio = 1; TRACE_DBG("%s", "NULLIO"); + } else if (!strncmp("BLOCKIO", p, 7)) { + p += 7; + virt_dev->blockio = 1; + TRACE_DBG("%s", "BLOCKIO"); } else { PRINT_ERROR_PR("Unknown flag \"%s\"", p); res = -EINVAL; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-03-02 16:32:10
|
Revision: 101 http://svn.sourceforge.net/scst/?rev=101&view=rev Author: vlnb Date: 2007-03-02 08:29:36 -0800 (Fri, 02 Mar 2007) Log Message: ----------- - BLOCKIO made async - Docs updates - Debug logging improvements Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/ToDo trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/ChangeLog 2007-03-02 16:29:36 UTC (rev 101) @@ -1,7 +1,7 @@ Summary of changes between versions 0.9.5 and 0.9.6 --------------------------------------------------- - - FILEIO was renamed to VDISK. BLOCK IO added to it, thanks to Ross S. W. + - FILEIO was renamed to VDISK. BLOCKIO added to it, thanks to Ross S. W. Walker and Vu Pham. - Internal locking and execution context were reimplemnted. Particularly, Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/README 2007-03-02 16:29:36 UTC (rev 101) @@ -108,10 +108,11 @@ mid-level via scsi_do_req()/scsi_execute_async() has advantage that data are transfered via system cache, so it is possible to fully benefit from caching and read ahead performed by Linux's VM subsystem. The only -disadvantage here that there is superfluous data copying between the -cache and SCST's buffers. This issue is going to be addressed in the -next release. Virtual CDROM's are useful for remote installation. See -below for details how to setup and use VDISK device handler. +disadvantage here that in the FILEIO mode there is superfluous data +copying between the cache and SCST's buffers. This issue is going to be +addressed in the next release. Virtual CDROM's are useful for remote +installation. See below for details how to setup and use VDISK device +handler. "Performance" device handlers for disks, MO disks and tapes in their exec() method skip (pretend to execute) all READ and WRITE operations @@ -351,8 +352,8 @@ For example, "echo "open disk1 /vdisks/disk1" >/proc/scsi_tgt/vdisk/vdisk" will open file /vdisks/disk1 as virtual VDISK disk with name "disk1". -IMPORTANT: By default for performance reasons VDISK devices use write back -========= caching policy. This is generally safe from the consistence of +IMPORTANT: By default for performance reasons VDISK FILEIO devices use write +========= back caching policy. This is generally safe from the consistence of journaled file systems, laying over them, point of view, but your unsaved cached data will be lost in case of power/hardware/software failure, so you must supply your @@ -389,8 +390,8 @@ first access to it from the remote initiator with another block size. -BLOCKIO VDISK mode (written by Ross S. W. Walker) -------------------------------------------------- +BLOCKIO VDISK mode +------------------ This module works best for these types of scenarios: @@ -411,20 +412,25 @@ 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 +considerable amount of CPU power and memory bandwidth. + Performance ----------- Before doing any performance measurements note that: I. Currently maximum performance is possible only with real SCSI devices -with several simultaneously executed commands (SCSI tagged queuing) or -performance handlers. If you have enough CPU power, VDISK handler also -could provide the same results, when aggregate throughput is close to -the aggregate throughput locally on the target from the same disks. Also -note, that currently IO subsystem in Linux implemented on such way, so a -VDISK device over a single file occupied entire formatted with some -file system device (eg /dev/hdc) could perform considerably better, than -a VDISK device over /dev/hdc itself without the file system involved. +or VDISK BLOCKIO mode with several simultaneously executed commands +(SCSI tagged queuing) or performance handlers. If you have enough CPU +power, VDISK FILEIO handler also could provide the same results, when +aggregate throughput is close to the aggregate throughput locally on the +target from the same disks. Also note, that currently IO subsystem in +Linux implemented on such way, so a VDISK FILEIO device over a single +file occupied entire formatted with some file system device (eg +/dev/hdc) could perform considerably better, than a VDISK FILEIO device +over /dev/hdc itself without the file system involved. II. In order to get the maximum performance you should: @@ -473,7 +479,7 @@ expected. IMPORTANT: If you use on initiator some versions of Windows (at least W2K) -========= you can't get good write performance for VDISK devices with +========= you can't get good write performance for VDISK FILEIO devices with default 512 bytes block sizes. You could get about 10% of the expected one. This is because of "unusual" write access pattern, with which Windows'es write data and which is Modified: trunk/scst/ToDo =================================================================== --- trunk/scst/ToDo 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/ToDo 2007-03-02 16:29:36 UTC (rev 101) @@ -20,10 +20,6 @@ - Move linear searches to hash-table based. - - Create dev handler for block devices, which would insert commands as - block requests in the device's block queue, so they would processed - by IO-scheduler then. - - Redone some semaphores with completion interface. - HIGHMEM cleanup. Looks like HIGHMEM usage doesn't worth the effort and Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-03-02 16:29:36 UTC (rev 101) @@ -665,9 +665,10 @@ case READ_10: case READ_12: case READ_16: - if (virt_dev->blockio) + if (virt_dev->blockio) { blockio_exec_rw(cmd, thr, lba_start, 0); - else + goto out; + } else vdisk_exec_read(cmd, thr, loff); break; case WRITE_6: @@ -691,9 +692,10 @@ if (vdisk_fsync(thr, 0, 0, cmd) != 0) goto done; } - if (virt_dev->blockio) + if (virt_dev->blockio) { blockio_exec_rw(cmd, thr, lba_start, 1); - else + goto out; + } else vdisk_exec_write(cmd, thr, loff); /* O_SYNC flag is used for WT devices */ if (do_fsync || fua) @@ -2060,7 +2062,6 @@ struct blockio_work { atomic_t bios_inflight; struct scst_cmd *cmd; - struct completion complete; }; static int blockio_endio(struct bio *bio, unsigned int bytes_done, int error) @@ -2089,8 +2090,12 @@ } /* Decrement the bios in processing, and if zero signal completion */ - if (atomic_dec_and_test(&blockio_work->bios_inflight)) - complete(&blockio_work->complete); + if (atomic_dec_and_test(&blockio_work->bios_inflight)) { + blockio_work->cmd->completed = 1; + blockio_work->cmd->scst_cmd_done(blockio_work->cmd, + SCST_CMD_STATE_DEFAULT); + kfree(blockio_work); + } bio_put(bio); return 0; @@ -2107,6 +2112,7 @@ int need_new_bio; struct scatterlist *sgl = cmd->sg; struct blockio_work *blockio_work; + int bios = 0; TRACE_ENTRY(); @@ -2117,10 +2123,8 @@ blockio_work = kmalloc(sizeof (*blockio_work), GFP_KERNEL); if (blockio_work == NULL) goto out_no_mem; - - atomic_set(&blockio_work->bios_inflight, 0); + blockio_work->cmd = cmd; - init_completion(&blockio_work->complete); if (q) max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES); @@ -2147,7 +2151,7 @@ goto out_no_bio; } - atomic_inc(&blockio_work->bios_inflight); + bios++; need_new_bio = 0; bio->bi_end_io = blockio_endio; bio->bi_sector = lba_start << @@ -2180,22 +2184,18 @@ lba_start += sgl[j].length >> virt_dev->block_shift; } + atomic_set(&blockio_work->bios_inflight, bios); while (hbio) { bio = hbio; hbio = hbio->bi_next; bio->bi_next = NULL; - submit_bio(write, bio); } if (q && q->unplug_fn) q->unplug_fn(q); - wait_for_completion(&blockio_work->complete); - - kfree(blockio_work); - out: TRACE_EXIT(); return; Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/src/scst.c 2007-03-02 16:29:36 UTC (rev 101) @@ -601,7 +601,6 @@ dev->virt_name = dev_name; scst_suspend_activity(); - if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out_free_dev; @@ -715,7 +714,6 @@ #endif scst_suspend_activity(); - if (down_interruptible(&scst_mutex) != 0) { res = -EINTR; goto out_err; Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/src/scst_lib.c 2007-03-02 16:29:36 UTC (rev 101) @@ -1193,6 +1193,11 @@ TRACE_ENTRY(); + if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) { + TRACE_MGMT_DBG("Freeing aborted cmd %p (scst_cmd_count %d)", + cmd, atomic_read(&scst_cmd_count)); + } + sBUG_ON(cmd->blocking); #if defined(EXTRACHECKS) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) Modified: trunk/scst/src/scst_proc.c =================================================================== --- trunk/scst/src/scst_proc.c 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/src/scst_proc.c 2007-03-02 16:29:36 UTC (rev 101) @@ -195,6 +195,8 @@ #if defined(DEBUG) || defined(TRACING) +static DECLARE_MUTEX(scst_log_mutex); + int scst_proc_log_entry_write(struct file *file, const char *buf, unsigned long length, unsigned long *log_level, unsigned long default_level, const struct scst_proc_log *tbl) @@ -356,7 +358,7 @@ TRACE_ENTRY(); - if (down_interruptible(&scst_proc_mutex) != 0) { + if (down_interruptible(&scst_log_mutex) != 0) { res = -EINTR; goto out; } @@ -364,7 +366,7 @@ res = scst_proc_log_entry_write(file, buf, length, &trace_flag, SCST_DEFAULT_LOG_FLAGS, scst_proc_local_trace_tbl); - up(&scst_proc_mutex); + up(&scst_log_mutex); out: TRACE_EXIT_RES(res); @@ -1882,14 +1884,14 @@ TRACE_ENTRY(); - if (down_interruptible(&scst_proc_mutex) != 0) { + if (down_interruptible(&scst_log_mutex) != 0) { res = -EINTR; goto out; } res = scst_proc_log_entry_read(seq, trace_flag, scst_proc_local_trace_tbl); - up(&scst_proc_mutex); + up(&scst_log_mutex); out: TRACE_EXIT_RES(res); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-03-02 15:06:55 UTC (rev 100) +++ trunk/scst/src/scst_targ.c 2007-03-02 16:29:36 UTC (rev 101) @@ -144,7 +144,8 @@ } else { unsigned long flags; spin_lock_irqsave(&scst_init_lock, flags); - TRACE_MGMT_DBG("Adding cmd %p to init cmd list", cmd); + TRACE_MGMT_DBG("Adding cmd %p to init cmd list (scst_cmd_count " + "%d)", cmd, atomic_read(&scst_cmd_count)); list_add_tail(&cmd->cmd_list_entry, &scst_init_cmd_list); if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) scst_init_poll_cnt++; @@ -974,161 +975,8 @@ return; } -/* No locks supposed to be held */ -static void scst_check_sense(struct scst_cmd *cmd, const uint8_t *rq_sense, - int rq_sense_len, int *next_state) -{ - int sense_valid; - struct scst_device *dev = cmd->dev; - int dbl_ua_possible, ua_sent = 0; - - TRACE_ENTRY(); - - /* If we had a internal bus reset behind us, set the command error UA */ - if ((dev->scsi_dev != NULL) && - unlikely(cmd->host_status == DID_RESET) && - scst_is_ua_command(cmd)) - { - TRACE(TRACE_MGMT, "DID_RESET: was_reset=%d host_status=%x", - dev->scsi_dev->was_reset, cmd->host_status); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_reset_UA)); - /* just in case */ - cmd->ua_ignore = 0; - /* It looks like it is safe to clear was_reset here */ - dev->scsi_dev->was_reset = 0; - smp_mb(); - } - - if (rq_sense != NULL) { - sense_valid = SCST_SENSE_VALID(rq_sense); - if (sense_valid) { - /* - * We checked that rq_sense_len < sizeof(cmd->sense_buffer) - * in init_scst() - */ - memcpy(cmd->sense_buffer, rq_sense, rq_sense_len); - memset(&cmd->sense_buffer[rq_sense_len], 0, - sizeof(cmd->sense_buffer) - rq_sense_len); - } - } else - sense_valid = SCST_SENSE_VALID(cmd->sense_buffer); - - dbl_ua_possible = dev->dev_double_ua_possible; - TRACE_DBG("cmd %p dbl_ua_possible %d", cmd, dbl_ua_possible); - if (unlikely(dbl_ua_possible)) { - spin_lock_bh(&dev->dev_lock); - barrier(); /* to reread dev_double_ua_possible */ - dbl_ua_possible = dev->dev_double_ua_possible; - if (dbl_ua_possible) - ua_sent = dev->dev_reset_ua_sent; - else - spin_unlock_bh(&dev->dev_lock); - } - - if (sense_valid) { - TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer, - sizeof(cmd->sense_buffer)); - /* Check Unit Attention Sense Key */ - if (cmd->sense_buffer[2] == UNIT_ATTENTION) { - if (cmd->sense_buffer[12] == SCST_SENSE_ASC_UA_RESET) { - if (dbl_ua_possible) - { - if (ua_sent) { - TRACE(TRACE_MGMT, "%s", - "Double UA detected"); - /* Do retry */ - TRACE(TRACE_MGMT, "Retrying cmd %p " - "(tag %d)", cmd, cmd->tag); - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - memset(cmd->sense_buffer, 0, - sizeof(cmd->sense_buffer)); - cmd->retry = 1; - *next_state = SCST_CMD_STATE_SEND_TO_MIDLEV; - /* - * Dev is still blocked by this cmd, so - * it's OK to clear SCST_DEV_SERIALIZED - * here. - */ - dev->dev_double_ua_possible = 0; - dev->dev_serialized = 0; - dev->dev_reset_ua_sent = 0; - goto out_unlock; - } else - dev->dev_reset_ua_sent = 1; - } - } - if (cmd->ua_ignore == 0) { - if (unlikely(dbl_ua_possible)) { - __scst_process_UA(dev, cmd, - cmd->sense_buffer, - sizeof(cmd->sense_buffer), 0); - } else { - scst_process_UA(dev, cmd, - cmd->sense_buffer, - sizeof(cmd->sense_buffer), 0); - } - } - } - } - - if (unlikely(dbl_ua_possible)) { - if (ua_sent && scst_is_ua_command(cmd)) { - TRACE_MGMT_DBG("%s", "Clearing dbl_ua_possible flag"); - dev->dev_double_ua_possible = 0; - dev->dev_serialized = 0; - dev->dev_reset_ua_sent = 0; - } - spin_unlock_bh(&dev->dev_lock); - } - -out: - TRACE_EXIT(); - return; - -out_unlock: - spin_unlock_bh(&dev->dev_lock); - goto out; -} - -static int scst_check_auto_sense(struct scst_cmd *cmd) -{ - int res = 0; - - TRACE_ENTRY(); - - if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) && - (!SCST_SENSE_VALID(cmd->sense_buffer) || - SCST_NO_SENSE(cmd->sense_buffer))) - { - TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: " - "cmd->status=%x, cmd->msg_status=%x, " - "cmd->host_status=%x, cmd->driver_status=%x", cmd->status, - cmd->msg_status, cmd->host_status, cmd->driver_status); - res = 1; - } else if (unlikely(cmd->host_status)) { - if ((cmd->host_status == DID_REQUEUE) || - (cmd->host_status == DID_IMM_RETRY) || - (cmd->host_status == DID_SOFT_ERROR)) { - scst_set_busy(cmd); - } else { - TRACE(TRACE_SCSI|TRACE_MINOR, "Host status %x " - "received, returning HARDWARE ERROR instead", - cmd->host_status); - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - } - } - - TRACE_EXIT_RES(res); - return res; -} - static void scst_do_cmd_done(struct scst_cmd *cmd, int result, - const uint8_t *rq_sense, int rq_sense_len, int resid, - int *next_state) + const uint8_t *rq_sense, int rq_sense_len, int resid) { unsigned char type; @@ -1148,6 +996,14 @@ scst_set_resp_data_len(cmd, cmd->resp_data_len - resid); } + /* + * We checked that rq_sense_len < sizeof(cmd->sense_buffer) + * in init_scst() + */ + memcpy(cmd->sense_buffer, rq_sense, rq_sense_len); + memset(&cmd->sense_buffer[rq_sense_len], 0, + sizeof(cmd->sense_buffer) - rq_sense_len); + TRACE(TRACE_SCSI, "result=%x, cmd->status=%x, resid=%d, " "cmd->msg_status=%x, cmd->host_status=%x, " "cmd->driver_status=%x", result, cmd->status, resid, @@ -1170,7 +1026,7 @@ if (unlikely(length <= 0)) { PRINT_ERROR_PR("%s: scst_get_buf_first() failed", __func__); - goto next; + goto out; } if (length > 2 && cmd->cdb[0] == MODE_SENSE) { address[2] |= 0x80; /* Write Protect*/ @@ -1181,9 +1037,7 @@ scst_put_buf(cmd, address); } -next: - scst_check_sense(cmd, rq_sense, rq_sense_len, next_state); - +out: TRACE_EXIT(); return; } @@ -1223,19 +1077,15 @@ { struct scsi_request *req = NULL; struct scst_cmd *cmd; - int next_state; TRACE_ENTRY(); - WARN_ON(in_irq()); - cmd = scst_get_cmd(scsi_cmd, &req); if (cmd == NULL) goto out; - next_state = SCST_CMD_STATE_DEV_DONE; scst_do_cmd_done(cmd, req->sr_result, req->sr_sense_buffer, - sizeof(req->sr_sense_buffer), scsi_cmd->resid, &next_state); + sizeof(req->sr_sense_buffer), scsi_cmd->resid); /* Clear out request structure */ req->sr_use_sg = 0; @@ -1247,7 +1097,7 @@ scst_release_request(cmd); - cmd->state = next_state; + cmd->state = SCST_CMD_STATE_DEV_DONE; scst_proccess_redirect_cmd(cmd, scst_optimize_post_exec_context(cmd, scst_get_context()), 0); @@ -1260,21 +1110,16 @@ static void scst_cmd_done(void *data, char *sense, int result, int resid) { struct scst_cmd *cmd; - int next_state; TRACE_ENTRY(); - WARN_ON(in_irq()); - cmd = (struct scst_cmd *)data; if (cmd == NULL) goto out; - next_state = SCST_CMD_STATE_DEV_DONE; - scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid, - &next_state); + scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid); - cmd->state = next_state; + cmd->state = SCST_CMD_STATE_DEV_DONE; scst_proccess_redirect_cmd(cmd, scst_optimize_post_exec_context(cmd, scst_get_context()), 0); @@ -1289,8 +1134,6 @@ { TRACE_ENTRY(); - sBUG_ON(in_irq()); - scst_dec_on_dev_cmd(cmd, 0); if (next_state == SCST_CMD_STATE_DEFAULT) @@ -1325,15 +1168,7 @@ SCST_LOAD_SENSE(scst_sense_hardw_error)); next_state = SCST_CMD_STATE_DEV_DONE; } - - if (scst_check_auto_sense(cmd)) { - PRINT_ERROR_PR("CHECK_CONDITION, but no valid sense for " - "opcode %d", cmd->cdb[0]); - } #endif - - scst_check_sense(cmd, NULL, 0, &next_state); - cmd->state = next_state; scst_proccess_redirect_cmd(cmd, @@ -2052,6 +1887,147 @@ return res; } +/* No locks supposed to be held */ +static int scst_check_sense(struct scst_cmd *cmd) +{ + int res = 0; + int sense_valid; + struct scst_device *dev = cmd->dev; + int dbl_ua_possible, ua_sent = 0; + + TRACE_ENTRY(); + + /* If we had a internal bus reset behind us, set the command error UA */ + if ((dev->scsi_dev != NULL) && + unlikely(cmd->host_status == DID_RESET) && + scst_is_ua_command(cmd)) + { + TRACE(TRACE_MGMT, "DID_RESET: was_reset=%d host_status=%x", + dev->scsi_dev->was_reset, cmd->host_status); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_reset_UA)); + /* just in case */ + cmd->ua_ignore = 0; + /* It looks like it is safe to clear was_reset here */ + dev->scsi_dev->was_reset = 0; + smp_mb(); + } + + sense_valid = SCST_SENSE_VALID(cmd->sense_buffer); + + dbl_ua_possible = dev->dev_double_ua_possible; + TRACE_DBG("cmd %p dbl_ua_possible %d", cmd, dbl_ua_possible); + if (unlikely(dbl_ua_possible)) { + spin_lock_bh(&dev->dev_lock); + barrier(); /* to reread dev_double_ua_possible */ + dbl_ua_possible = dev->dev_double_ua_possible; + if (dbl_ua_possible) + ua_sent = dev->dev_reset_ua_sent; + else + spin_unlock_bh(&dev->dev_lock); + } + + if (sense_valid) { + TRACE_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense_buffer, + sizeof(cmd->sense_buffer)); + /* Check Unit Attention Sense Key */ + if (cmd->sense_buffer[2] == UNIT_ATTENTION) { + if (cmd->sense_buffer[12] == SCST_SENSE_ASC_UA_RESET) { + if (dbl_ua_possible) + { + if (ua_sent) { + TRACE(TRACE_MGMT, "%s", + "Double UA detected"); + /* Do retry */ + TRACE(TRACE_MGMT, "Retrying cmd %p " + "(tag %d)", cmd, cmd->tag); + cmd->status = 0; + cmd->msg_status = 0; + cmd->host_status = DID_OK; + cmd->driver_status = 0; + memset(cmd->sense_buffer, 0, + sizeof(cmd->sense_buffer)); + cmd->retry = 1; + cmd->state = SCST_CMD_STATE_SEND_TO_MIDLEV; + res = 1; + /* + * Dev is still blocked by this cmd, so + * it's OK to clear SCST_DEV_SERIALIZED + * here. + */ + dev->dev_double_ua_possible = 0; + dev->dev_serialized = 0; + dev->dev_reset_ua_sent = 0; + goto out_unlock; + } else + dev->dev_reset_ua_sent = 1; + } + } + if (cmd->ua_ignore == 0) { + if (unlikely(dbl_ua_possible)) { + __scst_process_UA(dev, cmd, + cmd->sense_buffer, + sizeof(cmd->sense_buffer), 0); + } else { + scst_process_UA(dev, cmd, + cmd->sense_buffer, + sizeof(cmd->sense_buffer), 0); + } + } + } + } + + if (unlikely(dbl_ua_possible)) { + if (ua_sent && scst_is_ua_command(cmd)) { + TRACE_MGMT_DBG("%s", "Clearing dbl_ua_possible flag"); + dev->dev_double_ua_possible = 0; + dev->dev_serialized = 0; + dev->dev_reset_ua_sent = 0; + } + spin_unlock_bh(&dev->dev_lock); + } + +out: + TRACE_EXIT_RES(res); + return res; + +out_unlock: + spin_unlock_bh(&dev->dev_lock); + goto out; +} + +static int scst_check_auto_sense(struct scst_cmd *cmd) +{ + int res = 0; + + TRACE_ENTRY(); + + if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) && + (!SCST_SENSE_VALID(cmd->sense_buffer) || + SCST_NO_SENSE(cmd->sense_buffer))) + { + TRACE(TRACE_SCSI|TRACE_MINOR, "CHECK_CONDITION, but no sense: " + "cmd->status=%x, cmd->msg_status=%x, " + "cmd->host_status=%x, cmd->driver_status=%x", cmd->status, + cmd->msg_status, cmd->host_status, cmd->driver_status); + res = 1; + } else if (unlikely(cmd->host_status)) { + if ((cmd->host_status == DID_REQUEUE) || + (cmd->host_status == DID_IMM_RETRY) || + (cmd->host_status == DID_SOFT_ERROR)) { + scst_set_busy(cmd); + } else { + TRACE(TRACE_SCSI|TRACE_MINOR, "Host status %x " + "received, returning HARDWARE ERROR instead", + cmd->host_status); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + } + } + + TRACE_EXIT_RES(res); + return res; +} + static int scst_done_cmd_check(struct scst_cmd *cmd, int *pres) { int res = 0, rc; @@ -2077,6 +2053,10 @@ scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); } + } else if (scst_check_sense(cmd)) { + *pres = SCST_CMD_STATE_RES_CONT_SAME; + res = 1; + goto out; } type = cmd->dev->handler->type; @@ -2420,6 +2400,12 @@ list_del(&cmd->search_cmd_list_entry); spin_unlock_irq(&cmd->sess->sess_list_lock); + if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) { + TRACE_MGMT_DBG("Aborted cmd %p finished (cmd_ref %d, " + "scst_cmd_count %d)", cmd, atomic_read(&cmd->cmd_ref), + atomic_read(&scst_cmd_count)); + } + scst_cmd_put(cmd); res = SCST_CMD_STATE_RES_CONT_NEXT; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-04-03 14:49:23
|
Revision: 105 http://svn.sourceforge.net/scst/?rev=105&view=rev Author: vlnb Date: 2007-04-03 07:47:47 -0700 (Tue, 03 Apr 2007) Log Message: ----------- Parse() functions made generic Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_cdrom.c trunk/scst/src/dev_handlers/scst_changer.c trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_processor.c trunk/scst/src/dev_handlers/scst_raid.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/include/scsi_tgt.h 2007-04-03 14:47:47 UTC (rev 105) @@ -443,10 +443,22 @@ #define SCST_RES_3RDPTY 0x10 #define SCST_RES_LONGID 0x02 +/************************************************************* + ** Bits in the READ POSITION command + *************************************************************/ +#define TCLP_BIT 4 +#define LONG_BIT 2 +#define BT_BIT 1 + /************************************************************* ** Misc SCSI constants *************************************************************/ #define SCST_SENSE_ASC_UA_RESET 0x29 +#define READ_CAP_LEN 8 +#define READ_CAP16_LEN 12 +#define BYTCHK 0x02 +#define POSITION_LEN_SHORT 20 +#define POSITION_LEN_LONG 32 /************************************************************* ** Name of the entry in /proc @@ -754,8 +766,7 @@ * * MUST HAVE */ - int (*parse) (struct scst_cmd *cmd, - const struct scst_info_cdb *cdb_info); + int (*parse) (struct scst_cmd *cmd, struct scst_info_cdb *cdb_info); /* * Called to execute CDB. Useful, for instance, to implement @@ -2299,4 +2310,45 @@ data->free_fn(data); } +/** + ** Generic parse() support routines + **/ + +/* Calculates and returns block shift for the given sector size */ +int scst_calc_block_shift(int sector_size); + +/* Generic parse() for SBC (disk) devices */ +int scst_sbc_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for MMC (cdrom) devices */ +int scst_cdrom_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for MO disk devices */ +int scst_modisk_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for tape devices */ +int scst_tape_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_size); + +/* Generic parse() functions for other devices */ +int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb); +static inline int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} +static inline int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} +static inline int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} + #endif /* __SCST_H */ Modified: trunk/scst/src/dev_handlers/scst_cdrom.c =================================================================== --- trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 14:47:47 UTC (rev 105) @@ -37,23 +37,18 @@ dev_done: cdrom_done, \ } -#define CDROM_RETRIES 2 #define CDROM_SMALL_TIMEOUT (3 * HZ) #define CDROM_REG_TIMEOUT (900 * HZ) #define CDROM_LONG_TIMEOUT (14000 * HZ) -#define READ_CAP_LEN 8 -/* Flags */ -#define BYTCHK 0x02 - struct cdrom_params { - int sector_size; + int block_shift; }; int cdrom_attach(struct scst_device *); void cdrom_detach(struct scst_device *); -int cdrom_parse(struct scst_cmd *, const struct scst_info_cdb *); +int cdrom_parse(struct scst_cmd *, struct scst_info_cdb *); int cdrom_done(struct scst_cmd *); static struct scst_dev_type cdrom_devtype = CDROM_TYPE; @@ -117,7 +112,7 @@ TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - CDROM_REG_TIMEOUT, CDROM_RETRIES, 0); + CDROM_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -128,22 +123,22 @@ if (!--retries) { PRINT_ERROR_PR("UA not clear after %d retries", SCST_DEV_UA_RETRIES); - cdrom->sector_size = 2048; + cdrom->block_shift = 11; /* 2048 bytes */ // res = -ENODEV; goto out_free_buf; } } if (res == 0) { - cdrom->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + if (sector_size == 0) + sector_size = 2048; + cdrom->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", - cdrom->sector_size, dev->scsi_dev->scsi_level, SCSI_2); - if (!cdrom->sector_size) { - cdrom->sector_size = 2048; - } + sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); - cdrom->sector_size = 2048; + cdrom->block_shift = 11; /* 2048 bytes */ // res = -ENODEV; goto out_free_buf; } @@ -195,19 +190,20 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int cdrom_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct cdrom_params *cdrom; - int fixed; + struct cdrom_params *cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + scst_cdrom_generic_parse(cmd, info_cdb, cdrom->block_shift); + + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = CDROM_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -215,62 +211,6 @@ } else { cmd->timeout = CDROM_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", - info_cdb->op_name, - info_cdb->direction, - info_cdb->flags, - info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); - - cmd->cdb[1] &= 0x1f; - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - 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; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * cdrom->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); return res; } @@ -308,13 +248,9 @@ case READ_CAPACITY: { /* Always keep track of cdrom capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * cdrom->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -331,12 +267,16 @@ sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - if (!sector_size) - sector_size = 2048; - cdrom->sector_size = sector_size; - TRACE_DBG("Sector size is %i", cdrom->sector_size); - scst_put_buf(cmd, buffer); + if (sector_size == 0) + sector_size = 2048; + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * cdrom->block_shift access atomic + */ + barrier(); + cdrom->block_shift = block_shift; break; } default: Modified: trunk/scst/src/dev_handlers/scst_changer.c =================================================================== --- trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 14:47:47 UTC (rev 105) @@ -42,7 +42,7 @@ int changer_attach(struct scst_device *); void changer_detach(struct scst_device *); -int changer_parse(struct scst_cmd *, const struct scst_info_cdb *); +int changer_parse(struct scst_cmd *, struct scst_info_cdb *); int changer_done(struct scst_cmd *); static struct scst_dev_type changer_devtype = CHANGER_TYPE; @@ -124,17 +124,12 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int changer_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int changer_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); + scst_changer_generic_parse(cmd, info_cdb); - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - cmd->retries = 1; if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -143,21 +138,6 @@ cmd->timeout = CHANGER_TIMEOUT; } - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 14:47:47 UTC (rev 105) @@ -56,23 +56,18 @@ exec: disk_exec, \ } -#define DISK_RETRIES 5 #define DISK_SMALL_TIMEOUT (3 * HZ) #define DISK_REG_TIMEOUT (60 * HZ) #define DISK_LONG_TIMEOUT (3600 * HZ) -#define READ_CAP_LEN 8 -/* Flags */ -#define BYTCHK 0x02 - struct disk_params { - int sector_size; + int block_shift; }; int disk_attach(struct scst_device *dev); void disk_detach(struct scst_device *dev); -int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cmd); +int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cmd); int disk_done(struct scst_cmd *cmd); int disk_exec(struct scst_cmd *cmd); @@ -193,7 +188,7 @@ TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - DISK_REG_TIMEOUT, DISK_RETRIES, 0); + DISK_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -209,12 +204,9 @@ } } if (res == 0) { - disk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - TRACE_DBG("Sector size is %i", disk->sector_size); - if (!disk->sector_size) { - disk->sector_size = 512; - } + disk->block_shift = scst_calc_block_shift(sector_size); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); res = -ENODEV; @@ -268,21 +260,20 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { + struct disk_params *disk = (struct disk_params *)cmd->dev->dh_priv; int res = SCST_CMD_STATE_DEFAULT; - struct disk_params *disk; - int fixed; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ - cmd->retries = DISK_RETRIES; + scst_sbc_generic_parse(cmd, info_cdb, disk->block_shift); + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = DISK_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -291,49 +282,6 @@ cmd->timeout = DISK_REG_TIMEOUT; } - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - disk = (struct disk_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * disk->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT_RES(res); return res; } @@ -371,13 +319,9 @@ case READ_CAPACITY: { /* Always keep track of disk capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * disk->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -394,12 +338,14 @@ sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - if (!sector_size) - sector_size = 512; - disk->sector_size = sector_size; - TRACE_DBG("Sector size is %i", disk->sector_size); - scst_put_buf(cmd, buffer); + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * disk->block_shift access atomic + */ + barrier(); + disk->block_shift = block_shift; break; } default: Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 14:47:47 UTC (rev 105) @@ -56,23 +56,20 @@ exec: modisk_exec, \ } -#define MODISK_RETRIES 2 #define MODISK_SMALL_TIMEOUT (3 * HZ) #define MODISK_REG_TIMEOUT (900 * HZ) #define MODISK_LONG_TIMEOUT (14000 * HZ) -#define READ_CAP_LEN 8 -#define MODISK_SECTOR_SIZE 1024 -/* Flags */ -#define BYTCHK 0x02 +#define MODISK_BLOCK_SHIFT 10 +#define MODISK_SECTOR_SIZE (1 << MODISK_BLOCK_SHIFT) struct modisk_params { - int sector_size; + int block_shift; }; int modisk_attach(struct scst_device *); void modisk_detach(struct scst_device *); -int modisk_parse(struct scst_cmd *, const struct scst_info_cdb *); +int modisk_parse(struct scst_cmd *, struct scst_info_cdb *); int modisk_done(struct scst_cmd *); int modisk_exec(struct scst_cmd *); @@ -171,7 +168,7 @@ res = -ENOMEM; goto out; } - modisk->sector_size = MODISK_SECTOR_SIZE; + modisk->block_shift = MODISK_BLOCK_SHIFT; /* * If the device is offline, don't try to read capacity or any @@ -205,7 +202,7 @@ TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - MODISK_REG_TIMEOUT, MODISK_RETRIES, 0); + MODISK_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -220,13 +217,13 @@ } } if (res == 0) { - modisk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + if (sector_size == 0) + sector_size = MODISK_SECTOR_SIZE; + modisk->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", - modisk->sector_size, dev->scsi_dev->scsi_level, SCSI_2); - if (!modisk->sector_size) { - modisk->sector_size = MODISK_SECTOR_SIZE; - } + sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); @@ -282,19 +279,20 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int modisk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct modisk_params *modisk; - int fixed; + struct modisk_params *modisk = (struct modisk_params*)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + scst_modisk_generic_parse(cmd, info_cdb, modisk->block_shift); + + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = MODISK_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -302,62 +300,6 @@ } else { cmd->timeout = MODISK_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", - info_cdb->op_name, - info_cdb->direction, - info_cdb->flags, - info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); - - cmd->cdb[1] &= 0x1f; - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - 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; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - modisk = (struct modisk_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * modisk->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT_RES(res); return res; } @@ -395,13 +337,9 @@ case READ_CAPACITY: { /* Always keep track of modisk capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * modisk->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -418,12 +356,16 @@ sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + scst_put_buf(cmd, buffer); if (!sector_size) sector_size = MODISK_SECTOR_SIZE; - modisk->sector_size = sector_size; - TRACE_DBG("Sector size is %i", modisk->sector_size); - - scst_put_buf(cmd, buffer); + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * cdrom->block_shift access atomic + */ + barrier(); + modisk->block_shift = block_shift; break; } default: Modified: trunk/scst/src/dev_handlers/scst_processor.c =================================================================== --- trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 14:47:47 UTC (rev 105) @@ -42,7 +42,7 @@ int processor_attach(struct scst_device *); void processor_detach(struct scst_device *); -int processor_parse(struct scst_cmd *, const struct scst_info_cdb *); +int processor_parse(struct scst_cmd *, struct scst_info_cdb *); int processor_done(struct scst_cmd *); static struct scst_dev_type processor_devtype = PROCESSOR_TYPE; @@ -124,17 +124,12 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int processor_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int processor_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); + scst_processor_generic_parse(cmd, info_cdb); - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - cmd->retries = 1; if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -142,22 +137,6 @@ } else { cmd->timeout = PROCESSOR_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } Modified: trunk/scst/src/dev_handlers/scst_raid.c =================================================================== --- trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 14:47:47 UTC (rev 105) @@ -42,7 +42,7 @@ int raid_attach(struct scst_device *); void raid_detach(struct scst_device *); -int raid_parse(struct scst_cmd *, const struct scst_info_cdb *); +int raid_parse(struct scst_cmd *, struct scst_info_cdb *); int raid_done(struct scst_cmd *); static struct scst_dev_type raid_devtype = RAID_TYPE; @@ -124,17 +124,12 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int raid_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int raid_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); + scst_raid_generic_parse(cmd, info_cdb); - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - cmd->retries = 1; if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -142,22 +137,6 @@ } else { cmd->timeout = RAID_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 14:47:47 UTC (rev 105) @@ -65,14 +65,6 @@ /* The fixed bit in READ/WRITE/VERIFY */ #define SILI_BIT 2 -/* Bits in the READ POSITION command */ -#define TCLP_BIT 4 -#define LONG_BIT 2 -#define BT_BIT 1 - -#define POSITION_LEN_SHORT 20 -#define POSITION_LEN_LONG 32 - struct tape_params { spinlock_t tp_lock; @@ -85,7 +77,7 @@ int tape_attach(struct scst_device *); void tape_detach(struct scst_device *); -int tape_parse(struct scst_cmd *, const struct scst_info_cdb *); +int tape_parse(struct scst_cmd *, struct scst_info_cdb *); int tape_done(struct scst_cmd *); int tape_exec(struct scst_cmd *); @@ -280,18 +272,18 @@ * * Note: Not all states are allowed on return ********************************************************************/ -int tape_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct tape_params *tape; + struct tape_params *tape = (struct tape_params*)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be called, + * when there are existing commands. */ + scst_tape_generic_parse(cmd, info_cdb, tape->block_size); + cmd->retries = 1; if (info_cdb->flags & SCST_SMALL_TIMEOUT) { @@ -301,36 +293,6 @@ } else { cmd->timeout = TAPE_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - if (cmd->cdb[0] == READ_POSITION) { - int tclp = cmd->cdb[1] & TCLP_BIT; - int long_bit = cmd->cdb[1] & LONG_BIT; - int bt = cmd->cdb[1] & BT_BIT; - - if ((tclp == long_bit) && (!bt || !long_bit)) { - cmd->bufflen = - tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT; - cmd->data_direction = SCST_DATA_READ; - } else { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - } - } - - if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) { - /* - * No need for locks here, since *_detach() can not be called, - * when there are existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * tape->block_size; - } - - TRACE_EXIT_RES(res); return res; } Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 14:47:47 UTC (rev 105) @@ -65,13 +65,8 @@ /* 4 byte ASCII Product Revision Level - left aligned */ #define SCST_FIO_REV " 096" -#define READ_CAP_LEN 8 -#define READ_CAP16_LEN 12 - #define MAX_USN_LEN 20 -#define BYTCHK 0x02 - #define INQ_BUF_SZ 128 #define EVPD 0x01 #define CMDDT 0x02 @@ -145,9 +140,9 @@ static void vdisk_detach(struct scst_device *dev); static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev); static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev); -static int vdisk_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); +static int vdisk_parse(struct scst_cmd *, struct scst_info_cdb *info_cdb); static int vdisk_do_job(struct scst_cmd *cmd); -static int vcdrom_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); +static int vcdrom_parse(struct scst_cmd *, struct scst_info_cdb *info_cdb); static int vcdrom_exec(struct scst_cmd *cmd); static void vdisk_exec_read(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, loff_t loff); @@ -835,67 +830,13 @@ * Note: Not all states are allowed on return ********************************************************************/ static int vdisk_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) + struct scst_info_cdb *info_cdb) { - int res = SCST_CMD_STATE_DEFAULT; - int fixed; struct scst_vdisk_dev *virt_dev = (struct scst_vdisk_dev *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - 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; - cmd->data_direction = SCST_DATA_READ; - } - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT(); - return res; + scst_sbc_generic_parse(cmd, info_cdb, virt_dev->block_shift); + return SCST_CMD_STATE_DEFAULT; } /******************************************************************** @@ -910,61 +851,13 @@ * Note: Not all states are allowed on return ********************************************************************/ static int vcdrom_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) + struct scst_info_cdb *info_cdb) { - int res = SCST_CMD_STATE_DEFAULT; - int fixed; struct scst_vdisk_dev *virt_dev = (struct scst_vdisk_dev *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT_HRES(res); - return res; + scst_cdrom_generic_parse(cmd, info_cdb, virt_dev->block_shift); + return SCST_CMD_STATE_DEFAULT; } /******************************************************************** Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/scst.c 2007-04-03 14:47:47 UTC (rev 105) @@ -1476,6 +1476,14 @@ EXPORT_SYMBOL(scst_dev_del_all_thr_data); EXPORT_SYMBOL(scst_find_thr_data); +/* Generic parse() routines */ +EXPORT_SYMBOL(scst_calc_block_shift); +EXPORT_SYMBOL(scst_sbc_generic_parse); +EXPORT_SYMBOL(scst_cdrom_generic_parse); +EXPORT_SYMBOL(scst_modisk_generic_parse); +EXPORT_SYMBOL(scst_tape_generic_parse); +EXPORT_SYMBOL(scst_null_parse); + /* * Other Commands */ Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-04-03 14:42:47 UTC (rev 104) +++ trunk/scst/src/scst_lib.c 2007-04-03 14:47:47 UTC (rev 105) @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/sched.h> #include <linux/kthread.h> +#include <linux/cdrom.h> #include <asm/unistd.h> #include <asm/string.h> @@ -1829,6 +1830,275 @@ goto out; } +int scst_calc_block_shift(int sector_size) +{ + int block_shift = 0; + int t = sector_size; + + if (sector_size == 0) + sector_size = 512; + + while(1) { + if ((t & 1) != 0) + break; + t >>= 1; + block_shift++; + } + if (block_shift < 9) { + PRINT_ERROR_PR("Wrong sector size %d", sector_size); + block_shift = -1; + } + + TRACE_EXIT_RES(block_shift); + return block_shift; +} + +int scst_sbc_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + 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; + cmd->data_direction = SCST_DATA_READ; + } + break; + case VERIFY_6: + case VERIFY: + case VERIFY_12: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } else + cmd->data_len = 0; + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) { + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ + cmd->bufflen = info_cdb->transfer_len << block_shift; + } + + TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", + res, cmd->bufflen, cmd->data_len, cmd->data_direction); + + TRACE_EXIT_RES(res); + return res; +} + +int scst_cdrom_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", + info_cdb->op_name, + info_cdb->direction, + info_cdb->flags, + info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); + + 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: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) + cmd->bufflen = info_cdb->transfer_len << block_shift; + + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT(); + return res; +} + +int scst_modisk_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", + info_cdb->op_name, + info_cdb->direction, + info_cdb->flags, + info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); + + 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: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) + cmd->bufflen = info_cdb->transfer_len << block_shift;; + + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT_RES(res); + return res; +} + +int scst_tape_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_size) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); + + if (cmd->cdb[0] == READ_POSITION) { + int tclp = cmd->cdb[1] & TCLP_BIT; + int long_bit = cmd->cdb[1] & LONG_BIT; + int bt = cmd->cdb[1] & BT_BIT; + + if ((tclp == long_bit) && (!bt || !long_bit)) { + cmd->bufflen = + tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT; + cmd->data_direction = SCST_DATA_READ; + } else { + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + } + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) + cmd->bufflen = info_cdb->transfer_len * block_size; + + TRACE_EXIT_RES(res); + return res; +} + +int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); +#if 0 + switch (cmd->cdb[0]) { + default: + /* It's all good */ + break; + } +#endif + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT(); + return res; +} + /* Called under dev_lock and BH off */ void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-04-03 14:51:33
|
Revision: 107 http://svn.sourceforge.net/scst/?rev=107&view=rev Author: vlnb Date: 2007-04-03 07:51:18 -0700 (Tue, 03 Apr 2007) Log Message: ----------- dev_done() made generic, small generic parse() optimization and cleanups Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_cdrom.c trunk/scst/src/dev_handlers/scst_changer.c trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_processor.c trunk/scst/src/dev_handlers/scst_raid.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/include/scsi_tgt.h 2007-04-03 14:51:18 UTC (rev 107) @@ -2311,7 +2311,9 @@ } /** - ** Generic parse() support routines + ** Generic parse() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. **/ /* Calculates and returns block shift for the given sector size */ @@ -2319,36 +2321,48 @@ /* Generic parse() for SBC (disk) devices */ int scst_sbc_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for MMC (cdrom) devices */ int scst_cdrom_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for MO disk devices */ int scst_modisk_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for tape devices */ int scst_tape_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_size); + struct scst_info_cdb *info_cdb, + int (*get_block_size)(struct scst_cmd *cmd)); -/* Generic parse() functions for other devices */ -int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb); -static inline int scst_changer_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb) -{ - return scst_null_parse(cmd, info_cdb); -} -static inline int scst_processor_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb) -{ - return scst_null_parse(cmd, info_cdb); -} -static inline int scst_raid_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb) -{ - return scst_null_parse(cmd, info_cdb); -} +/* Generic parse() for changer devices */ +int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); +/* Generic parse() for "processor" devices */ +int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); + +/* Generic parse() for RAID devices */ +int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); + +/** + ** Generic dev_done() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. + **/ + +/* Generic dev_done() for block devices */ +int scst_block_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)); + +/* Generic dev_done() for tape devices */ +int scst_tape_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_size)(struct scst_cmd *cmd, int block_size)); + #endif /* __SCST_H */ Modified: trunk/scst/src/dev_handlers/scst_cdrom.c =================================================================== --- trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 14:51:18 UTC (rev 107) @@ -41,6 +41,8 @@ #define CDROM_REG_TIMEOUT (900 * HZ) #define CDROM_LONG_TIMEOUT (14000 * HZ) +#define CDROM_DEF_BLOCK_SHIFT 11 + struct cdrom_params { int block_shift; @@ -72,7 +74,7 @@ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct cdrom_params *cdrom; + struct cdrom_params *params; TRACE_ENTRY(); @@ -83,8 +85,8 @@ goto out; } - cdrom = kzalloc(sizeof(*cdrom), GFP_KERNEL); - if (cdrom == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct cdrom_params"); res = -ENOMEM; @@ -95,7 +97,7 @@ if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_cdrom; + goto out_free_params; } /* Clear any existing UA's and get cdrom capacity (cdrom block size) */ @@ -123,7 +125,7 @@ if (!--retries) { PRINT_ERROR_PR("UA not clear after %d retries", SCST_DEV_UA_RETRIES); - cdrom->block_shift = 11; /* 2048 bytes */ + params->block_shift = CDROM_DEF_BLOCK_SHIFT; // res = -ENODEV; goto out_free_buf; } @@ -132,13 +134,14 @@ int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); if (sector_size == 0) - sector_size = 2048; - cdrom->block_shift = scst_calc_block_shift(sector_size); + params->block_shift = CDROM_DEF_BLOCK_SHIFT; + else + params->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); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); - cdrom->block_shift = 11; /* 2048 bytes */ + params->block_shift = CDROM_DEF_BLOCK_SHIFT; // res = -ENODEV; goto out_free_buf; } @@ -146,11 +149,11 @@ out_free_buf: kfree(buffer); -out_free_cdrom: +out_free_params: if (res == 0) - dev->dh_priv = cdrom; + dev->dh_priv = params; else - kfree(cdrom); + kfree(params); out: TRACE_EXIT(); @@ -168,17 +171,24 @@ ************************************************************/ void cdrom_detach(struct scst_device *dev) { - struct cdrom_params *cdrom = (struct cdrom_params *)dev->dh_priv; + struct cdrom_params *params = + (struct cdrom_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(cdrom); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int cdrom_get_block_shift(struct scst_cmd *cmd) +{ + struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: cdrom_parse * @@ -193,14 +203,14 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct cdrom_params *cdrom = (struct cdrom_params *)cmd->dev->dh_priv; + /* * No need for locks here, since *_detach() can not be * called, when there are existing commands. */ - scst_cdrom_generic_parse(cmd, info_cdb, cdrom->block_shift); + scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift); cmd->retries = 1; @@ -214,6 +224,16 @@ return res; } +static void cdrom_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = CDROM_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: cdrom_done * @@ -227,69 +247,17 @@ ********************************************************************/ int cdrom_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct cdrom_params *cdrom; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, cdrom_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of cdrom capacity */ - int buffer_size, sector_size, block_shift; - uint8_t *buffer; - - buffer_size = scst_get_buf_first(cmd, &buffer); - if (unlikely(buffer_size <= 0)) { - PRINT_ERROR_PR("%s: Unable to get the buffer", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - sector_size = - ((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - scst_put_buf(cmd, buffer); - if (sector_size == 0) - sector_size = 2048; - block_shift = scst_calc_block_shift(sector_size); - /* - * To force the compiler not to optimize it out to keep - * cdrom->block_shift access atomic - */ - barrier(); - cdrom->block_shift = block_shift; - break; - } - default: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: - TRACE_EXIT(); + TRACE_EXIT_RES(res); return res; } Modified: trunk/scst/src/dev_handlers/scst_changer.c =================================================================== --- trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 14:51:18 UTC (rev 107) @@ -128,7 +128,7 @@ { int res = SCST_CMD_STATE_DEFAULT; - scst_changer_generic_parse(cmd, info_cdb); + scst_changer_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 14:51:18 UTC (rev 107) @@ -60,6 +60,8 @@ #define DISK_REG_TIMEOUT (60 * HZ) #define DISK_LONG_TIMEOUT (3600 * HZ) +#define DISK_DEF_BLOCK_SHIFT 9 + struct disk_params { int block_shift; @@ -148,7 +150,7 @@ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct disk_params *disk; + struct disk_params *params; TRACE_ENTRY(); @@ -159,8 +161,8 @@ goto out; } - disk = kzalloc(sizeof(*disk), GFP_KERNEL); - if (disk == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct disk_params"); res = -ENOMEM; @@ -171,7 +173,7 @@ if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_disk; + goto out_free_params; } /* Clear any existing UA's and get disk capacity (disk block size) */ @@ -206,7 +208,10 @@ if (res == 0) { int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - disk->block_shift = scst_calc_block_shift(sector_size); + if (sector_size == 0) + params->block_shift = DISK_DEF_BLOCK_SHIFT; + else + params->block_shift = scst_calc_block_shift(sector_size); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); res = -ENODEV; @@ -216,11 +221,11 @@ out_free_buf: kfree(buffer); -out_free_disk: +out_free_params: if (res == 0) - dev->dh_priv = disk; + dev->dh_priv = params; else - kfree(disk); + kfree(params); out: TRACE_EXIT_RES(res); @@ -238,17 +243,24 @@ ************************************************************/ void disk_detach(struct scst_device *dev) { - struct disk_params *disk = (struct disk_params *)dev->dh_priv; + struct disk_params *params = + (struct disk_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(disk); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int disk_get_block_shift(struct scst_cmd *cmd) +{ + struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: disk_parse * @@ -262,7 +274,6 @@ ********************************************************************/ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { - struct disk_params *disk = (struct disk_params *)cmd->dev->dh_priv; int res = SCST_CMD_STATE_DEFAULT; /* @@ -270,7 +281,7 @@ * called, when there are existing commands. */ - scst_sbc_generic_parse(cmd, info_cdb, disk->block_shift); + scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift); cmd->retries = 1; @@ -285,6 +296,16 @@ return res; } +static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = DISK_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: disk_done * @@ -298,66 +319,16 @@ ********************************************************************/ int disk_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct disk_params *disk; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, disk_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of disk capacity */ - int buffer_size, sector_size, block_shift; - uint8_t *buffer; - - buffer_size = scst_get_buf_first(cmd, &buffer); - if (unlikely(buffer_size <= 0)) { - PRINT_ERROR_PR("%s: Unable to get the buffer", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - disk = (struct disk_params *)cmd->dev->dh_priv; - sector_size = - ((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - scst_put_buf(cmd, buffer); - block_shift = scst_calc_block_shift(sector_size); - /* - * To force the compiler not to optimize it out to keep - * disk->block_shift access atomic - */ - barrier(); - disk->block_shift = block_shift; - break; - } - default: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: TRACE_EXIT_RES(res); return res; } Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 14:51:18 UTC (rev 107) @@ -59,9 +59,9 @@ #define MODISK_SMALL_TIMEOUT (3 * HZ) #define MODISK_REG_TIMEOUT (900 * HZ) #define MODISK_LONG_TIMEOUT (14000 * HZ) -#define MODISK_BLOCK_SHIFT 10 -#define MODISK_SECTOR_SIZE (1 << MODISK_BLOCK_SHIFT) +#define MODISK_DEF_BLOCK_SHIFT 10 + struct modisk_params { int block_shift; @@ -150,7 +150,7 @@ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct modisk_params *modisk; + struct modisk_params *params; TRACE_ENTRY(); @@ -161,14 +161,14 @@ goto out; } - modisk = kzalloc(sizeof(*modisk), GFP_KERNEL); - if (modisk == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct modisk_params"); res = -ENOMEM; goto out; } - modisk->block_shift = MODISK_BLOCK_SHIFT; + params->block_shift = MODISK_DEF_BLOCK_SHIFT; /* * If the device is offline, don't try to read capacity or any @@ -178,14 +178,14 @@ { TRACE_DBG("%s", "Device is offline"); res = -ENODEV; - goto out_free_modisk; + goto out_free_params; } buffer = kzalloc(buffer_size, GFP_KERNEL); if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_modisk; + goto out_free_params; } /* Clear any existing UA's and get modisk capacity (modisk block size) */ @@ -220,8 +220,9 @@ int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); if (sector_size == 0) - sector_size = MODISK_SECTOR_SIZE; - modisk->block_shift = scst_calc_block_shift(sector_size); + params->block_shift = MODISK_DEF_BLOCK_SHIFT; + else + params->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); } else { @@ -235,11 +236,11 @@ out_free_buf: kfree(buffer); -out_free_modisk: +out_free_params: if (res == 0) - dev->dh_priv = modisk; + dev->dh_priv = params; else - kfree(modisk); + kfree(params); out: TRACE_EXIT_RES(res); @@ -257,17 +258,24 @@ ************************************************************/ void modisk_detach(struct scst_device *dev) { - struct modisk_params *modisk = (struct modisk_params *)dev->dh_priv; + struct modisk_params *params = + (struct modisk_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(modisk); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int modisk_get_block_shift(struct scst_cmd *cmd) +{ + struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: modisk_parse * @@ -282,14 +290,13 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct modisk_params *modisk = (struct modisk_params*)cmd->dev->dh_priv; /* * No need for locks here, since *_detach() can not be * called, when there are existing commands. */ - scst_modisk_generic_parse(cmd, info_cdb, modisk->block_shift); + scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift); cmd->retries = 1; @@ -303,6 +310,16 @@ return res; } +static void modisk_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = MODISK_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: modisk_done * @@ -316,68 +333,16 @@ ********************************************************************/ int modisk_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct modisk_params *modisk; - int res = SCST_CMD_STATE_DEFAULT; + int res; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, modisk_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of modisk capacity */ - int buffer_size, sector_size, block_shift; - uint8_t *buffer; - - buffer_size = scst_get_buf_first(cmd, &buffer); - if (unlikely(buffer_size <= 0)) { - PRINT_ERROR_PR("%s: Unable to get the buffer", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - modisk = (struct modisk_params *)cmd->dev->dh_priv; - sector_size = - ((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - scst_put_buf(cmd, buffer); - if (!sector_size) - sector_size = MODISK_SECTOR_SIZE; - block_shift = scst_calc_block_shift(sector_size); - /* - * To force the compiler not to optimize it out to keep - * cdrom->block_shift access atomic - */ - barrier(); - modisk->block_shift = block_shift; - break; - } - default: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: TRACE_EXIT_RES(res); return res; } Modified: trunk/scst/src/dev_handlers/scst_processor.c =================================================================== --- trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 14:51:18 UTC (rev 107) @@ -128,7 +128,7 @@ { int res = SCST_CMD_STATE_DEFAULT; - scst_processor_generic_parse(cmd, info_cdb); + scst_processor_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; Modified: trunk/scst/src/dev_handlers/scst_raid.c =================================================================== --- trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 14:51:18 UTC (rev 107) @@ -128,7 +128,7 @@ { int res = SCST_CMD_STATE_DEFAULT; - scst_raid_generic_parse(cmd, info_cdb); + scst_raid_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 14:51:18 UTC (rev 107) @@ -62,16 +62,13 @@ #define TAPE_REG_TIMEOUT (900 * HZ) #define TAPE_LONG_TIMEOUT (14000 * HZ) +#define TAPE_DEF_BLOCK_SIZE 512 + /* The fixed bit in READ/WRITE/VERIFY */ #define SILI_BIT 2 struct tape_params { - spinlock_t tp_lock; - uint8_t density; - uint8_t mode; - uint8_t speed; - uint8_t medium_type; int block_size; }; @@ -155,7 +152,7 @@ struct scsi_mode_data data; const int buffer_size = 512; uint8_t *buffer = NULL; - struct tape_params *tape; + struct tape_params *params; TRACE_ENTRY(); @@ -166,14 +163,13 @@ goto out; } - tape = kzalloc(sizeof(*tape), GFP_KERNEL); - if (tape == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct tape_params"); res = -ENOMEM; goto out; } - spin_lock_init(&tape->tp_lock); buffer = kmalloc(buffer_size, GFP_KERNEL); if (!buffer) { @@ -205,21 +201,21 @@ TRACE_DBG("MODE_SENSE done: %x", res); if (res == 0) { + int medium_type, mode, speed, density; if (buffer[3] == 8) { - tape->block_size = ((buffer[9] << 16) | + params->block_size = ((buffer[9] << 16) | (buffer[10] << 8) | (buffer[11] << 0)); } else { - tape->block_size = 512; + params->block_size = TAPE_DEF_BLOCK_SIZE; } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - tape->density = buffer[4]; + medium_type = buffer[1]; + mode = (buffer[2] & 0x70) >> 4; + speed = buffer[2] & 0x0f; + density = buffer[4]; TRACE_DBG("Tape: lun %d. bs %d. type 0x%02x mode 0x%02x " "speed 0x%02x dens 0x%02x", dev->scsi_dev->lun, - tape->block_size, tape->medium_type, - tape->mode, tape->speed, tape->density); + params->block_size, medium_type, mode, speed, density); } else { res = -ENODEV; goto out_free_buf; @@ -230,9 +226,9 @@ out_free_req: if (res == 0) - dev->dh_priv = tape; + dev->dh_priv = params; else - kfree(tape); + kfree(params); out: TRACE_EXIT_RES(res); @@ -250,17 +246,24 @@ ************************************************************/ void tape_detach(struct scst_device *dev) { - struct tape_params *tape = (struct tape_params *)dev->dh_priv; + struct tape_params *params = + (struct tape_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(tape); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int tape_get_block_size(struct scst_cmd *cmd) +{ + struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + return params->block_size; +} + /******************************************************************** * Function: tape_parse * @@ -275,14 +278,13 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct tape_params *tape = (struct tape_params*)cmd->dev->dh_priv; /* * No need for locks here, since *_detach() can not be called, * when there are existing commands. */ - scst_tape_generic_parse(cmd, info_cdb, tape->block_size); + scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size); cmd->retries = 1; @@ -296,6 +298,13 @@ return res; } +static void tape_set_block_size(struct scst_cmd *cmd, int block_size) +{ + struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + params->block_size = block_size; + return; +} + /******************************************************************** * Function: tape_done * @@ -311,94 +320,21 @@ { int opcode = cmd->cdb[0]; int status = cmd->status; - struct tape_params *tape; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be called, when + * there are existing commands. */ if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - int buffer_size; - uint8_t *buffer = NULL; - - switch (opcode) { - case MODE_SENSE: - case MODE_SELECT: - buffer_size = scst_get_buf_first(cmd, &buffer); - if (unlikely(buffer_size <= 0)) { - PRINT_ERROR_PR("%s: Unable to get the buffer", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - break; - } - - switch (opcode) { - case MODE_SENSE: - TRACE_DBG("%s", "MODE_SENSE"); - if ((cmd->cdb[2] & 0xC0) == 0) { - /* - * No need for locks here, since *_detach() - * can not be called, when there are - * existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - spin_lock_bh(&tape->tp_lock); - if (buffer[3] == 8) { - tape->block_size = (buffer[9] << 16) | - (buffer[10] << 8) | buffer[11]; - } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - tape->density = buffer[4]; - spin_unlock_bh(&tape->tp_lock); - } - break; - case MODE_SELECT: - TRACE_DBG("%s", "MODE_SELECT"); - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - spin_lock_bh(&tape->tp_lock); - if (buffer[3] == 8) { - tape->block_size = - (buffer[9] << 16) | (buffer[10] << 8) | - (buffer[11]); - } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - if (buffer[4] != 0x7f) - tape->density = buffer[4]; - spin_unlock_bh(&tape->tp_lock); - break; - default: - /* It's all good */ - break; - } - - switch (opcode) { - case MODE_SENSE: - case MODE_SELECT: - scst_put_buf(cmd, buffer); - break; - } - } - else if ((status == SAM_STAT_CHECK_CONDITION) && + res = scst_tape_generic_dev_done(cmd, tape_set_block_size); + } else if ((status == SAM_STAT_CHECK_CONDITION) && SCST_SENSE_VALID(cmd->sense_buffer)) { + struct tape_params *params; TRACE_DBG("%s", "Extended sense"); if (opcode == READ_6 && !(cmd->cdb[1] & SILI_BIT) && (cmd->sense_buffer[2] & 0xe0)) { /* EOF, EOM, or ILI */ @@ -428,8 +364,8 @@ * *_detach() can not be called, when * there are existing commands. */ - tape = (struct tape_params *)cmd->dev->dh_priv; - resp_data_len *= tape->block_size; + params = (struct tape_params *)cmd->dev->dh_priv; + resp_data_len *= params->block_size; } scst_set_resp_data_len(cmd, resp_data_len); } @@ -439,7 +375,6 @@ TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); -out: TRACE_EXIT_RES(res); return res; } Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 14:51:18 UTC (rev 107) @@ -818,6 +818,13 @@ return SCST_EXEC_COMPLETED; } +static int vdisk_get_block_shift(struct scst_cmd *cmd) +{ + struct scst_vdisk_dev *virt_dev = + (struct scst_vdisk_dev *)cmd->dev->dh_priv; + return virt_dev->block_shift; +} + /******************************************************************** * Function: vdisk_parse * @@ -832,10 +839,7 @@ static int vdisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { - struct scst_vdisk_dev *virt_dev = - (struct scst_vdisk_dev *)cmd->dev->dh_priv; - - scst_sbc_generic_parse(cmd, info_cdb, virt_dev->block_shift); + scst_sbc_generic_parse(cmd, info_cdb, vdisk_get_block_shift); return SCST_CMD_STATE_DEFAULT; } @@ -853,10 +857,7 @@ static int vcdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { - struct scst_vdisk_dev *virt_dev = - (struct scst_vdisk_dev *)cmd->dev->dh_priv; - - scst_cdrom_generic_parse(cmd, info_cdb, virt_dev->block_shift); + scst_cdrom_generic_parse(cmd, info_cdb, vdisk_get_block_shift); return SCST_CMD_STATE_DEFAULT; } Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/scst.c 2007-04-03 14:51:18 UTC (rev 107) @@ -96,7 +96,7 @@ DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ); -DECLARE_MUTEX(scst_suspend_mutex);; +DECLARE_MUTEX(scst_suspend_mutex); LIST_HEAD(scst_cmd_lists_list); /* protected by scst_suspend_mutex */ static int scst_threads; @@ -1482,8 +1482,14 @@ EXPORT_SYMBOL(scst_cdrom_generic_parse); EXPORT_SYMBOL(scst_modisk_generic_parse); EXPORT_SYMBOL(scst_tape_generic_parse); -EXPORT_SYMBOL(scst_null_parse); +EXPORT_SYMBOL(scst_changer_generic_parse); +EXPORT_SYMBOL(scst_processor_generic_parse); +EXPORT_SYMBOL(scst_raid_generic_parse); +/* Generic dev_done() routines */ +EXPORT_SYMBOL(scst_block_generic_dev_done); +EXPORT_SYMBOL(scst_tape_generic_dev_done); + /* * Other Commands */ Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-04-03 14:49:33 UTC (rev 106) +++ trunk/scst/src/scst_lib.c 2007-04-03 14:51:18 UTC (rev 107) @@ -1854,7 +1854,8 @@ } int scst_sbc_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -1886,7 +1887,7 @@ case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -1903,7 +1904,7 @@ * No need for locks here, since *_detach() can not be * called, when there are existing commands. */ - cmd->bufflen = info_cdb->transfer_len << block_shift; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); } TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", @@ -1914,7 +1915,8 @@ } int scst_cdrom_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -1952,7 +1954,7 @@ case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -1964,7 +1966,7 @@ } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) - cmd->bufflen = info_cdb->transfer_len << block_shift; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); TRACE_DBG("res %d bufflen %zd direct %d", res, cmd->bufflen, cmd->data_direction); @@ -1974,7 +1976,8 @@ } int scst_modisk_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -2012,7 +2015,7 @@ case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -2024,7 +2027,7 @@ } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) - cmd->bufflen = info_cdb->transfer_len << block_shift;; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); TRACE_DBG("res %d bufflen %zd direct %d", res, cmd->bufflen, cmd->data_direction); @@ -2034,7 +2037,8 @@ } int scst_tape_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_size) + struct scst_info_cdb *info_cdb, + int (*get_block_size)(struct scst_cmd *cmd)) { int res = 0; @@ -2065,13 +2069,13 @@ } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) - cmd->bufflen = info_cdb->transfer_len * block_size; + cmd->bufflen = info_cdb->transfer_len * get_block_size(cmd); TRACE_EXIT_RES(res); return res; } -int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) +static int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = 0; @@ -2099,6 +2103,152 @@ return res; } +int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_block_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)) +{ + int opcode = cmd->cdb[0]; + int status = cmd->status; + int res = SCST_CMD_STATE_DEFAULT; + + TRACE_ENTRY(); + + if (unlikely(cmd->sg == NULL)) + goto out; + + /* + * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len + * based on cmd->status and cmd->data_direction, therefore change + * them only if necessary + */ + + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { + switch (opcode) { + case READ_CAPACITY: + { + /* Always keep track of disk capacity */ + int buffer_size, sector_size, sh; + uint8_t *buffer; + + buffer_size = scst_get_buf_first(cmd, &buffer); + if (unlikely(buffer_size <= 0)) { + PRINT_ERROR_PR("%s: Unable to get the buffer", + __FUNCTION__); + scst_set_busy(cmd); + goto out; + } + + sector_size = + ((buffer[4] << 24) | (buffer[5] << 16) | + (buffer[6] << 8) | (buffer[7] << 0)); + scst_put_buf(cmd, buffer); + if (sector_size != 0) + sh = scst_calc_block_shift(sector_size); + else + sh = 0; + set_block_shift(cmd, sh); + TRACE(TRACE_SCSI, "block_shift %d", sh); + break; + } + default: + /* It's all good */ + break; + } + } + + TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " + "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); + +out: + TRACE_EXIT_RES(res); + return res; +} + +int scst_tape_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_size)(struct scst_cmd *cmd, int block_shift)) +{ + int opcode = cmd->cdb[0]; + int res = SCST_CMD_STATE_DEFAULT; + int buffer_size, bs; + uint8_t *buffer = NULL; + + TRACE_ENTRY(); + + if (unlikely(cmd->sg == NULL)) + goto out; + + /* + * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len + * based on cmd->status and cmd->data_direction, therefore change + * them only if necessary + */ + + switch (opcode) { + case MODE_SENSE: + case MODE_SELECT: + buffer_size = scst_get_buf_first(cmd, &buffer); + if (unlikely(buffer_size <= 0)) { + PRINT_ERROR_PR("%s: Unable to get the buffer", + __FUNCTION__); + scst_set_busy(cmd); + goto out; + } + break; + } + + switch (opcode) { + case MODE_SENSE: + TRACE_DBG("%s", "MODE_SENSE"); + if ((cmd->cdb[2] & 0xC0) == 0) { + if (buffer[3] == 8) { + bs = (buffer[9] << 16) | + (buffer[10] << 8) | buffer[11]; + set_block_size(cmd, bs); + } + } + break; + case MODE_SELECT: + TRACE_DBG("%s", "MODE_SELECT"); + if (buffer[3] == 8) { + bs = (buffer[9] << 16) | (buffer[10] << 8) | + (buffer[11]); + set_block_size(cmd, bs); + } + break; + default: + /* It's all good */ + break; + } + + switch (opcode) { + case MODE_SENSE: + case MODE_SELECT: + scst_put_buf(cmd, buffer); + break; + } + +out: + TRACE_EXIT_RES(res); + return res; +} + /* Called under dev_lock and BH off */ void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-04-03 15:44:46
|
Revision: 108 http://svn.sourceforge.net/scst/?rev=108&view=rev Author: vlnb Date: 2007-04-03 08:44:44 -0700 (Tue, 03 Apr 2007) Log Message: ----------- Various fixes, cleanups updates and preparations Modified Paths: -------------- trunk/scst/README trunk/scst/include/scsi_tgt.h trunk/scst/include/scst_debug.h trunk/scst/src/Makefile trunk/scst/src/dev_handlers/Makefile trunk/scst/src/dev_handlers/scst_cdrom.c trunk/scst/src/dev_handlers/scst_changer.c trunk/scst/src/dev_handlers/scst_dev_handler.h trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_processor.c trunk/scst/src/dev_handlers/scst_raid.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_cdbprobe.h trunk/scst/src/scst_debug.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_mem.h trunk/scst/src/scst_module.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_proc.c trunk/scst/src/scst_targ.c Added Paths: ----------- trunk/scst/include/scst_const.h Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/README 2007-04-03 15:44:44 UTC (rev 108) @@ -416,6 +416,10 @@ the system cache and the commands data buffers, so it saves a considerable amount of CPU power and memory bandwidth. +IMPORTANT: Since data in BLOCKIO and FILEIO modes are not consistent between +========= them, if you try to use a device in both those modes simultaneously, + you will almost instantly corrupt your data on that device. + Performance ----------- Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/include/scsi_tgt.h 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * include/scsi_tgt.h * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * Main SCSI target mid-level include file. @@ -34,6 +34,8 @@ #include <scsi/scsi_eh.h> #include <scsi/scsi.h> +#include <scst_const.h> + /* Version numbers, the same as for the kernel */ #define SCST_VERSION_CODE 0x000906 #define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) @@ -96,6 +98,13 @@ *************************************************************/ #define SCST_CMD_STATE_NEED_THREAD_CTX 100 +/************************************************************* + ** Can be retuned instead of cmd's state by dev handlers' + ** parse function, if the cmd processing should be stopped + ** for now. The cmd will be restarted by dev handlers itself. + *************************************************************/ +#define SCST_CMD_STATE_STOP 101 + /************************************************************* ** States of mgmt command processing state machine *************************************************************/ @@ -240,14 +249,6 @@ *************************************************************/ #define SCST_DEFAULT_TIMEOUT (30*HZ) -/************************************************************* - ** Data direction aliases - *************************************************************/ -#define SCST_DATA_UNKNOWN DMA_BIDIRECTIONAL -#define SCST_DATA_WRITE DMA_TO_DEVICE -#define SCST_DATA_READ DMA_FROM_DEVICE -#define SCST_DATA_NONE DMA_NONE - /************************************************************* ** Flags of cmd->tgt_resp_flags *************************************************************/ @@ -261,48 +262,6 @@ */ #define SCST_TSC_FLAG_STATUS 0x2 -/************************************************************* - ** Values for management functions - *************************************************************/ -#define SCST_ABORT_TASK 0 -#define SCST_ABORT_TASK_SET 1 -#define SCST_CLEAR_ACA 2 -#define SCST_CLEAR_TASK_SET 3 -#define SCST_LUN_RESET 4 -#define SCST_TARGET_RESET 5 - -/** SCST extensions **/ - -/* - * Notifies about I_T nexus loss event in the corresponding session. - * Aborts all tasks there, resets the reservation, if any, and sets - * up the I_T Nexus loss UA. - */ -#define SCST_NEXUS_LOSS_SESS 6 - -/* Aborts all tasks in the corresponding session with TASK_ABORTED status */ -#define SCST_ABORT_ALL_TASKS_SESS 7 - -/* - * Notifies about I_T nexus loss event. Aborts all tasks in all sessions - * of the tgt, resets the reservations, if any, and sets up the I_T Nexus - * loss UA. - */ -#define SCST_NEXUS_LOSS 8 - -/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */ -#define SCST_ABORT_ALL_TASKS 9 - -/************************************************************* - ** Values for mgmt cmd's status field. Codes taken from iSCSI - *************************************************************/ -#define SCST_MGMT_STATUS_SUCCESS 0 -#define SCST_MGMT_STATUS_TASK_NOT_EXIST -1 -#define SCST_MGMT_STATUS_LUN_NOT_EXIST -2 -#define SCST_MGMT_STATUS_FN_NOT_SUPPORTED -5 -#define SCST_MGMT_STATUS_REJECTED -255 -#define SCST_MGMT_STATUS_FAILED -129 - /************************************************************* ** Additional return code for dev handler's task_mgmt_fn() *************************************************************/ @@ -366,6 +325,9 @@ /* Set if tgt_dev is RESERVED by another session */ #define SCST_TGT_DEV_RESERVED 1 +/* Set HEAD OF QUEUE cmd is being executed */ +#define SCST_TGT_DEV_HQ_ACTIVE 2 + /* Set if the corresponding context is atomic */ #define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC 5 #define SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC 6 @@ -374,107 +336,16 @@ #define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9 #define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10 -/* Set HEAD OF QUEUE cmd is being executed */ -#define SCST_TGT_DEV_HQ_ACTIVE 12 - #ifdef DEBUG_TM #define SCST_TGT_DEV_UNDER_TM_DBG 20 #endif -/************************************************************* - ** Commands that are not listed anywhere else - *************************************************************/ -#ifndef REPORT_DEVICE_IDENTIFIER -#define REPORT_DEVICE_IDENTIFIER 0xA3 -#endif -#ifndef INIT_ELEMENT_STATUS -#define INIT_ELEMENT_STATUS 0x07 -#endif -#ifndef INIT_ELEMENT_STATUS_RANGE -#define INIT_ELEMENT_STATUS_RANGE 0x37 -#endif -#ifndef PREVENT_ALLOW_MEDIUM -#define PREVENT_ALLOW_MEDIUM 0x1E -#endif -#ifndef READ_ATTRIBUTE -#define READ_ATTRIBUTE 0x8C -#endif -#ifndef REQUEST_VOLUME_ADDRESS -#define REQUEST_VOLUME_ADDRESS 0xB5 -#endif -#ifndef WRITE_ATTRIBUTE -#define WRITE_ATTRIBUTE 0x8D -#endif -#ifndef WRITE_VERIFY_16 -#define WRITE_VERIFY_16 0x8E -#endif -#ifndef VERIFY_6 -#define VERIFY_6 0x13 -#endif -#ifndef VERIFY_12 -#define VERIFY_12 0xAF -#endif - /************************************************************* - ** Control byte field in CDB - *************************************************************/ -#ifndef CONTROL_BYTE_LINK_BIT -#define CONTROL_BYTE_LINK_BIT 0x01 -#endif -#ifndef CONTROL_BYTE_NACA_BIT -#define CONTROL_BYTE_NACA_BIT 0x04 -#endif - -/************************************************************* - ** Byte 1 in INQUIRY CDB - *************************************************************/ -#define SCST_INQ_EVPD 0x01 - -/************************************************************* - ** Byte 3 in Standard INQUIRY data - *************************************************************/ -#define SCST_INQ_BYTE3 3 - -#define SCST_INQ_NORMACA_BIT 0x20 - -/************************************************************* - ** Byte 2 in RESERVE_10 CDB - *************************************************************/ -#define SCST_RES_3RDPTY 0x10 -#define SCST_RES_LONGID 0x02 - -/************************************************************* - ** Bits in the READ POSITION command - *************************************************************/ -#define TCLP_BIT 4 -#define LONG_BIT 2 -#define BT_BIT 1 - -/************************************************************* - ** Misc SCSI constants - *************************************************************/ -#define SCST_SENSE_ASC_UA_RESET 0x29 -#define READ_CAP_LEN 8 -#define READ_CAP16_LEN 12 -#define BYTCHK 0x02 -#define POSITION_LEN_SHORT 20 -#define POSITION_LEN_LONG 32 - -/************************************************************* ** Name of the entry in /proc *************************************************************/ #define SCST_PROC_ENTRY_NAME "scsi_tgt" /************************************************************* - ** Used with scst_set_cmd_error() - *************************************************************/ -#define SCST_LOAD_SENSE(key_asc_ascq) key_asc_ascq - -#define SCST_SENSE_VALID(sense) ((((uint8_t *)(sense))[0] & 0x70) == 0x70) - -#define SCST_NO_SENSE(sense) (((uint8_t *)(sense))[2] == 0) - -/************************************************************* * TYPES *************************************************************/ @@ -751,13 +622,21 @@ unsigned dev_done_atomic:1; unsigned dedicated_thread:1; + /* Set, if no /proc files should be automatically created by SCST */ + unsigned no_proc:1; + + /* Set if expected_sn in cmd->scst_cmd_done() */ + unsigned inc_expected_sn_on_done:1; + /* * Called to parse CDB from the cmd and initialize * cmd->bufflen and cmd->data_direction (both - REQUIRED). * Returns the command's next state or SCST_CMD_STATE_DEFAULT, * if the next default state should be used, or * SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic - * context, but requires sleeping. In the last case, the function + * context, but requires sleeping, or SCST_CMD_STATE_STOP if the + * command should not be further processed for now. In the + * SCST_CMD_STATE_NEED_THREAD_CTX case the function * will be recalled in the thread context, where sleeping is allowed. * * Pay attention to "atomic" attribute of the cmd, which can be get @@ -899,7 +778,10 @@ struct timer_list retry_timer; int retry_timer_active; - /* Maximum SG table size */ + /* + * Maximum SG table size. Needed here, since different cards on the + * same target template can have different SG table limitations. + */ int sg_tablesize; /* Used for storage of target driver private stuff */ @@ -979,15 +861,6 @@ void (*unreg_done_fn) (struct scst_session *sess); }; -enum scst_cmd_queue_type -{ - SCST_CMD_QUEUE_UNTAGGED = 0, - SCST_CMD_QUEUE_SIMPLE, - SCST_CMD_QUEUE_ORDERED, - SCST_CMD_QUEUE_HEAD_OF_QUEUE, - SCST_CMD_QUEUE_ACA -}; - struct scst_cmd_lists { spinlock_t cmd_list_lock; @@ -1100,14 +973,20 @@ unsigned int may_need_dma_sync:1; /* Set if the cmd was done or aborted out of its SN */ - unsigned long out_of_sn:1; + unsigned int out_of_sn:1; - /* Set if the cmd is HEAD OF QUEUE */ - unsigned long head_of_queue:1; - /* Set if the cmd is deferred HEAD OF QUEUE */ - unsigned long hq_deferred:1; + unsigned int hq_deferred:1; + /* Set if the internal parse should be skipped */ + unsigned int skip_parse:1; + + /* + * Set if inc expected_sn in cmd->scst_cmd_done() (to + * save extra dereferences) + */ + unsigned inc_expected_sn_on_done:1; + /**************************************************************/ unsigned long cmd_flags; /* cmd's async flags */ @@ -1128,7 +1007,7 @@ struct list_head sn_cmd_list_entry; /* Cmd's serial number, used to execute cmd's in order of arrival */ - unsigned int sn; + unsigned long sn; /* The corresponding sn_slot in tgt_dev->sn_slots */ atomic_t *sn_slot; @@ -1143,7 +1022,7 @@ uint32_t tag; /* CDB and its len */ - uint8_t cdb[MAX_COMMAND_SIZE]; + uint8_t cdb[SCST_MAX_CDB_SIZE]; int cdb_len; enum scst_cmd_queue_type queue_type; @@ -1156,17 +1035,21 @@ /* Remote initiator supplied values, if any */ scst_data_direction expected_data_direction; - unsigned int expected_transfer_len; + int expected_transfer_len; - /* cmd data length */ - size_t data_len; + /* + * Cmd data length. Could be different from bufflen for commands like + * VERIFY, which transfer different amount of data (if any), than + * processed. + */ + int data_len; /* Completition routine */ void (*scst_cmd_done) (struct scst_cmd *cmd, int next_state); struct sgv_pool_obj *sgv; /* sgv object */ - size_t bufflen; /* cmd buffer length */ + int bufflen; /* cmd buffer length */ struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ @@ -1199,7 +1082,7 @@ */ int orig_sg_cnt, orig_sg_entry, orig_entry_len; - uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* sense buffer */ + uint8_t sense_buffer[SCST_SENSE_BUFFERSIZE]; /* sense buffer */ /* The corresponding mgmt cmd, if any, protected by sess_list_lock */ struct scst_mgmt_cmd *mgmt_cmnd; @@ -1359,6 +1242,10 @@ /* How many cmds alive on this dev in this session */ atomic_t cmd_count; + int gfp_mask; + struct sgv_pool *pool; + int max_sg_cnt; + unsigned long tgt_dev_flags; /* tgt_dev's async flags */ /* @@ -1371,13 +1258,18 @@ */ int def_cmd_count; spinlock_t sn_lock; - int expected_sn; - int curr_sn; + unsigned long expected_sn, curr_sn; struct list_head deferred_cmd_list; struct list_head skipped_sn_list; struct list_head hq_cmd_list; - unsigned short prev_cmd_ordered; /* Set if the prev cmd was ORDERED */ - short num_free_sn_slots; + + /* + * Set if the prev cmd was ORDERED. Size must allow unprotected + * modifications + */ + unsigned long prev_cmd_ordered; + + int num_free_sn_slots; atomic_t *cur_sn_slot; atomic_t sn_slots[10]; @@ -1471,7 +1363,7 @@ /* List entry in tgt_dev->UA_list */ struct list_head UA_list_entry; /* Unit Attention sense */ - uint8_t UA_sense_buffer[SCSI_SENSE_BUFFERSIZE]; + uint8_t UA_sense_buffer[SCST_SENSE_BUFFERSIZE]; }; enum scst_cdb_flags @@ -1480,6 +1372,7 @@ SCST_SMALL_TIMEOUT = 0x02, SCST_LONG_TIMEOUT = 0x04, SCST_UNKNOWN_LENGTH = 0x08, + SCST_INFO_INVALID = 0x10, }; struct scst_info_cdb @@ -1491,28 +1384,6 @@ const char *op_name; }; -/* - * Sense data for the appropriate errors. Can be used with - * scst_set_cmd_error() - */ -#define scst_sense_no_sense NO_SENSE, 0x00, 0 -#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0 -#define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0 -#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0 -#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0 -#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0 -#define scst_sense_reset_UA UNIT_ATTENTION, 0x29, 0 -#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7 -#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0 -#define scst_sense_lun_not_supported ILLEGAL_REQUEST, 0x25, 0 -#define scst_sense_data_protect DATA_PROTECT, 0x00, 0 -#define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0 -#define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0 -#define scst_sense_medium_changed_UA UNIT_ATTENTION, 0x28, 0 -#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 - #ifndef smp_mb__after_set_bit /* There is no smp_mb__after_set_bit() in the kernel */ #define smp_mb__after_set_bit() smp_mb(); @@ -1788,6 +1659,20 @@ } /* + * Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise. + * Dev handlers parse() and dev_done() not called for such commands. + */ +static inline int scst_is_cmd_local(struct scst_cmd *cmd) +{ + int res = 0; + switch (cmd->cdb[0]) { + case REPORT_LUNS: + res = 1; + } + return res; +} + +/* * Registers a virtual device. * Parameters: * dev_type - the device's device handler @@ -2047,7 +1932,7 @@ return cmd->expected_data_direction; } -static inline unsigned int scst_cmd_get_expected_transfer_len( +static inline int scst_cmd_get_expected_transfer_len( struct scst_cmd *cmd) { return cmd->expected_transfer_len; @@ -2055,7 +1940,7 @@ static inline void scst_cmd_set_expected(struct scst_cmd *cmd, scst_data_direction expected_data_direction, - unsigned int expected_transfer_len) + int expected_transfer_len) { cmd->expected_data_direction = expected_data_direction; cmd->expected_transfer_len = expected_transfer_len; @@ -2162,6 +2047,13 @@ void scst_suspend_activity(void); void scst_resume_activity(void); +/* + * Main SCST commands processing routing. Must be used only by dev handlers. + * Argument context sets the execution context, only SCST_CONTEXT_DIRECT and + * SCST_CONTEXT_DIRECT_ATOMIC are allowed. + */ +void scst_process_active_cmd(struct scst_cmd *cmd, int context); + /* * Returns target driver's root entry in SCST's /proc hierarchy. * The driver can create own files/directoryes here, which should @@ -2310,6 +2202,34 @@ data->free_fn(data); } +/* SGV pool routines and flag bits */ + +/* Set if the allocated object must be not from the cache */ +#define SCST_POOL_ALLOC_NO_CACHED 1 + +/* Set if there should not be any memory allocations on a cache miss */ +#define SCST_POOL_NO_ALLOC_ON_CACHE_MISS 2 + +/* Set an object should be returned even if it doesn't have SG vector built */ +#define SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL 4 + +struct sgv_pool_obj; +struct sgv_pool; + +struct sgv_pool *sgv_pool_create(const char *name, int clustered); +void sgv_pool_destroy(struct sgv_pool *pool); + +void sgv_pool_set_allocator(struct sgv_pool *pool, + struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *), + void (*free_pages_fn)(struct scatterlist *, int, void *)); + +struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size, + unsigned long gfp_mask, int atomic, int *count, + struct sgv_pool_obj **sgv, void *priv); +void sgv_pool_free(struct sgv_pool_obj *sgv); + +void *sgv_get_priv(struct sgv_pool_obj *sgv); + /** ** Generic parse() support routines. ** Done via pointer on functions to avoid unneeded dereferences on @@ -2341,15 +2261,18 @@ /* Generic parse() for changer devices */ int scst_changer_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int nothing); + struct scst_info_cdb *info_cdb, + int (*nothing)(struct scst_cmd *cmd)); /* Generic parse() for "processor" devices */ int scst_processor_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int nothing); + struct scst_info_cdb *info_cdb, + int (*nothing)(struct scst_cmd *cmd)); /* Generic parse() for RAID devices */ int scst_raid_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int nothing); + struct scst_info_cdb *info_cdb, + int (*nothing)(struct scst_cmd *cmd)); /** ** Generic dev_done() support routines. Added: trunk/scst/include/scst_const.h =================================================================== --- trunk/scst/include/scst_const.h (rev 0) +++ trunk/scst/include/scst_const.h 2007-04-03 15:44:44 UTC (rev 108) @@ -0,0 +1,243 @@ +/* + * include/scst_const.h + * + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> + * + * Contains macroses for execution tracing and error reporting + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2 + * of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SCST_CONST_H +#define __SCST_CONST_H + +#include <scsi/scsi.h> + +/*** Shared constants between user and kernel spaces ***/ + +/* Max size of CDB */ +#define SCST_MAX_CDB_SIZE 16 + +/* Max size of sense */ +#define SCST_SENSE_BUFFERSIZE 96 + +/************************************************************* + ** Values for task management functions + *************************************************************/ +#define SCST_ABORT_TASK 0 +#define SCST_ABORT_TASK_SET 1 +#define SCST_CLEAR_ACA 2 +#define SCST_CLEAR_TASK_SET 3 +#define SCST_LUN_RESET 4 +#define SCST_TARGET_RESET 5 + +/** SCST extensions **/ + +/* + * Notifies about I_T nexus loss event in the corresponding session. + * Aborts all tasks there, resets the reservation, if any, and sets + * up the I_T Nexus loss UA. + */ +#define SCST_NEXUS_LOSS_SESS 6 + +/* Aborts all tasks in the corresponding session with TASK_ABORTED status */ +#define SCST_ABORT_ALL_TASKS_SESS 7 + +/* + * Notifies about I_T nexus loss event. Aborts all tasks in all sessions + * of the tgt, resets the reservations, if any, and sets up the I_T Nexus + * loss UA. + */ +#define SCST_NEXUS_LOSS 8 + +/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */ +#define SCST_ABORT_ALL_TASKS 9 + +/************************************************************* + ** Values for mgmt cmd's status field. Codes taken from iSCSI + *************************************************************/ +#define SCST_MGMT_STATUS_SUCCESS 0 +#define SCST_MGMT_STATUS_TASK_NOT_EXIST -1 +#define SCST_MGMT_STATUS_LUN_NOT_EXIST -2 +#define SCST_MGMT_STATUS_FN_NOT_SUPPORTED -5 +#define SCST_MGMT_STATUS_REJECTED -255 +#define SCST_MGMT_STATUS_FAILED -129 + +/************************************************************* + ** SCSI task attribute queue types + *************************************************************/ +enum scst_cmd_queue_type +{ + SCST_CMD_QUEUE_UNTAGGED = 0, + SCST_CMD_QUEUE_SIMPLE, + SCST_CMD_QUEUE_ORDERED, + SCST_CMD_QUEUE_HEAD_OF_QUEUE, + SCST_CMD_QUEUE_ACA +}; + +/************************************************************* + ** Data direction aliases + *************************************************************/ +#define SCST_DATA_UNKNOWN 0 +#define SCST_DATA_WRITE 1 +#define SCST_DATA_READ 2 +#define SCST_DATA_NONE 3 + +/************************************************************* + ** Sense manipulation and examination + *************************************************************/ +#define SCST_LOAD_SENSE(key_asc_ascq) key_asc_ascq + +#define SCST_SENSE_VALID(sense) ((((uint8_t *)(sense))[0] & 0x70) == 0x70) + +#define SCST_NO_SENSE(sense) (((uint8_t *)(sense))[2] == 0) + +/************************************************************* + ** Sense data for the appropriate errors. Can be used with + ** scst_set_cmd_error() + *************************************************************/ +#define scst_sense_no_sense NO_SENSE, 0x00, 0 +#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0 +#define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0 +#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0 +#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0 +#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0 +#define scst_sense_reset_UA UNIT_ATTENTION, 0x29, 0 +#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7 +#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0 +#define scst_sense_lun_not_supported ILLEGAL_REQUEST, 0x25, 0 +#define scst_sense_data_protect DATA_PROTECT, 0x00, 0 +#define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0 +#define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0 +#define scst_sense_medium_changed_UA UNIT_ATTENTION, 0x28, 0 +#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 + +/************************************************************* + * SCSI opcodes not listed anywhere else + *************************************************************/ +#ifndef REPORT_DEVICE_IDENTIFIER +#define REPORT_DEVICE_IDENTIFIER 0xA3 +#endif +#ifndef INIT_ELEMENT_STATUS +#define INIT_ELEMENT_STATUS 0x07 +#endif +#ifndef INIT_ELEMENT_STATUS_RANGE +#define INIT_ELEMENT_STATUS_RANGE 0x37 +#endif +#ifndef PREVENT_ALLOW_MEDIUM +#define PREVENT_ALLOW_MEDIUM 0x1E +#endif +#ifndef READ_ATTRIBUTE +#define READ_ATTRIBUTE 0x8C +#endif +#ifndef REQUEST_VOLUME_ADDRESS +#define REQUEST_VOLUME_ADDRESS 0xB5 +#endif +#ifndef WRITE_ATTRIBUTE +#define WRITE_ATTRIBUTE 0x8D +#endif +#ifndef WRITE_VERIFY_16 +#define WRITE_VERIFY_16 0x8E +#endif +#ifndef VERIFY_6 +#define VERIFY_6 0x13 +#endif +#ifndef VERIFY_12 +#define VERIFY_12 0xAF +#endif +#ifndef READ_16 +#define READ_16 0x88 +#endif +#ifndef WRITE_16 +#define WRITE_16 0x8a +#endif +#ifndef VERIFY_16 +#define VERIFY_16 0x8f +#endif +#ifndef SERVICE_ACTION_IN +#define SERVICE_ACTION_IN 0x9e +#endif +#ifndef SAI_READ_CAPACITY_16 +/* values for service action in */ +#define SAI_READ_CAPACITY_16 0x10 +#endif +#ifndef MI_REPORT_TARGET_PGS +/* values for maintenance in */ +#define MI_REPORT_TARGET_PGS 0x0a +#endif +#ifndef REPORT_LUNS +#define REPORT_LUNS 0xa0 +#endif + +/************************************************************* + ** SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft + ** T10/1561-D Revision 4 Draft dated 7th November 2002. + *************************************************************/ +#define SAM_STAT_GOOD 0x00 +#define SAM_STAT_CHECK_CONDITION 0x02 +#define SAM_STAT_CONDITION_MET 0x04 +#define SAM_STAT_BUSY 0x08 +#define SAM_STAT_INTERMEDIATE 0x10 +#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 +#define SAM_STAT_RESERVATION_CONFLICT 0x18 +#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */ +#define SAM_STAT_TASK_SET_FULL 0x28 +#define SAM_STAT_ACA_ACTIVE 0x30 +#define SAM_STAT_TASK_ABORTED 0x40 + +/************************************************************* + ** Control byte field in CDB + *************************************************************/ +#ifndef CONTROL_BYTE_LINK_BIT +#define CONTROL_BYTE_LINK_BIT 0x01 +#endif +#ifndef CONTROL_BYTE_NACA_BIT +#define CONTROL_BYTE_NACA_BIT 0x04 +#endif + +/************************************************************* + ** Byte 1 in INQUIRY CDB + *************************************************************/ +#define SCST_INQ_EVPD 0x01 + +/************************************************************* + ** Byte 3 in Standard INQUIRY data + *************************************************************/ +#define SCST_INQ_BYTE3 3 + +#define SCST_INQ_NORMACA_BIT 0x20 + +/************************************************************* + ** Byte 2 in RESERVE_10 CDB + *************************************************************/ +#define SCST_RES_3RDPTY 0x10 +#define SCST_RES_LONGID 0x02 + +/************************************************************* + ** Bits in the READ POSITION command + *************************************************************/ +#define TCLP_BIT 4 +#define LONG_BIT 2 +#define BT_BIT 1 + +/************************************************************* + ** Misc SCSI constants + *************************************************************/ +#define SCST_SENSE_ASC_UA_RESET 0x29 +#define READ_CAP_LEN 8 +#define READ_CAP16_LEN 12 +#define BYTCHK 0x02 +#define POSITION_LEN_SHORT 20 +#define POSITION_LEN_LONG 32 + +#endif /* __SCST_CONST_H */ Modified: trunk/scst/include/scst_debug.h =================================================================== --- trunk/scst/include/scst_debug.h 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/include/scst_debug.h 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * include/scst_debug.h * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * Contains macroses for execution tracing and error reporting @@ -100,7 +100,7 @@ #if defined(DEBUG) || defined(TRACING) extern int debug_print_prefix(unsigned long trace_flag, const char *func, int line); -extern void debug_print_buffer(unsigned long trace_flag, const void *data, int len); +extern void debug_print_buffer(const void *data, int len); #define TRACE(trace, format, args...) \ do { \ @@ -138,7 +138,7 @@ __tflag = NO_FLAG; \ } \ PRINT(NO_FLAG, "%s%s:", __tflag, message); \ - debug_print_buffer(trace_flag, buff, len); \ + debug_print_buffer(buff, len); \ } \ } while(0) @@ -152,7 +152,7 @@ __tflag = NO_FLAG; \ } \ PRINT(NO_FLAG, "%s%s:", __tflag, message); \ - debug_print_buffer(trace_flag, buff, len); \ + debug_print_buffer(buff, len); \ } \ } while(0) Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/Makefile 2007-04-03 15:44:44 UTC (rev 108) @@ -70,6 +70,7 @@ install -d $(INSTALL_DIR_H) install -m 644 ../include/scsi_tgt.h $(INSTALL_DIR_H) install -m 644 ../include/scst_debug.h $(INSTALL_DIR_H) + install -m 644 ../include/scst_const.h $(INSTALL_DIR_H) ifneq ($(MODS_VERS),) rm -f $(INSTALL_DIR_H)/Module.symvers install -m 644 Modules.symvers $(INSTALL_DIR_H) @@ -91,7 +92,7 @@ INSTALL_DIR := /lib/modules/$(shell uname -r)/extra INSTALL_DIR_H := /usr/local/include/scst -EXTRA_CFLAGS += -I$(SCST_INC_DIR) +EXTRA_CFLAGS += -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter #EXTRA_CFLAGS += -DSTRICT_SERIALIZING @@ -102,7 +103,7 @@ #EXTRA_CFLAGS += -DTRACING -EXTRA_CFLAGS += -DDEBUG +EXTRA_CFLAGS += -DDEBUG -g #EXTRA_CFLAGS += -DDEBUG_TM -DTM_DBG_GO_OFFLINE=0 #EXTRA_CFLAGS += -DDEBUG_RETRY #EXTRA_CFLAGS += -DDEBUG_OOM Modified: trunk/scst/src/dev_handlers/Makefile =================================================================== --- trunk/scst/src/dev_handlers/Makefile 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/Makefile 2007-04-03 15:44:44 UTC (rev 108) @@ -61,10 +61,12 @@ INSTALL_DIR := /lib/modules/$(shell uname -r)/extra -EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR) +EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter +EXTRA_CFLAGS += -DEXTRACHECKS + #EXTRA_CFLAGS += -DTRACING -EXTRA_CFLAGS += -DDEBUG +EXTRA_CFLAGS += -DDEBUG -g clean: rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers Module.symvers Modified: trunk/scst/src/dev_handlers/scst_cdrom.c =================================================================== --- trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_cdrom.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_cdrom.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI CDROM (type 5) dev handler @@ -71,7 +71,7 @@ const int buffer_size = 512; uint8_t *buffer = NULL; int retries; - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; + unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; struct cdrom_params *params; @@ -140,7 +140,7 @@ TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { - TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); + TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE); params->block_shift = CDROM_DEF_BLOCK_SHIFT; // res = -ENODEV; goto out_free_buf; @@ -186,6 +186,10 @@ static int cdrom_get_block_shift(struct scst_cmd *cmd) { struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ return params->block_shift; } @@ -203,13 +207,7 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift); cmd->retries = 1; @@ -227,6 +225,10 @@ static void cdrom_set_block_shift(struct scst_cmd *cmd, int block_shift) { struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ if (block_shift != 0) params->block_shift = block_shift; else @@ -251,10 +253,6 @@ TRACE_ENTRY(); - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ res = scst_block_generic_dev_done(cmd, cdrom_set_block_shift); TRACE_EXIT_RES(res); @@ -299,3 +297,6 @@ module_exit(cdrom_exit); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); +MODULE_DESCRIPTION("SCSI CDROM (type 5) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_changer.c =================================================================== --- trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_changer.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_changer.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI medium changer (type 8) dev handler @@ -158,9 +158,6 @@ TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len * based on cmd->status and cmd->data_direction, therefore change @@ -175,7 +172,6 @@ } #endif -out: TRACE_EXIT(); return res; } @@ -217,4 +213,7 @@ module_init(changer_init); module_exit(changer_exit); +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI medium changer (type 8) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_dev_handler.h =================================================================== --- trunk/scst/src/dev_handlers/scst_dev_handler.h 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_dev_handler.h 2007-04-03 15:44:44 UTC (rev 108) @@ -15,8 +15,8 @@ #ifdef DEBUG #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \ - TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | TRACE_MGMT_DEBUG | \ - TRACE_SPECIAL) + TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | \ + TRACE_MGMT_DEBUG | TRACE_SPECIAL) #else #define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR) #endif Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_disk.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_disk.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI disk (type 0) dev handler @@ -147,7 +147,7 @@ const int buffer_size = 512; uint8_t *buffer = NULL; int retries; - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; + unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; struct disk_params *params; @@ -213,7 +213,7 @@ else params->block_shift = scst_calc_block_shift(sector_size); } else { - TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); + TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE); res = -ENODEV; goto out_free_buf; } @@ -258,6 +258,10 @@ static int disk_get_block_shift(struct scst_cmd *cmd) { struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ return params->block_shift; } @@ -276,11 +280,6 @@ { int res = SCST_CMD_STATE_DEFAULT; - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift); cmd->retries = 1; @@ -299,6 +298,10 @@ static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift) { struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ if (block_shift != 0) params->block_shift = block_shift; else @@ -323,10 +326,6 @@ TRACE_ENTRY(); - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ res = scst_block_generic_dev_done(cmd, disk_set_block_shift); TRACE_EXIT_RES(res); @@ -373,4 +372,7 @@ return res; } +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI disk (type 0) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_modisk.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI MO disk (type 7) dev handler @@ -147,7 +147,7 @@ const int buffer_size = 512; uint8_t *buffer = NULL; int retries; - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; + unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; struct modisk_params *params; @@ -226,7 +226,7 @@ TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { - TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); + TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE); if (sbuff[2] != NOT_READY) res = -ENODEV; @@ -273,6 +273,10 @@ static int modisk_get_block_shift(struct scst_cmd *cmd) { struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ return params->block_shift; } @@ -291,11 +295,6 @@ { int res = SCST_CMD_STATE_DEFAULT; - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift); cmd->retries = 1; @@ -313,6 +312,10 @@ static void modisk_set_block_shift(struct scst_cmd *cmd, int block_shift) { struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ if (block_shift != 0) params->block_shift = block_shift; else @@ -337,10 +340,6 @@ TRACE_ENTRY(); - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ res = scst_block_generic_dev_done(cmd, modisk_set_block_shift); TRACE_EXIT_RES(res); @@ -387,4 +386,7 @@ return res; } +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI MO disk (type 7) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_processor.c =================================================================== --- trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_processor.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_processor.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI medium processor (type 3) dev handler @@ -157,9 +157,6 @@ TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len * based on cmd->status and cmd->data_direction, therefore change @@ -174,7 +171,6 @@ } #endif -out: TRACE_EXIT(); return res; } @@ -216,4 +212,7 @@ module_init(processor_init); module_exit(processor_exit); +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI medium processor (type 3) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_raid.c =================================================================== --- trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_raid.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_raid.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI raid(controller) (type 0xC) dev handler @@ -157,9 +157,6 @@ TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - /* * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len * based on cmd->status and cmd->data_direction, therefore change @@ -174,7 +171,6 @@ } #endif -out: TRACE_EXIT(); return res; } @@ -216,4 +212,7 @@ module_init(raid_init); module_exit(raid_exit); +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI raid(controller) (type 0xC) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_tape.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_tape.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * SCSI tape (type 1) dev handler @@ -261,6 +261,10 @@ static int tape_get_block_size(struct scst_cmd *cmd) { struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be called, + * when there are existing commands. + */ return params->block_size; } @@ -279,11 +283,6 @@ { int res = SCST_CMD_STATE_DEFAULT; - /* - * No need for locks here, since *_detach() can not be called, - * when there are existing commands. - */ - scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size); cmd->retries = 1; @@ -301,6 +300,10 @@ static void tape_set_block_size(struct scst_cmd *cmd, int block_size) { struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + /* + * No need for locks here, since *_detach() can not be called, when + * there are existing commands. + */ params->block_size = block_size; return; } @@ -324,11 +327,6 @@ TRACE_ENTRY(); - /* - * No need for locks here, since *_detach() can not be called, when - * there are existing commands. - */ - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { res = scst_tape_generic_dev_done(cmd, tape_set_block_size); } else if ((status == SAM_STAT_CHECK_CONDITION) && @@ -413,4 +411,7 @@ return res; } +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI tape (type 1) dev handler for SCST"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_vdisk.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com> * (C) 2007 Ross Walker <rswwalker at hotmail dot com> @@ -44,12 +44,14 @@ #define TRACE_ORDER 0x80000000 +#if defined(DEBUG) || defined(TRACING) static struct scst_proc_log vdisk_proc_local_trace_tbl[] = { { TRACE_ORDER, "order" }, { 0, NULL } }; #define trace_log_tbl vdisk_proc_local_trace_tbl +#endif #include "scst_dev_handler.h" @@ -122,6 +124,10 @@ }; struct scst_vdisk_tgt_dev { + /* + * Used without locking since SCST core ensures that only commands + * of the same type per tgt_dev can be processed simultaneously + */ enum scst_cmd_queue_type last_write_cmd_queue_type; }; @@ -949,10 +955,6 @@ goto out_free; } - /* - * ToDo: write through/back flags as well as read only one. - */ - if (cmd->cdb[1] & CMDDT) { TRACE_DBG("%s", "INQUIRY: CMDDT is unsupported"); scst_set_cmd_error(cmd, @@ -969,7 +971,7 @@ int dev_id_num; char dev_id_str[6]; - for (dev_id_num = 0, i = 0; i < strlen(virt_dev->name); i++) { + for (dev_id_num = 0, i = 0; i < (int)strlen(virt_dev->name); i++) { dev_id_num += virt_dev->name[i]; } len = scnprintf(dev_id_str, 6, "%d", dev_id_num); @@ -1218,8 +1220,6 @@ goto out_free; } - memset(buf, 0, sizeof(buf)); - if (0x3 == pcontrol) { TRACE_DBG("%s", "MODE SENSE: Saving values not supported"); scst_set_cmd_error(cmd, @@ -2029,7 +2029,7 @@ need_new_bio = 1; for (j = 0; j < cmd->sg_cnt; ++j) { - unsigned int len, bytes, off, thislen; + int len, bytes, off, thislen; struct page *page; page = sgl[j].page; @@ -2171,7 +2171,7 @@ compare = 1; while (length > 0) { - len_mem = length > LEN_MEM ? LEN_MEM : length; + len_mem = (length > LEN_MEM) ? LEN_MEM : length; TRACE_DBG("Verify: length %zd - len_mem %zd", length, len_mem); if (!virt_dev->nullio) @@ -2190,8 +2190,7 @@ scst_put_buf(cmd, address_sav); goto out_set_fs; } - if (compare && memcmp(address, mem_verify, len_mem) != 0) - { + if (compare && memcmp(address, mem_verify, len_mem) != 0) { TRACE_DBG("Verify: error memcmp length %zd", length); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_miscompare_error)); @@ -2200,8 +2199,7 @@ } length -= len_mem; address += len_mem; - if (compare && length <= 0) - { + if (compare && length <= 0) { scst_put_buf(cmd, address_sav); length = scst_get_buf_next(cmd, &address); address_sav = address; @@ -2398,7 +2396,6 @@ if (isdigit(*p)) { char *pp; - uint32_t t; block_size = simple_strtoul(p, &pp, 0); p = pp; if ((*p != '\0') && !isspace(*p)) { @@ -2409,17 +2406,8 @@ while (isspace(*p) && *p != '\0') p++; - t = block_size; - block_shift = 0; - while(1) { - if ((t & 1) != 0) - break; - t >>= 1; - block_shift++; - } + block_shift = scst_calc_block_shift(block_size); if (block_shift < 9) { - PRINT_ERROR_PR("Wrong block size %d", - block_size); res = -EINVAL; goto out_free_vdev; } @@ -3088,4 +3076,8 @@ module_init(init_scst_vdisk_driver); module_exit(exit_scst_vdisk_driver); +MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCSI disk (type 0) and CDROM (type 5) dev handler for " + "SCST using files on file systems or block devices"); +MODULE_VERSION(SCST_VERSION_STRING); Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/scst.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * This program is free software; you can redistribute it and/or @@ -111,7 +111,7 @@ * could fail in improper places. */ spinlock_t scst_temp_UA_lock = SPIN_LOCK_UNLOCKED; -uint8_t scst_temp_UA[SCSI_SENSE_BUFFERSIZE]; +uint8_t scst_temp_UA[SCST_SENSE_BUFFERSIZE]; module_param_named(scst_threads, scst_threads, int, 0); MODULE_PARM_DESC(scst_threads, "SCSI target threads count"); @@ -705,7 +705,7 @@ #ifdef VDISK_ONLY if (dev_type->exec == NULL) { - PRINT_ERROR_PR("Pass-through dev handlers (handler %s) not " + PRINT_ERROR_PR("Pass-through dev handlers (handler \"%s\") not " "supported. Recompile SCST with undefined VDISK_ONLY", dev_type->name); res = -EINVAL; @@ -722,8 +722,8 @@ exist = 0; list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) { if (strcmp(dt->name, dev_type->name) == 0) { - PRINT_ERROR_PR("Device type handler %s already exist", - dt->name); + PRINT_ERROR_PR("Device type handler \"%s\" already " + "exist", dt->name); exist = 1; break; } @@ -749,7 +749,7 @@ scst_resume_activity(); if (res == 0) { - PRINT_INFO_PR("Device handler %s for type %d registered " + PRINT_INFO_PR("Device handler \"%s\" for type %d registered " "successfully", dev_type->name, dev_type->type); } @@ -762,7 +762,7 @@ out_err: scst_resume_activity(); - PRINT_ERROR_PR("Failed to register device handler %s for type %d", + PRINT_ERROR_PR("Failed to register device handler \"%s\" for type %d", dev_type->name, dev_type->type); goto out; } @@ -785,7 +785,7 @@ } } if (!found) { - PRINT_ERROR_PR("Dev handler %s isn't registered", + PRINT_ERROR_PR("Dev handler \"%s\" isn't registered", dev_type->name); goto out_up; } @@ -804,7 +804,7 @@ scst_cleanup_proc_dev_handler_dir_entries(dev_type); - PRINT_INFO_PR("Device handler %s for type %d unloaded", + PRINT_INFO_PR("Device handler \"%s\" for type %d unloaded", dev_type->name, dev_type->type); out: @@ -827,20 +827,28 @@ if (res != 0) goto out_err; - res = scst_build_proc_dev_handler_dir_entries(dev_type); - if (res < 0) - goto out_err; - - PRINT_INFO_PR("Virtuel device handler %s for type %d registered " - "successfully", dev_type->name, dev_type->type); + if (!dev_type->no_proc) { + res = scst_build_proc_dev_handler_dir_entries(dev_type); + if (res < 0) + goto out_err; + } + if (dev_type->type != -1) { + PRINT_INFO_PR("Virtual device handler %s for type %d " + "registered successfully", dev_type->name, + dev_type->type); + } else { + PRINT_INFO_PR("Virtual device handler \"%s\" registered " + "successfully", dev_type->name); + } + out: TRACE_EXIT_RES(res); return res; out_err: - PRINT_ERROR_PR("Failed to register virtual device handler %s for " - "type %d", dev_type->name, dev_type->type); + PRINT_ERROR_PR("Failed to register virtual device handler \"%s\"", + dev_type->name); goto out; } @@ -848,10 +856,10 @@ { TRACE_ENTRY(); - scst_cleanup_proc_dev_handler_dir_entries(dev_type); + if (!dev_type->no_proc) + scst_cleanup_proc_dev_handler_dir_entries(dev_type); - PRINT_INFO_PR("Device handler %s for type %d unloaded", - dev_type->name, dev_type->type); + PRINT_INFO_PR("Device handler \"%s\" unloaded", dev_type->name); TRACE_EXIT(); return; @@ -1195,14 +1203,21 @@ { struct scsi_sense_hdr *shdr; BUILD_BUG_ON((sizeof(cmd->sense_buffer) < sizeof(*shdr)) && - (sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE)); + (sizeof(cmd->sense_buffer) >= SCST_SENSE_BUFFERSIZE)); } #endif { struct scst_tgt_dev *t; + struct scst_cmd *c; BUILD_BUG_ON(sizeof(t->curr_sn) != sizeof(t->expected_sn)); + BUILD_BUG_ON(sizeof(c->sn) != sizeof(t->expected_sn)); } + BUILD_BUG_ON(SCST_DATA_UNKNOWN != DMA_BIDIRECTIONAL); + BUILD_BUG_ON(SCST_DATA_WRITE != DMA_TO_DEVICE); + BUILD_BUG_ON(SCST_DATA_READ != DMA_FROM_DEVICE); + BUILD_BUG_ON(SCST_DATA_NONE != DMA_NONE); + spin_lock_init(&scst_main_cmd_lists.cmd_list_lock); INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list); init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ); @@ -1275,7 +1290,7 @@ scst_scsi_op_list_init(); - for (i = 0; i < ARRAY_SIZE(scst_tasklets); i++) { + for (i = 0; i < (int)ARRAY_SIZE(scst_tasklets); i++) { spin_lock_init(&scst_tasklets[i].tasklet_lock); INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list); tasklet_init(&scst_tasklets[i].tasklet, (void*)scst_cmd_tasklet, @@ -1425,6 +1440,8 @@ EXPORT_SYMBOL(scst_set_cmd_error); EXPORT_SYMBOL(scst_set_resp_data_len); +EXPORT_SYMBOL(scst_process_active_cmd); + /* * Target Driver Side (i.e. HBA) */ @@ -1476,6 +1493,14 @@ EXPORT_SYMBOL(scst_dev_del_all_thr_data); EXPORT_SYMBOL(scst_find_thr_data); +/* SGV pool routines */ +EXPORT_SYMBOL(sgv_pool_create); +EXPORT_SYMBOL(sgv_pool_destroy); +EXPORT_SYMBOL(sgv_pool_set_allocator); +EXPORT_SYMBOL(sgv_pool_alloc); +EXPORT_SYMBOL(sgv_pool_free); +EXPORT_SYMBOL(sgv_get_priv); + /* Generic parse() routines */ EXPORT_SYMBOL(scst_calc_block_shift); EXPORT_SYMBOL(scst_sbc_generic_parse); Modified: trunk/scst/src/scst_cdbprobe.h =================================================================== --- trunk/scst/src/scst_cdbprobe.h 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/scst_cdbprobe.h 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_cdbprobe.h * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * This program is free software; you can redistribute it and/or @@ -509,6 +509,6 @@ #define WRITE_LONG_2 0xea */ -#define SCST_CDB_TBL_SIZE ((sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops))) +#define SCST_CDB_TBL_SIZE ((int)(sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops))) #endif /* __SCST_CDBPROBE_H */ Modified: trunk/scst/src/scst_debug.c =================================================================== --- trunk/scst/src/scst_debug.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/scst_debug.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* - * include/scst_debug.c + * scst_debug.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * Contains helper functions for execution tracing and error reporting. @@ -52,8 +52,7 @@ return i; } -void debug_print_buffer(unsigned long trace_flag, const void *data, - int len) +void debug_print_buffer(const void *data, int len) { int z, z1, i; const unsigned char *buf = (const unsigned char *) data; Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-04-03 14:51:18 UTC (rev 107) +++ trunk/scst/src/scst_lib.c 2007-04-03 15:44:44 UTC (rev 108) @@ -1,7 +1,7 @@ /* * scst_lib.c * - * Copyright (C) 2004-2006 Vladislav Bolkhovitin <vs...@vl...> + * Copyright (C) 2004-2007 Vladislav Bolkhovitin <vs...@vl...> * and Leonid Stoljar * * This program is free software; you can redistribute it and/or @@ -126,7 +126,7 @@ l += cmd->sg[i].length; if (l >= resp_data_len) { int left = resp_data_len - (l - cmd->sg[i].length); - TRACE(TRACE_SG, "cmd %p (tag %d), " + TRACE(TRACE_SG|TRACE_MEMORY, "cmd %p (tag %d), " "resp_data_len %d, i %d, cmd->sg[i].length %d, " "left %d", cmd, cmd->tag, resp_data_len, i, cmd->sg[i].length, left); @@ -387,6 +387,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, struct scst_acg_dev *acg_dev) { + int ini_sg, ini_unchecked_isa_dma, ini_use_clustering; struct scst_tgt_dev *tgt_dev; struct scst_device *dev = acg_dev->dev; int rc, i; @@ -413,6 +414,40 @@ tgt_dev->sess = sess; atomic_set(&tgt_dev->cmd_count, 0); + tgt_dev->gfp_mask = __GFP_NOWARN; + tgt_dev->pool = &scst_sgv.norm; + + if (tgt_dev->dev->scsi_dev != NULL) { + ini_sg = tgt_dev->dev->scsi_dev->host->sg_tablesize; + ini_unchecked_isa_dma = + tgt_dev->dev->scsi_dev->host->unchecked_isa_dma; + ini_use_clustering = + (tgt_dev->dev->scsi_dev->host->use_clustering == + ENABLE_CLUSTERING); + } else { + ini_sg = (1 << 15) /* infinite */; + ini_unchecked_isa_dma = 0; + ini_use_clustering = 0; + } + tgt_dev->max_sg_cnt = min(ini_sg, sess->tgt->sg_tablesize); + + if ((sess->tgt->tgtt->use_clustering || ini_use_clustering) && + !sess->tgt->tgtt->no_clustering) { + TRACE_MEM("%s", "Use clustering"); + tgt_dev->pool = &scst_sgv.norm_clust; + } + + if (sess->tgt->tgtt->unchecked_isa_dma || ini_unchecked_isa_dma) { + TRACE_MEM("%s", "Use ISA DMA memory"); + tgt_dev->gfp_mask |= GFP_DMA; + tgt_dev->pool = &scst_sgv.dma; + } else { +#ifdef SCST_HIGHMEM + gfp_mask |= __GFP_HIGHMEM; + tgt_dev->pool = &scst_sgv.highmem; +#endif + } + tgt_dev->p_cmd_lists = &scst_main_cmd_lists; if (dev->scsi_dev != NULL) { @@ -437,7 +472,7 @@ tgt_dev->expected_sn = 1; tgt_dev->num_free_sn_slots = ARRAY_SIZE(tgt_dev->sn_slots); tgt_dev->cur_sn_slot = &tgt_dev->sn_slots[0]; - for(i = 0; i < ARRAY_SIZE(tgt_dev->sn_slots); i++) + for(i = 0; i < (int)ARRAY_SIZE(tgt_dev->sn_slots); i++) atomic_set(&tgt_dev->sn_slots[i], 0); if (dev->handler->parse_atomic && @@ -908,8 +943,8 @@ TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned", buf, len); memcpy(orig_cmd->sense_buffer, buf, - (sizeof(orig_cmd->sense_buffer) > len) ? - len : sizeof(orig_cmd->sense_buffer)); + ((int)sizeof(orig_cmd->sense_buffer) > len) ? + len : (int)sizeof(orig_cmd->sense_buffer)); } else { PRINT_ERROR_PR("%s", "Unable to get the sense via " "REQUEST SENSE, returning HARDWARE ERROR"); @@ -992,7 +1027,7 @@ { struct scsi_device *scsi_dev; unsigned char cdb[6]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; + unsigned char *sense; int rc; TRACE_ENTRY(); @@ -1000,6 +1035,9 @@ if (tgt_dev->dev->scsi_dev == NULL) goto out; + /* We can't afford missing RELEASE due to memory shortage */ + sense = kzalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL); + scsi_dev = tgt_dev->dev->scsi_dev; memset(cdb, 0, sizeof(cdb)); @@ -1010,13 +1048,15 @@ TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI " "mid-level"); rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0, - sense, SCST_DEFAULT_TIMEOUT, - ... [truncated message content] |
From: <vl...@us...> - 2007-04-24 16:45:12
|
Revision: 111 http://svn.sourceforge.net/scst/?rev=111&view=rev Author: vlnb Date: 2007-04-24 09:44:23 -0700 (Tue, 24 Apr 2007) Log Message: ----------- - SGV caching changed to be more space efficient - pre_unreg_sess() added to struct scst_dev_type - Minor fixes and cleanups Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst_mem.c trunk/scst/src/scst_mem.h trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-04-24 14:31:15 UTC (rev 110) +++ trunk/scst/include/scsi_tgt.h 2007-04-24 16:44:23 UTC (rev 111) @@ -719,6 +719,15 @@ */ int (*attach_tgt) (struct scst_tgt_dev *tgt_dev); + /* + * Called when a session, corresponding to a tgt_dev, is about to be + * unregistered and the tgt_dev - detached. Supposed to be used to + * clean out "stalled" commands, which otherwise could prevent SCST + * from entering into the suspended activity state and, so, + * unregistering the device. + */ + void (*pre_unreg_sess) (struct scst_tgt_dev *tgt_dev); + /* Called when tgt_dev (session) is detaching from the dev handler */ void (*detach_tgt) (struct scst_tgt_dev *tgt_dev); @@ -851,6 +860,9 @@ /* Used if scst_unregister_session() called in wait mode */ struct completion *shutdown_compl; + /* Used to push some unregister_session() works out of IRQ */ + struct work_struct unreg_work; + /* * Functions and data for user callbacks from scst_register_session() * and scst_unregister_session() Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-24 14:31:15 UTC (rev 110) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-04-24 16:44:23 UTC (rev 111) @@ -653,9 +653,9 @@ case WRITE_12: case WRITE_16: fua = (cdb[1] & 0x8); - if (cdb[1] & 0x8) { - TRACE(TRACE_ORDER, "FUA(%d): loff=%Ld, " - "data_len=%Ld", fua, (uint64_t)loff, + if (fua) { + TRACE(TRACE_ORDER, "FUA: loff=%Ld, " + "data_len=%Ld", (uint64_t)loff, (uint64_t)data_len); } break; Modified: trunk/scst/src/scst_mem.c =================================================================== --- trunk/scst/src/scst_mem.c 2007-04-24 14:31:15 UTC (rev 110) +++ trunk/scst/src/scst_mem.c 2007-04-24 16:44:23 UTC (rev 111) @@ -41,6 +41,15 @@ * of the existing SLAB code. */ +/* Chosen to have one page per slab for all orders */ +#ifdef CONFIG_DEBUG_SLAB +#define SGV_MAX_LOCAL_SLAB_ORDER 4 +#else +#define SGV_MAX_LOCAL_SLAB_ORDER 5 +#endif + +static int sgv_max_local_order, sgv_max_trans_order; + atomic_t sgv_other_total_alloc; DECLARE_MUTEX(scst_sgv_pool_mutex); @@ -229,20 +238,55 @@ goto out; } -static inline struct scatterlist *sgv_alloc_sg_entries(int pages_to_alloc, - unsigned long gfp_mask) +static int sgv_alloc_sg_entries(struct sgv_pool_obj *obj, + int pages_to_alloc, int order, unsigned long gfp_mask) { - int esz; - struct scatterlist *res; + int sz, tsz = 0; + int res = 0; - esz = pages_to_alloc * sizeof(*res); - res = (struct scatterlist*)kzalloc(esz, gfp_mask); - if (unlikely(res == NULL)) { + TRACE_ENTRY(); + + sz = pages_to_alloc * sizeof(obj->sg_entries[0]); + + obj->sg_entries = (struct scatterlist*)kzalloc(sz, gfp_mask); + if (unlikely(obj->sg_entries == NULL)) { TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj " - "SG vector failed (size %d)", esz); + "SG vector failed (size %d)", sz); + res = -ENOMEM; + goto out; + } + + if (obj->owner_pool->clustered) { + if (order <= sgv_max_trans_order) { + obj->trans_tbl = (struct trans_tbl_ent*)obj->sg_entries_data; + /* + * No need to clear trans_tbl, if needed, it will be + * fully rewritten in scst_alloc_sg_entries() + */ + } else { + tsz = pages_to_alloc * sizeof(obj->trans_tbl[0]); + obj->trans_tbl = (struct trans_tbl_ent*)kzalloc(tsz, gfp_mask); + if (unlikely(obj->trans_tbl == NULL)) { + TRACE(TRACE_OUT_OF_MEM, "Allocation of trans_tbl " + "failed (size %d)", tsz); + res = -ENOMEM; + goto out_free; + } + } } + TRACE_MEM("pages_to_alloc %d, order %d, sz %d, tsz %d, obj %p, " + "sg_entries %p, trans_tbl %p", pages_to_alloc, order, + sz, tsz, obj, obj->sg_entries, obj->trans_tbl); + +out: + TRACE_EXIT_RES(res); return res; + +out_free: + kfree(obj->sg_entries); + obj->sg_entries = NULL; + goto out; } struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size, @@ -254,7 +298,6 @@ struct scatterlist *res; int pages_to_alloc; struct kmem_cache *cache; - struct trans_tbl_ent *trans_tbl; int no_cached = flags & SCST_POOL_ALLOC_NO_CACHED; sBUG_ON(size == 0); @@ -268,13 +311,10 @@ if (*sgv != NULL) { obj = *sgv; TRACE_MEM("Supplied sgv_obj %p", obj); - pages_to_alloc = obj->sg_count; + pages_to_alloc = (1 << order); cache = obj->owner_cache; - trans_tbl = obj->trans_tbl; - EXTRACHECKS_BUG_ON(obj->sg_entries != NULL); - obj->sg_entries = sgv_alloc_sg_entries(pages_to_alloc, gfp_mask); - if (unlikely(obj->sg_entries == NULL)) - goto out_fail_free; + EXTRACHECKS_BUG_ON(cache != pool->caches[order]); + EXTRACHECKS_BUG_ON(obj->sg_count != 0); goto alloc; } @@ -287,30 +327,51 @@ "sgv_pool_obj failed (size %d)", size); goto out_fail; } - if (obj->sg_entries != NULL) { + if (obj->sg_count != 0) { TRACE_MEM("Cached sgv_obj %p", obj); EXTRACHECKS_BUG_ON(obj->owner_cache != cache); atomic_inc(&pool->acc.hit_alloc); atomic_inc(&pool->cache_acc[order].hit_alloc); goto success; } - obj->owner_cache = cache; pages_to_alloc = (1 << order); if (flags & SCST_POOL_NO_ALLOC_ON_CACHE_MISS) { - if (flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL) - goto out_return; - else + if (!(flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL)) goto out_fail_free; } TRACE_MEM("Brand new sgv_obj %p", obj); - obj->sg_entries = sgv_alloc_sg_entries(pages_to_alloc, gfp_mask); - if (unlikely(obj->sg_entries == NULL)) - goto out_fail_free; - trans_tbl = obj->trans_tbl; - /* - * No need to clear trans_tbl, if needed, it will be fully - * rewritten in scst_alloc_sg_entries() - */ + obj->owner_cache = cache; + obj->owner_pool = pool; + if (order <= sgv_max_local_order) { + obj->sg_entries = obj->sg_entries_data; + TRACE_MEM("sg_entries %p", obj->sg_entries); + memset(obj->sg_entries, 0, + pages_to_alloc*sizeof(obj->sg_entries[0])); + if (pool->clustered) { + obj->trans_tbl = (struct trans_tbl_ent*) + (obj->sg_entries + pages_to_alloc); + TRACE_MEM("trans_tbl %p", obj->trans_tbl); + /* We want to have all the data on the same page */ + EXTRACHECKS_BUG_ON(((unsigned long)obj->sg_entries & PAGE_MASK) != + ((unsigned long)&obj->trans_tbl[pages_to_alloc-1] & PAGE_MASK)); + /* + * No need to clear trans_tbl, if needed, it will + * be fully rewritten in scst_alloc_sg_entries() + */ + } else { + /* We want to have all the data on the same page */ + EXTRACHECKS_BUG_ON(((unsigned long)obj->sg_entries & PAGE_MASK) != + ((unsigned long)&obj->sg_entries[pages_to_alloc-1] & PAGE_MASK)); + } + } else { + if (unlikely(sgv_alloc_sg_entries(obj, pages_to_alloc, + order, gfp_mask) != 0)) + goto out_fail_free; + } + + if ((flags & SCST_POOL_NO_ALLOC_ON_CACHE_MISS) && + (flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL)) + goto out_return; } else { int sz; pages_to_alloc = pages; @@ -324,24 +385,22 @@ "sgv_pool_obj failed (size %d)", size); goto out_fail; } - obj->sg_entries = (struct scatterlist*)obj->trans_tbl; - trans_tbl = NULL; + obj->owner_pool = pool; + obj->sg_entries = obj->sg_entries_data; TRACE_MEM("Big or no_cached sgv_obj %p (size %d)", obj, sz); } obj->allocator_priv = priv; - obj->owner_pool = pool; alloc: obj->sg_count = scst_alloc_sg_entries(obj->sg_entries, - pages_to_alloc, gfp_mask, pool->clustered, trans_tbl, + pages_to_alloc, gfp_mask, pool->clustered, obj->trans_tbl, &pool->alloc_fns, priv); if (unlikely(obj->sg_count <= 0)) { - if ((flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL) && cache) { - kfree(obj->sg_entries); - obj->sg_entries = NULL; + obj->sg_count = 0; + if ((flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL) && cache) goto out_return1; - } else + else goto out_fail_free_sg_entries; } @@ -353,7 +412,7 @@ if (pool->clustered) cnt = obj->trans_tbl[pages-1].sg_num; else - cnt = obj->sg_count; + cnt = pages; sg = cnt-1; obj->orig_sg = sg; obj->orig_length = obj->sg_entries[sg].length; @@ -389,7 +448,6 @@ out_return1: *sgv = obj; - obj->sg_count = pages_to_alloc; TRACE_MEM("Returning failed sgv_obj %p (count %d)", obj, *count); out_return2: @@ -398,7 +456,12 @@ goto out; out_fail_free_sg_entries: - if (cache) { + if (obj->sg_entries != obj->sg_entries_data) { + if (obj->trans_tbl != (struct trans_tbl_ent*)obj->sg_entries_data) { + /* kfree() handles NULL parameter */ + kfree(obj->trans_tbl); + obj->trans_tbl = NULL; + } kfree(obj->sg_entries); obj->sg_entries = NULL; } @@ -428,8 +491,7 @@ "sg_count %d, allocator_priv %p", sgv, sgv->owner_cache, sgv->sg_entries, sgv->sg_count, sgv->allocator_priv); if (sgv->owner_cache != NULL) { - if (likely(sgv->sg_entries != NULL)) - sgv->sg_entries[sgv->orig_sg].length = sgv->orig_length; + sgv->sg_entries[sgv->orig_sg].length = sgv->orig_length; kmem_cache_free(sgv->owner_cache, sgv); } else { sgv->owner_pool->alloc_fns.free_pages_fn(sgv->sg_entries, @@ -455,9 +517,16 @@ static void sgv_dtor(void *data, struct kmem_cache *k, unsigned long f) { struct sgv_pool_obj *obj = data; - if (obj->sg_entries) { + if (obj->sg_count != 0) { obj->owner_pool->alloc_fns.free_pages_fn(obj->sg_entries, obj->sg_count, obj->allocator_priv); + } + if (obj->sg_entries != obj->sg_entries_data) { + if (obj->trans_tbl != (struct trans_tbl_ent*)obj->sg_entries_data) { + /* kfree() handles NULL parameter */ + kfree(obj->trans_tbl); + obj->trans_tbl = NULL; + } kfree(obj->sg_entries); } return; @@ -522,24 +591,32 @@ pool->alloc_fns.alloc_pages_fn = scst_alloc_sys_pages; pool->alloc_fns.free_pages_fn = scst_free_sys_sg_entries; - TRACE_MEM("name %s, sizeof(*obj)=%zd, clustered=%d, " - "sizeof(obj->trans_tbl[0])=%zd", name, sizeof(*obj), clustered, - sizeof(obj->trans_tbl[0])); + TRACE_MEM("name %s, sizeof(*obj)=%zd, clustered=%d", name, sizeof(*obj), + clustered); strncpy(pool->name, name, sizeof(pool->name)-1); pool->name[sizeof(pool->name)-1] = '\0'; for(i = 0; i < SGV_POOL_ELEMENTS; i++) { - int size, pages; + int size; atomic_set(&pool->cache_acc[i].total_alloc, 0); atomic_set(&pool->cache_acc[i].hit_alloc, 0); - pages = 1 << i; - size = sizeof(*obj) + pages * - (clustered ? sizeof(obj->trans_tbl[0]) : 0); - TRACE_MEM("pages=%d, size=%d", pages, size); + /* + * We need one page per SLAB. That's hackish, but is there + * any other choice? + */ + if (i <= SGV_MAX_LOCAL_SLAB_ORDER) { + int pages = 1 << i; + size = sizeof(*obj) + pages * + (sizeof(obj->sg_entries[0]) + + (clustered ? sizeof(obj->trans_tbl[0]) : 0)); + } else + size = PAGE_SIZE - 96; + TRACE_MEM("pages=%d, size=%d", 1 << i, size); + scnprintf(pool->cache_names[i], sizeof(pool->cache_names[i]), "%s-%luK", name, (PAGE_SIZE >> 10) << i); pool->caches[i] = kmem_cache_create(pool->cache_names[i], @@ -643,6 +720,18 @@ TRACE_ENTRY(); + sgv_max_local_order = get_order( + ((((PAGE_SIZE - sizeof(struct sgv_pool_obj)) / + (sizeof(struct trans_tbl_ent) + sizeof(struct scatterlist))) * + PAGE_SIZE) & PAGE_MASK)); + + sgv_max_trans_order = get_order( + ((((PAGE_SIZE - sizeof(struct sgv_pool_obj)) / + (sizeof(struct trans_tbl_ent))) * PAGE_SIZE) & PAGE_MASK)); + + TRACE_MEM("sgv_max_local_order %d, sgv_max_trans_order %d", + sgv_max_local_order, sgv_max_trans_order); + atomic_set(&sgv_other_total_alloc, 0); res = sgv_pool_init(&pools->norm, "sgv", 0); Modified: trunk/scst/src/scst_mem.h =================================================================== --- trunk/scst/src/scst_mem.h 2007-04-24 14:31:15 UTC (rev 110) +++ trunk/scst/src/scst_mem.h 2007-04-24 16:44:23 UTC (rev 111) @@ -41,9 +41,10 @@ int orig_sg; int orig_length; int sg_count; + void *allocator_priv; + struct trans_tbl_ent *trans_tbl; struct scatterlist *sg_entries; - void *allocator_priv; - struct trans_tbl_ent trans_tbl[0]; + struct scatterlist sg_entries_data[0]; }; struct sgv_pool_acc Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-04-24 14:31:15 UTC (rev 110) +++ trunk/scst/src/scst_targ.c 2007-04-24 16:44:23 UTC (rev 111) @@ -3536,13 +3536,13 @@ __scst_block_dev(dev); spin_unlock_bh(&dev->dev_lock); - rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); - if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) - mcmd->status = rc; - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); if (nexus_loss) scst_reset_tgt_dev(tgt_dev, 1); + + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); + if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) + mcmd->status = rc; } up(&scst_mutex); @@ -3586,14 +3586,14 @@ { int rc; + __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); + if (nexus_loss) + scst_reset_tgt_dev(tgt_dev, 1); + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) mcmd->status = rc; - - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); - if (nexus_loss) - scst_reset_tgt_dev(tgt_dev, 1); } } @@ -4197,6 +4197,42 @@ goto out; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void scst_unreg_work_fn(void *p) +#else +static void scst_unreg_work_fn(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + struct scst_session *sess = (struct scst_session*)p; +#else + struct scst_session *sess = container_of(work, struct scst_session, + unreg_work); +#endif + struct scst_tgt_dev *tgt_dev; + + TRACE_ENTRY(); + + down(&scst_mutex); + list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, + sess_tgt_dev_list_entry) { + struct scst_dev_type *handler = tgt_dev->dev->handler; + if (handler && handler->pre_unreg_sess) { + TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", + tgt_dev); + handler->pre_unreg_sess(tgt_dev); + TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " + "returned"); + } + } + up(&scst_mutex); + + scst_sess_put(sess); + + TRACE_EXIT(); + return; +} + /* * Must not been called in parallel with scst_rx_cmd() or * scst_rx_mgmt_fn_*() for the same sess @@ -4235,8 +4271,14 @@ tm_dbg_task_mgmt("UNREGISTER SESSION", 1); - scst_sess_put(sess); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&sess->unreg_work, scst_unreg_work_fn, sess); +#else + INIT_WORK(&sess->unreg_work, scst_unreg_work_fn); +#endif + schedule_work(&sess->unreg_work); + if (wait) { TRACE_DBG("Waiting for session %p to complete", sess); wait_for_completion(pc); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-05-17 15:30:24
|
Revision: 116 http://svn.sourceforge.net/scst/?rev=116&view=rev Author: vlnb Date: 2007-05-17 08:30:02 -0700 (Thu, 17 May 2007) Log Message: ----------- Linear search in the LUN translation routines scst_translate_lun() and scst_mgmt_translate_lun() was changed to a hash-based one, thanks to Michael G. Byrnes. Modified Paths: -------------- trunk/scst/ChangeLog trunk/scst/README trunk/scst/include/scsi_tgt.h trunk/scst/src/scst_lib.c trunk/scst/src/scst_targ.c Modified: trunk/scst/ChangeLog =================================================================== --- trunk/scst/ChangeLog 2007-05-17 14:45:18 UTC (rev 115) +++ trunk/scst/ChangeLog 2007-05-17 15:30:02 UTC (rev 116) @@ -8,7 +8,7 @@ implemented full support for SCSI task attributes (SIMPLE, ORDERED, etc.). - - Updated to work on 2.6.20.x + - Updated to work on 2.6.20.x, no update for 2.6.21.x is needed - Updated to work on 2.6.19.x, thanks to Ming Zhang. @@ -18,6 +18,10 @@ - /proc implementation moved to seq_*() library, thanks to Ming Zhang. Target drivers need to be updated accordingly. + - Linear search in the LUN translation routines scst_translate_lun() + and scst_mgmt_translate_lun() was changed to a hash-based one, thanks + to Michael G. Byrnes. + - Building from the Linux kernel tree updated, inside kernel building fixed. - Support for CPU cache flushing before doing DMA to target devices added. Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-05-17 14:45:18 UTC (rev 115) +++ trunk/scst/README 2007-05-17 15:30:02 UTC (rev 116) @@ -559,4 +559,6 @@ code and Vu Pham <hu...@ya...> who updated it for the VDISK dev handler. + * Michael G. Byrnes <mic...@hp...> for fixes. + Vladislav Bolkhovitin <vs...@vl...>, http://scst.sourceforge.net Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-05-17 14:45:18 UTC (rev 115) +++ trunk/scst/include/scsi_tgt.h 2007-05-17 15:30:02 UTC (rev 116) @@ -797,6 +797,11 @@ void *tgt_priv; }; +/* Hash size and hash fn for hash based lun translation */ +#define TGT_DEV_HASH_SHIFT 5 +#define TGT_DEV_HASH_SIZE (1<<TGT_DEV_HASH_SHIFT) +#define HASH_VAL(_val) (_val & (TGT_DEV_HASH_SIZE - 1)) + struct scst_session { /* Initialization phase, one of SCST_SESS_IPH_* constants */ @@ -814,10 +819,10 @@ /**************************************************************/ /* - * List of tgt_dev's for this session, protected by scst_mutex + * Hash list of tgt_dev's for this session, protected by scst_mutex * and suspended activity */ - struct list_head sess_tgt_dev_list; + struct list_head sess_tgt_dev_list_hash[TGT_DEV_HASH_SIZE]; /* Access control for this session and list entry there */ struct scst_acg *acg; @@ -1242,7 +1247,7 @@ */ struct scst_tgt_dev { - /* List entry in sess->sess_tgt_dev_list */ + /* List entry in sess->sess_tgt_dev_list_hash */ struct list_head sess_tgt_dev_list_entry; struct scst_device *dev; /* to save extra dereferences */ Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-05-17 14:45:18 UTC (rev 115) +++ trunk/scst/src/scst_lib.c 2007-05-17 15:30:02 UTC (rev 116) @@ -390,6 +390,7 @@ int ini_sg, ini_unchecked_isa_dma, ini_use_clustering; struct scst_tgt_dev *tgt_dev; struct scst_device *dev = acg_dev->dev; + struct list_head *sess_tgt_dev_list_head; int rc, i; TRACE_ENTRY(); @@ -451,7 +452,7 @@ tgt_dev->p_cmd_lists = &scst_main_cmd_lists; if (dev->scsi_dev != NULL) { - TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, " + TRACE_DBG("host=%d, channel=%d, id=%d, lun=%d, " "SCST lun=%Ld", dev->scsi_dev->host->host_no, dev->scsi_dev->channel, dev->scsi_dev->id, dev->scsi_dev->lun, (uint64_t)tgt_dev->lun); @@ -527,8 +528,9 @@ if (dev->dev_reserved) __set_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags); - list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, - &sess->sess_tgt_dev_list); + sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[HASH_VAL(tgt_dev->lun)]; + list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, sess_tgt_dev_list_head); out: TRACE_EXIT(); @@ -623,7 +625,6 @@ TRACE_ENTRY(); - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); list_for_each_entry(acg_dev, &sess->acg->acg_dev_list, acg_dev_list_entry) { @@ -646,17 +647,21 @@ /* scst_mutex supposed to be held and activity suspended */ void scst_sess_free_tgt_devs(struct scst_session *sess) { + int i; struct scst_tgt_dev *tgt_dev, *t; TRACE_ENTRY(); /* The session is going down, no users, so no locks */ - list_for_each_entry_safe(tgt_dev, t, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - scst_free_tgt_dev(tgt_dev); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry_safe(tgt_dev, t, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + scst_free_tgt_dev(tgt_dev); + } + INIT_LIST_HEAD(sess_tgt_dev_list_head); } - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); TRACE_EXIT(); return; @@ -1065,6 +1070,7 @@ const char *initiator_name) { struct scst_session *sess; + int i; int len; char *nm; @@ -1086,7 +1092,11 @@ sess->init_phase = SCST_SESS_IPH_INITING; atomic_set(&sess->refcnt, 0); - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + INIT_LIST_HEAD(sess_tgt_dev_list_head); + } spin_lock_init(&sess->sess_list_lock); INIT_LIST_HEAD(&sess->search_cmd_list); sess->tgt = tgt; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-05-17 14:45:18 UTC (rev 115) +++ trunk/scst/src/scst_targ.c 2007-05-17 15:30:02 UTC (rev 116) @@ -1240,6 +1240,7 @@ int res = SCST_EXEC_COMPLETED; int dev_cnt = 0; int buffer_size; + int i; struct scst_tgt_dev *tgt_dev = NULL; uint8_t *buffer; int offs, overflow = 0; @@ -1267,35 +1268,38 @@ memset(buffer, 0, buffer_size); offs = 8; - /* sess->sess_tgt_dev_list is protected by suspended activity */ - list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - if (!overflow) { - if (offs >= buffer_size) { - scst_put_buf(cmd, buffer); - buffer_size = scst_get_buf_next(cmd, &buffer); - if (buffer_size > 0) { - memset(buffer, 0, buffer_size); - offs = 0; - } else { - overflow = 1; - goto inc_dev_cnt; + /* sess->sess_tgt_dev_list_hash is protected by suspended activity */ + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &cmd->sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + if (!overflow) { + if (offs >= buffer_size) { + scst_put_buf(cmd, buffer); + buffer_size = scst_get_buf_next(cmd, &buffer); + if (buffer_size > 0) { + memset(buffer, 0, buffer_size); + offs = 0; + } else { + overflow = 1; + goto inc_dev_cnt; + } } + if ((buffer_size - offs) < 8) { + PRINT_ERROR_PR("Buffer allocated for REPORT " + "LUNS command doesn't allow to fit 8 " + "byte entry (buffer_size=%d)", + buffer_size); + goto out_put_hw_err; + } + buffer[offs] = (tgt_dev->lun >> 8) & 0xff; + buffer[offs+1] = tgt_dev->lun & 0xff; + offs += 8; } - if ((buffer_size - offs) < 8) { - PRINT_ERROR_PR("Buffer allocated for REPORT " - "LUNS command doesn't allow to fit 8 " - "byte entry (buffer_size=%d)", - buffer_size); - goto out_put_hw_err; - } - buffer[offs] = (tgt_dev->lun >> 8) & 0xff; - buffer[offs+1] = tgt_dev->lun & 0xff; - offs += 8; +inc_dev_cnt: + dev_cnt++; } -inc_dev_cnt: - dev_cnt++; } if (!overflow) scst_put_buf(cmd, buffer); @@ -2580,12 +2584,13 @@ __scst_get(1); if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) { + struct list_head *sess_tgt_dev_list_head = + &cmd->sess->sess_tgt_dev_list_hash[HASH_VAL(cmd->lun)]; + TRACE_DBG("Finding tgt_dev for cmd %p (lun %Ld)", cmd, + (uint64_t)cmd->lun); res = -1; - TRACE_DBG("Finding tgt_dev for cmd %p (lun %Ld)", cmd, - (uint64_t)cmd->lun); - list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { if (tgt_dev->lun == cmd->lun) { TRACE_DBG("tgt_dev %p found", tgt_dev); @@ -2988,6 +2993,7 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) { struct scst_tgt_dev *tgt_dev = NULL; + struct list_head *sess_tgt_dev_list_head; int res = -1; TRACE_ENTRY(); @@ -3005,9 +3011,10 @@ goto out; } - list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { + sess_tgt_dev_list_head = + &mcmd->sess->sess_tgt_dev_list_hash[HASH_VAL(mcmd->lun)]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { if (tgt_dev->lun == mcmd->lun) { TRACE_DBG("tgt_dev %p found", tgt_dev); mcmd->mcmd_tgt_dev = tgt_dev; @@ -3514,6 +3521,7 @@ int nexus_loss) { int res; + int i; struct scst_session *sess = mcmd->sess; struct scst_tgt_dev *tgt_dev; @@ -3528,23 +3536,26 @@ } down(&scst_mutex); - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - struct scst_device *dev = tgt_dev->dev; - int rc; - - spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); - spin_unlock_bh(&dev->dev_lock); - - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); - if (nexus_loss) - scst_reset_tgt_dev(tgt_dev, 1); - - rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); - if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) - mcmd->status = rc; + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + struct scst_device *dev = tgt_dev->dev; + int rc; + + spin_lock_bh(&dev->dev_lock); + __scst_block_dev(dev); + spin_unlock_bh(&dev->dev_lock); + + __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); + if (nexus_loss) + scst_reset_tgt_dev(tgt_dev, 1); + + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); + if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) + mcmd->status = rc; + } } up(&scst_mutex); @@ -3559,6 +3570,7 @@ int nexus_loss) { int res; + int i; struct scst_tgt *tgt = mcmd->sess->tgt; struct scst_session *sess; struct scst_device *dev; @@ -3583,19 +3595,22 @@ } list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) { - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - int rc; - - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); - if (nexus_loss) - scst_reset_tgt_dev(tgt_dev, 1); - - rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); - if ((rc < 0) && - (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) - mcmd->status = rc; + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + int rc; + + __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); + if (nexus_loss) + scst_reset_tgt_dev(tgt_dev, 1); + + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); + if ((rc < 0) && + (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) + mcmd->status = rc; + } } } @@ -3720,14 +3735,22 @@ case SCST_NEXUS_LOSS_SESS: case SCST_ABORT_ALL_TASKS_SESS: + { + int i; + down(&scst_mutex); - list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) { - scst_unblock_dev(tgt_dev->dev); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &mcmd->sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + scst_unblock_dev(tgt_dev->dev); + } } up(&scst_mutex); + break; - + } case SCST_CLEAR_ACA: default: break; @@ -4205,6 +4228,7 @@ static void scst_unreg_work_fn(struct work_struct *work) #endif { + int i; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct scst_session *sess = (struct scst_session*)p; #else @@ -4216,15 +4240,19 @@ TRACE_ENTRY(); down(&scst_mutex); - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) { - struct scst_dev_type *handler = tgt_dev->dev->handler; - if (handler && handler->pre_unreg_sess) { - TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", - tgt_dev); - handler->pre_unreg_sess(tgt_dev); - TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " - "returned"); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + struct scst_dev_type *handler = tgt_dev->dev->handler; + if (handler && handler->pre_unreg_sess) { + TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", + tgt_dev); + handler->pre_unreg_sess(tgt_dev); + TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " + "returned"); + } } } up(&scst_mutex); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-05-31 15:13:56
|
Revision: 118 http://svn.sourceforge.net/scst/?rev=118&view=rev Author: vlnb Date: 2007-05-31 08:13:13 -0700 (Thu, 31 May 2007) Log Message: ----------- Some docs updates Modified Paths: -------------- trunk/scst/README trunk/scst/src/scst.c Modified: trunk/scst/README =================================================================== --- trunk/scst/README 2007-05-17 15:35:45 UTC (rev 117) +++ trunk/scst/README 2007-05-31 15:13:13 UTC (rev 118) @@ -423,22 +423,25 @@ Pass-through mode ----------------- -As any other hardware, a local SCSI hardware for devices on target, -which are exported in the pass-through mode, can not handle commands -with amount of data and/or segments count in scatter-gather array -bigger, than some values. Therefore, when using the pass-through mode -you should note that the corresponding values on the corresponding -devices on initiators can not be bigger, than values, which the hardware -on the target can support. Otherwise you will see symptoms like small -transfers work well, but large ones stall and messages like: "Unable to -complete command due to SG IO count limitation" are printed in the -kernel logs. +In the pass-through mode (i.e. using the pass-through device handlers +scst_disk, scst_tape, etc) SCSI commands, coming from remote initiators, +are passed to local SCSI hardware on target as is, without any +modifications. As any other hardware, the local SCSI hardware can not +handle commands with amount of data and/or segments count in +scatter-gather array bigger some values. Therefore, when using the +pass-through mode you should note that values for maximum number of +segments and maximum amount of transferred data for each SCSI command on +devices on initiators can not be bigger, than corresponding values of +the corresponding SCSI devices on the target. Otherwise you will see +symptoms like small transfers work well, but large ones stall and +messages like: "Unable to complete command due to SG IO count +limitation" are printed in the kernel logs. You can't control from the user space limit of the scatter-gather segments, but for block devices usually it is sufficient if you set on -the initiator /sys/block/DEVICE_NAME/queue/max_sectors_kb in the same or -lower value as in /sys/block/DEVICE_NAME/queue/max_hw_sectors_kb for the -corresponding device on the target. +the initiators /sys/block/DEVICE_NAME/queue/max_sectors_kb in the same +or lower value as in /sys/block/DEVICE_NAME/queue/max_hw_sectors_kb for +the corresponding devices on the target. For not-block devices SCSI commands are usually generated directly by applications, so, if you experience large transfers stalls, you should Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-05-17 15:35:45 UTC (rev 117) +++ trunk/scst/src/scst.c 2007-05-31 15:13:13 UTC (rev 118) @@ -32,6 +32,11 @@ #include "scst_priv.h" #include "scst_mem.h" +#ifndef CONFIG_NOHIGHMEM +#warning HIGHMEM kernel configurations are supported, but not recommended. \ + Consider changing VMSPLIT option or using 64-bit configuration instead. +#endif + /* * All targets, devices and dev_types management is done under * this mutex. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2007-06-08 10:54:59
|
Revision: 126 http://svn.sourceforge.net/scst/?rev=126&view=rev Author: vlnb Date: 2007-06-08 03:54:18 -0700 (Fri, 08 Jun 2007) Log Message: ----------- Added limit on maximum queued on a device commands Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-06-08 10:25:29 UTC (rev 125) +++ trunk/scst/include/scsi_tgt.h 2007-06-08 10:54:18 UTC (rev 126) @@ -1184,6 +1184,9 @@ /* Lists of commands with the lock, if dedicated threads are used */ struct scst_cmd_lists cmd_lists; + /* How many cmds alive on this dev */ + atomic_t dev_cmd_count; + unsigned short type; /* SCSI type of the device */ /************************************************************* @@ -1283,7 +1286,7 @@ lun_t lun; /* to save extra dereferences */ /* How many cmds alive on this dev in this session */ - atomic_t cmd_count; + atomic_t tgt_dev_cmd_count; int gfp_mask; struct sgv_pool *pool; Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-06-08 10:25:29 UTC (rev 125) +++ trunk/scst/src/scst_lib.c 2007-06-08 10:54:18 UTC (rev 126) @@ -162,6 +162,7 @@ } dev->p_cmd_lists = &scst_main_cmd_lists; + atomic_set(&dev->dev_cmd_count, 0); spin_lock_init(&dev->dev_lock); atomic_set(&dev->on_dev_count, 0); INIT_LIST_HEAD(&dev->blocked_cmd_list); @@ -354,7 +355,7 @@ tgt_dev->lun = acg_dev->lun; tgt_dev->acg_dev = acg_dev; tgt_dev->sess = sess; - atomic_set(&tgt_dev->cmd_count, 0); + atomic_set(&tgt_dev->tgt_dev_cmd_count, 0); tgt_dev->gfp_mask = __GFP_NOWARN; tgt_dev->pool = &scst_sgv.norm; @@ -1211,8 +1212,10 @@ } #endif - if (likely(cmd->tgt_dev != NULL)) - atomic_dec(&cmd->tgt_dev->cmd_count); + if (likely(cmd->tgt_dev != NULL)) { + atomic_dec(&cmd->tgt_dev->tgt_dev_cmd_count); + atomic_dec(&cmd->dev->dev_cmd_count); + } /* * cmd->mgmt_cmnd can't being changed here, since for that it either Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2007-06-08 10:25:29 UTC (rev 125) +++ trunk/scst/src/scst_priv.h 2007-06-08 10:54:18 UTC (rev 126) @@ -105,13 +105,20 @@ /** ** Maximum count of uncompleted commands that an initiator could - ** queue on any device. Then it will take TASK QUEUE FULL status. + ** queue on any device. Then it will start getting TASK QUEUE FULL status. **/ -#define SCST_MAX_DEVICE_COMMANDS 128 +#define SCST_MAX_TGT_DEV_COMMANDS 64 -#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ) -#define SCST_CMD_MEM_TIMEOUT (120*HZ) +/** + ** Maximum count of uncompleted commands that could be queued on any device. + ** Then initiators sending commands to this device will start getting + ** TASK QUEUE FULL status. + **/ +#define SCST_MAX_DEV_COMMANDS 256 +#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ) +#define SCST_CMD_MEM_TIMEOUT (120*HZ) + static inline int scst_get_context(void) { if (in_irq()) return SCST_CONTEXT_TASKLET; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-06-08 10:25:29 UTC (rev 125) +++ trunk/scst/src/scst_targ.c 2007-06-08 10:54:18 UTC (rev 126) @@ -2632,15 +2632,23 @@ if (likely(res == 0)) { int cnt; cmd->state = SCST_CMD_STATE_DEV_PARSE; - cnt = atomic_inc_return(&cmd->tgt_dev->cmd_count); - if (unlikely(cnt > SCST_MAX_DEVICE_COMMANDS)) { + cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count); + if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) { TRACE(TRACE_RETRY, "Too many pending commands in " "session, returning BUSY to initiator \"%s\"", (cmd->sess->initiator_name[0] == '\0') ? "Anonymous" : cmd->sess->initiator_name); - scst_set_busy(cmd); - cmd->state = SCST_CMD_STATE_XMIT_RESP; - } else if (!cmd->no_sn) + goto out_busy; + } + cnt = atomic_inc_return(&cmd->dev->dev_cmd_count); + if (unlikely(cnt > SCST_MAX_DEV_COMMANDS)) { + TRACE(TRACE_RETRY, "Too many pending device commands, " + "returning BUSY to initiator \"%s\"", + (cmd->sess->initiator_name[0] == '\0') ? + "Anonymous" : cmd->sess->initiator_name); + goto out_busy; + } + if (!cmd->no_sn) scst_cmd_set_sn(cmd); } else if (res < 0) { TRACE_DBG("Finishing cmd %p", cmd); @@ -2653,6 +2661,11 @@ out: TRACE_EXIT_RES(res); return res; + +out_busy: + scst_set_busy(cmd); + cmd->state = SCST_CMD_STATE_XMIT_RESP; + goto out; } /* Called under scst_init_lock and IRQs disabled */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |