18c2ecf20Sopenharmony_ci==================== 28c2ecf20Sopenharmony_ciTCM Userspace Design 38c2ecf20Sopenharmony_ci==================== 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci.. Contents: 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci 1) Design 98c2ecf20Sopenharmony_ci a) Background 108c2ecf20Sopenharmony_ci b) Benefits 118c2ecf20Sopenharmony_ci c) Design constraints 128c2ecf20Sopenharmony_ci d) Implementation overview 138c2ecf20Sopenharmony_ci i. Mailbox 148c2ecf20Sopenharmony_ci ii. Command ring 158c2ecf20Sopenharmony_ci iii. Data Area 168c2ecf20Sopenharmony_ci e) Device discovery 178c2ecf20Sopenharmony_ci f) Device events 188c2ecf20Sopenharmony_ci g) Other contingencies 198c2ecf20Sopenharmony_ci 2) Writing a user pass-through handler 208c2ecf20Sopenharmony_ci a) Discovering and configuring TCMU uio devices 218c2ecf20Sopenharmony_ci b) Waiting for events on the device(s) 228c2ecf20Sopenharmony_ci c) Managing the command ring 238c2ecf20Sopenharmony_ci 3) A final note 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciDesign 278c2ecf20Sopenharmony_ci====== 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciTCM is another name for LIO, an in-kernel iSCSI target (server). 308c2ecf20Sopenharmony_ciExisting TCM targets run in the kernel. TCMU (TCM in Userspace) 318c2ecf20Sopenharmony_ciallows userspace programs to be written which act as iSCSI targets. 328c2ecf20Sopenharmony_ciThis document describes the design. 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciThe existing kernel provides modules for different SCSI transport 358c2ecf20Sopenharmony_ciprotocols. TCM also modularizes the data storage. There are existing 368c2ecf20Sopenharmony_cimodules for file, block device, RAM or using another SCSI device as 378c2ecf20Sopenharmony_cistorage. These are called "backstores" or "storage engines". These 388c2ecf20Sopenharmony_cibuilt-in modules are implemented entirely as kernel code. 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciBackground 418c2ecf20Sopenharmony_ci---------- 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciIn addition to modularizing the transport protocol used for carrying 448c2ecf20Sopenharmony_ciSCSI commands ("fabrics"), the Linux kernel target, LIO, also modularizes 458c2ecf20Sopenharmony_cithe actual data storage as well. These are referred to as "backstores" 468c2ecf20Sopenharmony_cior "storage engines". The target comes with backstores that allow a 478c2ecf20Sopenharmony_cifile, a block device, RAM, or another SCSI device to be used for the 488c2ecf20Sopenharmony_cilocal storage needed for the exported SCSI LUN. Like the rest of LIO, 498c2ecf20Sopenharmony_cithese are implemented entirely as kernel code. 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciThese backstores cover the most common use cases, but not all. One new 528c2ecf20Sopenharmony_ciuse case that other non-kernel target solutions, such as tgt, are able 538c2ecf20Sopenharmony_cito support is using Gluster's GLFS or Ceph's RBD as a backstore. The 548c2ecf20Sopenharmony_citarget then serves as a translator, allowing initiators to store data 558c2ecf20Sopenharmony_ciin these non-traditional networked storage systems, while still only 568c2ecf20Sopenharmony_ciusing standard protocols themselves. 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciIf the target is a userspace process, supporting these is easy. tgt, 598c2ecf20Sopenharmony_cifor example, needs only a small adapter module for each, because the 608c2ecf20Sopenharmony_cimodules just use the available userspace libraries for RBD and GLFS. 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciAdding support for these backstores in LIO is considerably more 638c2ecf20Sopenharmony_cidifficult, because LIO is entirely kernel code. Instead of undertaking 648c2ecf20Sopenharmony_cithe significant work to port the GLFS or RBD APIs and protocols to the 658c2ecf20Sopenharmony_cikernel, another approach is to create a userspace pass-through 668c2ecf20Sopenharmony_cibackstore for LIO, "TCMU". 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciBenefits 708c2ecf20Sopenharmony_ci-------- 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciIn addition to allowing relatively easy support for RBD and GLFS, TCMU 738c2ecf20Sopenharmony_ciwill also allow easier development of new backstores. TCMU combines 748c2ecf20Sopenharmony_ciwith the LIO loopback fabric to become something similar to FUSE 758c2ecf20Sopenharmony_ci(Filesystem in Userspace), but at the SCSI layer instead of the 768c2ecf20Sopenharmony_cifilesystem layer. A SUSE, if you will. 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ciThe disadvantage is there are more distinct components to configure, and 798c2ecf20Sopenharmony_cipotentially to malfunction. This is unavoidable, but hopefully not 808c2ecf20Sopenharmony_cifatal if we're careful to keep things as simple as possible. 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciDesign constraints 838c2ecf20Sopenharmony_ci------------------ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci- Good performance: high throughput, low latency 868c2ecf20Sopenharmony_ci- Cleanly handle if userspace: 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 1) never attaches 898c2ecf20Sopenharmony_ci 2) hangs 908c2ecf20Sopenharmony_ci 3) dies 918c2ecf20Sopenharmony_ci 4) misbehaves 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci- Allow future flexibility in user & kernel implementations 948c2ecf20Sopenharmony_ci- Be reasonably memory-efficient 958c2ecf20Sopenharmony_ci- Simple to configure & run 968c2ecf20Sopenharmony_ci- Simple to write a userspace backend 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciImplementation overview 1008c2ecf20Sopenharmony_ci----------------------- 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciThe core of the TCMU interface is a memory region that is shared 1038c2ecf20Sopenharmony_cibetween kernel and userspace. Within this region is: a control area 1048c2ecf20Sopenharmony_ci(mailbox); a lockless producer/consumer circular buffer for commands 1058c2ecf20Sopenharmony_cito be passed up, and status returned; and an in/out data buffer area. 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciTCMU uses the pre-existing UIO subsystem. UIO allows device driver 1088c2ecf20Sopenharmony_cidevelopment in userspace, and this is conceptually very close to the 1098c2ecf20Sopenharmony_ciTCMU use case, except instead of a physical device, TCMU implements a 1108c2ecf20Sopenharmony_cimemory-mapped layout designed for SCSI commands. Using UIO also 1118c2ecf20Sopenharmony_cibenefits TCMU by handling device introspection (e.g. a way for 1128c2ecf20Sopenharmony_ciuserspace to determine how large the shared region is) and signaling 1138c2ecf20Sopenharmony_cimechanisms in both directions. 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciThere are no embedded pointers in the memory region. Everything is 1168c2ecf20Sopenharmony_ciexpressed as an offset from the region's starting address. This allows 1178c2ecf20Sopenharmony_cithe ring to still work if the user process dies and is restarted with 1188c2ecf20Sopenharmony_cithe region mapped at a different virtual address. 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciSee target_core_user.h for the struct definitions. 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciThe Mailbox 1238c2ecf20Sopenharmony_ci----------- 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciThe mailbox is always at the start of the shared memory region, and 1268c2ecf20Sopenharmony_cicontains a version, details about the starting offset and size of the 1278c2ecf20Sopenharmony_cicommand ring, and head and tail pointers to be used by the kernel and 1288c2ecf20Sopenharmony_ciuserspace (respectively) to put commands on the ring, and indicate 1298c2ecf20Sopenharmony_ciwhen the commands are completed. 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civersion - 1 (userspace should abort if otherwise) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciflags: 1348c2ecf20Sopenharmony_ci - TCMU_MAILBOX_FLAG_CAP_OOOC: 1358c2ecf20Sopenharmony_ci indicates out-of-order completion is supported. 1368c2ecf20Sopenharmony_ci See "The Command Ring" for details. 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cicmdr_off 1398c2ecf20Sopenharmony_ci The offset of the start of the command ring from the start 1408c2ecf20Sopenharmony_ci of the memory region, to account for the mailbox size. 1418c2ecf20Sopenharmony_cicmdr_size 1428c2ecf20Sopenharmony_ci The size of the command ring. This does *not* need to be a 1438c2ecf20Sopenharmony_ci power of two. 1448c2ecf20Sopenharmony_cicmd_head 1458c2ecf20Sopenharmony_ci Modified by the kernel to indicate when a command has been 1468c2ecf20Sopenharmony_ci placed on the ring. 1478c2ecf20Sopenharmony_cicmd_tail 1488c2ecf20Sopenharmony_ci Modified by userspace to indicate when it has completed 1498c2ecf20Sopenharmony_ci processing of a command. 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ciThe Command Ring 1528c2ecf20Sopenharmony_ci---------------- 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciCommands are placed on the ring by the kernel incrementing 1558c2ecf20Sopenharmony_cimailbox.cmd_head by the size of the command, modulo cmdr_size, and 1568c2ecf20Sopenharmony_cithen signaling userspace via uio_event_notify(). Once the command is 1578c2ecf20Sopenharmony_cicompleted, userspace updates mailbox.cmd_tail in the same way and 1588c2ecf20Sopenharmony_cisignals the kernel via a 4-byte write(). When cmd_head equals 1598c2ecf20Sopenharmony_cicmd_tail, the ring is empty -- no commands are currently waiting to be 1608c2ecf20Sopenharmony_ciprocessed by userspace. 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciTCMU commands are 8-byte aligned. They start with a common header 1638c2ecf20Sopenharmony_cicontaining "len_op", a 32-bit value that stores the length, as well as 1648c2ecf20Sopenharmony_cithe opcode in the lowest unused bits. It also contains cmd_id and 1658c2ecf20Sopenharmony_ciflags fields for setting by the kernel (kflags) and userspace 1668c2ecf20Sopenharmony_ci(uflags). 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciCurrently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD. 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciWhen the opcode is CMD, the entry in the command ring is a struct 1718c2ecf20Sopenharmony_citcmu_cmd_entry. Userspace finds the SCSI CDB (Command Data Block) via 1728c2ecf20Sopenharmony_citcmu_cmd_entry.req.cdb_off. This is an offset from the start of the 1738c2ecf20Sopenharmony_cioverall shared memory region, not the entry. The data in/out buffers 1748c2ecf20Sopenharmony_ciare accessible via tht req.iov[] array. iov_cnt contains the number of 1758c2ecf20Sopenharmony_cientries in iov[] needed to describe either the Data-In or Data-Out 1768c2ecf20Sopenharmony_cibuffers. For bidirectional commands, iov_cnt specifies how many iovec 1778c2ecf20Sopenharmony_cientries cover the Data-Out area, and iov_bidi_cnt specifies how many 1788c2ecf20Sopenharmony_ciiovec entries immediately after that in iov[] cover the Data-In 1798c2ecf20Sopenharmony_ciarea. Just like other fields, iov.iov_base is an offset from the start 1808c2ecf20Sopenharmony_ciof the region. 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciWhen completing a command, userspace sets rsp.scsi_status, and 1838c2ecf20Sopenharmony_cirsp.sense_buffer if necessary. Userspace then increments 1848c2ecf20Sopenharmony_cimailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the 1858c2ecf20Sopenharmony_cikernel via the UIO method, a 4-byte write to the file descriptor. 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciIf TCMU_MAILBOX_FLAG_CAP_OOOC is set for mailbox->flags, kernel is 1888c2ecf20Sopenharmony_cicapable of handling out-of-order completions. In this case, userspace can 1898c2ecf20Sopenharmony_cihandle command in different order other than original. Since kernel would 1908c2ecf20Sopenharmony_cistill process the commands in the same order it appeared in the command 1918c2ecf20Sopenharmony_ciring, userspace need to update the cmd->id when completing the 1928c2ecf20Sopenharmony_cicommand(a.k.a steal the original command's entry). 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciWhen the opcode is PAD, userspace only updates cmd_tail as above -- 1958c2ecf20Sopenharmony_ciit's a no-op. (The kernel inserts PAD entries to ensure each CMD entry 1968c2ecf20Sopenharmony_ciis contiguous within the command ring.) 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciMore opcodes may be added in the future. If userspace encounters an 1998c2ecf20Sopenharmony_ciopcode it does not handle, it must set UNKNOWN_OP bit (bit 0) in 2008c2ecf20Sopenharmony_cihdr.uflags, update cmd_tail, and proceed with processing additional 2018c2ecf20Sopenharmony_cicommands, if any. 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciThe Data Area 2048c2ecf20Sopenharmony_ci------------- 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciThis is shared-memory space after the command ring. The organization 2078c2ecf20Sopenharmony_ciof this area is not defined in the TCMU interface, and userspace 2088c2ecf20Sopenharmony_cishould access only the parts referenced by pending iovs. 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciDevice Discovery 2128c2ecf20Sopenharmony_ci---------------- 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciOther devices may be using UIO besides TCMU. Unrelated user processes 2158c2ecf20Sopenharmony_cimay also be handling different sets of TCMU devices. TCMU userspace 2168c2ecf20Sopenharmony_ciprocesses must find their devices by scanning sysfs 2178c2ecf20Sopenharmony_ciclass/uio/uio*/name. For TCMU devices, these names will be of the 2188c2ecf20Sopenharmony_ciformat:: 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci tcm-user/<hba_num>/<device_name>/<subtype>/<path> 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ciwhere "tcm-user" is common for all TCMU-backed UIO devices. <hba_num> 2238c2ecf20Sopenharmony_ciand <device_name> allow userspace to find the device's path in the 2248c2ecf20Sopenharmony_cikernel target's configfs tree. Assuming the usual mount point, it is 2258c2ecf20Sopenharmony_cifound at:: 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /sys/kernel/config/target/core/user_<hba_num>/<device_name> 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciThis location contains attributes such as "hw_block_size", that 2308c2ecf20Sopenharmony_ciuserspace needs to know for correct operation. 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci<subtype> will be a userspace-process-unique string to identify the 2338c2ecf20Sopenharmony_ciTCMU device as expecting to be backed by a certain handler, and <path> 2348c2ecf20Sopenharmony_ciwill be an additional handler-specific string for the user process to 2358c2ecf20Sopenharmony_ciconfigure the device, if needed. The name cannot contain ':', due to 2368c2ecf20Sopenharmony_ciLIO limitations. 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciFor all devices so discovered, the user handler opens /dev/uioX and 2398c2ecf20Sopenharmony_cicalls mmap():: 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0) 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciwhere size must be equal to the value read from 2448c2ecf20Sopenharmony_ci/sys/class/uio/uioX/maps/map0/size. 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciDevice Events 2488c2ecf20Sopenharmony_ci------------- 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciIf a new device is added or removed, a notification will be broadcast 2518c2ecf20Sopenharmony_ciover netlink, using a generic netlink family name of "TCM-USER" and a 2528c2ecf20Sopenharmony_cimulticast group named "config". This will include the UIO name as 2538c2ecf20Sopenharmony_cidescribed in the previous section, as well as the UIO minor 2548c2ecf20Sopenharmony_cinumber. This should allow userspace to identify both the UIO device and 2558c2ecf20Sopenharmony_cithe LIO device, so that after determining the device is supported 2568c2ecf20Sopenharmony_ci(based on subtype) it can take the appropriate action. 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ciOther contingencies 2608c2ecf20Sopenharmony_ci------------------- 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciUserspace handler process never attaches: 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci- TCMU will post commands, and then abort them after a timeout period 2658c2ecf20Sopenharmony_ci (30 seconds.) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciUserspace handler process is killed: 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci- It is still possible to restart and re-connect to TCMU 2708c2ecf20Sopenharmony_ci devices. Command ring is preserved. However, after the timeout period, 2718c2ecf20Sopenharmony_ci the kernel will abort pending tasks. 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciUserspace handler process hangs: 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci- The kernel will abort pending tasks after a timeout period. 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciUserspace handler process is malicious: 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci- The process can trivially break the handling of devices it controls, 2808c2ecf20Sopenharmony_ci but should not be able to access kernel memory outside its shared 2818c2ecf20Sopenharmony_ci memory areas. 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciWriting a user pass-through handler (with example code) 2858c2ecf20Sopenharmony_ci======================================================= 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciA user process handing a TCMU device must support the following: 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cia) Discovering and configuring TCMU uio devices 2908c2ecf20Sopenharmony_cib) Waiting for events on the device(s) 2918c2ecf20Sopenharmony_cic) Managing the command ring: Parsing operations and commands, 2928c2ecf20Sopenharmony_ci performing work as needed, setting response fields (scsi_status and 2938c2ecf20Sopenharmony_ci possibly sense_buffer), updating cmd_tail, and notifying the kernel 2948c2ecf20Sopenharmony_ci that work has been finished 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ciFirst, consider instead writing a plugin for tcmu-runner. tcmu-runner 2978c2ecf20Sopenharmony_ciimplements all of this, and provides a higher-level API for plugin 2988c2ecf20Sopenharmony_ciauthors. 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciTCMU is designed so that multiple unrelated processes can manage TCMU 3018c2ecf20Sopenharmony_cidevices separately. All handlers should make sure to only open their 3028c2ecf20Sopenharmony_cidevices, based opon a known subtype string. 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cia) Discovering and configuring TCMU UIO devices:: 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* error checking omitted for brevity */ 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci int fd, dev_fd; 3098c2ecf20Sopenharmony_ci char buf[256]; 3108c2ecf20Sopenharmony_ci unsigned long long map_len; 3118c2ecf20Sopenharmony_ci void *map; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci fd = open("/sys/class/uio/uio0/name", O_RDONLY); 3148c2ecf20Sopenharmony_ci ret = read(fd, buf, sizeof(buf)); 3158c2ecf20Sopenharmony_ci close(fd); 3168c2ecf20Sopenharmony_ci buf[ret-1] = '\0'; /* null-terminate and chop off the \n */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* we only want uio devices whose name is a format we expect */ 3198c2ecf20Sopenharmony_ci if (strncmp(buf, "tcm-user", 8)) 3208c2ecf20Sopenharmony_ci exit(-1); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Further checking for subtype also needed here */ 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci fd = open(/sys/class/uio/%s/maps/map0/size, O_RDONLY); 3258c2ecf20Sopenharmony_ci ret = read(fd, buf, sizeof(buf)); 3268c2ecf20Sopenharmony_ci close(fd); 3278c2ecf20Sopenharmony_ci str_buf[ret-1] = '\0'; /* null-terminate and chop off the \n */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci map_len = strtoull(buf, NULL, 0); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dev_fd = open("/dev/uio0", O_RDWR); 3328c2ecf20Sopenharmony_ci map = mmap(NULL, map_len, PROT_READ|PROT_WRITE, MAP_SHARED, dev_fd, 0); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci b) Waiting for events on the device(s) 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci while (1) { 3388c2ecf20Sopenharmony_ci char buf[4]; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci int ret = read(dev_fd, buf, 4); /* will block */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci handle_device_events(dev_fd, map); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cic) Managing the command ring:: 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci #include <linux/target_core_user.h> 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci int handle_device_events(int fd, void *map) 3518c2ecf20Sopenharmony_ci { 3528c2ecf20Sopenharmony_ci struct tcmu_mailbox *mb = map; 3538c2ecf20Sopenharmony_ci struct tcmu_cmd_entry *ent = (void *) mb + mb->cmdr_off + mb->cmd_tail; 3548c2ecf20Sopenharmony_ci int did_some_work = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Process events from cmd ring until we catch up with cmd_head */ 3578c2ecf20Sopenharmony_ci while (ent != (void *)mb + mb->cmdr_off + mb->cmd_head) { 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (tcmu_hdr_get_op(ent->hdr.len_op) == TCMU_OP_CMD) { 3608c2ecf20Sopenharmony_ci uint8_t *cdb = (void *)mb + ent->req.cdb_off; 3618c2ecf20Sopenharmony_ci bool success = true; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Handle command here. */ 3648c2ecf20Sopenharmony_ci printf("SCSI opcode: 0x%x\n", cdb[0]); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Set response fields */ 3678c2ecf20Sopenharmony_ci if (success) 3688c2ecf20Sopenharmony_ci ent->rsp.scsi_status = SCSI_NO_SENSE; 3698c2ecf20Sopenharmony_ci else { 3708c2ecf20Sopenharmony_ci /* Also fill in rsp->sense_buffer here */ 3718c2ecf20Sopenharmony_ci ent->rsp.scsi_status = SCSI_CHECK_CONDITION; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci else if (tcmu_hdr_get_op(ent->hdr.len_op) != TCMU_OP_PAD) { 3758c2ecf20Sopenharmony_ci /* Tell the kernel we didn't handle unknown opcodes */ 3768c2ecf20Sopenharmony_ci ent->hdr.uflags |= TCMU_UFLAG_UNKNOWN_OP; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci else { 3798c2ecf20Sopenharmony_ci /* Do nothing for PAD entries except update cmd_tail */ 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* update cmd_tail */ 3838c2ecf20Sopenharmony_ci mb->cmd_tail = (mb->cmd_tail + tcmu_hdr_get_len(&ent->hdr)) % mb->cmdr_size; 3848c2ecf20Sopenharmony_ci ent = (void *) mb + mb->cmdr_off + mb->cmd_tail; 3858c2ecf20Sopenharmony_ci did_some_work = 1; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Notify the kernel that work has been finished */ 3898c2ecf20Sopenharmony_ci if (did_some_work) { 3908c2ecf20Sopenharmony_ci uint32_t buf = 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci write(fd, &buf, 4); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciA final note 4008c2ecf20Sopenharmony_ci============ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciPlease be careful to return codes as defined by the SCSI 4038c2ecf20Sopenharmony_cispecifications. These are different than some values defined in the 4048c2ecf20Sopenharmony_ciscsi/scsi.h include file. For example, CHECK CONDITION's status code 4058c2ecf20Sopenharmony_ciis 2, not 1. 406