aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_iscsi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/scsi_transport_iscsi.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
new file mode 100644
index 000000000000..8bb8222ea589
--- /dev/null
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -0,0 +1,388 @@
1/*
2 * iSCSI transport class definitions
3 *
4 * Copyright (C) IBM Corporation, 2004
5 * Copyright (C) Mike Christie, 2004
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21#include <linux/module.h>
22#include <scsi/scsi.h>
23#include <scsi/scsi_host.h>
24#include <scsi/scsi_device.h>
25#include <scsi/scsi_transport.h>
26#include <scsi/scsi_transport_iscsi.h>
27
28#define ISCSI_SESSION_ATTRS 20
29#define ISCSI_HOST_ATTRS 2
30
31struct iscsi_internal {
32 struct scsi_transport_template t;
33 struct iscsi_function_template *fnt;
34 /*
35 * We do not have any private or other attrs.
36 */
37 struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
38 struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
39};
40
41#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
42
43static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
44 "iscsi_transport",
45 NULL,
46 NULL,
47 NULL);
48
49static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
50 "iscsi_host",
51 NULL,
52 NULL,
53 NULL);
54/*
55 * iSCSI target and session attrs
56 */
57#define iscsi_session_show_fn(field, format) \
58 \
59static ssize_t \
60show_session_##field(struct class_device *cdev, char *buf) \
61{ \
62 struct scsi_target *starget = transport_class_to_starget(cdev); \
63 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
64 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
65 \
66 if (i->fnt->get_##field) \
67 i->fnt->get_##field(starget); \
68 return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
69}
70
71#define iscsi_session_rd_attr(field, format) \
72 iscsi_session_show_fn(field, format) \
73static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
74
75iscsi_session_rd_attr(tpgt, "%hu");
76iscsi_session_rd_attr(tsih, "%2x");
77iscsi_session_rd_attr(max_recv_data_segment_len, "%u");
78iscsi_session_rd_attr(max_burst_len, "%u");
79iscsi_session_rd_attr(first_burst_len, "%u");
80iscsi_session_rd_attr(def_time2wait, "%hu");
81iscsi_session_rd_attr(def_time2retain, "%hu");
82iscsi_session_rd_attr(max_outstanding_r2t, "%hu");
83iscsi_session_rd_attr(erl, "%d");
84
85
86#define iscsi_session_show_bool_fn(field) \
87 \
88static ssize_t \
89show_session_bool_##field(struct class_device *cdev, char *buf) \
90{ \
91 struct scsi_target *starget = transport_class_to_starget(cdev); \
92 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
93 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
94 \
95 if (i->fnt->get_##field) \
96 i->fnt->get_##field(starget); \
97 \
98 if (iscsi_##field(starget)) \
99 return sprintf(buf, "Yes\n"); \
100 return sprintf(buf, "No\n"); \
101}
102
103#define iscsi_session_rd_bool_attr(field) \
104 iscsi_session_show_bool_fn(field) \
105static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
106
107iscsi_session_rd_bool_attr(initial_r2t);
108iscsi_session_rd_bool_attr(immediate_data);
109iscsi_session_rd_bool_attr(data_pdu_in_order);
110iscsi_session_rd_bool_attr(data_sequence_in_order);
111
112#define iscsi_session_show_digest_fn(field) \
113 \
114static ssize_t \
115show_##field(struct class_device *cdev, char *buf) \
116{ \
117 struct scsi_target *starget = transport_class_to_starget(cdev); \
118 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
119 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
120 \
121 if (i->fnt->get_##field) \
122 i->fnt->get_##field(starget); \
123 \
124 if (iscsi_##field(starget)) \
125 return sprintf(buf, "CRC32C\n"); \
126 return sprintf(buf, "None\n"); \
127}
128
129#define iscsi_session_rd_digest_attr(field) \
130 iscsi_session_show_digest_fn(field) \
131static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
132
133iscsi_session_rd_digest_attr(header_digest);
134iscsi_session_rd_digest_attr(data_digest);
135
136static ssize_t
137show_port(struct class_device *cdev, char *buf)
138{
139 struct scsi_target *starget = transport_class_to_starget(cdev);
140 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
141 struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
142
143 if (i->fnt->get_port)
144 i->fnt->get_port(starget);
145
146 return snprintf(buf, 20, "%hu\n", ntohs(iscsi_port(starget)));
147}
148static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
149
150static ssize_t
151show_ip_address(struct class_device *cdev, char *buf)
152{
153 struct scsi_target *starget = transport_class_to_starget(cdev);
154 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
155 struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
156
157 if (i->fnt->get_ip_address)
158 i->fnt->get_ip_address(starget);
159
160 if (iscsi_addr_type(starget) == AF_INET)
161 return sprintf(buf, "%u.%u.%u.%u\n",
162 NIPQUAD(iscsi_sin_addr(starget)));
163 else if(iscsi_addr_type(starget) == AF_INET6)
164 return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
165 NIP6(iscsi_sin6_addr(starget)));
166 return -EINVAL;
167}
168static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL);
169
170static ssize_t
171show_isid(struct class_device *cdev, char *buf)
172{
173 struct scsi_target *starget = transport_class_to_starget(cdev);
174 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
175 struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
176
177 if (i->fnt->get_isid)
178 i->fnt->get_isid(starget);
179
180 return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
181 iscsi_isid(starget)[0], iscsi_isid(starget)[1],
182 iscsi_isid(starget)[2], iscsi_isid(starget)[3],
183 iscsi_isid(starget)[4], iscsi_isid(starget)[5]);
184}
185static CLASS_DEVICE_ATTR(isid, S_IRUGO, show_isid, NULL);
186
187/*
188 * This is used for iSCSI names. Normally, we follow
189 * the transport class convention of having the lld
190 * set the field, but in these cases the value is
191 * too large.
192 */
193#define iscsi_session_show_str_fn(field) \
194 \
195static ssize_t \
196show_session_str_##field(struct class_device *cdev, char *buf) \
197{ \
198 ssize_t ret = 0; \
199 struct scsi_target *starget = transport_class_to_starget(cdev); \
200 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
201 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
202 \
203 if (i->fnt->get_##field) \
204 ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
205 return ret; \
206}
207
208#define iscsi_session_rd_str_attr(field) \
209 iscsi_session_show_str_fn(field) \
210static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
211
212iscsi_session_rd_str_attr(target_name);
213iscsi_session_rd_str_attr(target_alias);
214
215/*
216 * iSCSI host attrs
217 */
218
219/*
220 * Again, this is used for iSCSI names. Normally, we follow
221 * the transport class convention of having the lld set
222 * the field, but in these cases the value is too large.
223 */
224#define iscsi_host_show_str_fn(field) \
225 \
226static ssize_t \
227show_host_str_##field(struct class_device *cdev, char *buf) \
228{ \
229 int ret = 0; \
230 struct Scsi_Host *shost = transport_class_to_shost(cdev); \
231 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
232 \
233 if (i->fnt->get_##field) \
234 ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \
235 return ret; \
236}
237
238#define iscsi_host_rd_str_attr(field) \
239 iscsi_host_show_str_fn(field) \
240static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
241
242iscsi_host_rd_str_attr(initiator_name);
243iscsi_host_rd_str_attr(initiator_alias);
244
245#define SETUP_SESSION_RD_ATTR(field) \
246 if (i->fnt->show_##field) { \
247 i->session_attrs[count] = &class_device_attr_##field; \
248 count++; \
249 }
250
251#define SETUP_HOST_RD_ATTR(field) \
252 if (i->fnt->show_##field) { \
253 i->host_attrs[count] = &class_device_attr_##field; \
254 count++; \
255 }
256
257static int iscsi_host_match(struct attribute_container *cont,
258 struct device *dev)
259{
260 struct Scsi_Host *shost;
261 struct iscsi_internal *i;
262
263 if (!scsi_is_host_device(dev))
264 return 0;
265
266 shost = dev_to_shost(dev);
267 if (!shost->transportt || shost->transportt->host_attrs.ac.class
268 != &iscsi_host_class.class)
269 return 0;
270
271 i = to_iscsi_internal(shost->transportt);
272
273 return &i->t.host_attrs.ac == cont;
274}
275
276static int iscsi_target_match(struct attribute_container *cont,
277 struct device *dev)
278{
279 struct Scsi_Host *shost;
280 struct iscsi_internal *i;
281
282 if (!scsi_is_target_device(dev))
283 return 0;
284
285 shost = dev_to_shost(dev->parent);
286 if (!shost->transportt || shost->transportt->host_attrs.ac.class
287 != &iscsi_host_class.class)
288 return 0;
289
290 i = to_iscsi_internal(shost->transportt);
291
292 return &i->t.target_attrs.ac == cont;
293}
294
295struct scsi_transport_template *
296iscsi_attach_transport(struct iscsi_function_template *fnt)
297{
298 struct iscsi_internal *i = kmalloc(sizeof(struct iscsi_internal),
299 GFP_KERNEL);
300 int count = 0;
301
302 if (unlikely(!i))
303 return NULL;
304
305 memset(i, 0, sizeof(struct iscsi_internal));
306 i->fnt = fnt;
307
308 i->t.target_attrs.ac.attrs = &i->session_attrs[0];
309 i->t.target_attrs.ac.class = &iscsi_transport_class.class;
310 i->t.target_attrs.ac.match = iscsi_target_match;
311 transport_container_register(&i->t.target_attrs);
312 i->t.target_size = sizeof(struct iscsi_class_session);
313
314 SETUP_SESSION_RD_ATTR(tsih);
315 SETUP_SESSION_RD_ATTR(isid);
316 SETUP_SESSION_RD_ATTR(header_digest);
317 SETUP_SESSION_RD_ATTR(data_digest);
318 SETUP_SESSION_RD_ATTR(target_name);
319 SETUP_SESSION_RD_ATTR(target_alias);
320 SETUP_SESSION_RD_ATTR(port);
321 SETUP_SESSION_RD_ATTR(tpgt);
322 SETUP_SESSION_RD_ATTR(ip_address);
323 SETUP_SESSION_RD_ATTR(initial_r2t);
324 SETUP_SESSION_RD_ATTR(immediate_data);
325 SETUP_SESSION_RD_ATTR(max_recv_data_segment_len);
326 SETUP_SESSION_RD_ATTR(max_burst_len);
327 SETUP_SESSION_RD_ATTR(first_burst_len);
328 SETUP_SESSION_RD_ATTR(def_time2wait);
329 SETUP_SESSION_RD_ATTR(def_time2retain);
330 SETUP_SESSION_RD_ATTR(max_outstanding_r2t);
331 SETUP_SESSION_RD_ATTR(data_pdu_in_order);
332 SETUP_SESSION_RD_ATTR(data_sequence_in_order);
333 SETUP_SESSION_RD_ATTR(erl);
334
335 BUG_ON(count > ISCSI_SESSION_ATTRS);
336 i->session_attrs[count] = NULL;
337
338 i->t.host_attrs.ac.attrs = &i->host_attrs[0];
339 i->t.host_attrs.ac.class = &iscsi_host_class.class;
340 i->t.host_attrs.ac.match = iscsi_host_match;
341 transport_container_register(&i->t.host_attrs);
342 i->t.host_size = 0;
343
344 count = 0;
345 SETUP_HOST_RD_ATTR(initiator_name);
346 SETUP_HOST_RD_ATTR(initiator_alias);
347
348 BUG_ON(count > ISCSI_HOST_ATTRS);
349 i->host_attrs[count] = NULL;
350
351 return &i->t;
352}
353
354EXPORT_SYMBOL(iscsi_attach_transport);
355
356void iscsi_release_transport(struct scsi_transport_template *t)
357{
358 struct iscsi_internal *i = to_iscsi_internal(t);
359
360 transport_container_unregister(&i->t.target_attrs);
361 transport_container_unregister(&i->t.host_attrs);
362
363 kfree(i);
364}
365
366EXPORT_SYMBOL(iscsi_release_transport);
367
368static __init int iscsi_transport_init(void)
369{
370 int err = transport_class_register(&iscsi_transport_class);
371
372 if (err)
373 return err;
374 return transport_class_register(&iscsi_host_class);
375}
376
377static void __exit iscsi_transport_exit(void)
378{
379 transport_class_unregister(&iscsi_host_class);
380 transport_class_unregister(&iscsi_transport_class);
381}
382
383module_init(iscsi_transport_init);
384module_exit(iscsi_transport_exit);
385
386MODULE_AUTHOR("Mike Christie");
387MODULE_DESCRIPTION("iSCSI Transport Attributes");
388MODULE_LICENSE("GPL");