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 <linux/string.h>
23 #include <linux/slab.h>
25 #include <scsi/scsi.h>
26 #include <scsi/scsi_host.h>
27 #include <scsi/scsi_device.h>
28 #include <scsi/scsi_transport.h>
29 #include <scsi/scsi_transport_iscsi.h>
31 #define ISCSI_SESSION_ATTRS 20
32 #define ISCSI_HOST_ATTRS 2
34 struct iscsi_internal
{
35 struct scsi_transport_template t
;
36 struct iscsi_function_template
*fnt
;
38 * We do not have any private or other attrs.
40 struct class_device_attribute
*session_attrs
[ISCSI_SESSION_ATTRS
+ 1];
41 struct class_device_attribute
*host_attrs
[ISCSI_HOST_ATTRS
+ 1];
44 #define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
46 static DECLARE_TRANSPORT_CLASS(iscsi_transport_class
,
52 static DECLARE_TRANSPORT_CLASS(iscsi_host_class
,
58 * iSCSI target and session attrs
60 #define iscsi_session_show_fn(field, format) \
63 show_session_##field(struct class_device *cdev, char *buf) \
65 struct scsi_target *starget = transport_class_to_starget(cdev); \
66 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
67 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
69 if (i->fnt->get_##field) \
70 i->fnt->get_##field(starget); \
71 return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
74 #define iscsi_session_rd_attr(field, format) \
75 iscsi_session_show_fn(field, format) \
76 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
78 iscsi_session_rd_attr(tpgt
, "%hu");
79 iscsi_session_rd_attr(tsih
, "%2x");
80 iscsi_session_rd_attr(max_recv_data_segment_len
, "%u");
81 iscsi_session_rd_attr(max_burst_len
, "%u");
82 iscsi_session_rd_attr(first_burst_len
, "%u");
83 iscsi_session_rd_attr(def_time2wait
, "%hu");
84 iscsi_session_rd_attr(def_time2retain
, "%hu");
85 iscsi_session_rd_attr(max_outstanding_r2t
, "%hu");
86 iscsi_session_rd_attr(erl
, "%d");
89 #define iscsi_session_show_bool_fn(field) \
92 show_session_bool_##field(struct class_device *cdev, char *buf) \
94 struct scsi_target *starget = transport_class_to_starget(cdev); \
95 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
96 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
98 if (i->fnt->get_##field) \
99 i->fnt->get_##field(starget); \
101 if (iscsi_##field(starget)) \
102 return sprintf(buf, "Yes\n"); \
103 return sprintf(buf, "No\n"); \
106 #define iscsi_session_rd_bool_attr(field) \
107 iscsi_session_show_bool_fn(field) \
108 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
110 iscsi_session_rd_bool_attr(initial_r2t
);
111 iscsi_session_rd_bool_attr(immediate_data
);
112 iscsi_session_rd_bool_attr(data_pdu_in_order
);
113 iscsi_session_rd_bool_attr(data_sequence_in_order
);
115 #define iscsi_session_show_digest_fn(field) \
118 show_##field(struct class_device *cdev, char *buf) \
120 struct scsi_target *starget = transport_class_to_starget(cdev); \
121 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
122 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
124 if (i->fnt->get_##field) \
125 i->fnt->get_##field(starget); \
127 if (iscsi_##field(starget)) \
128 return sprintf(buf, "CRC32C\n"); \
129 return sprintf(buf, "None\n"); \
132 #define iscsi_session_rd_digest_attr(field) \
133 iscsi_session_show_digest_fn(field) \
134 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
136 iscsi_session_rd_digest_attr(header_digest
);
137 iscsi_session_rd_digest_attr(data_digest
);
140 show_port(struct class_device
*cdev
, char *buf
)
142 struct scsi_target
*starget
= transport_class_to_starget(cdev
);
143 struct Scsi_Host
*shost
= dev_to_shost(starget
->dev
.parent
);
144 struct iscsi_internal
*i
= to_iscsi_internal(shost
->transportt
);
146 if (i
->fnt
->get_port
)
147 i
->fnt
->get_port(starget
);
149 return snprintf(buf
, 20, "%hu\n", ntohs(iscsi_port(starget
)));
151 static CLASS_DEVICE_ATTR(port
, S_IRUGO
, show_port
, NULL
);
154 show_ip_address(struct class_device
*cdev
, char *buf
)
156 struct scsi_target
*starget
= transport_class_to_starget(cdev
);
157 struct Scsi_Host
*shost
= dev_to_shost(starget
->dev
.parent
);
158 struct iscsi_internal
*i
= to_iscsi_internal(shost
->transportt
);
160 if (i
->fnt
->get_ip_address
)
161 i
->fnt
->get_ip_address(starget
);
163 if (iscsi_addr_type(starget
) == AF_INET
)
164 return sprintf(buf
, "%u.%u.%u.%u\n",
165 NIPQUAD(iscsi_sin_addr(starget
)));
166 else if(iscsi_addr_type(starget
) == AF_INET6
)
167 return sprintf(buf
, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
168 NIP6(iscsi_sin6_addr(starget
)));
171 static CLASS_DEVICE_ATTR(ip_address
, S_IRUGO
, show_ip_address
, NULL
);
174 show_isid(struct class_device
*cdev
, char *buf
)
176 struct scsi_target
*starget
= transport_class_to_starget(cdev
);
177 struct Scsi_Host
*shost
= dev_to_shost(starget
->dev
.parent
);
178 struct iscsi_internal
*i
= to_iscsi_internal(shost
->transportt
);
180 if (i
->fnt
->get_isid
)
181 i
->fnt
->get_isid(starget
);
183 return sprintf(buf
, "%02x%02x%02x%02x%02x%02x\n",
184 iscsi_isid(starget
)[0], iscsi_isid(starget
)[1],
185 iscsi_isid(starget
)[2], iscsi_isid(starget
)[3],
186 iscsi_isid(starget
)[4], iscsi_isid(starget
)[5]);
188 static CLASS_DEVICE_ATTR(isid
, S_IRUGO
, show_isid
, NULL
);
191 * This is used for iSCSI names. Normally, we follow
192 * the transport class convention of having the lld
193 * set the field, but in these cases the value is
196 #define iscsi_session_show_str_fn(field) \
199 show_session_str_##field(struct class_device *cdev, char *buf) \
202 struct scsi_target *starget = transport_class_to_starget(cdev); \
203 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
204 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
206 if (i->fnt->get_##field) \
207 ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
211 #define iscsi_session_rd_str_attr(field) \
212 iscsi_session_show_str_fn(field) \
213 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
215 iscsi_session_rd_str_attr(target_name
);
216 iscsi_session_rd_str_attr(target_alias
);
223 * Again, this is used for iSCSI names. Normally, we follow
224 * the transport class convention of having the lld set
225 * the field, but in these cases the value is too large.
227 #define iscsi_host_show_str_fn(field) \
230 show_host_str_##field(struct class_device *cdev, char *buf) \
233 struct Scsi_Host *shost = transport_class_to_shost(cdev); \
234 struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
236 if (i->fnt->get_##field) \
237 ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \
241 #define iscsi_host_rd_str_attr(field) \
242 iscsi_host_show_str_fn(field) \
243 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
245 iscsi_host_rd_str_attr(initiator_name
);
246 iscsi_host_rd_str_attr(initiator_alias
);
248 #define SETUP_SESSION_RD_ATTR(field) \
249 if (i->fnt->show_##field) { \
250 i->session_attrs[count] = &class_device_attr_##field; \
254 #define SETUP_HOST_RD_ATTR(field) \
255 if (i->fnt->show_##field) { \
256 i->host_attrs[count] = &class_device_attr_##field; \
260 static int iscsi_host_match(struct attribute_container
*cont
,
263 struct Scsi_Host
*shost
;
264 struct iscsi_internal
*i
;
266 if (!scsi_is_host_device(dev
))
269 shost
= dev_to_shost(dev
);
270 if (!shost
->transportt
|| shost
->transportt
->host_attrs
.ac
.class
271 != &iscsi_host_class
.class)
274 i
= to_iscsi_internal(shost
->transportt
);
276 return &i
->t
.host_attrs
.ac
== cont
;
279 static int iscsi_target_match(struct attribute_container
*cont
,
282 struct Scsi_Host
*shost
;
283 struct iscsi_internal
*i
;
285 if (!scsi_is_target_device(dev
))
288 shost
= dev_to_shost(dev
->parent
);
289 if (!shost
->transportt
|| shost
->transportt
->host_attrs
.ac
.class
290 != &iscsi_host_class
.class)
293 i
= to_iscsi_internal(shost
->transportt
);
295 return &i
->t
.target_attrs
.ac
== cont
;
298 struct scsi_transport_template
*
299 iscsi_attach_transport(struct iscsi_function_template
*fnt
)
301 struct iscsi_internal
*i
= kmalloc(sizeof(struct iscsi_internal
),
308 memset(i
, 0, sizeof(struct iscsi_internal
));
311 i
->t
.target_attrs
.ac
.attrs
= &i
->session_attrs
[0];
312 i
->t
.target_attrs
.ac
.class = &iscsi_transport_class
.class;
313 i
->t
.target_attrs
.ac
.match
= iscsi_target_match
;
314 transport_container_register(&i
->t
.target_attrs
);
315 i
->t
.target_size
= sizeof(struct iscsi_class_session
);
317 SETUP_SESSION_RD_ATTR(tsih
);
318 SETUP_SESSION_RD_ATTR(isid
);
319 SETUP_SESSION_RD_ATTR(header_digest
);
320 SETUP_SESSION_RD_ATTR(data_digest
);
321 SETUP_SESSION_RD_ATTR(target_name
);
322 SETUP_SESSION_RD_ATTR(target_alias
);
323 SETUP_SESSION_RD_ATTR(port
);
324 SETUP_SESSION_RD_ATTR(tpgt
);
325 SETUP_SESSION_RD_ATTR(ip_address
);
326 SETUP_SESSION_RD_ATTR(initial_r2t
);
327 SETUP_SESSION_RD_ATTR(immediate_data
);
328 SETUP_SESSION_RD_ATTR(max_recv_data_segment_len
);
329 SETUP_SESSION_RD_ATTR(max_burst_len
);
330 SETUP_SESSION_RD_ATTR(first_burst_len
);
331 SETUP_SESSION_RD_ATTR(def_time2wait
);
332 SETUP_SESSION_RD_ATTR(def_time2retain
);
333 SETUP_SESSION_RD_ATTR(max_outstanding_r2t
);
334 SETUP_SESSION_RD_ATTR(data_pdu_in_order
);
335 SETUP_SESSION_RD_ATTR(data_sequence_in_order
);
336 SETUP_SESSION_RD_ATTR(erl
);
338 BUG_ON(count
> ISCSI_SESSION_ATTRS
);
339 i
->session_attrs
[count
] = NULL
;
341 i
->t
.host_attrs
.ac
.attrs
= &i
->host_attrs
[0];
342 i
->t
.host_attrs
.ac
.class = &iscsi_host_class
.class;
343 i
->t
.host_attrs
.ac
.match
= iscsi_host_match
;
344 transport_container_register(&i
->t
.host_attrs
);
348 SETUP_HOST_RD_ATTR(initiator_name
);
349 SETUP_HOST_RD_ATTR(initiator_alias
);
351 BUG_ON(count
> ISCSI_HOST_ATTRS
);
352 i
->host_attrs
[count
] = NULL
;
357 EXPORT_SYMBOL(iscsi_attach_transport
);
359 void iscsi_release_transport(struct scsi_transport_template
*t
)
361 struct iscsi_internal
*i
= to_iscsi_internal(t
);
363 transport_container_unregister(&i
->t
.target_attrs
);
364 transport_container_unregister(&i
->t
.host_attrs
);
369 EXPORT_SYMBOL(iscsi_release_transport
);
371 static __init
int iscsi_transport_init(void)
373 int err
= transport_class_register(&iscsi_transport_class
);
377 return transport_class_register(&iscsi_host_class
);
380 static void __exit
iscsi_transport_exit(void)
382 transport_class_unregister(&iscsi_host_class
);
383 transport_class_unregister(&iscsi_transport_class
);
386 module_init(iscsi_transport_init
);
387 module_exit(iscsi_transport_exit
);
389 MODULE_AUTHOR("Mike Christie");
390 MODULE_DESCRIPTION("iSCSI Transport Attributes");
391 MODULE_LICENSE("GPL");