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