You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(19) |
Nov
(18) |
Dec
(34) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(14) |
Feb
(14) |
Mar
(3) |
Apr
(10) |
May
(10) |
Jun
(17) |
Jul
(15) |
Aug
(24) |
Sep
(24) |
Oct
(11) |
Nov
(13) |
Dec
(15) |
2008 |
Jan
(10) |
Feb
(46) |
Mar
(20) |
Apr
(42) |
May
(44) |
Jun
(22) |
Jul
(59) |
Aug
(8) |
Sep
(15) |
Oct
(52) |
Nov
(30) |
Dec
(38) |
2009 |
Jan
(27) |
Feb
(27) |
Mar
(47) |
Apr
(85) |
May
(74) |
Jun
(41) |
Jul
(70) |
Aug
(64) |
Sep
(97) |
Oct
(147) |
Nov
(67) |
Dec
(48) |
2010 |
Jan
(68) |
Feb
(33) |
Mar
(53) |
Apr
(98) |
May
(55) |
Jun
(71) |
Jul
(99) |
Aug
(132) |
Sep
(291) |
Oct
(220) |
Nov
(344) |
Dec
(300) |
2011 |
Jan
(57) |
Feb
(25) |
Mar
(59) |
Apr
(104) |
May
(60) |
Jun
(155) |
Jul
(143) |
Aug
(43) |
Sep
(53) |
Oct
(20) |
Nov
(35) |
Dec
(103) |
2012 |
Jan
(62) |
Feb
(43) |
Mar
(29) |
Apr
(80) |
May
(75) |
Jun
(61) |
Jul
(52) |
Aug
(58) |
Sep
(33) |
Oct
(32) |
Nov
(69) |
Dec
(37) |
2013 |
Jan
(77) |
Feb
(28) |
Mar
(52) |
Apr
(18) |
May
(37) |
Jun
(21) |
Jul
(22) |
Aug
(55) |
Sep
(29) |
Oct
(74) |
Nov
(50) |
Dec
(44) |
2014 |
Jan
(77) |
Feb
(62) |
Mar
(81) |
Apr
(99) |
May
(59) |
Jun
(95) |
Jul
(55) |
Aug
(34) |
Sep
(78) |
Oct
(33) |
Nov
(48) |
Dec
(51) |
2015 |
Jan
(56) |
Feb
(120) |
Mar
(37) |
Apr
(15) |
May
(22) |
Jun
(196) |
Jul
(54) |
Aug
(33) |
Sep
(32) |
Oct
(42) |
Nov
(149) |
Dec
(61) |
2016 |
Jan
(15) |
Feb
(26) |
Mar
(37) |
Apr
(27) |
May
(14) |
Jun
(11) |
Jul
(13) |
Aug
(64) |
Sep
(2) |
Oct
(36) |
Nov
(18) |
Dec
(46) |
2017 |
Jan
(6) |
Feb
(1) |
Mar
(2) |
Apr
(50) |
May
(42) |
Jun
(11) |
Jul
(4) |
Aug
(12) |
Sep
(11) |
Oct
(21) |
Nov
(15) |
Dec
(42) |
2018 |
Jan
(33) |
Feb
(27) |
Mar
(20) |
Apr
(5) |
May
(4) |
Jun
(1) |
Jul
(42) |
Aug
(29) |
Sep
(11) |
Oct
(40) |
Nov
(312) |
Dec
(18) |
2019 |
Jan
(44) |
Feb
(98) |
Mar
(125) |
Apr
(160) |
May
(123) |
Jun
(33) |
Jul
(56) |
Aug
(81) |
Sep
(24) |
Oct
(23) |
Nov
(52) |
Dec
(86) |
2020 |
Jan
(6) |
Feb
(17) |
Mar
(62) |
Apr
(21) |
May
(118) |
Jun
(42) |
Jul
(52) |
Aug
(62) |
Sep
(20) |
Oct
(5) |
Nov
(23) |
Dec
(111) |
2021 |
Jan
(31) |
Feb
(8) |
Mar
(26) |
Apr
(13) |
May
(54) |
Jun
(31) |
Jul
(17) |
Aug
(10) |
Sep
(83) |
Oct
(8) |
Nov
(21) |
Dec
(33) |
2022 |
Jan
(67) |
Feb
(11) |
Mar
(4) |
Apr
(46) |
May
(12) |
Jun
(17) |
Jul
(19) |
Aug
(7) |
Sep
(53) |
Oct
(14) |
Nov
(29) |
Dec
(22) |
2023 |
Jan
(20) |
Feb
(4) |
Mar
(37) |
Apr
(25) |
May
(15) |
Jun
(20) |
Jul
(38) |
Aug
(1) |
Sep
(1) |
Oct
(34) |
Nov
|
Dec
(8) |
2024 |
Jan
(15) |
Feb
(10) |
Mar
|
Apr
(4) |
May
(23) |
Jun
|
Jul
(8) |
Aug
(2) |
Sep
(18) |
Oct
(1) |
Nov
(18) |
Dec
(15) |
2025 |
Jan
(5) |
Feb
(1) |
Mar
(7) |
Apr
(4) |
May
(18) |
Jun
(7) |
Jul
|
Aug
(15) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <vl...@us...> - 2006-10-26 13:58:46
|
Revision: 13 http://svn.sourceforge.net/scst/?rev=13&view=rev Author: vlnb Date: 2006-10-26 06:58:39 -0700 (Thu, 26 Oct 2006) Log Message: ----------- Oops, previous commit erased ERASE16. Fixed. Modified Paths: -------------- trunk/scst/src/scst_cdbprobe.h Modified: trunk/scst/src/scst_cdbprobe.h =================================================================== --- trunk/scst/src/scst_cdbprobe.h 2006-10-26 13:56:42 UTC (rev 12) +++ trunk/scst/src/scst_cdbprobe.h 2006-10-26 13:58:39 UTC (rev 13) @@ -383,6 +383,8 @@ SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}, {0x93, "O O ", "WRITE SAME(16)", SCST_DATA_WRITE, 4, SCST_UNKNOWN_LENGTH, 1, 0}, /*N2! */ + {0x93, " M ", "ERASE(16)", + SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}, {0x9E, "M ", "SERVICE ACTION IN", SCST_DATA_READ, 4, 0, 0, 0}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-26 13:57:20
|
Revision: 12 http://svn.sourceforge.net/scst/?rev=12&view=rev Author: vlnb Date: 2006-10-26 06:56:42 -0700 (Thu, 26 Oct 2006) Log Message: ----------- Added SERVICE ACTION IN in scst_scsi_op_table Modified Paths: -------------- trunk/scst/src/scst_cdbprobe.h Modified: trunk/scst/src/scst_cdbprobe.h =================================================================== --- trunk/scst/src/scst_cdbprobe.h 2006-10-20 18:29:55 UTC (rev 11) +++ trunk/scst/src/scst_cdbprobe.h 2006-10-26 13:56:42 UTC (rev 12) @@ -383,8 +383,8 @@ SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}, {0x93, "O O ", "WRITE SAME(16)", SCST_DATA_WRITE, 4, SCST_UNKNOWN_LENGTH, 1, 0}, /*N2! */ - {0x93, " M ", "ERASE(16)", - SCST_DATA_NONE, 0, SCST_LONG_TIMEOUT, 0, 0}, + {0x9E, "M ", "SERVICE ACTION IN", + SCST_DATA_READ, 4, 0, 0, 0}, /* 12-bytes length CDB */ {0xA0, "VVVVVVVVVV M ", "REPORT LUN", 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:30:02
|
Revision: 11 http://svn.sourceforge.net/scst/?rev=11&view=rev Author: vlnb Date: 2006-10-20 11:29:55 -0700 (Fri, 20 Oct 2006) Log Message: ----------- Debugging cleanups Modified Paths: -------------- trunk/qla2x00t/qla2x00-target/qla2x00t.c Modified: trunk/qla2x00t/qla2x00-target/qla2x00t.c =================================================================== --- trunk/qla2x00t/qla2x00-target/qla2x00t.c 2006-10-20 18:18:46 UTC (rev 10) +++ trunk/qla2x00t/qla2x00-target/qla2x00t.c 2006-10-20 18:29:55 UTC (rev 11) @@ -772,10 +772,10 @@ prm.residual = le32_to_cpu(prm.cmd->atio.data_length) - prm.bufflen; if (prm.residual > 0) { - TRACE_MGMT_DBG("Residual underflow: %d", prm.residual); + TRACE_DBG("Residual underflow: %d", prm.residual); prm.rq_result |= SS_RESIDUAL_UNDER; } else if (prm.residual < 0) { - TRACE_MGMT_DBG("Residual overflow: %d", prm.residual); + TRACE_DBG("Residual overflow: %d", prm.residual); prm.rq_result |= SS_RESIDUAL_OVER; prm.residual = -prm.residual; } 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-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-12 16:43:50
|
Revision: 8 http://svn.sourceforge.net/scst/?rev=8&view=rev Author: vlnb Date: 2006-10-12 09:43:38 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Minor fixes and cleanups Modified Paths: -------------- trunk/qla2x00t/qla2x00-target/qla2x00t.c trunk/qla2x00t/qla2x00-target/qla2x00t.h trunk/qla2x00t/qla2x_tgt_def.h Modified: trunk/qla2x00t/qla2x00-target/qla2x00t.c =================================================================== --- trunk/qla2x00t/qla2x00-target/qla2x00t.c 2006-10-12 15:27:12 UTC (rev 7) +++ trunk/qla2x00t/qla2x00-target/qla2x00t.c 2006-10-12 16:43:38 UTC (rev 8) @@ -198,7 +198,7 @@ static void __q2t_send_notify_ack(scsi_qla_host_t *ha, uint16_t target_id, uint16_t status, uint16_t task_flags, uint16_t seq_id, uint32_t add_flags, uint16_t resp_code, - int resp_code_valid) + int resp_code_valid, uint16_t ox_id) { nack_entry_t *ntfy; @@ -226,7 +226,7 @@ /* Do not increment here, the chip isn't decrementing */ /* ntfy->flags = __constant_cpu_to_le16(NOTIFY_ACK_RES_COUNT); */ ntfy->flags |= cpu_to_le16(add_flags); - /* ntfy->ox_id = iocb->ox_id; ToDo */ + ntfy->ox_id = ox_id; if (resp_code_valid) { ntfy->resp_code = cpu_to_le16(resp_code); @@ -246,14 +246,12 @@ } /* ha->hardware_lock supposed to be held on entry */ static inline void q2t_send_notify_ack(scsi_qla_host_t *ha, - notify_entry_t *iocb, - uint32_t add_flags, - uint16_t resp_code, - int resp_code_valid) + notify_entry_t *iocb, uint32_t add_flags, uint16_t resp_code, + int resp_code_valid) { __q2t_send_notify_ack(ha, GET_TARGET_ID(ha, iocb), iocb->status, - iocb->task_flags, iocb->seq_id, - add_flags, resp_code, resp_code_valid); + iocb->task_flags, iocb->seq_id, add_flags, resp_code, + resp_code_valid, iocb->ox_id); } /* @@ -938,7 +936,7 @@ } SET_TARGET_ID(ha, ctio->target, GET_TARGET_ID(ha, atio)); -//ToDo!! ctio->rx_id = atio->rx_id; + ctio->exchange_id = atio->exchange_id; ctio->flags = __constant_cpu_to_le16(OF_FAST_POST | OF_TERM_EXCH | OF_NO_DATA | OF_SS_MODE_1); Modified: trunk/qla2x00t/qla2x00-target/qla2x00t.h =================================================================== --- trunk/qla2x00t/qla2x00-target/qla2x00t.h 2006-10-12 15:27:12 UTC (rev 7) +++ trunk/qla2x00t/qla2x00-target/qla2x00t.h 2006-10-12 16:43:38 UTC (rev 8) @@ -79,17 +79,6 @@ #define ATIO_ACA_QUEUE 4 #define ATIO_UNTAGGED 5 -/* CTIO additional flag ToDo: move to the appropriate place */ -#define OF_TERM_EXCH BIT_14 /* Terminate exchange */ - -/* ToDo: move to the appropriate place */ -#define CTIO_INVALID_RX_ID 0x08 -#define CTIO_TIMEOUT 0x0B -#define CTIO_LIP_RESET 0x0E -#define CTIO_TARGET_RESET 0x17 -#define CTIO_PORT_UNAVAILABLE 0x28 -#define CTIO_PORT_LOGGED_OUT 0x29 - /* TM failed response code, see FCP */ #define FC_TM_FAILED 0x5 Modified: trunk/qla2x00t/qla2x_tgt_def.h =================================================================== --- trunk/qla2x00t/qla2x_tgt_def.h 2006-10-12 15:27:12 UTC (rev 7) +++ trunk/qla2x00t/qla2x_tgt_def.h 2006-10-12 16:43:38 UTC (rev 8) @@ -74,6 +74,7 @@ #define OF_NO_DATA (BIT_7 | BIT_6) #define OF_INC_RC BIT_8 /* Increment command resource count */ #define OF_FAST_POST BIT_9 /* Enable mailbox fast posting. */ +#define OF_TERM_EXCH BIT_14 /* Terminate exchange */ #define OF_SSTS BIT_15 /* Send SCSI status */ #endif @@ -181,7 +182,8 @@ uint16_t seq_id; uint16_t reserved_5[11]; uint16_t scsi_status; - uint8_t sense_data[18]; + uint8_t sense_data[16]; + uint16_t ox_id; }notify_entry_t; #endif @@ -205,7 +207,8 @@ uint16_t status; uint16_t task_flags; uint16_t seq_id; - uint16_t reserved_3[21]; + uint16_t reserved_3[20]; + uint16_t ox_id; }nack_entry_t; #define NOTIFY_ACK_SUCCESS 0x01 #endif @@ -285,10 +288,14 @@ uint32_t dseg_2_address; /* Data segment 2 address. */ uint32_t dseg_2_length; /* Data segment 2 length. */ }ctio_entry_t; -#define CTIO_SUCCESS 0x01 -#define CTIO_ABORTED 0x02 -#define CTIO_ERROR_INVALID_RX_ID 0x08 -#define CTIO_ERROR_PORT_LOGGED_OUT 0x29 +#define CTIO_SUCCESS 0x01 +#define CTIO_ABORTED 0x02 +#define CTIO_INVALID_RX_ID 0x08 +#define CTIO_TIMEOUT 0x0B +#define CTIO_LIP_RESET 0x0E +#define CTIO_TARGET_RESET 0x17 +#define CTIO_PORT_UNAVAILABLE 0x28 +#define CTIO_PORT_LOGGED_OUT 0x29 #endif #ifndef CTIO_RET_TYPE This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 15:27:16
|
Revision: 7 http://svn.sourceforge.net/scst/?rev=7&view=rev Author: vlnb Date: 2006-10-12 08:27:12 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Tiny typo fixed Modified Paths: -------------- trunk/qla2x00t/qla2x00-target/README Modified: trunk/qla2x00t/qla2x00-target/README =================================================================== --- trunk/qla2x00t/qla2x00-target/README 2006-10-12 15:25:28 UTC (rev 6) +++ trunk/qla2x00t/qla2x00-target/README 2006-10-12 15:27:12 UTC (rev 7) @@ -16,7 +16,7 @@ If you have a driver's version (e.g. development) without the patch, but with the full patched initiator source code, you should replace by it qla2xxx subdirectory in kernel_source/drivers/scsi/ and then rebuild the -kernels or only its modules. +kernel or only its modules. This version is compatible with SCST version 0.9.5 and higher. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 15:25:42
|
Revision: 6 http://svn.sourceforge.net/scst/?rev=6&view=rev Author: vlnb Date: 2006-10-12 08:25:28 -0700 (Thu, 12 Oct 2006) Log Message: ----------- - Versions changed from "pre1" on "pre2" - Note added in qla2x00-target/README how to deal with full patched initiator driver Modified Paths: -------------- trunk/qla2x00t/qla2x00-target/README trunk/qla2x00t/qla2x00-target/qla2x00t.h trunk/scst/include/scsi_tgt.h Modified: trunk/qla2x00t/qla2x00-target/README =================================================================== --- trunk/qla2x00t/qla2x00-target/README 2006-10-12 15:15:46 UTC (rev 5) +++ trunk/qla2x00t/qla2x00-target/README 2006-10-12 15:25:28 UTC (rev 6) @@ -1,7 +1,7 @@ Target driver for Qlogic 2200/2300 Fibre Channel cards ====================================================== -Version 0.9.5-pre1, XX XXX 2006 +Version 0.9.5-pre2, XX XXX 2006 ------------------------------- This driver has all required features and looks to be quite stable (for @@ -13,6 +13,11 @@ a host acts as the initiator and the target simultaneously, is supported as well. +If you have a driver's version (e.g. development) without the patch, but +with the full patched initiator source code, you should replace by it +qla2xxx subdirectory in kernel_source/drivers/scsi/ and then rebuild the +kernels or only its modules. + This version is compatible with SCST version 0.9.5 and higher. Tested on stable kernels from http://www.kernel.org Modified: trunk/qla2x00t/qla2x00-target/qla2x00t.h =================================================================== --- trunk/qla2x00t/qla2x00-target/qla2x00t.h 2006-10-12 15:15:46 UTC (rev 5) +++ trunk/qla2x00t/qla2x00-target/qla2x00t.h 2006-10-12 15:25:28 UTC (rev 6) @@ -31,7 +31,7 @@ /* Version numbers, the same as for the kernel */ #define Q2T_VERSION(a,b,c,d) (((a) << 030) + ((b) << 020) + (c) << 010 + (d)) #define Q2T_VERSION_CODE Q2T_VERSION(0,9,5,0) -#define Q2T_VERSION_STRING "0.9.5-pre1" +#define Q2T_VERSION_STRING "0.9.5-pre2" #define Q2T_MAX_CDB_LEN 16 #define Q2T_TIMEOUT 10 /* in seconds */ Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2006-10-12 15:15:46 UTC (rev 5) +++ trunk/scst/include/scsi_tgt.h 2006-10-12 15:25:28 UTC (rev 6) @@ -32,7 +32,7 @@ /* Version numbers, the same as for the kernel */ #define SCST_VERSION_CODE 0x000905 #define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#define SCST_VERSION_STRING "0.9.5-pre1" +#define SCST_VERSION_STRING "0.9.5-pre2" /************************************************************* ** States of command processing state machine This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 15:15:55
|
Revision: 5 http://svn.sourceforge.net/scst/?rev=5&view=rev Author: vlnb Date: 2006-10-12 08:15:46 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Initial commit on SCST WWW page Added Paths: ----------- trunk/www/ trunk/www/scst_page.html Added: trunk/www/scst_page.html =================================================================== --- trunk/www/scst_page.html (rev 0) +++ trunk/www/scst_page.html 2006-10-12 15:15:46 UTC (rev 5) @@ -0,0 +1,246 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> +<head> + <meta http-equiv="content-type" + content="text/html; charset=ISO-8859-1"> + <title>SCST: Generic SCSI Target Middle Level for Linux</title> + <meta name="Keywords" + content="SCST, Linux, SCSI target, Qlogic, QLA2200, QLA2300, iSCSI, SCSI"> +</head> +<body> +<a href="http://sourceforge.net"> <img + src="http://sourceforge.net/sflogo.php?group_id=110471&type=5" + alt="SourceForge.net Logo" border="0" height="62" width="210"></a> +<h1><small>Generic SCSI Target Middle Level for Linux</small><br> +</h1> +<p style="text-align: justify;">The SCSI target mid-level subsystem for +Linux (SCST) is a new subsystem of the Linux kernel that provides a +standard framework for SCSI target drivers development. It is designed +to +provide unified, consistent interface between SCSI target drivers and +Linux kernel and simplify target drivers development as much as +possible. A system with a SCSI target device is able to share its local +or virtual devices with other systems on a network with SCSI protocol +support, e.g. SCSI bus, Fibre Channel, TCP/IP with iSCSI. This is +commonly used for data storage virtualization.<br> +</p> +<p style="text-align: justify;">SCST has the following features:</p> +<div style="text-align: justify;"> +</div> +<p style="text-align: justify;"> +</p> +<div style="text-align: justify;"> +</div> +<ul style="text-align: justify;"> + <li>Simple, easy to use interface with target drivers. Particularly, +SCST performs all required pre- and post- processing of incoming +requests and all necessary error recovery.</li> + <li>Undertakes most problems, related to execution contexts, thus +practically eliminating one of the most complicated problem in the +kernel drivers development. For example, a target driver for Qlogic +2200/2300 cards, which has all necessary features, is only ~2000 lines +of code long.</li> + <li> Very low overhead, fine-grained locks and simplest commands +processing path, which allow to reach maximum possible performance and +scalability. Particularly, incoming +requests can be processed in the caller's context or in +one of the internal SCST's tasklets, therefore no extra context +switches +required.</li> + <li>Provides advanced per-initiator device visibility management, +which allows different initiators could see different set of devices +with different access permissions. For instance, initiator A could see +exported from +target T devices Da and Db read-writable, and initiator B from the same +target T could see devices Db read-only and Dc read-writable.<br> + </li> + <li> Complete SMP support.<br> + </li> + <li> Emulates necessary functionality of SCSI host adapter, because +from a remote initiator's point of view SCST acts as a SCSI host with +its +own devices. Some of the emulated functions are the following: + <ul> + <li> Generation of necessary UNIT ATTENTIONs, their storage and +delivery to all connected remote initiators (sessions). </li> + <li> RESERVE/RELEASE functionality. </li> + <li> CA/ACA conditions. </li> + <li> All types of RESETs and other task management functions. </li> + <li> REPORT LUNS command as well as SCSI address space management +in order to have consistent address space on all remote initiators, +since local SCSI devices could not know about each other to report +via REPORT LUNS command. Additionally, SCST responds with error on +all commands to non-existing devices and provides access control +(not implemented yet), so different remote initiators could see +different set of devices. </li> + <li> Other necessary functionality (task attributes, etc.) as +specified in SAM-2, SPC-2, SAM-3, SPC-3 and other SCSI standards. </li> + </ul> + </li> + <li> Device handlers (i.e. plugins) architecture provides extra +flexibility by allowing to make any additional +requests processing, which is completely independent from target +drivers and SCST core, like, for instance, device dependent exceptional +conditions treatment, data caching or passing commands in the user +space for device emulation. Example of such plugin is FILEIO device +handler (see below) .<br> + </li> + <li>Well documented.<br> + </li> +</ul> +<div style="text-align: justify;"> +</div> +<p style="text-align: justify;">Interoperability between SCST and local +SCSI initiators (like sd, st) is +the additional issue that SCST is going to address (it is not +implemented yet). It is necessary, because local SCSI initiators can +change the state of the device, for example RESERVE the device, or some +of its parameters and that would be done behind SCST, which could lead +to various problems. Thus, RESERVE/RELEASE commands, locally generated +UNIT ATTENTIONs, etc. should be intercepted and processed as if local +SCSI initiators act as remote SCSI initiators connected to SCST. This +feature requires some the kernel modification. Since in the current +version it is not implemented, SCST and target drivers are +able to work with any 2.4 or 2.6 kernel version.<br> +</p> +<p style="text-align: justify;">Interface between SCST and target +drivers is based on work, done by <a href="http://www.iol.unh.edu/">University +of New Hampshire Interoperability Labs (UNH IOL)</a> for the <a + href="http://www.iol.unh.edu/consortiums/iscsi/index.html">UNH-iSCSI +project</a>, which is currently developed on <a + href="http://unh-iscsi.sourceforge.net/">SourceForge.net</a>.<br> +</p> +<p style="text-align: justify;">The latest stable version is 0.9.4. It +supports SCSI disks (type 0), tapes (type 1), processors (type +3), CDROMs (type 5), MO disks (type 7), medium changers (type 8) and +RAID controllers (type 0xC). Also it supports FILEIO and "performance" +device handlers. FILEIO device handler allows to use files on file +systems or block devices as virtual remotely available SCSI disks or +CDROM's. "Performance" device handlers provide a way for direct +performance measurements without overhead of actual data transferring +from/to underlying SCSI device. Requires Linux kernel 2.6.14 or higher. +Tested on i386 and x86_64 only, +but should also +work on any other +supported by Linux platform. More detail information you could find in +the project README file.<br> +</p> +<p style="text-align: justify;">Starting from version 0.9.4 2.4 Linux +kernels are not supported anymore, although there could be new SCST +releases those kernels with very important bug fixes. The latest stable +version of SCST with 2.4 kernels support is 0.9.3.1-24.</p> +<p style="text-align: justify;">If you have any questions you can ask +them on the SCST SF.net page either using forum, or scst-devel mailing +list.<br> +</p> +<a href="http://sourceforge.net/project/showfiles.php?group_id=110471">Download</a><br> +<a href="http://www.sourceforge.net/projects/scst">SCST SF.net project +page</a><br> +<a href="ChangeLog.scst">Change Log</a><br> +Documentation: <a href="doc/scst_pg.html">HTML</a>, <a + href="doc/scst_pg.pdf">PDF</a><br> +<p>The latest development versions of SCST and its drivers are +available directly from the +project's SVN. You can access it using either <a + href="http://svn.sourceforge.net/scst">web-based SVN +repository viewer</a> or using anonymous access: </p> +<p> <tt> svn co https://svn.sourceforge.net/svnroot/scst<br> +</tt></p> +<p>More information about accessing SVN repository may be found <a + href="http://sourceforge.net/docs/E09">here</a>.<br> +</p> +<p>History of the pre-SVN SCST development is available in SCST CVS +repository, which is accessible using <a + href="http://cvs.sourceforge.net/viewcvs.py/scst">web-based CVS +repository viewer</a> or anonymous CVS access.<br> +</p> +<hr + style="width: 100%; height: 2px; margin-left: 0px; margin-right: 0px;"> +<h1><small>Target driver for Qlogic 2200/2300 cards for 2.6 kernels<br> +</small></h1> +<div style="text-align: justify;"> +<p>This is ported version of the +previous target driver for 2.4 kernels (see below) to the in-tree 2.6 +Qlogic 2x00 initiator +driver. The port was done by Nathaniel Clark. This is stable and +functional driver with +the larger feature set, than the parent driver has.</p> +<p style="text-align: justify;">The latest version is 0.9.3.8. Requires +Linux kernel version 2.6.15.X and SCST version 0.9.4 or higher. +For usage with other kernel versions you will need to port the +initiator patch to that version of the kernel.<br> +</p> +<p style="text-align: justify;">You can find the latest development +version of this driver in the SCST CVS. See above how to setup access +to it.<br> +</p> +<p style="text-align: justify;"><a + href="http://sourceforge.net/project/showfiles.php?group_id=110471">Download</a><br> +<a href="ChangeLog.qla26">Change Log</a><br> +</p> +</div> +<hr style="width: 100%; height: 2px;"> +<h1><small>Target driver for Qlogic 2200/2300 cards<br> +</small></h1> +<div style="text-align: justify;">Target driver for Qlogic 2200/2300 +cards has all required features and +looks to be quite stable. It is designed to work in conjunction with +the initiator +driver, which is intended to perform all the initialization and +shutdown tasks. In the current release as a base for the initiator +driver was taken Red Hat's driver from the stock 2.4.20 kernel. Then it +was patched, basically, to enable the target mode and provide all +necessary callbacks, and it's still able to work as initiator only. +Mode, when a host acts as the initiator and the target simultaneously, +is also supported. This driver is going to be obsolete soon in favor of +2.6-based driver (see above).<br> +<br> +The latest version is 0.9.3.4. Requires Linux kernel versions 2.4.20 or +higher and SCST version 0.9.3-pre4 or higher. If you are lucky, it +works also on 2.6 kernels, see README file +for details. Tested on i386 only, but +should work on any other supported by Linux platform.<br> +<br> +</div> +<a href="http://sourceforge.net/project/showfiles.php?group_id=110471">Download</a><br> +<a href="ChangeLog.qla">Change Log</a> +<p style="text-align: justify;"></p> +<hr style="width: 100%; height: 2px;"> +<span style="font-weight: bold;"></span> +<h1><small>Target drivers for Adaptec 7xxx, LSI/MPT and Qlogic QLA12xx +cards</small></h1> +Target drivers for Adaptec 7xxx, LSI/MPT and Qlogic QLA12xx cards have +being developed by Hu Gang and they available for download from <a + href="http://bj.soulinfo.com/%7Ehugang/scst/tgt/">http://bj.soulinfo.com/~hugang/scst/tgt/</a>. +These drivers are not completed, but looks to be a good starting point +if you are going to use one of these cards. +SCST team don't have the appropriate hardware, therefore have not +tested and don't support these drivers. Send all questions to Hu Gang +<hugang +% soulinfo.com>. If some of these drivers don't compile for you, try +again with SCST version 0.9.3-pre2.<br> +<br> +<a href="http://bj.soulinfo.com/%7Ehugang/scst/tgt/">Download</a><br> +<br> +<hr style="width: 100%; height: 2px;"> +<h1><small>Patches for UNH-iSCSI Target 1.5.03 and 1.6.00 to work over +SCST</small></h1> +SCST is much more advanced, than the internal mid-level of <a + href="http://sourceforge.net/projects/unh-iscsi">UNH-iSCSI target +driver</a>. +With SCST the iSCSI target benefits from all its features and gets +ability to use all its advantages, like high performance and +scalability, SMP support, required SCSI functionality emulation, etc.<br> +<br> +Since the interface between SCST and the target drivers is based on +work, done by UNH IOL, it was relatively simple to update UNH-iSCSI +target to work over SCST. Mostly it was "search and replace" job. The +built-in scsi_target remains available as a compile-time option.<br> +<br> +Requires Linux kernel versions 2.4.20 or +higher or 2.6.7 or higher and SCST version 0.9.2 or higher.<br> +<br> +<a href="http://sourceforge.net/project/showfiles.php?group_id=110471">Download</a><br> +<br> +</body> +</html> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 14:25:16
|
Revision: 4 http://svn.sourceforge.net/scst/?rev=4&view=rev Author: vlnb Date: 2006-10-12 07:25:08 -0700 (Thu, 12 Oct 2006) Log Message: ----------- - Fixed dev->on_dev_count underleak - Minor fixes and cosmetics Modified Paths: -------------- trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2006-10-12 14:18:50 UTC (rev 3) +++ trunk/scst/src/scst_priv.h 2006-10-12 14:25:08 UTC (rev 4) @@ -346,7 +346,8 @@ __scst_block_dev(dev); spin_unlock_bh(&dev->dev_lock); - TRACE_MGMT_DBG("%s", "Waiting during blocking"); + TRACE_MGMT_DBG("Waiting during blocking outstanding %d (on_dev_count " + "%d)", outstanding, atomic_read(&dev->on_dev_count)); wait_event(dev->on_dev_waitQ, atomic_read(&dev->on_dev_count) <= outstanding); TRACE_MGMT_DBG("%s", "wait_event() returned"); Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2006-10-12 14:18:50 UTC (rev 3) +++ trunk/scst/src/scst_targ.c 2006-10-12 14:25:08 UTC (rev 4) @@ -1580,7 +1580,7 @@ } count = 0; - do { + while(1) { rc = scst_do_send_to_midlev(cmd); if (rc == SCST_EXEC_NEED_THREAD) { TRACE_DBG("%s", "scst_do_send_to_midlev() requested " @@ -1597,8 +1597,11 @@ count++; expected_sn = __scst_inc_expected_sn(tgt_dev); cmd = scst_check_deferred_commands(tgt_dev, expected_sn); + if (cmd == NULL) + break; + if (unlikely(scst_inc_on_dev_cmd(cmd) != 0)) + break; } - while(cmd != NULL); out_unplug: if (dev->scsi_dev != NULL) @@ -1742,9 +1745,6 @@ TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - if (cmd->cdb[0] == REQUEST_SENSE) { if (cmd->internal) cmd = scst_complete_request_sense(cmd); @@ -1775,15 +1775,12 @@ uint8_t *address; length = scst_get_buf_first(cmd, &address); - if (unlikely(length <= 0)) { + if (length <= 0) goto out; - } - if (length > 2 && cmd->cdb[0] == MODE_SENSE) { + if (length > 2 && cmd->cdb[0] == MODE_SENSE) address[2] |= 0x80; /* Write Protect*/ - } - else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) { + else if (length > 3 && cmd->cdb[0] == MODE_SENSE_10) address[3] |= 0x80; /* Write Protect*/ - } scst_put_buf(cmd, address); } @@ -1800,7 +1797,7 @@ /* ToDo: all pages ?? */ buflen = scst_get_buf_first(cmd, &buffer); - if (likely(buflen > 0)) { + if (buflen > 0) { if (buflen > SCST_INQ_BYTE3) { #ifdef EXTRACHECKS if (buffer[SCST_INQ_BYTE3] & SCST_INQ_NORMACA_BIT) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 14:19:13
|
Revision: 3 http://svn.sourceforge.net/scst/?rev=3&view=rev Author: vlnb Date: 2006-10-12 07:18:50 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Property svn:ignore set Property Changed: ---------------- / branches/ tags/ trunk/ trunk/doc/ trunk/qla2x00t/ trunk/qla2x00t/qla2x00-target/ trunk/scst/ trunk/scst/include/ trunk/scst/kernel/ trunk/scst/kernel/in-tree/ trunk/scst/src/ trunk/scst/src/dev_handlers/ Property changes on: ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: branches ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: tags ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/doc ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/qla2x00t ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/qla2x00t/qla2x00-target ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst/include ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst/kernel ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst/kernel/in-tree ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst/src ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers Property changes on: trunk/scst/src/dev_handlers ___________________________________________________________________ Name: svn:ignore + *.mod.c *.ko *.ko.cmd *.o.cmd .tmp_versions Modules.symvers This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <vl...@us...> - 2006-10-12 14:03:25
|
Revision: 2 http://svn.sourceforge.net/scst/?rev=2&view=rev Author: vlnb Date: 2006-10-12 07:02:57 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Initial doc's commit Added Paths: ----------- trunk/doc/ trunk/doc/Makefile trunk/doc/fig1.png trunk/doc/fig2.png trunk/doc/fig3.png trunk/doc/fig4.png trunk/doc/scst_pg.sgml Added: trunk/doc/Makefile =================================================================== --- trunk/doc/Makefile (rev 0) +++ trunk/doc/Makefile 2006-10-12 14:02:57 UTC (rev 2) @@ -0,0 +1,61 @@ +COMMAND=linuxdoc --backend= + +SOURCE_NAME=scst_pg + +SOURCE=$(SOURCE_NAME).sgml + +default: html txt pdf + +all: html txt pdf tex dvi ps info lyx rtf + +txt: $(SOURCE_NAME).txt + +html: $(SOURCE_NAME).html + +tex: $(SOURCE_NAME).tex + +dvi: $(SOURCE_NAME).dvi + +ps: $(SOURCE_NAME).ps + +pdf: $(SOURCE_NAME).pdf + +info: $(SOURCE_NAME).info + +lyx: $(SOURCE_NAME).lyx + +rtf: $(SOURCE_NAME).rtf + +$(SOURCE_NAME).txt: $(SOURCE) + $(COMMAND)txt $(SOURCE) + +$(SOURCE_NAME).html: $(SOURCE) + $(COMMAND)html --split=0 $(SOURCE) + +$(SOURCE_NAME).tex: $(SOURCE) + $(COMMAND)latex -o tex $(SOURCE) + +$(SOURCE_NAME).dvi: $(SOURCE) + $(COMMAND)latex -o dvi $(SOURCE) + +$(SOURCE_NAME).ps: $(SOURCE) + $(COMMAND)latex -o ps $(SOURCE) + +$(SOURCE_NAME).pdf: $(SOURCE) + $(COMMAND)latex -o pdf $(SOURCE) + +$(SOURCE_NAME).info: $(SOURCE) + $(COMMAND)info $(SOURCE) + +$(SOURCE_NAME).lyx: $(SOURCE) + $(COMMAND)lyx $(SOURCE) + +$(SOURCE_NAME).rtf: $(SOURCE) + $(COMMAND)rtf $(SOURCE) + +clean: + rm -f *.txt *.html *.tex *.dvi *.ps *.pdf *.info *.lyx *.rtf + +extraclean: clean + +.PHONY: all default html txt pdf tex dvi ps info lyx rtf clean extraclean Added: trunk/doc/fig1.png =================================================================== (Binary files differ) Property changes on: trunk/doc/fig1.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/doc/fig2.png =================================================================== (Binary files differ) Property changes on: trunk/doc/fig2.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/doc/fig3.png =================================================================== (Binary files differ) Property changes on: trunk/doc/fig3.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/doc/fig4.png =================================================================== (Binary files differ) Property changes on: trunk/doc/fig4.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/doc/scst_pg.sgml =================================================================== --- trunk/doc/scst_pg.sgml (rev 0) +++ trunk/doc/scst_pg.sgml 2006-10-12 14:02:57 UTC (rev 2) @@ -0,0 +1,2278 @@ +<!doctype linuxdoc system> + +<article> + +<title>Generic SCSI Target Middle Level for Linux</title> + +<author> + <name>Vladislav Bolkhovitin <<tt/vst @at@ vlnb .dot. net/></name> +</author> + +<date>Version 0.9.3-pre4 2006/02/07, actual for SCST 0.9.3-pre4 and later</date> + +<abstract> +This document describes SCSI target mid-level for Linux (SCST), its +architecture and drivers from the driver writer's point of view. +</abstract> + +<toc> + +<sect>Introduction + +<p> +SCST is a SCSI target mid-level subsystem for Linux. It is designed to +provide unified, consistent interface between SCSI target drivers and +Linux kernel and simplify target drivers development as much as +possible. It has the following features: + +<itemize> + +<item> Very low overhead, fine-grained locks and simplest commands +processing path, which allow to reach maximum possible performance and +scalability that close to theoretical limit. + +<item> Incoming requests can be processed in the caller's context or in +one of the internal SCST's tasklets, therefore no extra context switches +required. + +<item> Complete SMP support. + +<item> Undertakes most problems, related to execution contexts, thus +practically eliminating one of the most complicated problem in the +kernel drivers development. For example, a target driver for Qlogic +2200/2300 cards, which has all necessary features, is about 2000 +lines of code long, that is at least in several times less, than the +initiator one. + +<item> Performs all required pre- and post- processing of incoming +requests and all necessary error recovery functionality. + +<item> Emulates necessary functionality of SCSI host adapter, because +from a remote initiator's point of view SCST acts as a SCSI host with +its own devices. Some of the emulated functions are the following: + + <itemize> + + <item> Generation of necessary UNIT ATTENTIONs, their storage and + delivery to all connected remote initiators (sessions). + + <item> RESERVE/RELEASE functionality. + + <item> CA/ACA conditions. + + <item> All types of RESETs and other task management functions. + + <item> REPORT LUNS command as well as SCSI address space management + in order to have consistent address space on all remote initiators, + since local SCSI devices could not know about each other to report + via REPORT LUNS command. Additionally, SCST responds with error on + all commands to non-existing devices and provides access control + (not implemented yet), so different remote initiators could see + different set of devices. + + <item> Other necessary functionality (task attributes, etc.) as + specified in SAM-2, SPC-2, SAM-3, SPC-3 and other SCSI standards. + + </itemize> + +<item> Device handlers architecture provides extra reliability and +security via verifying all incoming requests and allows to make any +additional requests processing, which is completely independent from +target drivers, for example, data caching or device dependent +exceptional conditions treatment. + +</itemize> + +Interoperability between SCST and local SCSI initiators (like sd, st) is +the additional issue that SCST is going to address (it is not +implemented yet). It is necessary, because local SCSI initiators can +change the state of the device, for example RESERVE the device, or some +of its parameters and that would be done behind SCST, which could lead +to various problems. Thus, RESERVE/RELEASE commands, locally generated +UNIT ATTENTIONs, etc. should be intercepted and processed as if local +SCSI initiators act as remote SCSI initiators connected to SCST. This +feature requires some the kernel modification. Since in the current +version it is not implemented, SCST and the target drivers are able to +work with any unpatched 2.4 kernel version. + +Interface between SCST and the target drivers is based on work, done by +University of New Hampshire Interoperability Labs (UNH IOL). + +All described below data structures and function could be found in +<bf/scsi_tgt.h/. The SCST's Internet page is +<url url="http://scst.sourceforge.net">. + +<sect>Terms and Definitions + +<p><bf/SCSI initiator device/ + +A SCSI device that originates service and task management requests to be +processed by a SCSI target device and receives device service and task +management responses from SCSI target devices. + +<bf/SCSI target device/ + +A SCSI device that receives device service and task management requests +for processing and sends device service and task management responses +to SCSI initiator devices or drivers. + +<bf/SCST session/ + +SCST session is the object that describes relationship between a remote +initiator and SCST via a target driver. All the commands from the remote +initiator is passed to SCST in the session. For example, for connection +oriented protocols, like iSCSI, SCST session could be mapped to the TCP +connection. SCST session is the close equivalent of I_T nexus object. + +<bf/Local SCSI initiator/ + +A SCSI initiator that is located on the same host as SCST subsystem. +Examples are sg and st drivers. + +<bf/Remote SCSI initiator/ + +A SCSI initiator that is located on the remote host for SCST subsystem +and makes client connections to SCST via SCSI target drivers. + +<bf/SCSI target driver/ + +A Linux hardware or logical driver that acts as a SCSI target for remote +SCSI initiators, i.e. accepts remote connections, passes incoming SCSI +requests to SCST and sends SCSI responses from SCST back to their +originators. + +<bf/Device handler driver/ + +Also known as "device type specific driver" or "dev handler", is plugin +for SCST, which helps SCST to analyze incoming requests and determine +parameters, specific to various types of devices as well as perform some +processing. See appropriate section for details. + +<sect>SCST Architecture + +<p> +SCST accepts commands and passes them to SCSI mid-level at the same +way as SCSI high-level drivers (sg, sd, st) do. Figure 1 shows +interaction between SCST, its drivers and Linux SCSI subsystem. + +<figure> +<eps file="fig1.png"> +<img src="fig1.png"> +<caption> + <newline> Interaction between SCST, its drivers and Linux SCSI subsystem. +</caption> +</figure> + +<sect>Target driver registration + +<p> +To work with SCST a target driver must register its template in SCST by +calling scst_register_target_template(). The template lets SCST know the +target driver's entry points. It is defined as the following: + +<sect1>Structure scst_tgt_template + +<p> +<verb> +struct scst_tgt_template +{ + int sg_tablesize; + const char name[15]; + + unsigned unchecked_isa_dma:1; + unsigned use_clustering:1; + + unsigned xmit_response_atomic:1; + unsigned rdy_to_xfer_atomic:1; + unsigned report_aen_atomic:1; + + int (* detect) (struct scst_tgt_template *tgt_template); + int (* release)(struct scst_tgt *tgt); + + int (* xmit_response)(struct scst_cmd *cmd); + int (* rdy_to_xfer)(struct scst_cmd *cmd); + + void (*on_free_cmd) (struct scst_cmd *cmd); + + void (* task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd); + void (* report_aen)(int mgmt_fn, const uint8_t *lun, int lun_len); + + int (*proc_info) (char *buffer, char **start, off_t offset, + int length, int *eof, struct scst_tgt *tgt, int inout); +} +</verb> + +Where: + +<itemize> + +<item><bf/sg_tablesize/ - allows checking whether scatter/gather can be +used or not and, if yes, sets the maximum supported count of +scatter/gather entries + +<item><bf/name/ - the name of the template. Must be unique to identify +the template. Must be defined. + +<item><bf/unchecked_isa_dma/ - true, if this target adapter uses +unchecked DMA onto an ISA bus. + +<item><bf/use_clustering/ - true, if this target adapter wants to use +clustering (i.e. smaller number of segments). + +<item><bf/xmit_response_atomic/, <bf/rdy_to_xfer_atomic/ - true, if the +corresponding function supports execution in the atomic (non-sleeping) +context. + +<item><bf/int (* detect) (struct scst_tgt_template *tgt_template)/ - this +function is intended to detect the target adapters that are present in +the system. Each found adapter should be registered by calling +<bf/scst_register()/. The function should return a value >= 0 to signify +the number of detected target adapters. A negative value should be +returned whenever there is an error. Must be defined. + +<item><bf/int (* release)(struct scst_tgt *tgt)/ - this function is +intended to free up the resources allocated to the device. The function +should return 0 to indicate successful release or a negative value if +there are some issues with the release. In the current version of SCST +the return value is ignored. Must be defined. + +<item><bf/int (* xmit_response)(struct scst_cmd *cmd)/ - this +function is equivalent to the SCSI queuecommand(). The target should +transmit the response data and the status in the struct scst_cmd. See +below for details. Must be defined. + +<item><bf/int (* rdy_to_xfer)(struct scst_cmd *cmd)/ - this function +informs the driver that data buffer corresponding to the said command +have now been allocated and it is OK to receive data for this command. +This function is necessary because a SCSI target does not have any +control over the commands it receives. Most lower-level protocols have a +corresponding function which informs the initiator that buffers have +been allocated e.g., XFER_RDY in Fibre Channel. After the data is +actually received the low-level driver should call <bf/scst_rx_data()/ +in order to continue processing this command. Returns one of the +<bf/SCST_TGT_RES_*/ constants, described below. Pay attention to +"atomic" attribute of the command, which can be get via +<bf/scst_cmd_atomic()/: it is true if the function called in the atomic +(non-sleeping) context. Must be defined. + +<item><bf/void (*on_free_cmd)(struct scst_cmd *cmd)/ - this function +called to notify the driver that the command is about to be freed. +Necessary, because for aborted commands <bf/xmit_response()/ could not be +called. Could be used on IRQ context. Must be defined. + +<item><bf/void (* task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd)/ - +this function informs the driver that a received task management +function has been completed. Completion status could be get via +<bf/scst_mgmt_cmd_get_status()/. No return value expected. Must be +defined, if the target supports task management functionality. + +<item><bf/int (* report_aen)(int mgmt_fn, const uint8_t *lun, int +lun_len)/ - this function is used for Asynchronous Event Notification. +It is the responsibility of the driver to notify any/all initiators +about the Asynchronous Event reported. Returns one of the +<bf/SCST_TGT_RES_*/ constants, described below. Must be defined, if +low-level protocol supports AEN. This feature is not implemented yet. + +<item><bf/int (*proc_info) (char *buffer, char **start, off_t offset, +int length, int *eof, struct scst_tgt *tgt, int inout)/ - this function +can be used to export the driver's statistics and other information to +the world outside the kernel. Parameters: + + <enum> + + <item> <bf/buffer, start, offset, length, eof/ - have the same + meaning as for <bf/read_proc_t/ function of the kernel + + <item> <bf/tgt/ - pointer to the target, for which the function + is called + + <item> <bf/inout/ - read/write direction flag, 0 - for reads, other + value - for writes + + </enum> + +If the driver needs to create additional files in its /proc +subdirectory, it can use <bf/scst_proc_get_tgt_root()/ function to get +the root proc_dir_entry. + +</itemize> + +Functions <bf/xmit_response()/, <bf/rdy_to_xfer()/ are expected to be +non-blocking, i.e. return immediately and don't wait for actual data +transfer to finish. Blocking in such command could negatively impact on +overall system performance. If blocking is necessary, it is worth to +consider creating dedicated thread(s) in target driver, to which the +commands would be passed and which would perform blocking operations +instead of SCST. If the function allowed to sleep or not is defined by +"atomic" attribute of the cmd that can be get via +<bf/scst_cmd_atomic()/, which is true, if sleeping is not allowed. In +this case, if the function requires sleeping, it can return +<bf/SCST_TGT_RES_NEED_THREAD_CTX/ in order to be recalled in the thread +context, where sleeping is allowed. + +Functions <bf/task_mgmt_fn_done()/ and <bf/report_aen()/ are recommended +to be non-blocking as well. Blocking there will stop all management +processing for all target drivers in the system (there is only one +management thread in the system). + +Functions <bf/xmit_response()/, <bf/rdy_to_xfer()/ and <bf/report_aen()/ +can return the following error codes: + +<itemize> + +<item><bf/SCST_TGT_RES_SUCCESS/ - success. + +<item><bf/SCST_TGT_RES_QUEUE_FULL/ - internal device queue is full, retry +again later. + +<item><bf/SCST_TGT_RES_NEED_THREAD_CTX/ - it is impossible to complete +requested task in atomic context. The command should be restarted in the +thread context as described above. + +<item><bf/SCST_TGT_RES_FATAL_ERROR/ - fatal error, i.e. it is unable to +perform requested operation. If returned by <bf/xmit_response()/ the +command will be destroyed, if by <bf/rdy_to_xfer()/, +<bf/xmit_response()/ will be called with <bf/HARDWARE ERROR/ sense data. + +</itemize> + +<sect2>More about <bf/xmit_response()/ + +<p> +As already written above, function <bf/xmit_response()/ should transmit +the response data and the status from the cmd parameter. Either it +should transmit the data or the status is defined by bits of the value, +returned by <bf/scst_cmd_get_tgt_resp_flags()/. They are: + +<itemize> + +<item><bf/SCST_TSC_FLAG_DATA/ - set if there are data to be sent + +<item><bf/SCST_TSC_FLAG_STATUS/ - set if the command is finished and +there is status/sense to be sent + +</itemize> + +If <bf/SCST_TSC_FLAG_DATA/ is set, the data contained in the buffer, +returned by <bf/scst_cmd_get_buffer()/ (pay attention to +<bf/scst_cmd_get_use_sg()/ for scatter/gather) with length, returned by +<bf/scst_cmd_get_resp_data_len()/. It is recommended to use +<bf/scst_get_buf_*()/scst_put_buf()/ family of function instead of +direct access to the data buffers, because they hide all HIGHMEM and +SG/plain buffer issues. + +If <bf/SCST_TSC_FLAG_STATUS/ is set the status could be received by the +appropriate <bf/scst_cmd_get_*_status()/ functions (see below). + +The sense, if any, is contained in the buffer, returned by +<bf/scst_cmd_get_sense_buffer()/, with length, returned by +<bf/scst_cmd_get_sense_buffer_len()/. SCST always works in +<bf/autosense/ mode. If a low-level SCSI driver/device doesn't support +autosense mode, SCST will issue REQUEST SENSE command, if necessary. +Thus, if CHECK CONDITION established, target driver will always see +sense in the sense buffer and isn't required to request the sense +manually. + +It is possible, that <bf/SCST_TSC_FLAG_DATA/ is set, but +<bf/SCST_TSC_FLAG_STATUS/ is not set. In this case the driver should +only transmit the data, but not finish the command and transmit the +status. Function <bf/xmit_response()/ will be called again either to +transmit the status or data once more. + +After the response is completely sent, the target should call +<bf/scst_tgt_cmd_done()/ function in order to allow SCST to free the +command. + +Function <bf/xmit_response()/ returns one of the <bf/SCST_TGT_RES_*/ +constants, described above. Pay attention to "atomic" attribute of the +cmd, which can be get via <bf/scst_cmd_atomic()/: it is true if the +function called in the atomic (non-sleeping) context. + +<sect1>Target driver registration functions + +<sect2>scst_register_target_template() + +<p> +Function <bf/scst_register_target_template()/ is defined as the following: + +<verb> +int scst_register_target_template( + struct scst_tgt_template *vtt) +</verb> + +Where: + +<itemize> +<item><bf/vtt/ - pointer to the target driver template +</itemize> + +Returns 0 on success or appropriate error code otherwise. + +<sect2>scst_register() + +<p> +Function <bf/scst_register()/ is defined as the following: + +<verb> +struct scst_tgt *scst_register( + struct scst_tgt_template *vtt) +</verb> + +Where: + +<itemize> +<item><bf/vtt/ - pointer to the target driver template +</itemize> + +Returns target structure based on template vtt or NULL in case of error. + +<sect>Target driver unregistration + +<p> +In order to unregister itself target driver should at first call +<bf/scst_unregister()/ for all its adapters and then call +<bf/scst_unregister_target_template()/ for its template. + +<sect1>scst_unregister() + +<p> +Function <bf/scst_unregister()/ is defined as the following: + +<verb> +void scst_unregister( + struct scst_tgt *tgt) +</verb> + +Where: + +<itemize> +<item><bf/tgt/ - pointer to the target driver structure +</itemize> + +<sect1>scst_unregister_target_template() + +<p> +Function <bf/scst_unregister_target_template()/ is defined as the following: + +<verb> +void scst_unregister_target_template( + struct scst_tgt_template *vtt) +</verb> + +Where: + +<itemize> +<item><bf/vtt/ - pointer to the target driver template +</itemize> + +<sect>SCST session registration + +<p> +When target driver determines that it needs to create new SCST session +(for example, by receiving new TCP connection), it should call +<bf/scst_register_session()/, that is defined as the following: + +<verb> +struct scst_session *scst_register_session( + struct scst_tgt *tgt, + int atomic, + const char *initiator_name, + void *data, + void (*result_fn) ( + struct scst_session *sess, + void *data, + int result)); +</verb> + +Where: + +<itemize> + +<item><bf/tgt/ - target + +<item><bf/atomic/ - true, if the function called in the atomic context + +<item><bf/initiator_name/ - remote initiator's name, any NULL-terminated +string, e.g. iSCSI name, which used as the key to found appropriate +access control group. Could be NULL, then "default" group is used. The +groups are set up via /proc interface. + +<item><bf/data/ - data that will be used as the second +parameter for <bf/bf/result_fn/()/ function + +<item><bf/result_fn/ - pointer to the function that will be +asynchronously called when session initialization finishes. Can be NULL. +Parameters: + + <itemize> + + <item><bf/sess/ - session + + <item><bf/data/ - target driver supplied to + <bf/scst_register_session()/ data + + <item><bf/result/ - session initialization result, 0 on success or + appropriate error code otherwise + + </itemize> + +</itemize> + +A session creation and initialization is a complex task, which requires +sleeping state, so it can't be fully done in interrupt context. +Therefore the "bottom half" of it, if <bf/scst_register_session()/ is +called from atomic context, will be done in SCST thread context. In this +case <bf/scst_register_session()/ will return not completely initialized +session, but the target driver can supply commands to this session via +<bf/scst_rx_cmd()/. Those commands processing will be delayed inside +SCST until the session initialization is finished, then their processing +will be restarted. The target driver will be notified about finish of +the session initialization by function <bf/result_fn()/. On success the +target driver could do nothing, but if the initialization fails, the +target driver must ensure that no more new commands being sent or will +be sent to SCST after <bf/result_fn()/ returns. All already sent to SCST +commands for failed session will be returned in <bf/xmit_response()/ +with BUSY status. In case of failure the driver shall call +<bf/scst_unregister_session()/ inside <bf/result_fn()/, it will NOT be +called automatically. Thus, <bf/scst_register_session()/ can be called +even on IRQ context. + +Session registration is illustrated on Figure 2 and Figure 3. + +<figure> +<eps file="fig2.png"> +<img src="fig2.png"> +<caption> + <newline> Session registration when <bf/atomic/ parameter is false +</caption> +</figure> + +<figure> +<eps file="fig3.png"> +<img src="fig3.png"> +<caption> + <newline> Session registration when <bf/atomic/ parameter is true +</caption> +</figure> + +<sect>SCST session unregistration + +<p> +SCST session unregistration basically is the same, except that instead of +atomic parameter there is <bf/wait/ one. + +<verb> +void scst_unregister_session( + struct scst_session *sess, + int wait, + void (* unreg_done_fn)( + struct scst_session *sess)) +</verb> + +Where: + +<itemize> + +<item><bf/sess/ - session to be unregistered + +<item><bf/wait/ - if true, instructs to wait until all commands, which +currently executing and belonged to the session, finished. Otherwise, +target driver should be prepared to receive <bf/xmit_response()/ for +the session after <bf/scst_unregister_session()/ returns. + +<item><bf/unreg_done_fn/ - pointer to the function that will be +asynchronously called when the last session's command finishes and the +session is about to be completely freed. Can be NULL. Parameter: + + <itemize> + + <item><bf/sess/ - session + + </itemize> + +</itemize> + +All outstanding commands will be finished regularly. After +<bf/scst_unregister_session()/ returned no new commands must be sent to +SCST via <bf/scst_rx_cmd()/. Also, the caller must ensure that no +<bf/scst_rx_cmd()/ or <bf/scst_rx_mgmt_fn_*()/ is called in paralell +with <bf/scst_unregister_session()/. + +Function <bf/scst_unregister_session()/ can be called before +<bf/result_fn()/ of <bf/scst_register_session()/ called, i.e. during the +session registration/initialization. + +<sect>The commands processing and interaction between SCST and its drivers + +<p> +The commands processing by SCST started when target driver calls +<bf/scst_rx_cmd()/. This function returns SCST's command. Then the target +driver finishes the command's initialization, if necessary, for +example, storing necessary target driver specific data there, and calls +<bf/scst_cmd_init_done()/ telling SCST that it can start the processing. +Then SCST translates the command's LUN to local device, determines the +command's data direction and required data buffer size by calling +appropriate device handler's <bf/parse()/ function. Then: + +<itemize> + +<item>If the command required no data transfer, it will be passed to +SCSI mid-level directly or via device handler's <bf/exec()/ call. + +<item>If the command is <bf/READ/ command (data to the target), +necessary space will be allocated and then the command will be passed +to SCSI mid-level directly or via device handler's <bf/exec()/ call. + +<item>If the command is <bf/WRITE/ command (data from the target), +necessary space will be allocated, then the target's <bf/rdy_to_xfer()/ +function will be called, telling the target that the space is ready and +it can start data transferring. When all the data are read from the +target, it will call <bf/scst_rx_data()/, and the command will be passed +to SCSI mid-level directly or via device handler's <bf/exec()/ call. + +</itemize> + +When the command is finished by SCSI mid-level, device handler's +<bf/dev_done()/ is called to notify it about the command's +completion. Then in order to send the response the target's +<bf/xmit_response()/ is called. When the response, including data, if +any, is transmitted, the target will call <bf/scst_tgt_cmd_done()/ +telling SCST that it can free the command and its data buffer. + +Then during the command's deallocation device handler's and the target's +<bf/on_free_cmd()/ will be called in this order, if set. + +This sequence is illustrated on Figure 4. To simplify the picture, sign +"..." means SCST's waiting state for the corresponding command to +complete. During this state SCST and its drivers continue processing of +other commands, if there are any. One way arrow, for example to +<bf/xmit_response()/, means that after this function returns, nothing +valuable for the current command will be done and SCST goes sleeping or +to the next command processing until corresponding event happens. + +<figure> +<eps file="fig4.png"> +<img src="fig4.png"> +<caption> + <newline> The commands processing flow +</caption> +</figure> + +Additionally, before calling <bf/scst_cmd_init_done()/ the target driver can +set the following the command's flags or parameters: + +<itemize> + +<item> <bf/DATA_BUF_ALLOCED/ - set if the data buffer is already +allocated. The flag is set via <bf/scst_cmd_set_data_buff_alloced()/ and +get via <bf/scst_cmd_get_data_buff_alloced()/. Useful, for instance, for +iSCSI unsolicited data. + +<item> Expected transfer length and direction via +<bf/scst_cmd_set_expected()/ as supplied by remote initiator, if any. +This values will be used only if the command's opcode is unknown for +SCST, for example for vendor-specific commands. If these values not set +and opcode isn't known, the command will be completed by SCST in +preprocessing phase with <bf/INVALID OPCODE/ sense. + +</itemize> + +<sect1>The commands processing functions + +<sect2>scst_rx_cmd() + +<p> +Function <bf/scst_rx_cmd()/ creates and sends new command to SCST. Returns +the command on success or NULL otherwise. It is defined as the +following: + +<verb> +struct scst_cmd *scst_rx_cmd( + struct scst_session *sess, + const uint8_t *lun, + int lun_len, + const uint8_t *cdb, + int cdb_len, + int atomic) +</verb> + +Where: + +<itemize> + +<item><bf/sess/ - SCST's session + +<item><bf/lun/ - pointer to device's LUN as specified in SCSI +Architecture Model 2/3 without any byte order translation. Extended +addressing method is not supported. + +<item><bf/lun_len/ - LUN's length + +<item><bf/cdb/ - SCSI CDB + +<item><bf/cdb_len/ - CDB's length + +<item><bf/atomic/ - if true, the command will be allocated with +GFP_ATOMIC flag, otherwise GFP_KERNEL will be used + +</itemize> + +<sect2>scst_cmd_init_done() + +<p> +Function <bf/scst_cmd_init_done()/ notifies SCST that the driver finished +its part of the command initialization, and the command is ready for +execution. It is defined as the following: + +<verb> +void scst_cmd_init_done( + struct scst_cmd *cmd, + int pref_context) +</verb> + +Where: + +<itemize> + +<item><bf/cmd/ - the command + +<item><bf/pref_context/ - preferred command execution context. See +<bf/SCST_CONTEXT_*/ constants below for details. + +</itemize> + +<sect2>scst_rx_data() + +<p> +Function <bf/scst_rx_data()/ notifies SCST that the driver received all +the necessary data and the command is ready for further processing. It +is defined as the following: + +<verb> +void scst_rx_data( + struct scst_cmd *cmd, + int status, + int pref_context) +</verb> + +Where: + +<itemize> + +<item><bf/cmd/ - the command + +<item><bf/status/ - completion status, see below. + +<item><bf/pref_context/ - preferred command execution context. See +<bf/SCST_CONTEXT_*/ constants below for details. + +</itemize> + +Parameter <bf/status/ can have one of the following values: + +<itemize> + +<item><bf/SCST_RX_STATUS_SUCCESS/ - success + +<item><bf/SCST_RX_STATUS_ERROR/ - data receiving finished with error, so +SCST should set the sense and finish the command by calling +<bf/xmit_response()/ + +<item><bf/SCST_RX_STATUS_ERROR_SENSE_SET/ - data receiving finished with +error and the sense is set, so SCST should finish the command by calling +<bf/xmit_response()/ + +<item><bf/SCST_RX_STATUS_ERROR_FATAL/ - data receiving finished with +fatal error, so SCST should finish the command, but don't call +<bf/xmit_response()/. In this case the driver must free all associated +with the command data before calling <bf/scst_rx_data()/. + +</itemize> + +<sect2>scst_tgt_cmd_done() + +<p> +Function <bf/scst_tgt_cmd_done()/ notifies SCST that the driver sent the +data and/or response. It must not been called if there are an error and +<bf/xmit_response()/ returned something other, than +<bf/SCST_TGT_RES_SUCCESS/. It is defined as the following: + +<verb> +void scst_tgt_cmd_done( + struct scst_cmd *cmd) +</verb> + +Where: +<itemize> +<item><bf/cmd/ - the command +</itemize> + +<sect1>The commands processing context + +<p> +Execution context often is a major problem in the kernel drivers +development, because many contexts, like IRQ one, greatly limit +available functionality, therefore require additional complex code in +order to pass processing to more simple context. SCST does its best to +undertake most of the context handling. + +On the initialization time SCST creates for internal command processing +as many threads as there are processors in the system or specified by +user via <bf/scst_threads/ module parameter. Similarly, as many tasklets +created as there are processors in the system. + +Each command can be processed in one of four contexts: + +<enum> +<item>Directly, i.e. in the caller's context, without limitations +<item>Directly atomically, i.e. with sleeping forbidden +<item>In the SCST's internal per processor or per session thread +<item>In the SCST's per processor tasklet +</enum> + +The target driver sets this context as pref_context parameter for +<bf/scst_cmd_init_done()/ and <bf/scst_rx_data()/. Additionally, target's +template's <bf/xmit_response_atomic/ and <bf/rdy_to_xfer_atomic/ flags +have direct influence on the context. If one of them is false, the +corresponding function will never be called in the atomic context and, +if necessary, the command will be rescheduled to one of the SCST's +threads. + +SCST in some circumstances can change preferred context to less +restrictive one, for example, for large data buffer allocation, if +there is not enough GFP_ATOMIC memory. + +<sect2>Preferred context constants + +<p> +There are the following preferred context constants: + +<itemize> + +<item><bf/SCST_CONTEXT_DIRECT/ - sets direct command processing (i.e. +regular function calls in the current context) sleeping is allowed, no +context restrictions. Supposed to be used when calling from thread +context where no locks are held and the driver's architecture allows +sleeping without performance degradation or anything like that. + +<item><bf/SCST_CONTEXT_DIRECT_ATOMIC/ - sets direct command processing +(i.e. regular function calls in the current context), sleeping is not +allowed. Supposed to be used when calling on thread context where there +are locks held, when calling on softirq context or the driver's +architecture does not allow sleeping without performance degradation or +anything like that. + +<item><bf/SCST_CONTEXT_TASKLET/ - tasklet or thread context required for +the command processing. Supposed to be used when calling from IRQ +context. + +<item><bf/SCST_CONTEXT_THREAD/ - thread context required for the +command processing. Supposed to be used if the driver's architecture +does not allow using any of above. + +</itemize> + +<sect>Task management functions + +<p> +There are the following task management functions supported: + +<itemize> + +<item> <bf/SCST_ABORT_TASK/ - <bf/ABORT_TASK/ task management function, +aborts the specified task (command). Returns completion status via +<bf/task_mgmt_fn_done()/ when the command (task) is actually aborted. + +<item> <bf/SCST_ABORT_TASK_SET/ - <bf/ABORT_TASK_SET/ task management +function, aborts all tasks (commands) on the specified device. Returns +the success via <bf/task_mgmt_fn_done()/ immediately, not waiting for +the commands being actually aborted. + +<item> <bf/SCST_CLEAR_ACA/ - <bf/CLEAR_ACA/ task management function, +currently does nothing. + +<item> <bf/SCST_CLEAR_TASK_SET/ - <bf/CLEAR_TASK_SET/ task management +function, the same as <bf/SCST_ABORT_TASK_SET/. + +<item> <bf/SCST_LUN_RESET/ - <bf/LUN_RESET/ task management function, +implemented via <bf/scsi_reset_provider()/ call for the specified device +with <bf/SCSI_TRY_RESET_DEVICE/ parameter. + +<item> <bf/SCST_TARGET_RESET/ - <bf/TARGET_RESET/ task management +function, implemented via <bf/scsi_reset_provider()/ call for all the +hosts in the system (one device per each host) with +<bf/SCSI_TRY_RESET_BUS/ parameter at first and then, if failed, with +<bf/SCSI_TRY_RESET_HOST/. + +</itemize> + +<sect1>scst_rx_mgmt_fn_tag() + +<p> +Function <bf/scst_rx_mgmt_fn_tag()/ tells SCST to perform the specified +task management function, based on the command's tag. Can be used only +for <bf/SCST_ABORT_TASK/. + +It is defined as the following: + +<verb> +int scst_rx_mgmt_fn_tag( + struct scst_session *sess, + int fn, + uint32_t tag, + int atomic, + void *tgt_specific) +</verb> + +Where: + +<itemize> + +<item> <bf/sess/ - the session, on which the command should be performed. + +<item> <bf/fn/ - task management function, one of the constants above. + +<item> <bf/tag/ - the command's tag. + +<item> <bf/atomic/ - true, if the function called in the atomic context. + +<item> <bf/tgt_specific/ - pointer to the target driver specific data, +can be retrieved in <bf/task_mgmt_fn_done()/ via +<bf/scst_mgmt_cmd_get_status()/ function. + +</itemize> + +Returns 0 if the command was successfully created and scheduled for +execution, error code otherwise. On success, the completion status of +the command will be reported asynchronously via <bf/task_mgmt_fn_done()/ +driver's callback. + +<sect1>scst_rx_mgmt_fn_lun() + +<p> +Function <bf/scst_rx_mgmt_fn_lun()/ tells SCST to perform the specified +task management function, based on the LUN. Currently it can be used for +any function, except <bf/SCST_ABORT_TASK/. + +It is defined as the following: + +<verb> +int scst_rx_mgmt_fn_lun( + struct scst_session *sess, + int fn, + const uint8_t *lun, + int lun_len, + int atomic, + void *tgt_specific); +</verb> + +Where: + +<itemize> + +<item> <bf/sess/ - the session, on which the command should be performed. + +<item> <bf/fn/ - task management function, one of the constants above. + +<item> <bf/lun/ - LUN, the format is the same as for <bf/scst_rx_cmd()/. + +<item> <bf/lun_len/ - LUN's length. + +<item> <bf/atomic/ - true, if the function called in the atomic context. + +<item> <bf/tgt_specific/ - pointer to the target driver specific data, +can be retrieved in <bf/task_mgmt_fn_done()/ via +<bf/scst_mgmt_cmd_get_status()/ function. + +</itemize> + +Returns 0 if the command was successfully created and scheduled for +execution, error code otherwise. On success, the completion status of +the command will be reported asynchronously via <bf/task_mgmt_fn_done()/ +driver's callback. + +<sect>Device specific drivers (device handlers) + +<p> +Device specific drivers are plugins for SCST, which help SCST to analyze +incoming requests and determine parameters, specific to various types +of devices. Device handlers are intended for the following: + +<itemize> + +<item>To get data transfer length and direction directly from CDB and +current device's configuration exactly as an end-target SCSI device +does. This serves two purposes: + + <itemize> + + <item> Improves security and reliability by not trusting the data + supplied by remote initiator via SCSI low-level protocol. + + <item> Some low-level SCSI protocols don't provide data transfer + length and direction, so that information can be get only + directly from CDB and current device's configuration. For + example, for tape devices to get data transfer size it might be + necessary to know block size setting. + + </itemize> + +<item>To process some exceptional conditions, like ILI on tape devices. + +<item>To initialize incoming commands with some device-specific +parameters, like timeout value. + +<item>To allow some additional device-specific commands pre-, post- +processing or alternative execution, like copying data from system +cache, and do that completely independently from target drivers. + +</itemize> + +Device handlers performs very lightweight processing and therefore +should not considerably affect performance or CPU load. They are +considered to be part of SCST, so they could directly access any fields +in SCST's structures as well as use the corresponding functions. + +Without appropriate device handler SCST hides devices of this type from +remote initiators and returns <bf/HARDWARE ERROR/ sense data to any +requests to them. + +<sect1>Device specific driver registration + +<sect2>scst_register_dev_driver() + +<p> +To work with SCST a device specific driver must register itself in SCST by +calling <bf/scst_register_dev_driver()/. It is defined as the following: + +<verb> +int scst_register_dev_driver( + struct scst_dev_type *dev_type) +</verb> + +Where: + +<itemize> +<item><bf/dev_type/ - device specific driver's description structure +</itemize> + +The function returns 0 on success or appropriate error code otherwise. + +<sect2>Structure <bf/scst_dev_type/ + +<p> +Structure <bf/scst_dev_type/ is defined as the following: + +<verb> +struct scst_dev_type +{ + char name[15]; + int type; + + unsigned parse_atomic:1; + unsigned exec_atomic:1; + unsigned dev_done_atomic:1; + + int (*init) (struct scst_dev_type *dev_type); + void (*release) (struct scst_dev_type *dev_type); + + int (*attach) (struct scst_device *dev); + void (*detach) (struct scst_device *dev); + + int (*attach_tgt) (struct scst_tgt_device *tgt_dev); + void (*detach_tgt) (struct scst_tgt_device *tgt_dev); + + int (*parse) (struct scst_cmd *cmd); + int (*exec) (struct scst_cmd *cmd, + void (*scst_cmd_done)(struct scsi_cmnd *cmd, int next_state)); + int (*dev_done) (struct scst_cmd *cmd); + int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, + struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd_to_abort); + int (*on_free_cmd) (struct scst_cmd *cmd); + + int (*proc_info) (char *buffer, char **start, off_t offset, + int length, int *eof, struct scst_dev_type *dev_type, + int inout) + + struct module *module; +} +</verb> + +Where: + +<itemize> + +<item><bf/name/ - the name of the device handler. Must be defined and +unique + +<item><bf/type/ - SCSI type of the supported device. Must be defined. + +<item><bf/parse_atomic/, <bf/exec_atomic/, <bf/dev_done_atomic/ - true, +if corresponding function supports execution in the atomic +(non-sleeping) context + +<item><bf/int (*init) (struct scst_dev_type *dev_type)/ - called on the +device handler load, before the first attach(). Returns 0 on success, +error code otherwise. + +<item><bf/void (*release) (struct scst_dev_type *dev_type)/ - called on +the device handler unload, after final detach() + +<item><bf/int (*attach) (struct scst_device *dev)/ - called when new +device is attaching to the device handler + +<item><bf/void (*detach) (struct scst_device *dev)/ - called when new +device is detaching from the device handler + +<item><bf/int (*attach_tgt) (struct scst_tgt_device *tgt_dev)/ - called +when new tgt_device (session) is attaching to the device handler + +<item><bf/void (*detach_tgt) (struct scst_tgt_device *tgt_dev)/ - called +when tgt_device (session) is detaching from the device handler + +<item><bf/int (*parse) (struct scst_cmd *cmd, const struct scst_info_cdb +*cdb_info)/ - called to parse CDB from the command. It should initialize +<bf/cmd->bufflen/ and <bf/cmd->data_direction/ (see below +<bf/SCST_DATA_*/ constants) if necessary, otherwise defaults based on +<bf/cdb_info/ will be used. Parameter <bf/cdb_info/ provides some info +about the CDB (see below). Pay attention to "atomic" attribute of the +cmd, which can be via by <bf/scst_cmd_atomic()/: it is true if the +function called in the atomic (non-sleeping) context. Returns the +command's next state or <bf/SCST_CMD_STATE_DEFAULT/, if the next default +state should be used, or <bf/SCST_CMD_STATE_NEED_THREAD_CTX/ if the +function called in atomic context, but requires sleeping. In the last +case, the function will be recalled in the thread context, where +sleeping is allowed. Additionally, <bf/SCST_CMD_DATA_BUF_ALLOCED/ flag +can be set by <bf/parse()/ (see above). Must be defined. + +<item><bf/int (*exec) (struct scst_cmd *cmd, void (*scst_cmd_done)( struct +scst_cmd *cmd, int next_state))/ - called to execute CDB. The result of +the CDB execution is reported via <bf/scst_cmd_done()/ callback. Pay +attention to "atomic" attribute of the command, which can be get via +<bf/scst_cmd_atomic()/: it is true if the function called in the +atomic (non-sleeping) context. For <bf/scst_cmd_done()/ parameter +<bf/next_state/ is the command's next state or +<bf/SCST_CMD_STATE_DEFAULT/, if the next default state should be used. +Using this function modules <bf/devdisk_perf/ and <bf/devtape_perf/ were +implemented. These modules in their <bf/exec()/ method skip (pretend to +execute) all READ and WRITE operations and thus allow direct link +performance measurements without overhead of actual data transferring +from/to underlying SCSI device. See also <bf/scst_is_cmd_local()/ below. +Returns: + + <itemize> + + <item><bf/SCST_EXEC_COMPLETED/ - the command is done, go to + other ones + + <item><bf/SCST_EXEC_NEED_THREAD/ - thread context is required to + execute the command. <bf/Exec()/ will be called again in the + thread context. + + <item><bf/SCST_EXEC_NOT_COMPLETED/ - the command should be sent + to SCSI mid-level. + + </itemize> + +<item><bf/int (*dev_done) (struct scst_cmd *cmd)/ - called to notify +device handler about the result of the command's execution and perform +some post processing. If <bf/parse()/ function is called, +<bf/dev_done()/ is guaranteed to be called as well. The command's fields +<bf/tgt_resp_flags/ and <bf/resp_data_len/ should be set by this +function, but SCST offers good defaults. Pay attention to "atomic" +attribute of the command, which can be get via +<bf/scst_cmd_atomic()/: it is true if the function called in the +atomic (non-sleeping) context. Returns the command's next state or +<bf/SCST_CMD_STATE_DEFAULT/, if the next default state should be used, +or <bf/SCST_CMD_STATE_NEED_THREAD_CTX/ if the function called in atomic +context, but requires sleeping. In the last case, the function will be +recalled in the thread context, where sleeping is allowed. + +<item><bf/int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, struct +scst_tgt_dev *tgt_dev, struct scst_cmd *cmd_to_abort)/ - called to +execute a task management command. Returns: + + <itemize> + + <item><bf/SCST_DEV_TM_COMPLETED_SUCCESS/ - the command is done + with success, no firther actions required + + <item><bf/SCST_DEV_TM_COMPLETED_FAILED/ - the command is failed, + no firther actions required + + <item><bf/SCST_DEV_TM_NOT_COMPLETED/ - regular standard actions + for the command should be done + + </itemize> + +<bf/NOTE/: for <bf/SCST_ABORT_TASK/ called under spinlock + +<item><bf/void (*on_free_cmd) (struct scst_cmd *cmd)/ - called to notify +device handler that the command is about to be freed. Could be called on +IRQ context. + +<item><bf/int (*proc_info) (char *buffer, char **start, off_t offset, +int length, int *eof, struct scst_dev_type *dev_type, int inout)/ - this +function can be used to export the handler's statistics and other +information to the world outside the kernel. Parameters: + + <enum> + + <item> <bf/buffer, start, offset, length, eof/ - have the same + meaning as for <bf/read_proc_t/ function of the kernel + + <item> <bf/dev_type/ - pointer to the device handler, for which + the function is called + + <item> <bf/inout/ - read/write direction flag, 0 - for reads, other + value - for writes + + </enum> + +If the driver needs to create additional files in its /proc +subdirectory, it can use <bf/scst_proc_get_dev_type_root()/ function to get +the root proc_dir_entry. + +<item><bf/struct module *module/ - pointer to device handler's module + +</itemize> + +Structure <bf/scst_info_cdb/ is defined as the following: + +<verb> +struct scst_info_cdb +{ + enum scst_cdb_flags flags; + scst_data_direction direction; + unsigned int transfer_len; + unsigned short cdb_len; + const char *op_name; +} +</verb> + +Where: + +<itemize> + +<item><bf/flags/ - CDB's flags can be (OR'ed): + + <itemize> + + <item><bf/SCST_TRANSFER_LEN_TYPE_FIXED/ - set if data length in + CDB set in blocks + + <item><bf/SCST_SMALL_TIMEOUT/ - set if CDB requires small timeout + + <item><bf/SCST_LONG_TIMEOUT/ - set if CDB requires long timeout + + </itemize> + +<item><bf/direction/ - one of the <bf/SCST_DATA_*/ constants (see below) + +<item><bf/transfer_len/ - CDB's data length as set in CDB + +<item><bf/cdb_len/ - CDB's length + +<item><bf/op_name/ - the name of the command + +</itemize> + +Field <bf/cmd->data_direction/, set by <bf/parse()/, can have one of the +following values: + +<itemize> + +<item><bf/SCST_DATA_UNKNOWN/ - data flow direction is unknown + +<item><bf/SCST_DATA_WRITE/ - data flow direction is <bf/WRITE/ (from +target to initiator) + +<item><bf/SCST_DATA_READ/ - data flow direction is <bf/READ/ (from +initiator to target) + +<item><bf/SCST_DATA_NONE/ - there is no data transfer + +</itemize> + +<sect1>Device specific driver unregistration + +<p> +Device specific driver is unregistered by calling +<bf/scst_unregister_dev_driver()/. It is defined as the following: + +<verb> +void scst_unregister_dev_driver( + struct scst_dev_type *dev_type) +</verb> + +Where: + +<itemize> +<item><bf/dev_type/ - device specific driver's description structure +</itemize> + +<sect>SCST commands' states + +<p> +There are the following states, which a SCST command passes through +during execution and which could be returned by device handler's +<bf/parse()/ and <bf/dev_done()/ (but not all states are allowed to be +returned): + +<itemize> + +<item><bf/SCST_CMD_STATE_INIT_WAIT/ - the command is created, but +<bf/scst_cmd_init_done()/ not called + +<item><bf/SCST_CMD_STATE_INIT/ - LUN translation (i.e. <bf/cmd->tgt_dev/ +assignment) state + +<item><bf/SCST_CMD_STATE_REINIT/ - again LUN translation, used if device +handler wants to restart the command on another LUN + +<item><bf/SCST_CMD_STATE_DEV_PARSE/ - device handler's <bf/parse()/ is going +to be called + +<item><bf/SCST_CMD_STATE_PREPARE_SPACE/ - allocation of the command's +data buffer + +<item><bf/SCST_CMD_STATE_RDY_TO_XFER/ - target driver's +<bf/rdy_to_xfer()/ is going to be called + +<item><bf/SCST_CMD_STATE_DATA_WAIT/ - waiting for data from the initiator +(until <bf/scst_rx_data()/ called) + +<item><bf/SCST_CMD_STATE_SEND_TO_MIDLEV/ - the command is going to be +sent to SCSI mid-level for execution + +<item><bf/SCST_CMD_STATE_EXECUTING/ - waiting for the command's execution +finish + +<item><bf/SCST_CMD_STATE_DEV_DONE/ - device handler's <bf/dev_done()/ is +going to be called + +<item><bf/SCST_CMD_STATE_XMIT_RESP/ - target driver's +<bf/xmit_response()/ is going to be called + +<item><bf/SCST_CMD_STATE_XMIT_WAIT/ - waiting for data/response's +transmission finish (until <bf/scst_tgt_cmd_done()/ called) + +<item><bf/SCST_CMD_STATE_FINISHED/ - the command finished and going to be +freed + +</itemize> + +<sect>SCST's structures manipulation functions + +<p> +Target drivers must not directly access any fields in SCST's structures, +they must use only described below functions. + +<sect1>SCST target driver manipulation functions + +<sect2>scst_tgt_get_tgt_specific() and scst_tgt_set_tgt_specific() + +<p> +Function <bf/scst_tgt_get_tgt_specific()/ returns pointer to the target +driver specific data, set by <bf/scst_tgt_set_tgt_specific()/. It is +defined as the following: + +<verb> +void *scst_tgt_get_tgt_specific( + struct scst_tgt *tgt) +</verb> + +Function <bf/scst_tgt_set_tgt_specific()/ stores the target driver +specific data that could be retrieved later by +by<bf/scst_tgt_get_tgt_specific()/. It is defined as the following: + +<verb> +void scst_tgt_set_tgt_specific( + struct scst_tgt *tgt, + void *val) +</verb> + +Where: + +<itemize> +<item><bf/tgt/ - pointer to the SCST target structure +<item><bf/val/ - pointer to the target driver specific data +</itemize> + +<sect1>SCST session manipulation functions + +<sect2>scst_sess_get_tgt_specific() and scst_sess_set_tgt_specific() + +<p> +Function <bf/scst_sess_get_tgt_specific()/ returns pointer to the target +driver specific data, set by <bf/scst_sess_set_tgt_specific()/. It is +defined as the following: + +<verb> +void *scst_sess_get_tgt_specific( + struct scst_session *sess) +</verb> + +Function <bf/scst_sess_set_tgt_specific()/ stores the target driver +specific data that could be retrieved later by +by<bf/scst_sess_get_tgt_specific()/. It is defined as the following: + +<verb> +void scst_sess_set_tgt_specific( + struct scst_session *sess, + void *val) +</verb> + +Where: + +<itemize> +<item><bf/sess/ - pointer to the SCST session structure +<item><bf/val/ - pointer to the target driver specific data +</itemize> + +<sect1>SCST command manipulation functions + +<sect2>scst_cmd_atomic() + +<p> +Function <bf/scst_cmd_atomic()/ returns true if the command is +being executed in the atomic context or false otherwise. It is defined +as the following: + +<verb> +int scst_cmd_atomic( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command to check +</itemize> + +<sect2>scst_cmd_get_session() + +<p> +Function <bf/scst_cmd_get_session()/ returns the command's session. It +is defined as the following: + +<verb> +struct scst_session *scst_cmd_get_session( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_resp_data_len() + +<p> +Function <bf/scst_cmd_get_resp_data_len()/ returns the command's +response data length. It is defined as the following: + +<verb> +unsigned int scst_cmd_get_resp_data_len( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_tgt_resp_flags() + +<p> +Function <bf/scst_cmd_get_tgt_resp_flags()/ returns the command's +response data response flags (SCST_TSC_FLAG_* constants). It is defined +as the following: + +<verb> +int scst_cmd_get_tgt_resp_flags( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_buffer() + +<p> +Function <bf/scst_cmd_get_buffer()/ returns the command's data buffer. +It is defined as the following: + +<verb> +void *scst_cmd_get_buffer( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +It is recommended to use <bf/scst_get_buf_*()/scst_put_buf()/ family of +function instead of direct access to the data buffers, because they hide +all HIGHMEM and SG/plain buffer issues. + +<sect2>scst_cmd_get_bufflen() + +<p> +Function <bf/scst_cmd_get_bufflen()/ returns the command's data buffer +length. It is defined as the following: + +<verb> +unsigned int scst_cmd_get_bufflen( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +It is recommended to use <bf/scst_get_buf_*()/scst_put_buf()/ family of +function instead of direct access to the data buffers, because they hide +all HIGHMEM and SG/plain buffer issues. + +<sect2>scst_cmd_get_use_sg() + +<p> +Function <bf/scst_cmd_get_use_sg()/ returns the command's <bf/use_sg/ +value. Its meaning is the same as for <bf/scsi_cmnd/. The function is +defined as the following: + +<verb> +unsigned short scst_cmd_get_use_sg( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +It is recommended to use <bf/scst_get_buf_*()/scst_put_buf()/ family of +function instead of direct access to the data buffers, because they hide +all HIGHMEM and SG/plain buffer issues. + +<sect2>scst_cmd_get_data_direction() + +<p> +Function <bf/scst_cmd_get_data_direction()/ returns the command's data +direction (SCST_DATA_* constants). It is defined as the following: + +<verb> +scst_data_direction scst_cmd_get_data_direction( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_status() + +<p> +Functions <bf/scst_cmd_get_status()/ returns the status byte from +host device. It is defined as the following: + +<verb> +uint8_t scst_cmd_get_status( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_masked_status() + +<p> +Functions <bf/scst_cmd_get_masked_status()/ returns the status byte set +from host device by status_byte(). It is defined as the following: + +<verb> +uint8_t scst_cmd_get_masked_status( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_msg_status() + +<p> +Functions <bf/scst_cmd_get_msg_status()/ returns the status from host +adapter itself. It is defined as the following: + +<verb> +uint8_t scst_cmd_get_msg_status( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_host_status() + +<p> +Functions <bf/scst_cmd_get_host_status()/ returns the status set by +low-level driver to indicate its status. It is defined as the following: + +<verb> +uint16_t scst_cmd_get_host_status( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_driver_status() + +<p> +Functions <bf/scst_cmd_get_driver_status()/ returns the status set by +SCSI mid-level. It is defined as the following: + +<verb> +uint16_t scst_cmd_get_driver_status( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_sense_buffer() + +<p> +Functions <bf/scst_cmd_get_sense_buffer()/ returns pointer to the sense +buffer. It is defined as the following: + +<verb> +uint8_t *scst_cmd_get_sense_buffer( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_sense_buffer_len() + +<p> +Functions <bf/scst_cmd_get_sense_buffer_len()/ returns the sense buffer +length. It is defined as the following: + +<verb> +int scst_cmd_get_sense_buffer_len( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_get_tag() and scst_cmd_set_tag() + +<p> Function <bf/scst_cmd_get_tag()/ returns the command's tag, set by +<bf/scst_cmd_set_tag()/. It is defined as the following: + +<verb> +uint32_t scst_cmd_get_tag( + struct scst_cmd *cmd) +</verb> + +Function <bf/scst_cmd_set_tag()/ sets command's tag that could be +retrieved later by <bf/scst_cmd_get_tag()/. It is defined as the +following: + +<verb> +void scst_cmd_set_tag( + struct scst_cmd *cmd, + uint32_t tag) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +<item><bf/tag/ - the tag +</itemize> + +<sect2>scst_cmd_get_tgt_specific() and scst_cmd_get_tgt_specific_lock() + +<p> +Functions <bf/scst_cmd_get_tgt_specific()/ and +<bf/scst_cmd_get_tgt_specific_lock()/ return pointer to the target +driver specific data, set by <bf/scst_cmd_set_tgt_specific()/ or +<bf/scst_cmd_set_tgt_specific_lock()/. Both function are basically the +same, but the later one additionally takes lock, which helps to prevent +some races. See <bf/scst_find_cmd()/ below for details. + +They are defined as the following: + +<verb> +void *scst_cmd_get_tgt_specific( + struct scst_cmd *cmd) +</verb> + +<verb> +void *scst_cmd_get_tgt_specific_lock( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_set_tgt_specific() and scst_cmd_set_tgt_specific_lock() + +<p> +Functions <bf/scst_cmd_set_tgt_specific()/ and +<bf/scst_cmd_set_tgt_specific_lock()/ store the target driver specific +data, that could be retrieved later by <bf/scst_cmd_get_tgt_specific()/ +or <bf/scst_cmd_get_tgt_specific_lock()/. Both function are basically +the same, but the later one additionally takes lock, which helps to +prevent some races. See <bf/scst_find_cmd()/ below for details. + +They are defined as the following: + +<verb> +void *scst_cmd_set_tgt_specific( + struct scst_cmd *cmd, + void *val) +</verb> + +<verb> +void *scst_cmd_set_tgt_specific_lock( + struct scst_cmd *cmd, + void *val) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +<item><bf/val/ - pointer to the target driver specific data +</itemize> + +<sect2>scst_cmd_get_data_buff_alloced() and scst_cmd_set_data_buff_alloced() + +<p> +Function <bf/scst_cmd_get_data_buff_alloced()/ returns the state of the +<bf/SCST_CMD_DATA_BUF_ALLOCED/ flag. It is defined as the following: + +<verb> +int scst_cmd_get_data_buff_alloced( + struct scst_cmd *cmd) +</verb> + +Function <bf/scst_cmd_set_data_buff_alloced()/ tells SCST that the data +buffer is alloced by target driver or device handler by setting the +<bf/SCST_CMD_DATA_BUF_ALLOCED/ flag on. Could be useful, for instance, +for iSCSI unsolicited data. It is defined as the following: + +<verb> +void scst_cmd_set_data_buff_alloced( + struct scst_cmd *cmd) +</verb> + +Where: + +<itemize> +<item><bf/cmd/ - pointer to the command +</itemize> + +<sect2>scst_cmd_set_expected(), scst_cmd_is_expected_set(), +scst_cmd_get_expected_data_direction() and +scst_cmd_get_expected_transfer_len() + +<p> +Function <bf/scst_cmd_set_expected()/ tells SCST expected data transfer +direction and its length, as supplied by remote initiator. It is defined +as the following: + +<verb> +void scst_cmd_set_expected( + struct scst_cmd *cmd, + scst_data_direction expected_data_direction, + unsigned int expected_transfer_len) +</verb> + +Function <bf/scst_cmd_is_expected_set()/ returns true, if the expected +values were set by target driver and false ot... [truncated message content] |
From: <vl...@us...> - 2006-10-12 13:49:00
|
Revision: 1 http://svn.sourceforge.net/scst/?rev=1&view=rev Author: vlnb Date: 2006-10-12 06:47:28 -0700 (Thu, 12 Oct 2006) Log Message: ----------- Initial commit Added Paths: ----------- branches/ tags/ trunk/ trunk/Makefile trunk/qla2x00t/ trunk/qla2x00t/Kconfig trunk/qla2x00t/Makefile trunk/qla2x00t/ql2100.c trunk/qla2x00t/ql2100_fw.c trunk/qla2x00t/ql2200.c trunk/qla2x00t/ql2200_fw.c trunk/qla2x00t/ql2300.c trunk/qla2x00t/ql2300_fw.c trunk/qla2x00t/ql2322.c trunk/qla2x00t/ql2322_fw.c trunk/qla2x00t/ql2400.c trunk/qla2x00t/ql2400_fw.c trunk/qla2x00t/qla2x00-target/ trunk/qla2x00t/qla2x00-target/ChangeLog trunk/qla2x00t/qla2x00-target/Makefile trunk/qla2x00t/qla2x00-target/README trunk/qla2x00t/qla2x00-target/ToDo trunk/qla2x00t/qla2x00-target/qla2x00t.c trunk/qla2x00t/qla2x00-target/qla2x00t.h trunk/qla2x00t/qla2x_tgt.h trunk/qla2x00t/qla2x_tgt_def.h trunk/qla2x00t/qla_attr.c trunk/qla2x00t/qla_dbg.c trunk/qla2x00t/qla_dbg.h trunk/qla2x00t/qla_def.h trunk/qla2x00t/qla_devtbl.h trunk/qla2x00t/qla_fw.h trunk/qla2x00t/qla_gbl.h trunk/qla2x00t/qla_gs.c trunk/qla2x00t/qla_init.c trunk/qla2x00t/qla_inline.h trunk/qla2x00t/qla_iocb.c trunk/qla2x00t/qla_isr.c trunk/qla2x00t/qla_mbx.c trunk/qla2x00t/qla_os.c trunk/qla2x00t/qla_rscn.c trunk/qla2x00t/qla_settings.h trunk/qla2x00t/qla_sup.c trunk/qla2x00t/qla_version.h trunk/scst/ trunk/scst/COPYING trunk/scst/ChangeLog trunk/scst/Makefile trunk/scst/README trunk/scst/ToDo trunk/scst/include/ trunk/scst/include/scsi_tgt.h trunk/scst/include/scst_debug.c trunk/scst/include/scst_debug.h trunk/scst/kernel/ trunk/scst/kernel/26_scst-2.6.14-.patch trunk/scst/kernel/26_scst-2.6.15+.patch trunk/scst/kernel/26_scst-2.6.16.patch trunk/scst/kernel/in-tree/ trunk/scst/kernel/in-tree/Kconfig.scsi.Linux-2.6.7.patch trunk/scst/kernel/in-tree/Kconfig.scsi_tgt trunk/scst/kernel/in-tree/Makefile.scsi.Linux-2.6.7.patch trunk/scst/kernel/in-tree/Makefile.scsi_tgt trunk/scst/src/ trunk/scst/src/Makefile trunk/scst/src/dev_handlers/ 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_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.c trunk/scst/src/scst_cdbprobe.h 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: trunk/Makefile =================================================================== --- trunk/Makefile (rev 0) +++ trunk/Makefile 2006-10-12 13:47:28 UTC (rev 1) @@ -0,0 +1,102 @@ +# +# Common makefile for SCSI target mid-level and its drivers +# +# Copyright (C) 2006 Vladislav Bolkhovitin <vs...@vl...> +# +# 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. +# +# + +# Decide to use which kernel src. If not specified, is current running kernel. +#export KDIR=/usr/src/linux-2.6 + +SCST_DIR=scst +QLA_INI_DIR=qla2x00t +QLA_DIR=qla2x00t/qla2x00-target + +all: + cd $(SCST_DIR) && $(MAKE) $@ + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + +install: + cd $(SCST_DIR) && $(MAKE) $@ + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + +uninstall: + cd $(SCST_DIR) && $(MAKE) $@ + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + +clean: + cd $(SCST_DIR) && $(MAKE) $@ + @if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + +extraclean: + cd $(SCST_DIR) && $(MAKE) $@ + @if [ -d $(QLA_INI_DIR) ]; then cd $(QLA_INI_DIR) && $(MAKE) $@; fi + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + +scst: + cd $(SCST_DIR) && $(MAKE) + +scst_install: + cd $(SCST_DIR) && $(MAKE) install + +scst_uninstall: + cd $(SCST_DIR) && $(MAKE) uninstall + +scst_clean: + cd $(SCST_DIR) && $(MAKE) clean + +scst_extraclean: + cd $(SCST_DIR) && $(MAKE) extraclean + +qla: + cd $(QLA_DIR) && $(MAKE) + +qla_install: + cd $(QLA_DIR) && $(MAKE) install + +qla_uninstall: + cd $(QLA_DIR) && $(MAKE) uninstall + +qla_clean: + cd $(QLA_INI_DIR) && $(MAKE) clean + cd $(QLA_DIR) && $(MAKE) clean + +qla_extraclean: + cd $(QLA_INI_DIR)/.. && $(MAKE) extraclean + cd $(QLA_DIR) && $(MAKE) extraclean + +help: + @echo " all (the default) : make all" + @echo " clean : clean files" + @echo " extraclean : clean + clean dependencies" + @echo " install : install" + @echo " uninstall : uninstall" + @echo "" + @echo " scst : make scst only" + @echo " scst_clean : scst: clean " + @echo " scst_extraclean : scst: clean + clean dependencies" + @echo " scst_install : scst: install" + @echo " scst_uninstall : scst: uninstall" + @echo "" + @echo " qla : make new qla target using 2.6.x kernel qla2xxx" + @echo " qla_clean : 2.6 qla target: clean " + @echo " qla_extraclean : 2.6 qla target: clean + clean dependencies" + @echo " qla_install : 2.6 qla target: install" + @echo " qla_uninstall : 2.6 qla target: uninstall" + @echo " Notes :" + @echo " - install and uninstall must be made as root" + +.PHONY: all install uninstall clean extraclean help \ + qla qla_install qla_uninstall qla_clean qla_extraclean \ + scst scst_install scst_uninstall scst_clean scst_extraclean Added: trunk/qla2x00t/Kconfig =================================================================== --- trunk/qla2x00t/Kconfig (rev 0) +++ trunk/qla2x00t/Kconfig 2006-10-12 13:47:28 UTC (rev 1) @@ -0,0 +1,82 @@ +config SCSI_QLA_FC + tristate "QLogic QLA2XXX Fibre Channel Support" + depends on PCI && SCSI + select SCSI_FC_ATTRS + select FW_LOADER + ---help--- + This qla2xxx driver supports all QLogic Fibre Channel + PCI and PCIe host adapters. + + By default, firmware for the ISP parts will be loaded + via the Firmware Loader interface. + + ISP Firmware Filename + ---------- ----------------- + 21xx ql2100_fw.bin + 22xx ql2200_fw.bin + 2300, 2312, 6312 ql2300_fw.bin + 2322, 6322 ql2322_fw.bin + 24xx ql2400_fw.bin + + Upon request, the driver caches the firmware image until + the driver is unloaded. + + Firmware images can be retrieved from: + + ftp://ftp.qlogic.com/outgoing/linux/firmware/ + + NOTE: The original method of building firmware-loader + modules has been deprecated as the firmware-images will + be removed from the kernel sources. + +config SCSI_QLA2XXX_TARGET + bool "QLogic 2xxx target mode support" + depends on SCSI_QLA_FC + default y + ---help--- + This option enables target mode hooks used by the SCST QLA2x00tgt driver. + Once the qla2x00tgt module is loaded, target mode can be enable via a + sysfs interface under scsi_host, thus enabling target mode for specific + cards. + You will also need the SCST middle level drivers from http://scst.sf.net/. + +config SCSI_QLA2XXX_EMBEDDED_FIRMWARE + bool " Use firmware-loader modules (DEPRECATED)" + depends on SCSI_QLA_FC + help + This option offers you the deprecated firmware-loader + modules that have been obsoleted by the usage of the + Firmware Loader interface in the qla2xxx driver. + +config SCSI_QLA21XX + tristate " Build QLogic ISP2100 firmware-module" + depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE + ---help--- + This driver supports the QLogic 21xx (ISP2100) host adapter family. + +config SCSI_QLA22XX + tristate " Build QLogic ISP2200 firmware-module" + depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE + ---help--- + This driver supports the QLogic 22xx (ISP2200) host adapter family. + +config SCSI_QLA2300 + tristate " Build QLogic ISP2300/ISP6312 firmware-module" + depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE + ---help--- + This driver supports the QLogic 2300 (ISP2300, ISP2312 and + ISP6312) host adapter family. + +config SCSI_QLA2322 + tristate " Build QLogic ISP2322/ISP6322 firmware-module" + depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE + ---help--- + This driver supports the QLogic 2322 (ISP2322 and ISP6322) host + adapter family. + +config SCSI_QLA24XX + tristate " Build QLogic ISP24xx firmware-module" + depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE + ---help--- + This driver supports the QLogic 24xx (ISP2422 and ISP2432) host + adapter family. Added: trunk/qla2x00t/Makefile =================================================================== --- trunk/qla2x00t/Makefile (rev 0) +++ trunk/qla2x00t/Makefile 2006-10-12 13:47:28 UTC (rev 1) @@ -0,0 +1,48 @@ +ifneq ($(KERNELRELEASE),) +EXTRA_CFLAGS += -DUNIQUE_FW_NAME + +qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ + qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o + +obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o + +qla2100-y := ql2100.o ql2100_fw.o +qla2200-y := ql2200.o ql2200_fw.o +qla2300-y := ql2300.o ql2300_fw.o +qla2322-y := ql2322.o ql2322_fw.o +qla2400-y := ql2400.o ql2400_fw.o + +obj-$(CONFIG_SCSI_QLA21XX) += qla2xxx.o qla2100.o +obj-$(CONFIG_SCSI_QLA22XX) += qla2xxx.o qla2200.o +obj-$(CONFIG_SCSI_QLA2300) += qla2xxx.o qla2300.o +obj-$(CONFIG_SCSI_QLA2322) += qla2xxx.o qla2322.o +obj-$(CONFIG_SCSI_QLA24XX) += qla2xxx.o qla2400.o + +else +ifeq ($(KVER),) + ifeq ($(KDIR),) + KDIR := /lib/modules/$(shell uname -r)/build + endif +else + KDIR := /lib/modules/$(KVER)/build +endif + +all: + $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) + +install: all + $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + modules_install + +uninstall: + rm -f $(INSTALL_DIR)/qla2[2-3]00.ko $(INSTALL_DIR)/qla2xxx.ko + -/sbin/depmod -a +endif + +clean: + rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend *~ Modules.symvers + rm -rf .tmp_versions + +extraclean: clean + +.PHONY: all install uninstall clean extraclean Added: trunk/qla2x00t/ql2100.c =================================================================== --- trunk/qla2x00t/ql2100.c (rev 0) +++ trunk/qla2x00t/ql2100.c 2006-10-12 13:47:28 UTC (rev 1) @@ -0,0 +1,91 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (C) 2003 Christoph Hellwig. + * Copyright (c) 2003-2005 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include "qla_def.h" + +static char qla_driver_name[] = "qla2100"; + +extern unsigned char fw2100tp_version[]; +extern unsigned char fw2100tp_version_str[]; +extern unsigned short fw2100tp_addr01; +extern unsigned short fw2100tp_code01[]; +extern unsigned short fw2100tp_length01; + +static struct qla_fw_info qla_fw_tbl[] = { + { + .addressing = FW_INFO_ADDR_NORMAL, + .fwcode = &fw2100tp_code01[0], + .fwlen = &fw2100tp_length01, + .fwstart = &fw2100tp_addr01, + }, + + { FW_INFO_ADDR_NOMORE, }, +}; + +static struct qla_board_info qla_board_tbl = { + .drv_name = qla_driver_name, + + .isp_name = "ISP2100", + .fw_info = qla_fw_tbl, +}; + +static struct pci_device_id qla2100_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2100, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl, + }, + + {0, 0}, +}; +MODULE_DEVICE_TABLE(pci, qla2100_pci_tbl); + +static int __devinit +qla2100_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return qla2x00_probe_one(pdev, + (struct qla_board_info *)id->driver_data); +} + +static void __devexit +qla2100_remove_one(struct pci_dev *pdev) +{ + qla2x00_remove_one(pdev); +} + +static struct pci_driver qla2100_pci_driver = { + .name = "qla2100", + .id_table = qla2100_pci_tbl, + .probe = qla2100_probe_one, + .remove = __devexit_p(qla2100_remove_one), +}; + +static int __init +qla2100_init(void) +{ + return pci_module_init(&qla2100_pci_driver); +} + +static void __exit +qla2100_exit(void) +{ + pci_unregister_driver(&qla2100_pci_driver); +} + +module_init(qla2100_init); +module_exit(qla2100_exit); + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(QLA2XXX_VERSION); Added: trunk/qla2x00t/ql2100_fw.c =================================================================== --- trunk/qla2x00t/ql2100_fw.c (rev 0) +++ trunk/qla2x00t/ql2100_fw.c 2006-10-12 13:47:28 UTC (rev 1) @@ -0,0 +1,4848 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2005 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ + +/* + * Firmware Version 1.19.25 (13:12 Dec 10, 2003) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_version = 1*1024+19; +#else +unsigned short risc_code_version = 1*1024+19; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw2100tp_version_str[] = {1,19,25}; +#else +unsigned char firmware_version[] = {1,19,25}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw2100tp_VERSION_STRING "1.19.25" +#else +#define FW_VERSION_STRING "1.19.25" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw2100tp_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0078, 0x102d, 0x0000, 0x9601, 0x0000, 0x0001, 0x0013, 0x0019, + 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030, + 0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1, + 0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff, + 0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04, + 0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c, + 0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020, + 0x2039, 0x8fff, 0x20a1, 0xae00, 0x2708, 0x810d, 0x810d, 0x810d, + 0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8, + 0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102, + 0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1, + 0xa601, 0x2009, 0x0000, 0x20a9, 0x07ff, 0x41a4, 0x3400, 0x20c9, + 0xabff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x25c7, + 0x2051, 0xa700, 0x2a70, 0x7762, 0xa786, 0x8fff, 0x0040, 0x1092, + 0x705f, 0xce00, 0x705b, 0xcdf1, 0x7067, 0x0200, 0x706b, 0x0200, + 0x0078, 0x109a, 0x705b, 0xbe01, 0x7067, 0x0100, 0x706b, 0x0100, + 0x705f, 0xbe00, 0x1078, 0x12df, 0x1078, 0x13ca, 0x1078, 0x1577, + 0x1078, 0x1ce9, 0x1078, 0x42ec, 0x1078, 0x76bf, 0x1078, 0x1355, + 0x1078, 0x2ac0, 0x1078, 0x4e93, 0x1078, 0x49a3, 0x1078, 0x594a, + 0x1078, 0x2263, 0x1078, 0x5c43, 0x1078, 0x5485, 0x1078, 0x2162, + 0x1078, 0x2240, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf, + 0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068, + 0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, + 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, + 0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x365e, 0x1078, 0x2ae8, + 0x1078, 0x4ee3, 0x1078, 0x4b66, 0x2009, 0x0100, 0x2104, 0xa082, + 0x0002, 0x0048, 0x10f3, 0x1078, 0x5966, 0x0078, 0x10d6, 0x1079, + 0x10f7, 0x0078, 0x10dc, 0x1078, 0x7197, 0x0078, 0x10eb, 0x1101, + 0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078, + 0x1332, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086, + 0x0001, 0x00c0, 0x1198, 0x1078, 0x3aec, 0x2079, 0x0100, 0x7844, + 0xa005, 0x00c0, 0x1198, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x1078, + 0x1adf, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, + 0x8010, 0x73c4, 0x1078, 0x361b, 0x2001, 0xffff, 0x1078, 0x5ae6, + 0x723c, 0xc284, 0x723e, 0x2001, 0xa70c, 0x2014, 0xc2ac, 0x2202, + 0x1078, 0x6f9f, 0x2011, 0x0004, 0x1078, 0x8d2b, 0x1078, 0x489e, + 0x1078, 0x42d4, 0x0040, 0x1144, 0x7087, 0x0001, 0x70bf, 0x0000, + 0x1078, 0x3c9e, 0x0078, 0x1198, 0x1078, 0x4967, 0x0040, 0x114d, + 0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x90b6, 0x70cc, + 0xd09c, 0x00c0, 0x1159, 0x7098, 0xa005, 0x0040, 0x1159, 0x1078, + 0x42b8, 0x70d7, 0x0000, 0x70d3, 0x0000, 0x72cc, 0x2079, 0xa752, + 0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ce, 0xa296, 0x0004, + 0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8d2b, 0x7093, 0x0000, + 0x7097, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x2677, 0x2011, + 0x0005, 0x1078, 0x70e0, 0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100, + 0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x7093, 0x0000, + 0x7097, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x70e0, + 0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, + 0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e, + 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078, + 0x73d0, 0x027f, 0x1078, 0xa501, 0x037f, 0x027f, 0x017f, 0x1078, + 0x298e, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706f, 0x0000, 0x7070, + 0xa084, 0x00ff, 0x7072, 0x709b, 0x0000, 0x007c, 0x127e, 0x2091, + 0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7094, 0xa086, + 0xffff, 0x0040, 0x11d1, 0x1078, 0x2677, 0x1078, 0x62d1, 0x0078, + 0x1244, 0x70cc, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd, + 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, + 0x0040, 0x11fd, 0x70d0, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078, + 0x27f7, 0x1078, 0x62d1, 0x70cc, 0xd094, 0x00c0, 0x1244, 0x2011, + 0x0001, 0x2019, 0x0000, 0x1078, 0x282f, 0x1078, 0x62d1, 0x0078, + 0x1244, 0x70d4, 0xa005, 0x00c0, 0x1244, 0x7090, 0xa005, 0x00c0, + 0x1244, 0x1078, 0x4967, 0x00c0, 0x1244, 0x2001, 0xa753, 0x2004, + 0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x017e, 0x1078, 0x45c4, 0x00c0, 0x121a, 0x6000, 0xd0ec, + 0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f, + 0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003, + 0x0003, 0x7097, 0xffff, 0x2001, 0x0000, 0x1078, 0x24e8, 0x1078, + 0x3699, 0x2001, 0xa9b2, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c, + 0x2011, 0x0000, 0x1078, 0x70e0, 0x2011, 0x0000, 0x1078, 0x70ea, + 0x1078, 0x62d1, 0x1078, 0x639b, 0x127f, 0x007c, 0x017e, 0x0f7e, + 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078, + 0x42a1, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040, + 0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008, + 0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5ae6, 0x7900, 0xa18a, + 0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009, + 0x00f8, 0x1078, 0x42a1, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, + 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0, + 0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x24e8, 0x0078, + 0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0, + 0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f, + 0x0000, 0x2009, 0x00f8, 0x1078, 0x42a1, 0x20a9, 0x000e, 0x0005, + 0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, + 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4, + 0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009, + 0xa732, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4, + 0x200b, 0x0000, 0x1078, 0x2588, 0x2001, 0x0001, 0x1078, 0x24e8, + 0x0078, 0x12d3, 0x2001, 0xa732, 0x2003, 0x0000, 0x7828, 0xc09d, + 0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, + 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, + 0x2061, 0xa9ad, 0x2063, 0x0001, 0x6007, 0x0013, 0x600b, 0x0019, + 0x600f, 0x0017, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, + 0x12f5, 0x7053, 0xffff, 0x0078, 0x12f7, 0x7053, 0x0000, 0x7057, + 0xffff, 0x706f, 0x0000, 0x7073, 0x0000, 0x1078, 0x90b6, 0x2061, + 0xa98d, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, + 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, + 0x07d0, 0x2061, 0xa995, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, + 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, + 0x0001, 0x601f, 0x0000, 0x2061, 0xa9a5, 0x6003, 0x514c, 0x6007, + 0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0xa726, 0x2003, + 0x0000, 0x007c, 0x2091, 0x8000, 0x0068, 0x1334, 0x007e, 0x017e, + 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x133a, 0x017f, 0x792e, + 0x007f, 0x782a, 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, + 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa700, + 0x7803, 0x0005, 0x0078, 0x1352, 0x007c, 0x2071, 0xa700, 0x715c, + 0x712e, 0x2021, 0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048, + 0x136b, 0x7060, 0xa302, 0x00c8, 0x136b, 0x220a, 0x2208, 0x2310, + 0x8420, 0x0078, 0x135d, 0x200b, 0x0000, 0x74aa, 0x74ae, 0x007c, + 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa700, 0x70ac, 0xa0ea, + 0x0010, 0x00c8, 0x137e, 0xa06e, 0x0078, 0x1388, 0x8001, 0x70ae, + 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, + 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa700, 0x127e, 0x2091, + 0x8000, 0x70ac, 0x8001, 0x00c8, 0x1398, 0xa06e, 0x0078, 0x13a1, + 0x70ae, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, + 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa700, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, + 0x70ae, 0x127f, 0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13c0, 0x6804, + 0x6807, 0x0000, 0x007e, 0x1078, 0x13a4, 0x0d7f, 0x0078, 0x13b4, + 0x007c, 0x0e7e, 0x2071, 0xa700, 0x70ac, 0xa08a, 0x0010, 0xa00d, + 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa9d6, 0x7007, 0x0000, 0x701b, + 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, + 0x7012, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x0e7e, 0x2270, + 0x700b, 0x0000, 0x2071, 0xa9d6, 0x7018, 0xa088, 0xa9df, 0x220a, + 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, 0x13f6, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x127f, + 0x007c, 0x0e7e, 0x2071, 0xa9d6, 0x7004, 0xa005, 0x00c0, 0x1406, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x007c, + 0x7000, 0x0079, 0x140b, 0x140f, 0x1479, 0x1496, 0x1496, 0x7018, + 0x711c, 0xa106, 0x00c0, 0x1417, 0x7007, 0x0000, 0x007c, 0x0d7e, + 0xa180, 0xa9df, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, + 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, + 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, + 0x0d7f, 0xd084, 0x0040, 0x1439, 0x7007, 0x0001, 0x1078, 0x143e, + 0x007c, 0x7007, 0x0002, 0x1078, 0x1454, 0x007c, 0x017e, 0x027e, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1449, 0x2110, + 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, + 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, 0x137e, 0x147e, + 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, + 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1468, 0x2110, 0xa006, + 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, + 0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, + 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa7fa, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, + 0xa7f5, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e, + 0x157e, 0x2001, 0xa829, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, + 0x2001, 0xa82a, 0x20ac, 0x53a6, 0x2099, 0xa82b, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000, + 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, + 0xa826, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e, + 0x2071, 0xa9d6, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, + 0xd1fc, 0x0040, 0x14d0, 0xa18c, 0x0700, 0x7004, 0x1079, 0x14d4, + 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x1408, 0x14dc, 0x1509, 0x1531, + 0x1564, 0x14da, 0x0078, 0x14da, 0xa18c, 0x0700, 0x00c0, 0x1502, + 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, + 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f, + 0x137f, 0x700c, 0xa005, 0x0040, 0x151e, 0x1078, 0x143e, 0x007c, + 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, + 0x1408, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, + 0x14fd, 0xa18c, 0x0700, 0x00c0, 0x1514, 0x700c, 0xa005, 0x0040, + 0x151e, 0x1078, 0x1454, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0200, 0x7007, 0x0000, 0x1078, 0x1408, 0x007c, 0x0d7e, 0x7008, + 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x1408, + 0x007c, 0xa18c, 0x0700, 0x00c0, 0x155e, 0x137e, 0x147e, 0x157e, + 0x2001, 0xa7f8, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, + 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, 0xa7fa, 0x2004, + 0xd0bc, 0x0040, 0x1554, 0x2001, 0xa803, 0x2004, 0xa080, 0x000d, + 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f, 0x137f, 0x7007, + 0x0000, 0x1078, 0x4f8c, 0x1078, 0x1408, 0x007c, 0x2011, 0x8003, + 0x1078, 0x361b, 0x0078, 0x1562, 0xa18c, 0x0700, 0x00c0, 0x1571, + 0x2001, 0xa828, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x1408, + 0x007c, 0x2011, 0x8004, 0x1078, 0x361b, 0x0078, 0x1575, 0x127e, + 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa9e7, 0x7803, 0x0004, + 0x7003, 0x0000, 0x700f, 0xa9ed, 0x7013, 0xa9ed, 0x780f, 0x0076, + 0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079, + 0x1591, 0x1599, 0x15df, 0x1599, 0x1599, 0x1599, 0x15c4, 0x15a8, + 0x159d, 0xa085, 0x0001, 0x0078, 0x15f9, 0x684c, 0xd0bc, 0x0040, + 0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x15e7, + 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1599, 0x684c, 0xd0bc, + 0x0040, 0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, + 0x6832, 0x6858, 0x0078, 0x15ef, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x00c0, 0x1599, 0x684c, 0xd0ac, 0x0040, 0x1599, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, + 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x15ef, 0x684c, + 0xd0ac, 0x0040, 0x1599, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, + 0x000f, 0xa188, 0x206a, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, + 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, + 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a, + 0x2004, 0x82ff, 0x0040, 0x161c, 0xa280, 0x0004, 0x0d7e, 0x206c, + 0x684c, 0xd0dc, 0x00c0, 0x1618, 0x1078, 0x158c, 0x0040, 0x1618, + 0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0078, 0x161c, + 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, + 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, + 0x1630, 0x7206, 0x2001, 0x1651, 0x007e, 0x2260, 0x0078, 0x17e0, + 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, + 0xaa08, 0x0048, 0x163d, 0x2009, 0xa9ed, 0x710e, 0x7010, 0xa102, + 0xa082, 0x0009, 0x0040, 0x1648, 0xa080, 0x001b, 0x00c0, 0x164b, + 0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0, 0x1651, 0x1078, + 0x17c1, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, 0x0c7e, 0x007e, + 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, 0x0d7e, 0x0c7e, + 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0040, 0x16dd, + 0x6808, 0xa005, 0x0040, 0x174a, 0x7000, 0xa005, 0x00c0, 0x1672, + 0x0078, 0x16d2, 0x700c, 0x7110, 0xa106, 0x00c0, 0x1753, 0x7004, + 0xa406, 0x00c0, 0x16d2, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, + 0x168f, 0x047e, 0x1078, 0x1913, 0x047f, 0x2460, 0x6010, 0xa080, + 0x0002, 0x2004, 0xa005, 0x0040, 0x174a, 0x0078, 0x166c, 0x2001, + 0x0207, 0x2004, 0xd09c, 0x00c0, 0x167b, 0x7804, 0xa084, 0x6000, + 0x0040, 0x16a0, 0xa086, 0x6000, 0x0040, 0x16a0, 0x0078, 0x167b, + 0x7100, 0xa186, 0x0002, 0x00c0, 0x16c0, 0x0e7e, 0x2b68, 0x6818, + 0x2060, 0x1078, 0x203f, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, + 0x16b5, 0x7108, 0x720c, 0x0078, 0x16b7, 0x7110, 0x7214, 0x6810, + 0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f, 0x0078, 0x16c4, + 0xa186, 0x0001, 0x00c0, 0x16cc, 0x7820, 0x6910, 0xa100, 0x6812, + 0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009, + 0x0048, 0x1078, 0x775c, 0x0078, 0x1753, 0x6808, 0xa005, 0x0040, + 0x174a, 0x7000, 0xa005, 0x00c0, 0x16e7, 0x0078, 0x174a, 0x700c, + 0x7110, 0xa106, 0x00c0, 0x16f0, 0x7004, 0xa406, 0x00c0, 0x174a, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x1704, 0x047e, 0x1078, + 0x1913, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, + 0x0040, 0x174a, 0x0078, 0x16e1, 0x2001, 0x0207, 0x2004, 0xd09c, + 0x00c0, 0x16f0, 0x2001, 0x0005, 0x2004, 0xd08c, 0x00c0, 0x16f6, + 0x7804, 0xa084, 0x6000, 0x0040, 0x171b, 0xa086, 0x6000, 0x0040, + 0x171b, 0x0078, 0x16f0, 0x7007, 0x0000, 0xa016, 0x2218, 0x7000, + 0xa08e, 0x0001, 0x0040, 0x173c, 0xa08e, 0x0002, 0x00c0, 0x174a, + 0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x203f, 0x2804, 0xac70, + 0x6034, 0xd09c, 0x00c0, 0x1738, 0x7308, 0x720c, 0x0078, 0x173a, + 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, 0x7824, 0xa211, + 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, 0x7803, 0x0004, + 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009, + 0x0048, 0x1078, 0x775c, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, + 0x0e7e, 0x027e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa9e7, 0x7000, + 0xa086, 0x0000, 0x0040, 0x17ba, 0x7004, 0xac06, 0x00c0, 0x17ab, + 0x2079, 0x0030, 0x7000, 0xa086, 0x0003, 0x0040, 0x17ab, 0x7804, + 0xd0fc, 0x00c0, 0x17a7, 0x20e1, 0x6000, 0x2011, 0x0032, 0x2001, + 0x0208, 0x200c, 0x2001, 0x0209, 0x2004, 0xa106, 0x00c0, 0x176f, + 0x8211, 0x00c0, 0x1777, 0x7804, 0xd0fc, 0x00c0, 0x17a7, 0x1078, + 0x1b22, 0x027e, 0x057e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x178d, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007, + 0x0000, 0x057f, 0x027f, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, + 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0078, 0x17ab, 0x1078, + 0x1913, 0x0078, 0x175f, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa9ed, + 0x2104, 0xac06, 0x00c0, 0x17b5, 0x200a, 0xa188, 0x0003, 0x00f0, + 0x17b0, 0x157f, 0x057f, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f, + 0x007c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x17c9, 0x7003, 0x0000, + 0x007c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, + 0x8108, 0xa182, 0xaa08, 0x0048, 0x17d7, 0x2009, 0xa9ed, 0x7112, + 0x700c, 0xa106, 0x00c0, 0x17e0, 0x2001, 0x0138, 0x2003, 0x0008, + 0x8cff, 0x00c0, 0x17e7, 0x1078, 0x1b4d, 0x0078, 0x1854, 0x6010, + 0x2068, 0x2d58, 0x6828, 0xa406, 0x00c0, 0x17f2, 0x682c, 0xa306, + 0x0040, 0x182f, 0x601c, 0xa086, 0x0008, 0x0040, 0x182f, 0x6024, + 0xd0f4, 0x00c0, 0x181c, 0xd0d4, 0x0040, 0x1818, 0x6038, 0xa402, + 0x6034, 0xa303, 0x0040, 0x1806, 0x00c8, 0x1818, 0x643a, 0x6336, + 0x6c2a, 0x6b2e, 0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812, + 0x2300, 0x6b80, 0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x181c, + 0x1078, 0x9063, 0x0040, 0x17e3, 0x2001, 0xa774, 0x2004, 0xd0b4, + 0x00c0, 0x182b, 0x6018, 0x2004, 0xd0bc, 0x00c0, 0x182b, 0x6817, + 0x7fff, 0x6813, 0xffff, 0x1078, 0x208a, 0x00c0, 0x17e3, 0x0c7e, + 0x7004, 0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4, + 0x0040, 0x1840, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17e3, + 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, + 0x000f, 0x2009, 0x0011, 0x1078, 0x1855, 0x0040, 0x1853, 0x2009, + 0x0001, 0x1078, 0x1855, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18ec, + 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1877, 0xd0f4, 0x00c0, + 0x1887, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1867, 0x18ce, + 0x188e, 0x188e, 0x18ce, 0x18ce, 0x18c6, 0x18ce, 0x188e, 0x18ce, + 0x1894, 0x1894, 0x18ce, 0x18ce, 0x18ce, 0x18bd, 0x1894, 0xc0fc, + 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040, + 0x18d1, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0xc0f4, + 0x6852, 0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18d8, 0x6b08, 0x6a0c, + 0x6d00, 0x6c04, 0x0078, 0x18d1, 0x7b0c, 0xd3bc, 0x0040, 0x18b5, + 0x7004, 0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0, + 0x18b5, 0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, + 0x82ff, 0x00c0, 0x18b0, 0x6810, 0xa302, 0x0048, 0x18b0, 0x6b10, + 0x2011, 0x0000, 0x2468, 0x0078, 0x18b7, 0x6b10, 0x6a14, 0x6d00, + 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0x0d7f, 0x0d7e, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x18ce, 0x0d7f, 0x1078, + 0x2026, 0x00c0, 0x1855, 0xa00e, 0x0078, 0x18ec, 0x0d7f, 0x1078, + 0x1332, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, + 0x7000, 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, + 0xa201, 0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14, + 0xa203, 0x6816, 0x1078, 0x2026, 0x007c, 0x1078, 0x1332, 0x1078, + 0x1c97, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000, + 0x1078, 0x1af4, 0x1078, 0x8d16, 0x0040, 0x190c, 0x6808, 0x8001, + 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, + 0xffff, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8a11, 0x0078, + 0x1adb, 0x1078, 0x1332, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, + 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, + 0x00c0, 0x18ef, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x1911, + 0x7000, 0x0079, 0x192b, 0x1933, 0x1935, 0x1a34, 0x1ab2, 0x1ac9, + 0x1933, 0x1933, 0x1933, 0x1078, 0x1332, 0x8001, 0x7002, 0xa184, + 0x0880, 0x00c0, 0x194a, 0x8aff, 0x0040, 0x19d4, 0x2009, 0x0001, + 0x1078, 0x1855, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078, 0x1855, + 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0, + 0x19b2, 0x027e, 0x037e, 0x017e, 0x7808, 0xd0ec, 0x00c0, 0x1962, + 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004, + 0x0078, 0x1964, 0x1078, 0x1bd7, 0x017f, 0xd194, 0x0040, 0x196b, + 0x8aff, 0x0040, 0x19a1, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, + 0x2500, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060, + 0x6024, 0xd0f4, 0x00c0, 0x197e, 0x633a, 0x6236, 0x0c7f, 0x2400, + 0x6910, 0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f, + 0x027f, 0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x203f, 0x2a00, + 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, + 0x6808, 0x8001, 0x680a, 0x00c0, 0x19a7, 0x684c, 0xd0e4, 0x0040, + 0x19a7, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x7000, + 0xa086, 0x0004, 0x0040, 0x1adb, 0x7003, 0x0000, 0x1078, 0x17c1, + 0x0078, 0x1adb, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x19b9, 0x1078, + 0xa58e, 0x057f, 0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078, + 0x4963, 0x0040, 0x19c6, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, + 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, + 0x6980, 0x6916, 0x0078, 0x1adb, 0x7004, 0x0c7e, 0x2060, 0x6024, + 0x0c7f, 0xd0f4, 0x0040, 0x19e1, 0x6808, 0x8001, 0x680a, 0x0078, + 0x19f5, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19f9, + 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19f5, 0x7004, + 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078, + 0x1adb, 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, + 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, 0x00c8, + 0x18ef, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, + 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x1078, 0x1b5e, + 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc, + 0x0040, 0x1a1e, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x0076, + 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, + 0x1078, 0x1b92, 0x0040, 0x19f5, 0x8001, 0x7002, 0xd194, 0x0040, + 0x1a46, 0x7804, 0xd0fc, 0x00c0, 0x191b, 0x8aff, 0x0040, 0x1adb, + 0x2009, 0x0001, 0x1078, 0x1855, 0x0078, 0x1adb, 0xa184, 0x0880, + 0x00c0, 0x1a53, 0x8aff, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078, + 0x1855, 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, + 0x00c0, 0x1a93, 0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1a66, + 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a68, 0x1078, 0x1bd7, + 0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, + 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a83, 0x6808, 0x2008, 0xa31a, + 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, + 0x7816, 0x0078, 0x1a8f, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, + 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, 0x7816, 0x0f7f, + 0x0d7f, 0x0078, 0x196d, 0x057e, 0x7d0c, 0x1078, 0xa58e, 0x057f, + 0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4963, 0x0040, + 0x1aa4, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff, 0x682f, + 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, + 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, + 0x0040, 0x1ac5, 0x6808, 0x8001, 0x680a, 0x00c0, 0x1ac5, 0x7004, + 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078, + 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, + 0xa005, 0x0040, 0x1ac5, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, + 0x6b2c, 0x1078, 0x17e0, 0x017f, 0x007f, 0x127f, 0x007c, 0x127e, + 0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0, 0x1af2, 0x700c, + 0x7110, 0xa106, 0x0040, 0x1af2, 0x20e1, 0x9028, 0x700f, 0xa9ed, + 0x7013, 0xa9ed, 0x127f, 0x007c, 0x0c7e, 0x1078, 0x1b22, 0x20e1, + 0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1b19, 0x2104, 0xa005, + 0x0040, 0x1b08, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, 0x600a, + 0xa188, 0x0003, 0xa182, 0xaa08, 0x0048, 0x1b10, 0x2009, 0xa9ed, + 0x7112, 0x700c, 0xa106, 0x00c0, 0x1af9, 0x2011, 0x0008, 0x0078, + 0x1af9, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, 0x0138, 0x2202, + 0x0c7f, 0x007c, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, + 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x00c0, 0x1b3f, 0x2001, + 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, 0x1b3f, 0x2001, 0x0111, + 0x201c, 0x83ff, 0x00c0, 0x1b3f, 0x8421, 0x00c0, 0x1b29, 0x007c, + 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, 0x00c0, 0x1b4c, + 0x8109, 0x00c0, 0x1b44, 0x007c, 0x007c, 0x1078, 0x1b40, 0x0040, + 0x1b55, 0x780c, 0xd0a4, 0x0040, 0x1b5b, 0x1078, 0x1af4, 0xa085, + 0x0001, 0x0078, 0x1b5d, 0x1078, 0x1b92, 0x007c, 0x0e7e, 0x2071, + 0x0200, 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1b22, 0x2019, + 0x5000, 0x8319, 0x0040, 0x1b7c, 0x2001, 0xaa08, 0x2004, 0xa086, + 0x0000, 0x0040, 0x1b7c, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b69, + 0x1078, 0x1eaa, 0x0078, 0x1b67, 0x20e1, 0x7000, 0x7324, 0x7420, + 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, + 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, + 0x0e7f, 0x007c, 0x027e, 0x2001, 0x015d, 0x2001, 0x0000, 0x7908, + 0xa18c, 0x0fff, 0xa182, 0x0ffd, 0x0048, 0x1ba0, 0x2009, 0x0000, + 0xa190, 0x0007, 0xa294, 0x1ff8, 0x8214, 0x8214, 0x8214, 0x2001, + 0x020a, 0x82ff, 0x0040, 0x1bb5, 0x20e1, 0x6000, 0x200c, 0x200c, + 0x200c, 0x200c, 0x8211, 0x00c0, 0x1bae, 0x20e1, 0x7000, 0x200c, + 0x200c, 0x7003, 0x0000, 0x20e1, 0x6000, 0x2001, 0x0208, 0x200c, + 0x2001, 0x0209, 0x2004, 0xa106, 0x0040, 0x1bd4, 0x1078, 0x1b40, + 0x0040, 0x1bd2, 0x7908, 0xd1ec, 0x00c0, 0x1bd4, 0x790c, 0xd1a4, + 0x0040, 0x1b97, 0x1078, 0x1af4, 0xa006, 0x027f, 0x007c, 0x7c20, + 0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c69, + 0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c69, 0x0d7e, + 0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c67, 0x681c, 0xa086, + 0x0008, 0x0040, 0x1c67, 0x6824, 0xd0d4, 0x00c0, 0x1c67, 0x6810, + 0x2068, 0x6850, 0xd0fc, 0x0040, 0x1c29, 0x8108, 0x2104, 0x6b2c, + 0xa306, 0x00c0, 0x1c67, 0x8108, 0x2104, 0x6a28, 0xa206, 0x00c0, + 0x1c67, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870, + 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034, + 0xd09c, 0x0040, 0x1c24, 0x6830, 0x2004, 0xac68, 0x6808, 0x783a, + 0x680c, 0x783e, 0x0078, 0x1c65, 0xa006, 0x783a, 0x783e, 0x0078, + 0x1c65, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6b2c, 0xa306, + 0x00c0, 0x1c67, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6a28, + 0xa206, 0x00c0, 0x1c67, 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2004, + 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c, 0x00c0, 0x1c57, + 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, 0x6000, 0x7832, + 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0078, 0x1c65, 0x6010, + 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004, + 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x7803, 0x0011, 0x0c7f, + 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0x027e, 0x2071, 0xa9e7, + 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x0040, + 0x1c92, 0x8211, 0x0040, 0x1c90, 0x2001, 0x0005, 0x2004, 0xd08c, + 0x0040, 0x1c79, 0x7904, 0xa18c, 0x0780, 0x017e, 0x1078, 0x1913, + 0x017f, 0x81ff, 0x00c0, 0x1c90, 0x2011, 0x0050, 0x0078, 0x1c74, + 0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f, 0x0f7f, 0x007c, 0x7803, + 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, 0x0040, 0x1ce8, 0x8109, + 0x00c0, 0x1c9b, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0003, 0x1048, + 0x1332, 0x1078, 0x1fca, 0x0e7e, 0x0f7e, 0x2071, 0xa9d6, 0x2079, + 0x0010, 0x7004, 0xa086, 0x0000, 0x0040, 0x1ce0, 0x7800, 0x007e, + 0x7820, 0x007e, 0x7830, 0x007e, 0x7834, 0x007e, 0x7838, 0x007e, + 0x783c, 0x007e, 0x7803, 0x0004, 0x7823, 0x0000, 0x0005, 0x0005, + 0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x2079, 0x0010, + 0x007f, 0x783e, 0x007f, 0x783a, 0x007f, 0x7836, 0x007f, 0x7832, + 0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f, 0x0e7f, 0x0078, 0x1ce6, + 0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x1078, 0x639b, + 0x007c, 0x0e7e, 0x2071, 0xaa08, 0x7003, 0x0000, 0x0e7f, 0x007c, + 0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1d6b, + 0x6934, 0xa184, 0x0007, 0x0079, 0x1cfd, 0x1d05, 0x1d56, 0x1d05, + 0x1d05, 0x1d05, 0x1d3b, 0x1d18, 0x1d07, 0x1078, 0x1332, 0x684c, + 0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, + 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1d5e, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1d05, 0x684c, + 0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, + 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, + 0x6958, 0x0078, 0x1d67, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, + 0x1d6b, 0x684c, 0xd0b4, 0x0040, 0x1e79, 0x6804, 0x681a, 0xa080, + 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, + 0x6958, 0xa006, 0x682e, 0x682a, 0x0078, 0x1d67, 0x684c, 0xd0b4, + 0x0040, 0x18ed, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, + 0x6834, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, 0x6926, + 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, 0x0f7e, 0x2079, 0x0020, + 0x7804, 0xd0fc, 0x10c0, 0x1eaa, 0x0e7e, 0x0d7e, 0x2071, 0xaa08, + 0x7000, 0xa005, 0x00c0, 0x1df0, 0x0c7e, 0x7206, 0xa280, 0x0004, + 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x0d7e, 0x2068, + 0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, + 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, + 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, + 0x000f, 0x6908, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0007, 0x0040, + 0x1db2, 0xa184, 0x0007, 0x0040, 0x1db2, 0x017e, 0x2009, 0x0008, + 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, + 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, + 0x6814, 0xa106, 0x00c0, 0x1dc9, 0x6928, 0x6810, 0xa106, 0x0040, + 0x1dd6, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, 0x208a, 0x047f, + 0x037f, 0x0040, 0x1dd6, 0x0c7f, 0x0078, 0x1df0, 0x8aff, 0x00c0, + 0x1dde, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x1df0, 0x127e, 0x2091, + 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0040, + 0x1ded, 0x2009, 0x0001, 0x1078, 0x1df4, 0x127f, 0x0c7f, 0xa006, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, + 0x037e, 0x027e, 0x8aff, 0x0040, 0x1e72, 0x700c, 0x7214, 0xa23a, + 0x7010, 0x7218, 0xa203, 0x0048, 0x1e71, 0xa705, 0x0040, 0x1e71, + 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1e24, 0x0d7e, 0x2804, + 0xac68, 0x2900, 0x0079, 0x1e14, 0x1e53, 0x1e34, 0x1e34, 0x1e53, + 0x1e53, 0x1e4b, 0x1e53, 0x1e34, 0x1e53, 0x1e3a, 0x1e3a, 0x1e53, + 0x1e53, 0x1e53, 0x1e42, 0x1e3a, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, + 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e57, 0x0d7e, 0x2804, 0xac68, + 0x6f08, 0x6e0c, 0x0078, 0x1e56, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, + 0x0078, 0x1e56, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, + 0x0078, 0x1e56, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, + 0x001e, 0x00c0, 0x1e53, 0x0d7f, 0x1078, 0x2026, 0x00c0, 0x1dfa, + 0xa00e, 0x0078, 0x1e72, 0x0d7f, 0x1078, 0x1332, 0x0d7f, 0x7b22, + 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, + 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, + 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, 0x1078, 0x2026, 0x0078, + 0x1e72, 0xa006, 0x027f, 0x037f, 0x047f, 0x057f, 0x067f, 0x077f, + 0x007c, 0x1078, 0x1332, 0x027e, 0x2001, 0x0105, 0x2003, 0x0010, + 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d16, 0x0040, 0x1e92, 0x6850, + 0xc0bd, 0x6852, 0x0d7f, 0x0c7e, 0x1078, 0x8a11, 0x0c7f, 0x2001, + 0xa9c0, 0x2004, 0xac06, 0x00c0, 0x1ea7, 0x20e1, 0x9040, 0x1078, + 0x738a, 0x2011, 0x0000, 0x1078, 0x70ea, 0x1078, 0x639b, 0x027f, + 0x0078, 0x1f76, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, + 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0xaa08, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, + 0x1e7b, 0x7000, 0x0079, 0x1ec4, 0x1f76, 0x1ec8, 0x1f43, 0x1f74, + 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1edc, 0x8aff, 0x0040, 0x1efb, + 0x2009, 0x0001, 0x1078, 0x1df4, 0x0040, 0x1f76, 0x2009, 0x0001, + 0x1078, 0x1df4, 0x0078, 0x1f76, 0x7803, 0x0004, 0xd194, 0x0040, + 0x1eec, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1ef1, 0x684c, + 0xc0f5, 0x684e, 0x0078, 0x1ef1, 0x1078, 0x203f, 0x6850, 0xc0fd, + 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, + 0x0000, 0x0078, 0x1f76, 0x711c, 0x81ff, 0x0040, 0x1f11, 0x7918, + 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, + 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, + 0x1f76, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, + 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x037e, + 0x2019, 0x1000, 0x8319, 0x1040, 0x1332, 0x7820, 0xd0bc, 0x00c0, + 0x1f22, 0x037f, 0x79c8, 0x007f, 0xa102, 0x017f, 0x007e, 0x017e, + 0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f, 0x78ca, 0xa284, 0x0004, + 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, 0x7803, 0x0008, 0x7003, + 0x0000, 0x0078, 0x1f76, 0x8001, 0x7002, 0xd194, 0x0040, 0x1f58, + 0x7804, 0xd0fc, 0x00c0, 0x1eba, 0xd19c, 0x00c0, 0x1f72, 0x8aff, + 0x0040, 0x1f76, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0078, 0x1f76, + 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x2804, + 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f6b, 0x6808, 0xa31a, 0x680c, + 0xa213, 0x0078, 0x1f6f, 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f, + 0x0078, 0x1eec, 0x0078, 0x1eec, 0x1078, 0x1332, 0x0c7f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0xaa08, 0x7000, 0xa086, 0x0000, 0x0040, 0x1fc7, 0x2079, + 0x0020, 0x017e, 0x2009, 0x0207, 0x210c, 0xd194, 0x0040, 0x1fa4, + 0x2009, 0x020c, 0x210c, 0xa184, 0x0003, 0x0040, 0x1fa4, 0x1078, + 0xa5e2, 0x2001, 0x0133, 0x2004, 0xa005, 0x1040, 0x1332, 0x20e1, + 0x9040, 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104, 0x2009, + 0x0203, 0x210c, 0xa106, 0x00c0, 0x1faf, 0x20e1, 0x9040, 0x7804, + 0xd0fc, 0x0040, 0x1f8a, 0x1078, 0x1eaa, 0x7000, 0xa086, 0x0000, + 0x00c0, 0x1f8a, 0x017f, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x1fbd, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, + 0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, + 0xaa08, 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0040, 0x2003, + 0x7004, 0x2060, 0x6010, 0x2068, 0x1078, 0x8d16, 0x0040, 0x1fed, + 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, 0xa206, 0x00c0, 0x1fed, + 0x6808, 0x7a18, 0xa206, 0x0040, 0x2009, 0x2001, 0x0105, 0x2003, + 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, + 0x2060, 0x1078, 0x8a11, 0x20e1, 0x9040, 0x1078, 0x738a, 0x2011, + 0x0000, 0x1078, 0x70ea, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x027f, + 0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0, 0x1fed, 0x684c, 0xc0dc, + 0x684e, 0x2c10, 0x1078, 0x1cf0, 0x2001, 0x0105, 0x2003, 0x0010, + 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x2069, 0xa9b1, + 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x2003, 0x8840, 0x2804, + 0xa005, 0x00c0, 0x203a, 0x6004, 0xa005, 0x0040, 0x203c, 0x681a, + 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x206a, 0x2044, 0x88ff, + 0x1040, 0x1332, 0x8a51, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, + 0x8841, 0x2804, 0xa005, 0x00c0, 0x2059, 0x2c00, 0xad06, 0x0040, + 0x204e, 0x6000, 0xa005, 0x00c0, 0x204e, 0x2d00, 0x2060, 0x681a, + 0x6034, 0xa084, 0x000f, 0xa080, 0x207a, 0x2044, 0x88ff, 0x1040, + 0x1332, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021, + 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027, + 0x0000, 0x0000, 0x0000, 0x205f, 0x205b, 0x0000, 0x0000, 0x2069, + 0x0000, 0x205f, 0x0000, 0x2066, 0x2063, 0x0000, 0x0000, 0x0000, + 0x2069, 0x2066, 0x0000, 0x2061, 0x2061, 0x0000, 0x0000, 0x2069, + 0x0000, 0x2061, 0x0000, 0x2067, 0x2067, 0x0000, 0x0000, 0x0000, + 0x2069, 0x2067, 0x0a7e, 0x097e, 0x087e, 0x6b2e, 0x6c2a, 0x6858, + 0xa055, 0x0040, 0x212d, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, + 0x206a, 0xa986, 0x0007, 0x0040, 0x20a5, 0xa986, 0x000e, 0x0040, + 0x20a5, 0xa986, 0x000f, 0x00c0, 0x20a9, 0x605c, 0xa422, 0x6060, + 0xa31b, 0x2804, 0xa045, 0x00c0, 0x20b7, 0x0050, 0x20b1, 0x0078, + 0x212d, 0x6004, 0xa065, 0x0040, 0x212d, 0x0078, 0x2094, 0x2804, + 0xa005, 0x0040, 0x20d5, 0xac68, 0xd99c, 0x00c0, 0x20c5, 0x6808, + 0xa422, 0x680c, 0xa31b, 0x0078, 0x20c9, 0x6810, 0xa422, 0x6814, + 0xa31b, 0x0048, 0x20f4, 0x2300, 0xa405, 0x0040, 0x20db, 0x8a51, + 0x0040, 0x212d, 0x8840, 0x0078, 0x20b7, 0x6004, 0xa065, 0x0040, + 0x212d, 0x0078, 0x2094, 0x8a51, 0x0040, 0x212d, 0x8840, 0x2804, + 0xa005, 0x00c0, 0x20ee, 0x6004, 0xa065, 0x0040, 0x212d, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x206a, 0x2804, 0x2040, 0x2b68, 0x6850, + 0xc0fc, 0x6852, 0x0078, 0x2121, 0x8422, 0x8420, 0x831a, 0xa399, + 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, 0x00c0, + 0x210f, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1048, + 0x1332, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x211b, 0x6910, + 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x1332, 0x6800, + 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd, + 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x007f, + 0x007f, 0x007f, 0xa006, 0x0078, 0x2132, 0x087f, 0x097f, 0x0a7f, + 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, 0xa084, 0x0007, + 0x0079, 0x213a, 0x2142, 0x2143, 0x2146, 0x2149, 0x214e, 0x2151, + 0x2156, 0x215b, 0x007c, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x1913, + 0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x14be, + 0x007c, 0x1078, 0x1eaa, 0x1078, 0x14be, 0x007c, 0x1078, 0x1913, + 0x1078, 0x14be, 0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x1078, + 0x14be, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, 0x0200, 0x2071, + 0xac80, 0x2069, 0xa700, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, + 0x1078, 0x251f, 0x781b, 0x0002, 0x20e1, 0x8700, 0x127f, 0x007c, + 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, 0x0079, 0x2180, + 0x21a4, 0x2188, 0x218c, 0x2190, 0x2196, 0x219a, 0x219e, 0x21a2, + 0x1078, 0x548e, 0x0078, 0x21a4, 0x1078, 0x54da, 0x0078, 0x21a4, + 0x1078, 0x548e, 0x1078, 0x54da, 0x0078, 0x21a4, 0x1078, 0x21a6, + 0x0078, 0x21a4, 0x1078, 0x21a6, 0x0078, 0x21a4, 0x1078, 0x21a6, + 0x0078, 0x21a4, 0x1078, 0x21a6, 0x127f, 0x007c, 0x007e, 0x017e, + 0x027e, 0x1078, 0xa5e2, 0x7930, 0xa184, 0x0003, 0x0040, 0x21c9, + 0x2001, 0xa9c0, 0x2004, 0xa005, 0x0040, 0x21c5, 0x2001, 0x0133, + 0x2004, 0xa005, 0x1040, 0x1332, 0x0c7e, 0x2001, 0xa9c0, 0x2064, + 0x1078, 0x8a11, 0x0c7f, 0x0078, 0x21f2, 0x20e1, 0x9040, 0x0078, + 0x21f2, 0xa184, 0x0030, 0x0040, 0x21da, 0x6a00, 0xa286, 0x0003, + 0x00c0, 0x21d4, 0x0078, 0x21d6, 0x1078, 0x4224, 0x20e1, 0x9010, + 0x0078, 0x21f2, 0xa184, 0x00c0, 0x0040, 0x21ec, 0x0e7e, 0x037e, + 0x047e, 0x057e, 0x2071, 0xa9e7, 0x1078, 0x1af4, 0x057f, 0x047f, + 0x037f, 0x0e7f, 0x0078, 0x21f2, 0xa184, 0x0300, 0x0040, 0x21f2, + 0x20e1, 0x9020, 0x7932, 0x027f, 0x017f, 0x007f, 0x007c, 0x017e, + 0x0e7e, 0x0f7e, 0x2071, 0xa700, 0x7128, 0x2001, 0xa990, 0x2102, + 0x2001, 0xa998, 0x2102, 0xa182, 0x0211, 0x00c8, 0x220b, 0x2009, + 0x0008, 0x0078, 0x2235, 0xa182, 0x0259, 0x00c8, 0x2213, 0x2009, + 0x0007, 0x0078, 0x2235, 0xa182, 0x02c1, 0x00c8, 0x221b, 0x2009, + 0x0006, 0x0078, 0x2235, 0xa182, 0x0349, 0x00c8, 0x2223, 0x2009, + 0x0005, 0x0078, 0x2235, 0xa182, 0x0421, 0x00c8, 0x222b, 0x2009, + 0x0004, 0x0078, 0x2235, 0xa182, 0x0581, 0x00c8, 0x2233, 0x2009, + 0x0003, 0x0078, 0x2235, 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, + 0x7817, 0x0004, 0x1078, 0x251f, 0x0f7f, 0x0e7f, 0x017f, 0x007c, + 0x127e, 0x2091, 0x2200, 0x2061, 0x0100, 0x2071, 0xa700, 0x6024, + 0x6026, 0x6053, 0x0030, 0x6033, 0x00ef, 0x60e7, 0x0000, 0x60eb, + 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, + 0x0080, 0x602f, 0x0000, 0x6007, 0x0eaf, 0x600f, 0x00ff, 0x602b, + 0x002f, 0x127f, 0x007c, 0x2001, 0xa730, 0x2003, 0x0000, 0x2001, + 0xa72f, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x007e, + 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, 0x227b, 0xa184, + 0x0007, 0x0079, 0x2281, 0xa195, 0x0004, 0xa284, 0x0007, 0x0079, + 0x2281, 0x22ad, 0x2289, 0x228d, 0x2291, 0x2297, 0x229b, 0x22a1, + 0x22a7, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078, 0x5d45, 0x0078, + 0x22ad, 0x1078, 0x5d45, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078, + 0x22b2, 0x0078, 0x22ad, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x0078, + 0x22ad, 0x1078, 0x5d45, 0x1078, 0x22b2, 0x0078, 0x22ad, 0x1078, + 0x5d45, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x027f, 0x017f, 0x007f, + 0x127f, 0x007c, 0x6124, 0xd1ac, 0x0040, 0x23ac, 0x017e, 0x047e, + 0x0c7e, 0x644c, 0xa486, 0xf0f0, 0x00c0, 0x22c5, 0x2061, 0x0100, + 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74c6, 0xa48c, 0xff00, + 0x7034, 0xd084, 0x0040, 0x22dd, 0xa186, 0xf800, 0x00c0, 0x22dd, + 0x703c, 0xd084, 0x00c0, 0x22dd, 0xc085, 0x703e, 0x037e, 0x2418, + 0x2011, 0x8016, 0x1078, 0x361b, 0x037f, 0xa196, 0xff00, 0x0040, + 0x231f, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, 0x231f, + 0x7130, 0xd184, 0x00c0, 0x231f, 0x2011, 0xa753, 0x2214, 0xd2ec, + 0x0040, 0x22fa, 0xc18d, 0x7132, 0x2011, 0xa753, 0x2214, 0xd2ac, + 0x00c0, 0x231f, 0x6240, 0xa294, 0x0010, 0x0040, 0x2306, 0x6248, + 0xa294, 0xff00, 0xa296, 0xff00, 0x0040, 0x231f, 0x7030, 0xd08c, + 0x0040, 0x2371, 0x7034, 0xd08c, 0x00c0, 0x2316, 0x2001, 0xa70c, + 0x200c, 0xd1ac, 0x00c0, 0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4, + 0x2011, 0x8013, 0x1078, 0x361b, 0x037f, 0x0078, 0x2371, 0x7034, + 0xd08c, 0x00c0, 0x232b, 0x2001, 0xa70c, 0x200c, 0xd1ac, 0x00c0, + 0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4, 0x2011, 0x8013, 0x1078, + 0x361b, 0x037f, 0x7130, 0xc185, 0x7132, 0x2011, 0xa753, 0x220c, + 0xd1a4, 0x0040, 0x2355, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, + 0x1078, 0x5bf1, 0x2019, 0x000e, 0x1078, 0xa1a5, 0xa484, 0x00ff, + 0xa080, 0x29c0, 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, + 0x2009, 0x000e, 0x1078, 0xa22d, 0x017f, 0xd1ac, 0x00c0, 0x2362, + 0x017e, 0x2009, 0x0000, 0x2019, 0x0004, 0x1078, 0x284f, 0x017f, + 0x0078, 0x2371, 0x157e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x1078, + 0x45c4, 0x00c0, 0x236d, 0x1078, 0x42f8, 0x8108, 0x00f0, 0x2367, + 0x157f, 0x0c7f, 0x047f, 0x0f7e, 0x2079, 0xa9c4, 0x783c, 0xa086, + 0x0000, 0x0040, 0x2383, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, + 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, 0x1078, 0x70e0, + 0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, 0x2019, + 0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, + 0xa700, 0x2014, 0xa296, 0x0004, 0x00c0, 0x23a4, 0xd19c, 0x00c0, + 0x23ac, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa722, + 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, 0x2490, 0x0f7e, + 0x2079, 0xa9c4, 0x783c, 0xa086, 0x0001, 0x00c0, 0x23d0, 0x017e, + 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000, + 0x7803, 0x0000, 0x2079, 0xa9b1, 0x7807, 0x0000, 0x7833, 0x0000, + 0x1078, 0x62d1, 0x1078, 0x639b, 0x017f, 0x0f7f, 0x0078, 0x2490, + 0x0f7f, 0x017e, 0x3900, 0xa082, 0xaae3, 0x00c8, 0x23db, 0x017e, + 0x1078, 0x747a, 0x017f, 0x6220, 0xd2b4, 0x0040, 0x2446, 0x1078, + 0x5acb, 0x1078, 0x6e0f, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa9ba, + 0x2304, 0xa07d, 0x0040, 0x241c, 0x7804, 0xa086, 0x0032, 0x00c0, + 0x241c, 0x0d7e, 0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288, + 0x7818, 0x608e, 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, + 0x8001, 0x00c0, 0x2400, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, + 0x0000, 0x618e, 0x628a, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x7810, + 0x2070, 0x7037, 0x0103, 0x2f60, 0x1078, 0x772d, 0x0e7f, 0x0c7f, + 0x0d7f, 0x0f7f, 0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140, + 0x6804, 0xa084, 0x4000, 0x0040, 0x2429, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa9b1, 0x6028, 0xa09a, 0x00c8, + 0x00c8, 0x2439, 0x8000, 0x602a, 0x0c7f, 0x1078, 0x6e01, 0x0078, + 0x248f, 0x2019, 0xa9ba, 0x2304, 0xa065, 0x0040, 0x2443, 0x2009, + 0x0027, 0x1078, 0x775c, 0x0c7f, 0x0078, 0x248f, 0xd2bc, 0x0040, + 0x248f, 0x1078, 0x5ad8, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, + 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x245b, 0x6803, + 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa9b1, 0x6044, + 0xa09a, 0x00c8, 0x00c8, 0x247e, 0x8000, 0x6046, 0x603c, 0x0c7f, + 0xa005, 0x0040, 0x248f, 0x2009, 0x07d0, 0x1078, 0x5ad0, 0xa080, + 0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, 0x247a, 0x6017, 0x0012, + 0x0078, 0x248f, 0x6017, 0x0016, 0x0078, 0x248f, 0x037e, 0x2019, + 0x0001, 0x1078, 0x7058, 0x037f, 0x2019, 0xa9c0, 0x2304, 0xa065, + 0x0040, 0x248e, 0x2009, 0x004f, 0x1078, 0x775c, 0x0c7f, 0x017f, + 0xd19c, 0x0040, 0x24e4, 0x7034, 0xd0ac, 0x00c0, 0x24c1, 0x017e, + 0x157e, 0x6027, 0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0, + 0x249f, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9, + 0x0320, 0x00e0, 0x24a9, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0, + 0x24b8, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x24e4, + 0x1078, 0x2577, 0x00f0, 0x24a9, 0x157f, 0x6152, 0x017f, 0x6027, + 0x0008, 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, + 0x70e0, 0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, + 0x2019, 0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x1078, + 0xa5bd, 0x1078, 0xa5db, 0x2001, 0xa700, 0x2003, 0x0004, 0x6027, + 0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, + 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, + 0x2071, 0xa700, 0x71bc, 0x70be, 0xa116, 0x0040, 0x2518, 0x81ff, + 0x0040, 0x2500, 0x2011, 0x8011, 0x1078, 0x361b, 0x0078, 0x2518, + 0x2011, 0x8012, 0x1078, 0x361b, 0x2001, 0xa772, 0x2004, 0xd0fc, + 0x00c0, 0x2518, 0x037e, 0x0c7e, 0x1078, 0x6f9f, 0x2061, 0x0100, + 0x2019, 0x0028, 0x2009, 0x0000, 0x1078, 0x284f, 0x0c7f, 0x037f, + 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, + 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x253b, 0x2204, + 0x60f2, 0x2011, 0x2548, 0x6000, 0xa082, 0x0003, 0x00c8, 0x2534, + 0x2001, 0x00ff, 0x0078, 0x2535, 0x2204, 0x60ee, 0x027f, 0x007f, + 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, + 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, + 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, + 0x2130, 0xa094, 0xff00, 0x00c0, 0x2558, 0x81ff, 0x0040, 0x255c, + 0x1078, 0x5761, 0x0078, 0x2563, 0xa080, 0x29c0, 0x200c, 0xa18c, + 0xff00, 0x810f, 0xa006, 0x007c, 0xa080, 0x29c0, 0x200c, 0xa18c, + 0x00ff, 0x007c, 0x0c7e, 0x2061, 0xa700, 0x6030, 0x0040, 0x2573, + 0xc09d, 0x0078, 0x2574, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e, + 0x157e, 0x0f7e, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, + 0x00c0, 0x2584, 0x00f0, 0x257e, 0x0f7f, 0x157f, 0x007f, 0x007c, + 0x0c7e, 0x007e, 0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e, + 0x60e4, 0x007e, 0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e, + 0x60ec, 0x007e, 0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e, + 0x60e0, 0x007e, 0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005, + 0x0005, 0x0005, 0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2, + 0x007f, 0x602a, 0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee, + 0x007f, 0x60f2, 0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6, + 0x007f, 0x604a, 0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x25e7, + 0x25eb, 0x25ef, 0x25f5, 0x25fb, 0x2601, 0x2607, 0x260f, 0x2617, + 0x261d, 0x2623, 0x262b, 0x2633, 0x263b, 0x2643, 0x264d, 0x2657, + 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, + 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x107e, + 0x007e, 0x0078, 0x2670, 0x107e, 0x007e, 0x0078, 0x2670, 0x107e, + 0x007e, 0x1078, 0x226c, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, + 0x226c, 0x0078, 0x2670, 0x107e, 0x007e... [truncated message content] |