2 * iSCSI transport class definitions
4 * Copyright (C) IBM Corporation, 2004
5 * Copyright (C) Mike Christie, 2004
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.
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.
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.
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>
28 #define ISCSI_SESSION_ATTRS 20
29 #define ISCSI_HOST_ATTRS 2
31 struct iscsi_internal
{
32 struct scsi_transport_template t
;
33 struct iscsi_function_template
*fnt
;
35 * We do not have any private or other attrs.
37 struct class_device_attribute
*session_attrs
[ISCSI_SESSION_ATTRS
+ 1];
38 struct class_device_attribute
*host_attrs
[ISCSI_HOST_ATTRS
+ 1];
41 #define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
43 static DECLARE_TRANSPORT_CLASS(iscsi_transport_class
,
49 static DECLARE_TRANSPORT_CLASS(iscsi_host_class
,
55 * iSCSI target and session attrs
57 #define iscsi_session_show_fn(field, format) \
60 show_session_##field(struct class_device *cdev, char *buf) \
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); \
66 if (i->fnt->get_##field) \
67 i->fnt->get_##field(starget); \
68 return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
71 #define iscsi_session_rd_attr(field, format) \
72 iscsi_session_show_fn(field, format) \
73 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
75 iscsi_session_rd_attr(tpgt
, "%hu");
76 iscsi_session_rd_attr(tsih
, "%2x");
77 iscsi_session_rd_attr(max_recv_data_segment_len
, "%u");
78 iscsi_session_rd_attr(max_burst_len
, "%u");
79 iscsi_session_rd_attr(first_burst_len
, "%u");
80 iscsi_session_rd_attr(def_time2wait
, "%hu");
81 iscsi_session_rd_attr(def_time2retain
, "%hu");
82 iscsi_session_rd_attr(max_outstanding_r2t
, "%hu");
83 iscsi_session_rd_attr(erl
, "%d");
86 #define iscsi_session_show_bool_fn(field) \
89 show_session_bool_##field(struct class_device *cdev, char *buf) \
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); \
95 if (i->fnt->get_##field) \
96 i->fnt->get_##field(starget); \
98 if (iscsi_##field(starget)) \
99 return sprintf(buf, "Yes\n"); \
100 return sprintf(buf, "No\n"); \
103 #define iscsi_session_rd_bool_attr(field) \
104 iscsi_session_show_bool_fn(field) \
105 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
107 iscsi_session_rd_bool_attr(initial_r2t
);
108 iscsi_session_rd_bool_attr(immediate_data
);
109 iscsi_session_rd_bool_attr(data_pdu_in_order
);
110 iscsi_session_rd_bool_attr(data_sequence_in_order
);
112 #define iscsi_session_show_digest_fn(field) \
115 show_##field(struct class_device *cdev, char *buf) \
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); \
121 if (i->fnt->get_##field) \
122 i->fnt->get_##field(starget); \
124 if (iscsi_##field(starget)) \
125 return sprintf(buf, "CRC32C\n"); \
126 return sprintf(buf, "None\n"); \
129 #define iscsi_session_rd_digest_attr(field) \
130 iscsi_session_show_digest_fn(field) \
131 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
133 iscsi_session_rd_digest_attr(header_digest
);
134 iscsi_session_rd_digest_attr(data_digest
);
137 show_port(struct class_device
*cdev
, char *buf
)
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
);
143 if (i
->fnt
->get_port
)
144 i
->fnt
->get_port(starget
);
146 return snprintf(buf
, 20, "%hu\n", ntohs(iscsi_port(starget
)));
148 static CLASS_DEVICE_ATTR(port
, S_IRUGO
, show_port
, NULL
);
151 show_ip_address(struct class_device
*cdev
, char *buf
)
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
);
157 if (i
->fnt
->get_ip_address
)
158 i
->fnt
->get_ip_address(starget
);
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
)));
168 static CLASS_DEVICE_ATTR(ip_address
, S_IRUGO
, show_ip_address
, NULL
);
171 show_isid(struct class_device
*cdev
, char *buf
)
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
);
177 if (i
->fnt
->get_isid
)
178 i
->fnt
->get_isid(starget
);
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]);
185 static CLASS_DEVICE_ATTR(isid
, S_IRUGO
, show_isid
, NULL
);
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
193 #define iscsi_session_show_str_fn(field) \
196 show_session_str_##field(struct class_device *cdev, char *buf) \
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); \
203 if (i->fnt->get_##field) \
204 ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
208 #define iscsi_session_rd_str_attr(field) \
209 iscsi_session_show_str_fn(field) \
210 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
212 iscsi_session_rd_str_attr(target_name
);
213 iscsi_session_rd_str_attr(target_alias
);
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.
224 #define iscsi_host_show_str_fn(field) \
227 show_host_str_##field(struct class_device *cdev, char *buf) \
230 struct Scsi_Host *shost = transport_class_to_shost(cdev); \
231 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
233 if (i->fnt->get_##field) \
234 ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \
238 #define iscsi_host_rd_str_attr(field) \
239 iscsi_host_show_str_fn(field) \
240 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
242 iscsi_host_rd_str_attr(initiator_name
);
243 iscsi_host_rd_str_attr(initiator_alias
);
245 #define SETUP_SESSION_RD_ATTR(field) \
246 if (i->fnt->show_##field) { \
247 i->session_attrs[count] = &class_device_attr_##field; \
251 #define SETUP_HOST_RD_ATTR(field) \
252 if (i->fnt->show_##field) { \
253 i->host_attrs[count] = &class_device_attr_##field; \
257 static int iscsi_host_match(struct attribute_container
*cont
,
260 struct Scsi_Host
*shost
;
261 struct iscsi_internal
*i
;
263 if (!scsi_is_host_device(dev
))
266 shost
= dev_to_shost(dev
);
267 if (!shost
->transportt
|| shost
->transportt
->host_attrs
.ac
.class
268 != &iscsi_host_class
.class)
271 i
= to_iscsi_internal(shost
->transportt
);
273 return &i
->t
.host_attrs
.ac
== cont
;
276 static int iscsi_target_match(struct attribute_container
*cont
,
279 struct Scsi_Host
*shost
;
280 struct iscsi_internal
*i
;
282 if (!scsi_is_target_device(dev
))
285 shost
= dev_to_shost(dev
->parent
);
286 if (!shost
->transportt
|| shost
->transportt
->host_attrs
.ac
.class
287 != &iscsi_host_class
.class)
290 i
= to_iscsi_internal(shost
->transportt
);
292 return &i
->t
.target_attrs
.ac
== cont
;
295 struct scsi_transport_template
*
296 iscsi_attach_transport(struct iscsi_function_template
*fnt
)
298 struct iscsi_internal
*i
= kmalloc(sizeof(struct iscsi_internal
),
305 memset(i
, 0, sizeof(struct iscsi_internal
));
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
);
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
);
335 BUG_ON(count
> ISCSI_SESSION_ATTRS
);
336 i
->session_attrs
[count
] = NULL
;
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
);
345 SETUP_HOST_RD_ATTR(initiator_name
);
346 SETUP_HOST_RD_ATTR(initiator_alias
);
348 BUG_ON(count
> ISCSI_HOST_ATTRS
);
349 i
->host_attrs
[count
] = NULL
;
354 EXPORT_SYMBOL(iscsi_attach_transport
);
356 void iscsi_release_transport(struct scsi_transport_template
*t
)
358 struct iscsi_internal
*i
= to_iscsi_internal(t
);
360 transport_container_unregister(&i
->t
.target_attrs
);
361 transport_container_unregister(&i
->t
.host_attrs
);
366 EXPORT_SYMBOL(iscsi_release_transport
);
368 static __init
int iscsi_transport_init(void)
370 int err
= transport_class_register(&iscsi_transport_class
);
374 return transport_class_register(&iscsi_host_class
);
377 static void __exit
iscsi_transport_exit(void)
379 transport_class_unregister(&iscsi_host_class
);
380 transport_class_unregister(&iscsi_transport_class
);
383 module_init(iscsi_transport_init
);
384 module_exit(iscsi_transport_exit
);
386 MODULE_AUTHOR("Mike Christie");
387 MODULE_DESCRIPTION("iSCSI Transport Attributes");
388 MODULE_LICENSE("GPL");