diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2010-12-17 14:11:26 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-01-14 11:12:29 -0500 |
commit | c66ac9db8d4ad9994a02b3e933ea2ccc643e1fe5 (patch) | |
tree | 71c6344688bf56ea6aaf18c586ab69ff4f077ade /Documentation | |
parent | f4013c3879d1bbd9f3ab8351185decd049502368 (diff) |
[SCSI] target: Add LIO target core v4.0.0-rc6
LIO target is a full featured in-kernel target framework with the
following feature set:
High-performance, non-blocking, multithreaded architecture with SIMD
support.
Advanced SCSI feature set:
* Persistent Reservations (PRs)
* Asymmetric Logical Unit Assignment (ALUA)
* Protocol and intra-nexus multiplexing, load-balancing and failover (MC/S)
* Full Error Recovery (ERL=0,1,2)
* Active/active task migration and session continuation (ERL=2)
* Thin LUN provisioning (UNMAP and WRITE_SAMExx)
Multiprotocol target plugins
Storage media independence:
* Virtualization of all storage media; transparent mapping of IO to LUNs
* No hard limits on number of LUNs per Target; maximum LUN size ~750 TB
* Backstores: SATA, SAS, SCSI, BluRay, DVD, FLASH, USB, ramdisk, etc.
Standards compliance:
* Full compliance with IETF (RFC 3720)
* Full implementation of SPC-4 PRs and ALUA
Significant code cleanups done by Christoph Hellwig.
[jejb: fix up for new block bdev exclusive interface. Minor fixes from
Randy Dunlap and Dan Carpenter.]
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'Documentation')
-rwxr-xr-x | Documentation/target/tcm_mod_builder.py | 1094 | ||||
-rw-r--r-- | Documentation/target/tcm_mod_builder.txt | 145 |
2 files changed, 1239 insertions, 0 deletions
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py new file mode 100755 index 00000000000..dbeb8a0d717 --- /dev/null +++ b/Documentation/target/tcm_mod_builder.py | |||
@@ -0,0 +1,1094 @@ | |||
1 | #!/usr/bin/python | ||
2 | # The TCM v4 multi-protocol fabric module generation script for drivers/target/$NEW_MOD | ||
3 | # | ||
4 | # Copyright (c) 2010 Rising Tide Systems | ||
5 | # Copyright (c) 2010 Linux-iSCSI.org | ||
6 | # | ||
7 | # Author: nab@kernel.org | ||
8 | # | ||
9 | import os, sys | ||
10 | import subprocess as sub | ||
11 | import string | ||
12 | import re | ||
13 | import optparse | ||
14 | |||
15 | tcm_dir = "" | ||
16 | |||
17 | fabric_ops = [] | ||
18 | fabric_mod_dir = "" | ||
19 | fabric_mod_port = "" | ||
20 | fabric_mod_init_port = "" | ||
21 | |||
22 | def tcm_mod_err(msg): | ||
23 | print msg | ||
24 | sys.exit(1) | ||
25 | |||
26 | def tcm_mod_create_module_subdir(fabric_mod_dir_var): | ||
27 | |||
28 | if os.path.isdir(fabric_mod_dir_var) == True: | ||
29 | return 1 | ||
30 | |||
31 | print "Creating fabric_mod_dir: " + fabric_mod_dir_var | ||
32 | ret = os.mkdir(fabric_mod_dir_var) | ||
33 | if ret: | ||
34 | tcm_mod_err("Unable to mkdir " + fabric_mod_dir_var) | ||
35 | |||
36 | return | ||
37 | |||
38 | def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): | ||
39 | global fabric_mod_port | ||
40 | global fabric_mod_init_port | ||
41 | buf = "" | ||
42 | |||
43 | f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" | ||
44 | print "Writing file: " + f | ||
45 | |||
46 | p = open(f, 'w'); | ||
47 | if not p: | ||
48 | tcm_mod_err("Unable to open file: " + f) | ||
49 | |||
50 | buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" | ||
51 | buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" | ||
52 | buf += "\n" | ||
53 | buf += "struct " + fabric_mod_name + "_nacl {\n" | ||
54 | buf += " /* Binary World Wide unique Port Name for FC Initiator Nport */\n" | ||
55 | buf += " u64 nport_wwpn;\n" | ||
56 | buf += " /* ASCII formatted WWPN for FC Initiator Nport */\n" | ||
57 | buf += " char nport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
58 | buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" | ||
59 | buf += " struct se_node_acl se_node_acl;\n" | ||
60 | buf += "};\n" | ||
61 | buf += "\n" | ||
62 | buf += "struct " + fabric_mod_name + "_tpg {\n" | ||
63 | buf += " /* FC lport target portal group tag for TCM */\n" | ||
64 | buf += " u16 lport_tpgt;\n" | ||
65 | buf += " /* Pointer back to " + fabric_mod_name + "_lport */\n" | ||
66 | buf += " struct " + fabric_mod_name + "_lport *lport;\n" | ||
67 | buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" | ||
68 | buf += " struct se_portal_group se_tpg;\n" | ||
69 | buf += "};\n" | ||
70 | buf += "\n" | ||
71 | buf += "struct " + fabric_mod_name + "_lport {\n" | ||
72 | buf += " /* SCSI protocol the lport is providing */\n" | ||
73 | buf += " u8 lport_proto_id;\n" | ||
74 | buf += " /* Binary World Wide unique Port Name for FC Target Lport */\n" | ||
75 | buf += " u64 lport_wwpn;\n" | ||
76 | buf += " /* ASCII formatted WWPN for FC Target Lport */\n" | ||
77 | buf += " char lport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
78 | buf += " /* Returned by " + fabric_mod_name + "_make_lport() */\n" | ||
79 | buf += " struct se_wwn lport_wwn;\n" | ||
80 | buf += "};\n" | ||
81 | |||
82 | ret = p.write(buf) | ||
83 | if ret: | ||
84 | tcm_mod_err("Unable to write f: " + f) | ||
85 | |||
86 | p.close() | ||
87 | |||
88 | fabric_mod_port = "lport" | ||
89 | fabric_mod_init_port = "nport" | ||
90 | |||
91 | return | ||
92 | |||
93 | def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): | ||
94 | global fabric_mod_port | ||
95 | global fabric_mod_init_port | ||
96 | buf = "" | ||
97 | |||
98 | f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" | ||
99 | print "Writing file: " + f | ||
100 | |||
101 | p = open(f, 'w'); | ||
102 | if not p: | ||
103 | tcm_mod_err("Unable to open file: " + f) | ||
104 | |||
105 | buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" | ||
106 | buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" | ||
107 | buf += "\n" | ||
108 | buf += "struct " + fabric_mod_name + "_nacl {\n" | ||
109 | buf += " /* Binary World Wide unique Port Name for SAS Initiator port */\n" | ||
110 | buf += " u64 iport_wwpn;\n" | ||
111 | buf += " /* ASCII formatted WWPN for Sas Initiator port */\n" | ||
112 | buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
113 | buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" | ||
114 | buf += " struct se_node_acl se_node_acl;\n" | ||
115 | buf += "};\n\n" | ||
116 | buf += "struct " + fabric_mod_name + "_tpg {\n" | ||
117 | buf += " /* SAS port target portal group tag for TCM */\n" | ||
118 | buf += " u16 tport_tpgt;\n" | ||
119 | buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n" | ||
120 | buf += " struct " + fabric_mod_name + "_tport *tport;\n" | ||
121 | buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" | ||
122 | buf += " struct se_portal_group se_tpg;\n" | ||
123 | buf += "};\n\n" | ||
124 | buf += "struct " + fabric_mod_name + "_tport {\n" | ||
125 | buf += " /* SCSI protocol the tport is providing */\n" | ||
126 | buf += " u8 tport_proto_id;\n" | ||
127 | buf += " /* Binary World Wide unique Port Name for SAS Target port */\n" | ||
128 | buf += " u64 tport_wwpn;\n" | ||
129 | buf += " /* ASCII formatted WWPN for SAS Target port */\n" | ||
130 | buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
131 | buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" | ||
132 | buf += " struct se_wwn tport_wwn;\n" | ||
133 | buf += "};\n" | ||
134 | |||
135 | ret = p.write(buf) | ||
136 | if ret: | ||
137 | tcm_mod_err("Unable to write f: " + f) | ||
138 | |||
139 | p.close() | ||
140 | |||
141 | fabric_mod_port = "tport" | ||
142 | fabric_mod_init_port = "iport" | ||
143 | |||
144 | return | ||
145 | |||
146 | def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): | ||
147 | global fabric_mod_port | ||
148 | global fabric_mod_init_port | ||
149 | buf = "" | ||
150 | |||
151 | f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h" | ||
152 | print "Writing file: " + f | ||
153 | |||
154 | p = open(f, 'w'); | ||
155 | if not p: | ||
156 | tcm_mod_err("Unable to open file: " + f) | ||
157 | |||
158 | buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" | ||
159 | buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" | ||
160 | buf += "\n" | ||
161 | buf += "struct " + fabric_mod_name + "_nacl {\n" | ||
162 | buf += " /* ASCII formatted InitiatorName */\n" | ||
163 | buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
164 | buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" | ||
165 | buf += " struct se_node_acl se_node_acl;\n" | ||
166 | buf += "};\n\n" | ||
167 | buf += "struct " + fabric_mod_name + "_tpg {\n" | ||
168 | buf += " /* iSCSI target portal group tag for TCM */\n" | ||
169 | buf += " u16 tport_tpgt;\n" | ||
170 | buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n" | ||
171 | buf += " struct " + fabric_mod_name + "_tport *tport;\n" | ||
172 | buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n" | ||
173 | buf += " struct se_portal_group se_tpg;\n" | ||
174 | buf += "};\n\n" | ||
175 | buf += "struct " + fabric_mod_name + "_tport {\n" | ||
176 | buf += " /* SCSI protocol the tport is providing */\n" | ||
177 | buf += " u8 tport_proto_id;\n" | ||
178 | buf += " /* ASCII formatted TargetName for IQN */\n" | ||
179 | buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" | ||
180 | buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" | ||
181 | buf += " struct se_wwn tport_wwn;\n" | ||
182 | buf += "};\n" | ||
183 | |||
184 | ret = p.write(buf) | ||
185 | if ret: | ||
186 | tcm_mod_err("Unable to write f: " + f) | ||
187 | |||
188 | p.close() | ||
189 | |||
190 | fabric_mod_port = "tport" | ||
191 | fabric_mod_init_port = "iport" | ||
192 | |||
193 | return | ||
194 | |||
195 | def tcm_mod_build_base_includes(proto_ident, fabric_mod_dir_val, fabric_mod_name): | ||
196 | |||
197 | if proto_ident == "FC": | ||
198 | tcm_mod_build_FC_include(fabric_mod_dir_val, fabric_mod_name) | ||
199 | elif proto_ident == "SAS": | ||
200 | tcm_mod_build_SAS_include(fabric_mod_dir_val, fabric_mod_name) | ||
201 | elif proto_ident == "iSCSI": | ||
202 | tcm_mod_build_iSCSI_include(fabric_mod_dir_val, fabric_mod_name) | ||
203 | else: | ||
204 | print "Unsupported proto_ident: " + proto_ident | ||
205 | sys.exit(1) | ||
206 | |||
207 | return | ||
208 | |||
209 | def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | ||
210 | buf = "" | ||
211 | |||
212 | f = fabric_mod_dir_var + "/" + fabric_mod_name + "_configfs.c" | ||
213 | print "Writing file: " + f | ||
214 | |||
215 | p = open(f, 'w'); | ||
216 | if not p: | ||
217 | tcm_mod_err("Unable to open file: " + f) | ||
218 | |||
219 | buf = "#include <linux/module.h>\n" | ||
220 | buf += "#include <linux/moduleparam.h>\n" | ||
221 | buf += "#include <linux/version.h>\n" | ||
222 | buf += "#include <generated/utsrelease.h>\n" | ||
223 | buf += "#include <linux/utsname.h>\n" | ||
224 | buf += "#include <linux/init.h>\n" | ||
225 | buf += "#include <linux/slab.h>\n" | ||
226 | buf += "#include <linux/kthread.h>\n" | ||
227 | buf += "#include <linux/types.h>\n" | ||
228 | buf += "#include <linux/string.h>\n" | ||
229 | buf += "#include <linux/configfs.h>\n" | ||
230 | buf += "#include <linux/ctype.h>\n" | ||
231 | buf += "#include <asm/unaligned.h>\n\n" | ||
232 | buf += "#include <target/target_core_base.h>\n" | ||
233 | buf += "#include <target/target_core_transport.h>\n" | ||
234 | buf += "#include <target/target_core_fabric_ops.h>\n" | ||
235 | buf += "#include <target/target_core_fabric_configfs.h>\n" | ||
236 | buf += "#include <target/target_core_fabric_lib.h>\n" | ||
237 | buf += "#include <target/target_core_device.h>\n" | ||
238 | buf += "#include <target/target_core_tpg.h>\n" | ||
239 | buf += "#include <target/target_core_configfs.h>\n" | ||
240 | buf += "#include <target/target_core_base.h>\n" | ||
241 | buf += "#include <target/configfs_macros.h>\n\n" | ||
242 | buf += "#include <" + fabric_mod_name + "_base.h>\n" | ||
243 | buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" | ||
244 | |||
245 | buf += "/* Local pointer to allocated TCM configfs fabric module */\n" | ||
246 | buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" | ||
247 | |||
248 | buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" | ||
249 | buf += " struct se_portal_group *se_tpg,\n" | ||
250 | buf += " struct config_group *group,\n" | ||
251 | buf += " const char *name)\n" | ||
252 | buf += "{\n" | ||
253 | buf += " struct se_node_acl *se_nacl, *se_nacl_new;\n" | ||
254 | buf += " struct " + fabric_mod_name + "_nacl *nacl;\n" | ||
255 | |||
256 | if proto_ident == "FC" or proto_ident == "SAS": | ||
257 | buf += " u64 wwpn = 0;\n" | ||
258 | |||
259 | buf += " u32 nexus_depth;\n\n" | ||
260 | buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" | ||
261 | buf += " return ERR_PTR(-EINVAL); */\n" | ||
262 | buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n" | ||
263 | buf += " if (!(se_nacl_new))\n" | ||
264 | buf += " return ERR_PTR(-ENOMEM);\n" | ||
265 | buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n" | ||
266 | buf += " nexus_depth = 1;\n" | ||
267 | buf += " /*\n" | ||
268 | buf += " * se_nacl_new may be released by core_tpg_add_initiator_node_acl()\n" | ||
269 | buf += " * when converting a NodeACL from demo mode -> explict\n" | ||
270 | buf += " */\n" | ||
271 | buf += " se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,\n" | ||
272 | buf += " name, nexus_depth);\n" | ||
273 | buf += " if (IS_ERR(se_nacl)) {\n" | ||
274 | buf += " " + fabric_mod_name + "_release_fabric_acl(se_tpg, se_nacl_new);\n" | ||
275 | buf += " return se_nacl;\n" | ||
276 | buf += " }\n" | ||
277 | buf += " /*\n" | ||
278 | buf += " * Locate our struct " + fabric_mod_name + "_nacl and set the FC Nport WWPN\n" | ||
279 | buf += " */\n" | ||
280 | buf += " nacl = container_of(se_nacl, struct " + fabric_mod_name + "_nacl, se_node_acl);\n" | ||
281 | |||
282 | if proto_ident == "FC" or proto_ident == "SAS": | ||
283 | buf += " nacl->" + fabric_mod_init_port + "_wwpn = wwpn;\n" | ||
284 | |||
285 | buf += " /* " + fabric_mod_name + "_format_wwn(&nacl->" + fabric_mod_init_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n" | ||
286 | buf += " return se_nacl;\n" | ||
287 | buf += "}\n\n" | ||
288 | buf += "static void " + fabric_mod_name + "_drop_nodeacl(struct se_node_acl *se_acl)\n" | ||
289 | buf += "{\n" | ||
290 | buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" | ||
291 | buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" | ||
292 | buf += " kfree(nacl);\n" | ||
293 | buf += "}\n\n" | ||
294 | |||
295 | buf += "static struct se_portal_group *" + fabric_mod_name + "_make_tpg(\n" | ||
296 | buf += " struct se_wwn *wwn,\n" | ||
297 | buf += " struct config_group *group,\n" | ||
298 | buf += " const char *name)\n" | ||
299 | buf += "{\n" | ||
300 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + "*" + fabric_mod_port + " = container_of(wwn,\n" | ||
301 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n\n" | ||
302 | buf += " struct " + fabric_mod_name + "_tpg *tpg;\n" | ||
303 | buf += " unsigned long tpgt;\n" | ||
304 | buf += " int ret;\n\n" | ||
305 | buf += " if (strstr(name, \"tpgt_\") != name)\n" | ||
306 | buf += " return ERR_PTR(-EINVAL);\n" | ||
307 | buf += " if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)\n" | ||
308 | buf += " return ERR_PTR(-EINVAL);\n\n" | ||
309 | buf += " tpg = kzalloc(sizeof(struct " + fabric_mod_name + "_tpg), GFP_KERNEL);\n" | ||
310 | buf += " if (!(tpg)) {\n" | ||
311 | buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_tpg\");\n" | ||
312 | buf += " return ERR_PTR(-ENOMEM);\n" | ||
313 | buf += " }\n" | ||
314 | buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" | ||
315 | buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" | ||
316 | buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n" | ||
317 | buf += " &tpg->se_tpg, (void *)tpg,\n" | ||
318 | buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" | ||
319 | buf += " if (ret < 0) {\n" | ||
320 | buf += " kfree(tpg);\n" | ||
321 | buf += " return NULL;\n" | ||
322 | buf += " }\n" | ||
323 | buf += " return &tpg->se_tpg;\n" | ||
324 | buf += "}\n\n" | ||
325 | buf += "static void " + fabric_mod_name + "_drop_tpg(struct se_portal_group *se_tpg)\n" | ||
326 | buf += "{\n" | ||
327 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
328 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n\n" | ||
329 | buf += " core_tpg_deregister(se_tpg);\n" | ||
330 | buf += " kfree(tpg);\n" | ||
331 | buf += "}\n\n" | ||
332 | |||
333 | buf += "static struct se_wwn *" + fabric_mod_name + "_make_" + fabric_mod_port + "(\n" | ||
334 | buf += " struct target_fabric_configfs *tf,\n" | ||
335 | buf += " struct config_group *group,\n" | ||
336 | buf += " const char *name)\n" | ||
337 | buf += "{\n" | ||
338 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + ";\n" | ||
339 | |||
340 | if proto_ident == "FC" or proto_ident == "SAS": | ||
341 | buf += " u64 wwpn = 0;\n\n" | ||
342 | |||
343 | buf += " /* if (" + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" | ||
344 | buf += " return ERR_PTR(-EINVAL); */\n\n" | ||
345 | buf += " " + fabric_mod_port + " = kzalloc(sizeof(struct " + fabric_mod_name + "_" + fabric_mod_port + "), GFP_KERNEL);\n" | ||
346 | buf += " if (!(" + fabric_mod_port + ")) {\n" | ||
347 | buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_" + fabric_mod_port + "\");\n" | ||
348 | buf += " return ERR_PTR(-ENOMEM);\n" | ||
349 | buf += " }\n" | ||
350 | |||
351 | if proto_ident == "FC" or proto_ident == "SAS": | ||
352 | buf += " " + fabric_mod_port + "->" + fabric_mod_port + "_wwpn = wwpn;\n" | ||
353 | |||
354 | buf += " /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "__NAMELEN, wwpn); */\n\n" | ||
355 | buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_wwn;\n" | ||
356 | buf += "}\n\n" | ||
357 | buf += "static void " + fabric_mod_name + "_drop_" + fabric_mod_port + "(struct se_wwn *wwn)\n" | ||
358 | buf += "{\n" | ||
359 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = container_of(wwn,\n" | ||
360 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n" | ||
361 | buf += " kfree(" + fabric_mod_port + ");\n" | ||
362 | buf += "}\n\n" | ||
363 | buf += "static ssize_t " + fabric_mod_name + "_wwn_show_attr_version(\n" | ||
364 | buf += " struct target_fabric_configfs *tf,\n" | ||
365 | buf += " char *page)\n" | ||
366 | buf += "{\n" | ||
367 | buf += " return sprintf(page, \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" | ||
368 | buf += " \"on \"UTS_RELEASE\"\\n\", " + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" | ||
369 | buf += " utsname()->machine);\n" | ||
370 | buf += "}\n\n" | ||
371 | buf += "TF_WWN_ATTR_RO(" + fabric_mod_name + ", version);\n\n" | ||
372 | buf += "static struct configfs_attribute *" + fabric_mod_name + "_wwn_attrs[] = {\n" | ||
373 | buf += " &" + fabric_mod_name + "_wwn_version.attr,\n" | ||
374 | buf += " NULL,\n" | ||
375 | buf += "};\n\n" | ||
376 | |||
377 | buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" | ||
378 | buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" | ||
379 | buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" | ||
380 | buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" | ||
381 | buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" | ||
382 | buf += " .tpg_get_default_depth = " + fabric_mod_name + "_get_default_depth,\n" | ||
383 | buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" | ||
384 | buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n" | ||
385 | buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n" | ||
386 | buf += " .tpg_check_demo_mode = " + fabric_mod_name + "_check_false,\n" | ||
387 | buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" | ||
388 | buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" | ||
389 | buf += " .tpg_check_prod_mode_write_protect = " + fabric_mod_name + "_check_false,\n" | ||
390 | buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n" | ||
391 | buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n" | ||
392 | buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n" | ||
393 | buf += " .release_cmd_to_pool = " + fabric_mod_name + "_release_cmd,\n" | ||
394 | buf += " .release_cmd_direct = " + fabric_mod_name + "_release_cmd,\n" | ||
395 | buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n" | ||
396 | buf += " .close_session = " + fabric_mod_name + "_close_session,\n" | ||
397 | buf += " .stop_session = " + fabric_mod_name + "_stop_session,\n" | ||
398 | buf += " .fall_back_to_erl0 = " + fabric_mod_name + "_reset_nexus,\n" | ||
399 | buf += " .sess_logged_in = " + fabric_mod_name + "_sess_logged_in,\n" | ||
400 | buf += " .sess_get_index = " + fabric_mod_name + "_sess_get_index,\n" | ||
401 | buf += " .sess_get_initiator_sid = NULL,\n" | ||
402 | buf += " .write_pending = " + fabric_mod_name + "_write_pending,\n" | ||
403 | buf += " .write_pending_status = " + fabric_mod_name + "_write_pending_status,\n" | ||
404 | buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n" | ||
405 | buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n" | ||
406 | buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n" | ||
407 | buf += " .new_cmd_failure = " + fabric_mod_name + "_new_cmd_failure,\n" | ||
408 | buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n" | ||
409 | buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n" | ||
410 | buf += " .queue_tm_rsp = " + fabric_mod_name + "_queue_tm_rsp,\n" | ||
411 | buf += " .get_fabric_sense_len = " + fabric_mod_name + "_get_fabric_sense_len,\n" | ||
412 | buf += " .set_fabric_sense_len = " + fabric_mod_name + "_set_fabric_sense_len,\n" | ||
413 | buf += " .is_state_remove = " + fabric_mod_name + "_is_state_remove,\n" | ||
414 | buf += " .pack_lun = " + fabric_mod_name + "_pack_lun,\n" | ||
415 | buf += " /*\n" | ||
416 | buf += " * Setup function pointers for generic logic in target_core_fabric_configfs.c\n" | ||
417 | buf += " */\n" | ||
418 | buf += " .fabric_make_wwn = " + fabric_mod_name + "_make_" + fabric_mod_port + ",\n" | ||
419 | buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n" | ||
420 | buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" | ||
421 | buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" | ||
422 | buf += " .fabric_post_link = NULL,\n" | ||
423 | buf += " .fabric_pre_unlink = NULL,\n" | ||
424 | buf += " .fabric_make_np = NULL,\n" | ||
425 | buf += " .fabric_drop_np = NULL,\n" | ||
426 | buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" | ||
427 | buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" | ||
428 | buf += "};\n\n" | ||
429 | |||
430 | buf += "static int " + fabric_mod_name + "_register_configfs(void)\n" | ||
431 | buf += "{\n" | ||
432 | buf += " struct target_fabric_configfs *fabric;\n" | ||
433 | buf += " int ret;\n\n" | ||
434 | buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" | ||
435 | buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" | ||
436 | buf += " utsname()->machine);\n" | ||
437 | buf += " /*\n" | ||
438 | buf += " * Register the top level struct config_item_type with TCM core\n" | ||
439 | buf += " */\n" | ||
440 | buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n" | ||
441 | buf += " if (!(fabric)) {\n" | ||
442 | buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n" | ||
443 | buf += " return -ENOMEM;\n" | ||
444 | buf += " }\n" | ||
445 | buf += " /*\n" | ||
446 | buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n" | ||
447 | buf += " */\n" | ||
448 | buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n" | ||
449 | buf += " /*\n" | ||
450 | buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n" | ||
451 | buf += " */\n" | ||
452 | buf += " TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n" | ||
453 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;\n" | ||
454 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;\n" | ||
455 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;\n" | ||
456 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;\n" | ||
457 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n" | ||
458 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n" | ||
459 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n" | ||
460 | buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n" | ||
461 | buf += " /*\n" | ||
462 | buf += " * Register the fabric for use within TCM\n" | ||
463 | buf += " */\n" | ||
464 | buf += " ret = target_fabric_configfs_register(fabric);\n" | ||
465 | buf += " if (ret < 0) {\n" | ||
466 | buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n" | ||
467 | buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n" | ||
468 | buf += " return ret;\n" | ||
469 | buf += " }\n" | ||
470 | buf += " /*\n" | ||
471 | buf += " * Setup our local pointer to *fabric\n" | ||
472 | buf += " */\n" | ||
473 | buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n" | ||
474 | buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n" | ||
475 | buf += " return 0;\n" | ||
476 | buf += "};\n\n" | ||
477 | buf += "static void " + fabric_mod_name + "_deregister_configfs(void)\n" | ||
478 | buf += "{\n" | ||
479 | buf += " if (!(" + fabric_mod_name + "_fabric_configfs))\n" | ||
480 | buf += " return;\n\n" | ||
481 | buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n" | ||
482 | buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n" | ||
483 | buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n" | ||
484 | buf += "};\n\n" | ||
485 | |||
486 | buf += "static int __init " + fabric_mod_name + "_init(void)\n" | ||
487 | buf += "{\n" | ||
488 | buf += " int ret;\n\n" | ||
489 | buf += " ret = " + fabric_mod_name + "_register_configfs();\n" | ||
490 | buf += " if (ret < 0)\n" | ||
491 | buf += " return ret;\n\n" | ||
492 | buf += " return 0;\n" | ||
493 | buf += "};\n\n" | ||
494 | buf += "static void " + fabric_mod_name + "_exit(void)\n" | ||
495 | buf += "{\n" | ||
496 | buf += " " + fabric_mod_name + "_deregister_configfs();\n" | ||
497 | buf += "};\n\n" | ||
498 | |||
499 | buf += "#ifdef MODULE\n" | ||
500 | buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" | ||
501 | buf += "MODULE_LICENSE(\"GPL\");\n" | ||
502 | buf += "module_init(" + fabric_mod_name + "_init);\n" | ||
503 | buf += "module_exit(" + fabric_mod_name + "_exit);\n" | ||
504 | buf += "#endif\n" | ||
505 | |||
506 | ret = p.write(buf) | ||
507 | if ret: | ||
508 | tcm_mod_err("Unable to write f: " + f) | ||
509 | |||
510 | p.close() | ||
511 | |||
512 | return | ||
513 | |||
514 | def tcm_mod_scan_fabric_ops(tcm_dir): | ||
515 | |||
516 | fabric_ops_api = tcm_dir + "include/target/target_core_fabric_ops.h" | ||
517 | |||
518 | print "Using tcm_mod_scan_fabric_ops: " + fabric_ops_api | ||
519 | process_fo = 0; | ||
520 | |||
521 | p = open(fabric_ops_api, 'r') | ||
522 | |||
523 | line = p.readline() | ||
524 | while line: | ||
525 | if process_fo == 0 and re.search('struct target_core_fabric_ops {', line): | ||
526 | line = p.readline() | ||
527 | continue | ||
528 | |||
529 | if process_fo == 0: | ||
530 | process_fo = 1; | ||
531 | line = p.readline() | ||
532 | # Search for function pointer | ||
533 | if not re.search('\(\*', line): | ||
534 | continue | ||
535 | |||
536 | fabric_ops.append(line.rstrip()) | ||
537 | continue | ||
538 | |||
539 | line = p.readline() | ||
540 | # Search for function pointer | ||
541 | if not re.search('\(\*', line): | ||
542 | continue | ||
543 | |||
544 | fabric_ops.append(line.rstrip()) | ||
545 | |||
546 | p.close() | ||
547 | return | ||
548 | |||
549 | def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): | ||
550 | buf = "" | ||
551 | bufi = "" | ||
552 | |||
553 | f = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.c" | ||
554 | print "Writing file: " + f | ||
555 | |||
556 | p = open(f, 'w') | ||
557 | if not p: | ||
558 | tcm_mod_err("Unable to open file: " + f) | ||
559 | |||
560 | fi = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.h" | ||
561 | print "Writing file: " + fi | ||
562 | |||
563 | pi = open(fi, 'w') | ||
564 | if not pi: | ||
565 | tcm_mod_err("Unable to open file: " + fi) | ||
566 | |||
567 | buf = "#include <linux/slab.h>\n" | ||
568 | buf += "#include <linux/kthread.h>\n" | ||
569 | buf += "#include <linux/types.h>\n" | ||
570 | buf += "#include <linux/list.h>\n" | ||
571 | buf += "#include <linux/types.h>\n" | ||
572 | buf += "#include <linux/string.h>\n" | ||
573 | buf += "#include <linux/ctype.h>\n" | ||
574 | buf += "#include <asm/unaligned.h>\n" | ||
575 | buf += "#include <scsi/scsi.h>\n" | ||
576 | buf += "#include <scsi/scsi_host.h>\n" | ||
577 | buf += "#include <scsi/scsi_device.h>\n" | ||
578 | buf += "#include <scsi/scsi_cmnd.h>\n" | ||
579 | buf += "#include <scsi/libfc.h>\n\n" | ||
580 | buf += "#include <target/target_core_base.h>\n" | ||
581 | buf += "#include <target/target_core_transport.h>\n" | ||
582 | buf += "#include <target/target_core_fabric_ops.h>\n" | ||
583 | buf += "#include <target/target_core_fabric_lib.h>\n" | ||
584 | buf += "#include <target/target_core_device.h>\n" | ||
585 | buf += "#include <target/target_core_tpg.h>\n" | ||
586 | buf += "#include <target/target_core_configfs.h>\n" | ||
587 | buf += "#include <" + fabric_mod_name + "_base.h>\n" | ||
588 | buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" | ||
589 | |||
590 | buf += "int " + fabric_mod_name + "_check_true(struct se_portal_group *se_tpg)\n" | ||
591 | buf += "{\n" | ||
592 | buf += " return 1;\n" | ||
593 | buf += "}\n\n" | ||
594 | bufi += "int " + fabric_mod_name + "_check_true(struct se_portal_group *);\n" | ||
595 | |||
596 | buf += "int " + fabric_mod_name + "_check_false(struct se_portal_group *se_tpg)\n" | ||
597 | buf += "{\n" | ||
598 | buf += " return 0;\n" | ||
599 | buf += "}\n\n" | ||
600 | bufi += "int " + fabric_mod_name + "_check_false(struct se_portal_group *);\n" | ||
601 | |||
602 | total_fabric_ops = len(fabric_ops) | ||
603 | i = 0 | ||
604 | |||
605 | while i < total_fabric_ops: | ||
606 | fo = fabric_ops[i] | ||
607 | i += 1 | ||
608 | # print "fabric_ops: " + fo | ||
609 | |||
610 | if re.search('get_fabric_name', fo): | ||
611 | buf += "char *" + fabric_mod_name + "_get_fabric_name(void)\n" | ||
612 | buf += "{\n" | ||
613 | buf += " return \"" + fabric_mod_name[4:] + "\";\n" | ||
614 | buf += "}\n\n" | ||
615 | bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n" | ||
616 | continue | ||
617 | |||
618 | if re.search('get_fabric_proto_ident', fo): | ||
619 | buf += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *se_tpg)\n" | ||
620 | buf += "{\n" | ||
621 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
622 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
623 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" | ||
624 | buf += " u8 proto_id;\n\n" | ||
625 | buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" | ||
626 | if proto_ident == "FC": | ||
627 | buf += " case SCSI_PROTOCOL_FCP:\n" | ||
628 | buf += " default:\n" | ||
629 | buf += " proto_id = fc_get_fabric_proto_ident(se_tpg);\n" | ||
630 | buf += " break;\n" | ||
631 | elif proto_ident == "SAS": | ||
632 | buf += " case SCSI_PROTOCOL_SAS:\n" | ||
633 | buf += " default:\n" | ||
634 | buf += " proto_id = sas_get_fabric_proto_ident(se_tpg);\n" | ||
635 | buf += " break;\n" | ||
636 | elif proto_ident == "iSCSI": | ||
637 | buf += " case SCSI_PROTOCOL_ISCSI:\n" | ||
638 | buf += " default:\n" | ||
639 | buf += " proto_id = iscsi_get_fabric_proto_ident(se_tpg);\n" | ||
640 | buf += " break;\n" | ||
641 | |||
642 | buf += " }\n\n" | ||
643 | buf += " return proto_id;\n" | ||
644 | buf += "}\n\n" | ||
645 | bufi += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *);\n" | ||
646 | |||
647 | if re.search('get_wwn', fo): | ||
648 | buf += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *se_tpg)\n" | ||
649 | buf += "{\n" | ||
650 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
651 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
652 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n\n" | ||
653 | buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_name[0];\n" | ||
654 | buf += "}\n\n" | ||
655 | bufi += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *);\n" | ||
656 | |||
657 | if re.search('get_tag', fo): | ||
658 | buf += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *se_tpg)\n" | ||
659 | buf += "{\n" | ||
660 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
661 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
662 | buf += " return tpg->" + fabric_mod_port + "_tpgt;\n" | ||
663 | buf += "}\n\n" | ||
664 | bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n" | ||
665 | |||
666 | if re.search('get_default_depth', fo): | ||
667 | buf += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *se_tpg)\n" | ||
668 | buf += "{\n" | ||
669 | buf += " return 1;\n" | ||
670 | buf += "}\n\n" | ||
671 | bufi += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *);\n" | ||
672 | |||
673 | if re.search('get_pr_transport_id\)\(', fo): | ||
674 | buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n" | ||
675 | buf += " struct se_portal_group *se_tpg,\n" | ||
676 | buf += " struct se_node_acl *se_nacl,\n" | ||
677 | buf += " struct t10_pr_registration *pr_reg,\n" | ||
678 | buf += " int *format_code,\n" | ||
679 | buf += " unsigned char *buf)\n" | ||
680 | buf += "{\n" | ||
681 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
682 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
683 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" | ||
684 | buf += " int ret = 0;\n\n" | ||
685 | buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" | ||
686 | if proto_ident == "FC": | ||
687 | buf += " case SCSI_PROTOCOL_FCP:\n" | ||
688 | buf += " default:\n" | ||
689 | buf += " ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" | ||
690 | buf += " format_code, buf);\n" | ||
691 | buf += " break;\n" | ||
692 | elif proto_ident == "SAS": | ||
693 | buf += " case SCSI_PROTOCOL_SAS:\n" | ||
694 | buf += " default:\n" | ||
695 | buf += " ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" | ||
696 | buf += " format_code, buf);\n" | ||
697 | buf += " break;\n" | ||
698 | elif proto_ident == "iSCSI": | ||
699 | buf += " case SCSI_PROTOCOL_ISCSI:\n" | ||
700 | buf += " default:\n" | ||
701 | buf += " ret = iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" | ||
702 | buf += " format_code, buf);\n" | ||
703 | buf += " break;\n" | ||
704 | |||
705 | buf += " }\n\n" | ||
706 | buf += " return ret;\n" | ||
707 | buf += "}\n\n" | ||
708 | bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id(struct se_portal_group *,\n" | ||
709 | bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" | ||
710 | bufi += " int *, unsigned char *);\n" | ||
711 | |||
712 | if re.search('get_pr_transport_id_len\)\(', fo): | ||
713 | buf += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(\n" | ||
714 | buf += " struct se_portal_group *se_tpg,\n" | ||
715 | buf += " struct se_node_acl *se_nacl,\n" | ||
716 | buf += " struct t10_pr_registration *pr_reg,\n" | ||
717 | buf += " int *format_code)\n" | ||
718 | buf += "{\n" | ||
719 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
720 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
721 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" | ||
722 | buf += " int ret = 0;\n\n" | ||
723 | buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" | ||
724 | if proto_ident == "FC": | ||
725 | buf += " case SCSI_PROTOCOL_FCP:\n" | ||
726 | buf += " default:\n" | ||
727 | buf += " ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" | ||
728 | buf += " format_code);\n" | ||
729 | buf += " break;\n" | ||
730 | elif proto_ident == "SAS": | ||
731 | buf += " case SCSI_PROTOCOL_SAS:\n" | ||
732 | buf += " default:\n" | ||
733 | buf += " ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" | ||
734 | buf += " format_code);\n" | ||
735 | buf += " break;\n" | ||
736 | elif proto_ident == "iSCSI": | ||
737 | buf += " case SCSI_PROTOCOL_ISCSI:\n" | ||
738 | buf += " default:\n" | ||
739 | buf += " ret = iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" | ||
740 | buf += " format_code);\n" | ||
741 | buf += " break;\n" | ||
742 | |||
743 | |||
744 | buf += " }\n\n" | ||
745 | buf += " return ret;\n" | ||
746 | buf += "}\n\n" | ||
747 | bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(struct se_portal_group *,\n" | ||
748 | bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" | ||
749 | bufi += " int *);\n" | ||
750 | |||
751 | if re.search('parse_pr_out_transport_id\)\(', fo): | ||
752 | buf += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(\n" | ||
753 | buf += " struct se_portal_group *se_tpg,\n" | ||
754 | buf += " const char *buf,\n" | ||
755 | buf += " u32 *out_tid_len,\n" | ||
756 | buf += " char **port_nexus_ptr)\n" | ||
757 | buf += "{\n" | ||
758 | buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" | ||
759 | buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" | ||
760 | buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" | ||
761 | buf += " char *tid = NULL;\n\n" | ||
762 | buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" | ||
763 | if proto_ident == "FC": | ||
764 | buf += " case SCSI_PROTOCOL_FCP:\n" | ||
765 | buf += " default:\n" | ||
766 | buf += " tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" | ||
767 | buf += " port_nexus_ptr);\n" | ||
768 | elif proto_ident == "SAS": | ||
769 | buf += " case SCSI_PROTOCOL_SAS:\n" | ||
770 | buf += " default:\n" | ||
771 | buf += " tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" | ||
772 | buf += " port_nexus_ptr);\n" | ||
773 | elif proto_ident == "iSCSI": | ||
774 | buf += " case SCSI_PROTOCOL_ISCSI:\n" | ||
775 | buf += " default:\n" | ||
776 | buf += " tid = iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" | ||
777 | buf += " port_nexus_ptr);\n" | ||
778 | |||
779 | buf += " }\n\n" | ||
780 | buf += " return tid;\n" | ||
781 | buf += "}\n\n" | ||
782 | bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" | ||
783 | bufi += " const char *, u32 *, char **);\n" | ||
784 | |||
785 | if re.search('alloc_fabric_acl\)\(', fo): | ||
786 | buf += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *se_tpg)\n" | ||
787 | buf += "{\n" | ||
788 | buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n" | ||
789 | buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n" | ||
790 | buf += " if (!(nacl)) {\n" | ||
791 | buf += " printk(KERN_ERR \"Unable to alocate struct " + fabric_mod_name + "_nacl\\n\");\n" | ||
792 | buf += " return NULL;\n" | ||
793 | buf += " }\n\n" | ||
794 | buf += " return &nacl->se_node_acl;\n" | ||
795 | buf += "}\n\n" | ||
796 | bufi += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *);\n" | ||
797 | |||
798 | if re.search('release_fabric_acl\)\(', fo): | ||
799 | buf += "void " + fabric_mod_name + "_release_fabric_acl(\n" | ||
800 | buf += " struct se_portal_group *se_tpg,\n" | ||
801 | buf += " struct se_node_acl *se_nacl)\n" | ||
802 | buf += "{\n" | ||
803 | buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_nacl,\n" | ||
804 | buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" | ||
805 | buf += " kfree(nacl);\n" | ||
806 | buf += "}\n\n" | ||
807 | bufi += "void " + fabric_mod_name + "_release_fabric_acl(struct se_portal_group *,\n" | ||
808 | bufi += " struct se_node_acl *);\n" | ||
809 | |||
810 | if re.search('tpg_get_inst_index\)\(', fo): | ||
811 | buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" | ||
812 | buf += "{\n" | ||
813 | buf += " return 1;\n" | ||
814 | buf += "}\n\n" | ||
815 | bufi += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *);\n" | ||
816 | |||
817 | if re.search('release_cmd_to_pool', fo): | ||
818 | buf += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *se_cmd)\n" | ||
819 | buf += "{\n" | ||
820 | buf += " return;\n" | ||
821 | buf += "}\n\n" | ||
822 | bufi += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *);\n" | ||
823 | |||
824 | if re.search('shutdown_session\)\(', fo): | ||
825 | buf += "int " + fabric_mod_name + "_shutdown_session(struct se_session *se_sess)\n" | ||
826 | buf += "{\n" | ||
827 | buf += " return 0;\n" | ||
828 | buf += "}\n\n" | ||
829 | bufi += "int " + fabric_mod_name + "_shutdown_session(struct se_session *);\n" | ||
830 | |||
831 | if re.search('close_session\)\(', fo): | ||
832 | buf += "void " + fabric_mod_name + "_close_session(struct se_session *se_sess)\n" | ||
833 | buf += "{\n" | ||
834 | buf += " return;\n" | ||
835 | buf += "}\n\n" | ||
836 | bufi += "void " + fabric_mod_name + "_close_session(struct se_session *);\n" | ||
837 | |||
838 | if re.search('stop_session\)\(', fo): | ||
839 | buf += "void " + fabric_mod_name + "_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep)\n" | ||
840 | buf += "{\n" | ||
841 | buf += " return;\n" | ||
842 | buf += "}\n\n" | ||
843 | bufi += "void " + fabric_mod_name + "_stop_session(struct se_session *, int, int);\n" | ||
844 | |||
845 | if re.search('fall_back_to_erl0\)\(', fo): | ||
846 | buf += "void " + fabric_mod_name + "_reset_nexus(struct se_session *se_sess)\n" | ||
847 | buf += "{\n" | ||
848 | buf += " return;\n" | ||
849 | buf += "}\n\n" | ||
850 | bufi += "void " + fabric_mod_name + "_reset_nexus(struct se_session *);\n" | ||
851 | |||
852 | if re.search('sess_logged_in\)\(', fo): | ||
853 | buf += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *se_sess)\n" | ||
854 | buf += "{\n" | ||
855 | buf += " return 0;\n" | ||
856 | buf += "}\n\n" | ||
857 | bufi += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *);\n" | ||
858 | |||
859 | if re.search('sess_get_index\)\(', fo): | ||
860 | buf += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *se_sess)\n" | ||
861 | buf += "{\n" | ||
862 | buf += " return 0;\n" | ||
863 | buf += "}\n\n" | ||
864 | bufi += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *);\n" | ||
865 | |||
866 | if re.search('write_pending\)\(', fo): | ||
867 | buf += "int " + fabric_mod_name + "_write_pending(struct se_cmd *se_cmd)\n" | ||
868 | buf += "{\n" | ||
869 | buf += " return 0;\n" | ||
870 | buf += "}\n\n" | ||
871 | bufi += "int " + fabric_mod_name + "_write_pending(struct se_cmd *);\n" | ||
872 | |||
873 | if re.search('write_pending_status\)\(', fo): | ||
874 | buf += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *se_cmd)\n" | ||
875 | buf += "{\n" | ||
876 | buf += " return 0;\n" | ||
877 | buf += "}\n\n" | ||
878 | bufi += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *);\n" | ||
879 | |||
880 | if re.search('set_default_node_attributes\)\(', fo): | ||
881 | buf += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *nacl)\n" | ||
882 | buf += "{\n" | ||
883 | buf += " return;\n" | ||
884 | buf += "}\n\n" | ||
885 | bufi += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *);\n" | ||
886 | |||
887 | if re.search('get_task_tag\)\(', fo): | ||
888 | buf += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *se_cmd)\n" | ||
889 | buf += "{\n" | ||
890 | buf += " return 0;\n" | ||
891 | buf += "}\n\n" | ||
892 | bufi += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *);\n" | ||
893 | |||
894 | if re.search('get_cmd_state\)\(', fo): | ||
895 | buf += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *se_cmd)\n" | ||
896 | buf += "{\n" | ||
897 | buf += " return 0;\n" | ||
898 | buf += "}\n\n" | ||
899 | bufi += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *);\n" | ||
900 | |||
901 | if re.search('new_cmd_failure\)\(', fo): | ||
902 | buf += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *se_cmd)\n" | ||
903 | buf += "{\n" | ||
904 | buf += " return;\n" | ||
905 | buf += "}\n\n" | ||
906 | bufi += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *);\n" | ||
907 | |||
908 | if re.search('queue_data_in\)\(', fo): | ||
909 | buf += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *se_cmd)\n" | ||
910 | buf += "{\n" | ||
911 | buf += " return 0;\n" | ||
912 | buf += "}\n\n" | ||
913 | bufi += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *);\n" | ||
914 | |||
915 | if re.search('queue_status\)\(', fo): | ||
916 | buf += "int " + fabric_mod_name + "_queue_status(struct se_cmd *se_cmd)\n" | ||
917 | buf += "{\n" | ||
918 | buf += " return 0;\n" | ||
919 | buf += "}\n\n" | ||
920 | bufi += "int " + fabric_mod_name + "_queue_status(struct se_cmd *);\n" | ||
921 | |||
922 | if re.search('queue_tm_rsp\)\(', fo): | ||
923 | buf += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *se_cmd)\n" | ||
924 | buf += "{\n" | ||
925 | buf += " return 0;\n" | ||
926 | buf += "}\n\n" | ||
927 | bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n" | ||
928 | |||
929 | if re.search('get_fabric_sense_len\)\(', fo): | ||
930 | buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n" | ||
931 | buf += "{\n" | ||
932 | buf += " return 0;\n" | ||
933 | buf += "}\n\n" | ||
934 | bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n" | ||
935 | |||
936 | if re.search('set_fabric_sense_len\)\(', fo): | ||
937 | buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n" | ||
938 | buf += "{\n" | ||
939 | buf += " return 0;\n" | ||
940 | buf += "}\n\n" | ||
941 | bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n" | ||
942 | |||
943 | if re.search('is_state_remove\)\(', fo): | ||
944 | buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n" | ||
945 | buf += "{\n" | ||
946 | buf += " return 0;\n" | ||
947 | buf += "}\n\n" | ||
948 | bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n" | ||
949 | |||
950 | if re.search('pack_lun\)\(', fo): | ||
951 | buf += "u64 " + fabric_mod_name + "_pack_lun(unsigned int lun)\n" | ||
952 | buf += "{\n" | ||
953 | buf += " WARN_ON(lun >= 256);\n" | ||
954 | buf += " /* Caller wants this byte-swapped */\n" | ||
955 | buf += " return cpu_to_le64((lun & 0xff) << 8);\n" | ||
956 | buf += "}\n\n" | ||
957 | bufi += "u64 " + fabric_mod_name + "_pack_lun(unsigned int);\n" | ||
958 | |||
959 | |||
960 | ret = p.write(buf) | ||
961 | if ret: | ||
962 | tcm_mod_err("Unable to write f: " + f) | ||
963 | |||
964 | p.close() | ||
965 | |||
966 | ret = pi.write(bufi) | ||
967 | if ret: | ||
968 | tcm_mod_err("Unable to write fi: " + fi) | ||
969 | |||
970 | pi.close() | ||
971 | return | ||
972 | |||
973 | def tcm_mod_build_kbuild(fabric_mod_dir_var, fabric_mod_name): | ||
974 | |||
975 | buf = "" | ||
976 | f = fabric_mod_dir_var + "/Kbuild" | ||
977 | print "Writing file: " + f | ||
978 | |||
979 | p = open(f, 'w') | ||
980 | if not p: | ||
981 | tcm_mod_err("Unable to open file: " + f) | ||
982 | |||
983 | buf = "EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/include/ -I$(srctree)/drivers/scsi/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/" + fabric_mod_name + "\n\n" | ||
984 | buf += fabric_mod_name + "-objs := " + fabric_mod_name + "_fabric.o \\\n" | ||
985 | buf += " " + fabric_mod_name + "_configfs.o\n" | ||
986 | buf += "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name + ".o\n" | ||
987 | |||
988 | ret = p.write(buf) | ||
989 | if ret: | ||
990 | tcm_mod_err("Unable to write f: " + f) | ||
991 | |||
992 | p.close() | ||
993 | return | ||
994 | |||
995 | def tcm_mod_build_kconfig(fabric_mod_dir_var, fabric_mod_name): | ||
996 | |||
997 | buf = "" | ||
998 | f = fabric_mod_dir_var + "/Kconfig" | ||
999 | print "Writing file: " + f | ||
1000 | |||
1001 | p = open(f, 'w') | ||
1002 | if not p: | ||
1003 | tcm_mod_err("Unable to open file: " + f) | ||
1004 | |||
1005 | buf = "config " + fabric_mod_name.upper() + "\n" | ||
1006 | buf += " tristate \"" + fabric_mod_name.upper() + " fabric module\"\n" | ||
1007 | buf += " depends on TARGET_CORE && CONFIGFS_FS\n" | ||
1008 | buf += " default n\n" | ||
1009 | buf += " ---help---\n" | ||
1010 | buf += " Say Y here to enable the " + fabric_mod_name.upper() + " fabric module\n" | ||
1011 | |||
1012 | ret = p.write(buf) | ||
1013 | if ret: | ||
1014 | tcm_mod_err("Unable to write f: " + f) | ||
1015 | |||
1016 | p.close() | ||
1017 | return | ||
1018 | |||
1019 | def tcm_mod_add_kbuild(tcm_dir, fabric_mod_name): | ||
1020 | buf = "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name.lower() + "/\n" | ||
1021 | kbuild = tcm_dir + "/drivers/target/Kbuild" | ||
1022 | |||
1023 | f = open(kbuild, 'a') | ||
1024 | f.write(buf) | ||
1025 | f.close() | ||
1026 | return | ||
1027 | |||
1028 | def tcm_mod_add_kconfig(tcm_dir, fabric_mod_name): | ||
1029 | buf = "source \"drivers/target/" + fabric_mod_name.lower() + "/Kconfig\"\n" | ||
1030 | kconfig = tcm_dir + "/drivers/target/Kconfig" | ||
1031 | |||
1032 | f = open(kconfig, 'a') | ||
1033 | f.write(buf) | ||
1034 | f.close() | ||
1035 | return | ||
1036 | |||
1037 | def main(modname, proto_ident): | ||
1038 | # proto_ident = "FC" | ||
1039 | # proto_ident = "SAS" | ||
1040 | # proto_ident = "iSCSI" | ||
1041 | |||
1042 | tcm_dir = os.getcwd(); | ||
1043 | tcm_dir += "/../../" | ||
1044 | print "tcm_dir: " + tcm_dir | ||
1045 | fabric_mod_name = modname | ||
1046 | fabric_mod_dir = tcm_dir + "drivers/target/" + fabric_mod_name | ||
1047 | print "Set fabric_mod_name: " + fabric_mod_name | ||
1048 | print "Set fabric_mod_dir: " + fabric_mod_dir | ||
1049 | print "Using proto_ident: " + proto_ident | ||
1050 | |||
1051 | if proto_ident != "FC" and proto_ident != "SAS" and proto_ident != "iSCSI": | ||
1052 | print "Unsupported proto_ident: " + proto_ident | ||
1053 | sys.exit(1) | ||
1054 | |||
1055 | ret = tcm_mod_create_module_subdir(fabric_mod_dir) | ||
1056 | if ret: | ||
1057 | print "tcm_mod_create_module_subdir() failed because module already exists!" | ||
1058 | sys.exit(1) | ||
1059 | |||
1060 | tcm_mod_build_base_includes(proto_ident, fabric_mod_dir, fabric_mod_name) | ||
1061 | tcm_mod_scan_fabric_ops(tcm_dir) | ||
1062 | tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir, fabric_mod_name) | ||
1063 | tcm_mod_build_configfs(proto_ident, fabric_mod_dir, fabric_mod_name) | ||
1064 | tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name) | ||
1065 | tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name) | ||
1066 | |||
1067 | input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kbuild..? [yes,no]: ") | ||
1068 | if input == "yes" or input == "y": | ||
1069 | tcm_mod_add_kbuild(tcm_dir, fabric_mod_name) | ||
1070 | |||
1071 | input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kconfig..? [yes,no]: ") | ||
1072 | if input == "yes" or input == "y": | ||
1073 | tcm_mod_add_kconfig(tcm_dir, fabric_mod_name) | ||
1074 | |||
1075 | return | ||
1076 | |||
1077 | parser = optparse.OptionParser() | ||
1078 | parser.add_option('-m', '--modulename', help='Module name', dest='modname', | ||
1079 | action='store', nargs=1, type='string') | ||
1080 | parser.add_option('-p', '--protoident', help='Protocol Ident', dest='protoident', | ||
1081 | action='store', nargs=1, type='string') | ||
1082 | |||
1083 | (opts, args) = parser.parse_args() | ||
1084 | |||
1085 | mandatories = ['modname', 'protoident'] | ||
1086 | for m in mandatories: | ||
1087 | if not opts.__dict__[m]: | ||
1088 | print "mandatory option is missing\n" | ||
1089 | parser.print_help() | ||
1090 | exit(-1) | ||
1091 | |||
1092 | if __name__ == "__main__": | ||
1093 | |||
1094 | main(str(opts.modname), opts.protoident) | ||
diff --git a/Documentation/target/tcm_mod_builder.txt b/Documentation/target/tcm_mod_builder.txt new file mode 100644 index 00000000000..84533d8e747 --- /dev/null +++ b/Documentation/target/tcm_mod_builder.txt | |||
@@ -0,0 +1,145 @@ | |||
1 | >>>>>>>>>> The TCM v4 fabric module script generator <<<<<<<<<< | ||
2 | |||
3 | Greetings all, | ||
4 | |||
5 | This document is intended to be a mini-HOWTO for using the tcm_mod_builder.py | ||
6 | script to generate a brand new functional TCM v4 fabric .ko module of your very own, | ||
7 | that once built can be immediately be loaded to start access the new TCM/ConfigFS | ||
8 | fabric skeleton, by simply using: | ||
9 | |||
10 | modprobe $TCM_NEW_MOD | ||
11 | mkdir -p /sys/kernel/config/target/$TCM_NEW_MOD | ||
12 | |||
13 | This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following | ||
14 | |||
15 | *) Generate new API callers for drivers/target/target_core_fabric_configs.c logic | ||
16 | ->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg() | ||
17 | ->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c | ||
18 | *) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module | ||
19 | using a skeleton struct target_core_fabric_ops API template. | ||
20 | *) Based on user defined T10 Proto_Ident for the new fabric module being built, | ||
21 | the TransportID / Initiator and Target WWPN related handlers for | ||
22 | SPC-3 persistent reservation are automatically generated in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c | ||
23 | using drivers/target/target_core_fabric_lib.c logic. | ||
24 | *) NOP API calls for all other Data I/O path and fabric dependent attribute logic | ||
25 | in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c | ||
26 | |||
27 | tcm_mod_builder.py depends upon the mandatory '-p $PROTO_IDENT' and '-m | ||
28 | $FABRIC_MOD_name' parameters, and actually running the script looks like: | ||
29 | |||
30 | target:/mnt/sdb/lio-core-2.6.git/Documentation/target# python tcm_mod_builder.py -p iSCSI -m tcm_nab5000 | ||
31 | tcm_dir: /mnt/sdb/lio-core-2.6.git/Documentation/target/../../ | ||
32 | Set fabric_mod_name: tcm_nab5000 | ||
33 | Set fabric_mod_dir: | ||
34 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000 | ||
35 | Using proto_ident: iSCSI | ||
36 | Creating fabric_mod_dir: | ||
37 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000 | ||
38 | Writing file: | ||
39 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_base.h | ||
40 | Using tcm_mod_scan_fabric_ops: | ||
41 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../include/target/target_core_fabric_ops.h | ||
42 | Writing file: | ||
43 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.c | ||
44 | Writing file: | ||
45 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.h | ||
46 | Writing file: | ||
47 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_configfs.c | ||
48 | Writing file: | ||
49 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kbuild | ||
50 | Writing file: | ||
51 | /mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kconfig | ||
52 | Would you like to add tcm_nab5000to drivers/target/Kbuild..? [yes,no]: yes | ||
53 | Would you like to add tcm_nab5000to drivers/target/Kconfig..? [yes,no]: yes | ||
54 | |||
55 | At the end of tcm_mod_builder.py. the script will ask to add the following | ||
56 | line to drivers/target/Kbuild: | ||
57 | |||
58 | obj-$(CONFIG_TCM_NAB5000) += tcm_nab5000/ | ||
59 | |||
60 | and the same for drivers/target/Kconfig: | ||
61 | |||
62 | source "drivers/target/tcm_nab5000/Kconfig" | ||
63 | |||
64 | *) Run 'make menuconfig' and select the new CONFIG_TCM_NAB5000 item: | ||
65 | |||
66 | <M> TCM_NAB5000 fabric module | ||
67 | |||
68 | *) Build using 'make modules', once completed you will have: | ||
69 | |||
70 | target:/mnt/sdb/lio-core-2.6.git# ls -la drivers/target/tcm_nab5000/ | ||
71 | total 1348 | ||
72 | drwxr-xr-x 2 root root 4096 2010-10-05 03:23 . | ||
73 | drwxr-xr-x 9 root root 4096 2010-10-05 03:22 .. | ||
74 | -rw-r--r-- 1 root root 282 2010-10-05 03:22 Kbuild | ||
75 | -rw-r--r-- 1 root root 171 2010-10-05 03:22 Kconfig | ||
76 | -rw-r--r-- 1 root root 49 2010-10-05 03:23 modules.order | ||
77 | -rw-r--r-- 1 root root 738 2010-10-05 03:22 tcm_nab5000_base.h | ||
78 | -rw-r--r-- 1 root root 9096 2010-10-05 03:22 tcm_nab5000_configfs.c | ||
79 | -rw-r--r-- 1 root root 191200 2010-10-05 03:23 tcm_nab5000_configfs.o | ||
80 | -rw-r--r-- 1 root root 40504 2010-10-05 03:23 .tcm_nab5000_configfs.o.cmd | ||
81 | -rw-r--r-- 1 root root 5414 2010-10-05 03:22 tcm_nab5000_fabric.c | ||
82 | -rw-r--r-- 1 root root 2016 2010-10-05 03:22 tcm_nab5000_fabric.h | ||
83 | -rw-r--r-- 1 root root 190932 2010-10-05 03:23 tcm_nab5000_fabric.o | ||
84 | -rw-r--r-- 1 root root 40713 2010-10-05 03:23 .tcm_nab5000_fabric.o.cmd | ||
85 | -rw-r--r-- 1 root root 401861 2010-10-05 03:23 tcm_nab5000.ko | ||
86 | -rw-r--r-- 1 root root 265 2010-10-05 03:23 .tcm_nab5000.ko.cmd | ||
87 | -rw-r--r-- 1 root root 459 2010-10-05 03:23 tcm_nab5000.mod.c | ||
88 | -rw-r--r-- 1 root root 23896 2010-10-05 03:23 tcm_nab5000.mod.o | ||
89 | -rw-r--r-- 1 root root 22655 2010-10-05 03:23 .tcm_nab5000.mod.o.cmd | ||
90 | -rw-r--r-- 1 root root 379022 2010-10-05 03:23 tcm_nab5000.o | ||
91 | -rw-r--r-- 1 root root 211 2010-10-05 03:23 .tcm_nab5000.o.cmd | ||
92 | |||
93 | *) Load the new module, create a lun_0 configfs group, and add new TCM Core | ||
94 | IBLOCK backstore symlink to port: | ||
95 | |||
96 | target:/mnt/sdb/lio-core-2.6.git# insmod drivers/target/tcm_nab5000.ko | ||
97 | target:/mnt/sdb/lio-core-2.6.git# mkdir -p /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0 | ||
98 | target:/mnt/sdb/lio-core-2.6.git# cd /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0/ | ||
99 | target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# ln -s /sys/kernel/config/target/core/iblock_0/lvm_test0 nab5000_port | ||
100 | |||
101 | target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# cd - | ||
102 | target:/mnt/sdb/lio-core-2.6.git# tree /sys/kernel/config/target/nab5000/ | ||
103 | /sys/kernel/config/target/nab5000/ | ||
104 | |-- discovery_auth | ||
105 | |-- iqn.foo | ||
106 | | `-- tpgt_1 | ||
107 | | |-- acls | ||
108 | | |-- attrib | ||
109 | | |-- lun | ||
110 | | | `-- lun_0 | ||
111 | | | |-- alua_tg_pt_gp | ||
112 | | | |-- alua_tg_pt_offline | ||
113 | | | |-- alua_tg_pt_status | ||
114 | | | |-- alua_tg_pt_write_md | ||
115 | | | `-- nab5000_port -> ../../../../../../target/core/iblock_0/lvm_test0 | ||
116 | | |-- np | ||
117 | | `-- param | ||
118 | `-- version | ||
119 | |||
120 | target:/mnt/sdb/lio-core-2.6.git# lsmod | ||
121 | Module Size Used by | ||
122 | tcm_nab5000 3935 4 | ||
123 | iscsi_target_mod 193211 0 | ||
124 | target_core_stgt 8090 0 | ||
125 | target_core_pscsi 11122 1 | ||
126 | target_core_file 9172 2 | ||
127 | target_core_iblock 9280 1 | ||
128 | target_core_mod 228575 31 | ||
129 | tcm_nab5000,iscsi_target_mod,target_core_stgt,target_core_pscsi,target_core_file,target_core_iblock | ||
130 | libfc 73681 0 | ||
131 | scsi_debug 56265 0 | ||
132 | scsi_tgt 8666 1 target_core_stgt | ||
133 | configfs 20644 2 target_core_mod | ||
134 | |||
135 | ---------------------------------------------------------------------- | ||
136 | |||
137 | Future TODO items: | ||
138 | |||
139 | *) Add more T10 proto_idents | ||
140 | *) Make tcm_mod_dump_fabric_ops() smarter and generate function pointer | ||
141 | defs directly from include/target/target_core_fabric_ops.h:struct target_core_fabric_ops | ||
142 | structure members. | ||
143 | |||
144 | October 5th, 2010 | ||
145 | Nicholas A. Bellinger <nab@linux-iscsi.org> | ||