scsi_transport_iscsi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. #define ISCSI_SESSION_ATTRS 20
  28. #define ISCSI_HOST_ATTRS 2
  29. struct iscsi_internal {
  30. struct scsi_transport_template t;
  31. struct iscsi_function_template *fnt;
  32. /*
  33. * We do not have any private or other attrs.
  34. */
  35. struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
  36. struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
  37. };
  38. #define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
  39. static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
  40. "iscsi_transport",
  41. NULL,
  42. NULL,
  43. NULL);
  44. static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
  45. "iscsi_host",
  46. NULL,
  47. NULL,
  48. NULL);
  49. /*
  50. * iSCSI target and session attrs
  51. */
  52. #define iscsi_session_show_fn(field, format) \
  53. \
  54. static ssize_t \
  55. show_session_##field(struct class_device *cdev, char *buf) \
  56. { \
  57. struct scsi_target *starget = transport_class_to_starget(cdev); \
  58. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
  59. struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
  60. \
  61. if (i->fnt->get_##field) \
  62. i->fnt->get_##field(starget); \
  63. return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
  64. }
  65. #define iscsi_session_rd_attr(field, format) \
  66. iscsi_session_show_fn(field, format) \
  67. static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
  68. iscsi_session_rd_attr(tpgt, "%hu");
  69. iscsi_session_rd_attr(tsih, "%2x");
  70. iscsi_session_rd_attr(max_recv_data_segment_len, "%u");
  71. iscsi_session_rd_attr(max_burst_len, "%u");
  72. iscsi_session_rd_attr(first_burst_len, "%u");
  73. iscsi_session_rd_attr(def_time2wait, "%hu");
  74. iscsi_session_rd_attr(def_time2retain, "%hu");
  75. iscsi_session_rd_attr(max_outstanding_r2t, "%hu");
  76. iscsi_session_rd_attr(erl, "%d");
  77. #define iscsi_session_show_bool_fn(field) \
  78. \
  79. static ssize_t \
  80. show_session_bool_##field(struct class_device *cdev, char *buf) \
  81. { \
  82. struct scsi_target *starget = transport_class_to_starget(cdev); \
  83. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
  84. struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
  85. \
  86. if (i->fnt->get_##field) \
  87. i->fnt->get_##field(starget); \
  88. \
  89. if (iscsi_##field(starget)) \
  90. return sprintf(buf, "Yes\n"); \
  91. return sprintf(buf, "No\n"); \
  92. }
  93. #define iscsi_session_rd_bool_attr(field) \
  94. iscsi_session_show_bool_fn(field) \
  95. static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
  96. iscsi_session_rd_bool_attr(initial_r2t);
  97. iscsi_session_rd_bool_attr(immediate_data);
  98. iscsi_session_rd_bool_attr(data_pdu_in_order);
  99. iscsi_session_rd_bool_attr(data_sequence_in_order);
  100. #define iscsi_session_show_digest_fn(field) \
  101. \
  102. static ssize_t \
  103. show_##field(struct class_device *cdev, char *buf) \
  104. { \
  105. struct scsi_target *starget = transport_class_to_starget(cdev); \
  106. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
  107. struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
  108. \
  109. if (i->fnt->get_##field) \
  110. i->fnt->get_##field(starget); \
  111. \
  112. if (iscsi_##field(starget)) \
  113. return sprintf(buf, "CRC32C\n"); \
  114. return sprintf(buf, "None\n"); \
  115. }
  116. #define iscsi_session_rd_digest_attr(field) \
  117. iscsi_session_show_digest_fn(field) \
  118. static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
  119. iscsi_session_rd_digest_attr(header_digest);
  120. iscsi_session_rd_digest_attr(data_digest);
  121. static ssize_t
  122. show_port(struct class_device *cdev, char *buf)
  123. {
  124. struct scsi_target *starget = transport_class_to_starget(cdev);
  125. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  126. struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
  127. if (i->fnt->get_port)
  128. i->fnt->get_port(starget);
  129. return snprintf(buf, 20, "%hu\n", ntohs(iscsi_port(starget)));
  130. }
  131. static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
  132. static ssize_t
  133. show_ip_address(struct class_device *cdev, char *buf)
  134. {
  135. struct scsi_target *starget = transport_class_to_starget(cdev);
  136. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  137. struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
  138. if (i->fnt->get_ip_address)
  139. i->fnt->get_ip_address(starget);
  140. if (iscsi_addr_type(starget) == AF_INET)
  141. return sprintf(buf, "%u.%u.%u.%u\n",
  142. NIPQUAD(iscsi_sin_addr(starget)));
  143. else if(iscsi_addr_type(starget) == AF_INET6)
  144. return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  145. NIP6(iscsi_sin6_addr(starget)));
  146. return -EINVAL;
  147. }
  148. static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL);
  149. static ssize_t
  150. show_isid(struct class_device *cdev, char *buf)
  151. {
  152. struct scsi_target *starget = transport_class_to_starget(cdev);
  153. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  154. struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
  155. if (i->fnt->get_isid)
  156. i->fnt->get_isid(starget);
  157. return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
  158. iscsi_isid(starget)[0], iscsi_isid(starget)[1],
  159. iscsi_isid(starget)[2], iscsi_isid(starget)[3],
  160. iscsi_isid(starget)[4], iscsi_isid(starget)[5]);
  161. }
  162. static CLASS_DEVICE_ATTR(isid, S_IRUGO, show_isid, NULL);
  163. /*
  164. * This is used for iSCSI names. Normally, we follow
  165. * the transport class convention of having the lld
  166. * set the field, but in these cases the value is
  167. * too large.
  168. */
  169. #define iscsi_session_show_str_fn(field) \
  170. \
  171. static ssize_t \
  172. show_session_str_##field(struct class_device *cdev, char *buf) \
  173. { \
  174. ssize_t ret = 0; \
  175. struct scsi_target *starget = transport_class_to_starget(cdev); \
  176. struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
  177. struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
  178. \
  179. if (i->fnt->get_##field) \
  180. ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
  181. return ret; \
  182. }
  183. #define iscsi_session_rd_str_attr(field) \
  184. iscsi_session_show_str_fn(field) \
  185. static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
  186. iscsi_session_rd_str_attr(target_name);
  187. iscsi_session_rd_str_attr(target_alias);
  188. /*
  189. * iSCSI host attrs
  190. */
  191. /*
  192. * Again, this is used for iSCSI names. Normally, we follow
  193. * the transport class convention of having the lld set
  194. * the field, but in these cases the value is too large.
  195. */
  196. #define iscsi_host_show_str_fn(field) \
  197. \
  198. static ssize_t \
  199. show_host_str_##field(struct class_device *cdev, char *buf) \
  200. { \
  201. int ret = 0; \
  202. struct Scsi_Host *shost = transport_class_to_shost(cdev); \
  203. struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
  204. \
  205. if (i->fnt->get_##field) \
  206. ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \
  207. return ret; \
  208. }
  209. #define iscsi_host_rd_str_attr(field) \
  210. iscsi_host_show_str_fn(field) \
  211. static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
  212. iscsi_host_rd_str_attr(initiator_name);
  213. iscsi_host_rd_str_attr(initiator_alias);
  214. #define SETUP_SESSION_RD_ATTR(field) \
  215. if (i->fnt->show_##field) { \
  216. i->session_attrs[count] = &class_device_attr_##field; \
  217. count++; \
  218. }
  219. #define SETUP_HOST_RD_ATTR(field) \
  220. if (i->fnt->show_##field) { \
  221. i->host_attrs[count] = &class_device_attr_##field; \
  222. count++; \
  223. }
  224. static int iscsi_host_match(struct attribute_container *cont,
  225. struct device *dev)
  226. {
  227. struct Scsi_Host *shost;
  228. struct iscsi_internal *i;
  229. if (!scsi_is_host_device(dev))
  230. return 0;
  231. shost = dev_to_shost(dev);
  232. if (!shost->transportt || shost->transportt->host_attrs.ac.class
  233. != &iscsi_host_class.class)
  234. return 0;
  235. i = to_iscsi_internal(shost->transportt);
  236. return &i->t.host_attrs.ac == cont;
  237. }
  238. static int iscsi_target_match(struct attribute_container *cont,
  239. struct device *dev)
  240. {
  241. struct Scsi_Host *shost;
  242. struct iscsi_internal *i;
  243. if (!scsi_is_target_device(dev))
  244. return 0;
  245. shost = dev_to_shost(dev->parent);
  246. if (!shost->transportt || shost->transportt->host_attrs.ac.class
  247. != &iscsi_host_class.class)
  248. return 0;
  249. i = to_iscsi_internal(shost->transportt);
  250. return &i->t.target_attrs.ac == cont;
  251. }
  252. struct scsi_transport_template *
  253. iscsi_attach_transport(struct iscsi_function_template *fnt)
  254. {
  255. struct iscsi_internal *i = kmalloc(sizeof(struct iscsi_internal),
  256. GFP_KERNEL);
  257. int count = 0;
  258. if (unlikely(!i))
  259. return NULL;
  260. memset(i, 0, sizeof(struct iscsi_internal));
  261. i->fnt = fnt;
  262. i->t.target_attrs.ac.attrs = &i->session_attrs[0];
  263. i->t.target_attrs.ac.class = &iscsi_transport_class.class;
  264. i->t.target_attrs.ac.match = iscsi_target_match;
  265. transport_container_register(&i->t.target_attrs);
  266. i->t.target_size = sizeof(struct iscsi_class_session);
  267. SETUP_SESSION_RD_ATTR(tsih);
  268. SETUP_SESSION_RD_ATTR(isid);
  269. SETUP_SESSION_RD_ATTR(header_digest);
  270. SETUP_SESSION_RD_ATTR(data_digest);
  271. SETUP_SESSION_RD_ATTR(target_name);
  272. SETUP_SESSION_RD_ATTR(target_alias);
  273. SETUP_SESSION_RD_ATTR(port);
  274. SETUP_SESSION_RD_ATTR(tpgt);
  275. SETUP_SESSION_RD_ATTR(ip_address);
  276. SETUP_SESSION_RD_ATTR(initial_r2t);
  277. SETUP_SESSION_RD_ATTR(immediate_data);
  278. SETUP_SESSION_RD_ATTR(max_recv_data_segment_len);
  279. SETUP_SESSION_RD_ATTR(max_burst_len);
  280. SETUP_SESSION_RD_ATTR(first_burst_len);
  281. SETUP_SESSION_RD_ATTR(def_time2wait);
  282. SETUP_SESSION_RD_ATTR(def_time2retain);
  283. SETUP_SESSION_RD_ATTR(max_outstanding_r2t);
  284. SETUP_SESSION_RD_ATTR(data_pdu_in_order);
  285. SETUP_SESSION_RD_ATTR(data_sequence_in_order);
  286. SETUP_SESSION_RD_ATTR(erl);
  287. BUG_ON(count > ISCSI_SESSION_ATTRS);
  288. i->session_attrs[count] = NULL;
  289. i->t.host_attrs.ac.attrs = &i->host_attrs[0];
  290. i->t.host_attrs.ac.class = &iscsi_host_class.class;
  291. i->t.host_attrs.ac.match = iscsi_host_match;
  292. transport_container_register(&i->t.host_attrs);
  293. i->t.host_size = 0;
  294. count = 0;
  295. SETUP_HOST_RD_ATTR(initiator_name);
  296. SETUP_HOST_RD_ATTR(initiator_alias);
  297. BUG_ON(count > ISCSI_HOST_ATTRS);
  298. i->host_attrs[count] = NULL;
  299. return &i->t;
  300. }
  301. EXPORT_SYMBOL(iscsi_attach_transport);
  302. void iscsi_release_transport(struct scsi_transport_template *t)
  303. {
  304. struct iscsi_internal *i = to_iscsi_internal(t);
  305. transport_container_unregister(&i->t.target_attrs);
  306. transport_container_unregister(&i->t.host_attrs);
  307. kfree(i);
  308. }
  309. EXPORT_SYMBOL(iscsi_release_transport);
  310. static __init int iscsi_transport_init(void)
  311. {
  312. int err = transport_class_register(&iscsi_transport_class);
  313. if (err)
  314. return err;
  315. return transport_class_register(&iscsi_host_class);
  316. }
  317. static void __exit iscsi_transport_exit(void)
  318. {
  319. transport_class_unregister(&iscsi_host_class);
  320. transport_class_unregister(&iscsi_transport_class);
  321. }
  322. module_init(iscsi_transport_init);
  323. module_exit(iscsi_transport_exit);
  324. MODULE_AUTHOR("Mike Christie");
  325. MODULE_DESCRIPTION("iSCSI Transport Attributes");
  326. MODULE_LICENSE("GPL");