xref: /openbmc/linux/drivers/scsi/scsi_transport_iscsi.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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 
31 struct 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 
43 static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
44 			       "iscsi_transport",
45 			       NULL,
46 			       NULL,
47 			       NULL);
48 
49 static 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 									\
59 static ssize_t								\
60 show_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)				\
73 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
74 
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");
84 
85 
86 #define iscsi_session_show_bool_fn(field)				\
87 									\
88 static ssize_t								\
89 show_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)				\
105 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
106 
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);
111 
112 #define iscsi_session_show_digest_fn(field)				\
113 									\
114 static ssize_t								\
115 show_##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)				\
131 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
132 
133 iscsi_session_rd_digest_attr(header_digest);
134 iscsi_session_rd_digest_attr(data_digest);
135 
136 static ssize_t
137 show_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 }
148 static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
149 
150 static ssize_t
151 show_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 }
168 static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL);
169 
170 static ssize_t
171 show_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 }
185 static 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 									\
195 static ssize_t								\
196 show_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)				\
210 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
211 
212 iscsi_session_rd_str_attr(target_name);
213 iscsi_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 									\
226 static ssize_t								\
227 show_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)					\
240 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
241 
242 iscsi_host_rd_str_attr(initiator_name);
243 iscsi_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 
257 static 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 
276 static 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 
295 struct scsi_transport_template *
296 iscsi_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 
354 EXPORT_SYMBOL(iscsi_attach_transport);
355 
356 void 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 
366 EXPORT_SYMBOL(iscsi_release_transport);
367 
368 static __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 
377 static void __exit iscsi_transport_exit(void)
378 {
379 	transport_class_unregister(&iscsi_host_class);
380 	transport_class_unregister(&iscsi_transport_class);
381 }
382 
383 module_init(iscsi_transport_init);
384 module_exit(iscsi_transport_exit);
385 
386 MODULE_AUTHOR("Mike Christie");
387 MODULE_DESCRIPTION("iSCSI Transport Attributes");
388 MODULE_LICENSE("GPL");
389