smartpqi_sas_transport.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * driver for Microsemi PQI-based storage controllers
  3. * Copyright (c) 2016-2017 Microsemi Corporation
  4. * Copyright (c) 2016 PMC-Sierra, Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  13. * NON INFRINGEMENT. See the GNU General Public License for more details.
  14. *
  15. * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
  16. *
  17. */
  18. #include <linux/kernel.h>
  19. #include <scsi/scsi_host.h>
  20. #include <scsi/scsi_cmnd.h>
  21. #include <scsi/scsi_transport_sas.h>
  22. #include "smartpqi.h"
  23. static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port)
  24. {
  25. struct pqi_sas_phy *pqi_sas_phy;
  26. struct sas_phy *phy;
  27. pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL);
  28. if (!pqi_sas_phy)
  29. return NULL;
  30. phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev,
  31. pqi_sas_port->next_phy_index);
  32. if (!phy) {
  33. kfree(pqi_sas_phy);
  34. return NULL;
  35. }
  36. pqi_sas_port->next_phy_index++;
  37. pqi_sas_phy->phy = phy;
  38. pqi_sas_phy->parent_port = pqi_sas_port;
  39. return pqi_sas_phy;
  40. }
  41. static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy)
  42. {
  43. struct sas_phy *phy = pqi_sas_phy->phy;
  44. sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy);
  45. sas_phy_free(phy);
  46. if (pqi_sas_phy->added_to_port)
  47. list_del(&pqi_sas_phy->phy_list_entry);
  48. kfree(pqi_sas_phy);
  49. }
  50. static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy)
  51. {
  52. int rc;
  53. struct pqi_sas_port *pqi_sas_port;
  54. struct sas_phy *phy;
  55. struct sas_identify *identify;
  56. pqi_sas_port = pqi_sas_phy->parent_port;
  57. phy = pqi_sas_phy->phy;
  58. identify = &phy->identify;
  59. memset(identify, 0, sizeof(*identify));
  60. identify->sas_address = pqi_sas_port->sas_address;
  61. identify->device_type = SAS_END_DEVICE;
  62. identify->initiator_port_protocols = SAS_PROTOCOL_STP;
  63. identify->target_port_protocols = SAS_PROTOCOL_STP;
  64. phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
  65. phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
  66. phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
  67. phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
  68. phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
  69. rc = sas_phy_add(pqi_sas_phy->phy);
  70. if (rc)
  71. return rc;
  72. sas_port_add_phy(pqi_sas_port->port, pqi_sas_phy->phy);
  73. list_add_tail(&pqi_sas_phy->phy_list_entry,
  74. &pqi_sas_port->phy_list_head);
  75. pqi_sas_phy->added_to_port = true;
  76. return 0;
  77. }
  78. static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port,
  79. struct sas_rphy *rphy)
  80. {
  81. struct sas_identify *identify;
  82. identify = &rphy->identify;
  83. identify->sas_address = pqi_sas_port->sas_address;
  84. identify->initiator_port_protocols = SAS_PROTOCOL_STP;
  85. identify->target_port_protocols = SAS_PROTOCOL_STP;
  86. return sas_rphy_add(rphy);
  87. }
  88. static struct pqi_sas_port *pqi_alloc_sas_port(
  89. struct pqi_sas_node *pqi_sas_node, u64 sas_address)
  90. {
  91. int rc;
  92. struct pqi_sas_port *pqi_sas_port;
  93. struct sas_port *port;
  94. pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL);
  95. if (!pqi_sas_port)
  96. return NULL;
  97. INIT_LIST_HEAD(&pqi_sas_port->phy_list_head);
  98. pqi_sas_port->parent_node = pqi_sas_node;
  99. port = sas_port_alloc_num(pqi_sas_node->parent_dev);
  100. if (!port)
  101. goto free_pqi_port;
  102. rc = sas_port_add(port);
  103. if (rc)
  104. goto free_sas_port;
  105. pqi_sas_port->port = port;
  106. pqi_sas_port->sas_address = sas_address;
  107. list_add_tail(&pqi_sas_port->port_list_entry,
  108. &pqi_sas_node->port_list_head);
  109. return pqi_sas_port;
  110. free_sas_port:
  111. sas_port_free(port);
  112. free_pqi_port:
  113. kfree(pqi_sas_port);
  114. return NULL;
  115. }
  116. static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port)
  117. {
  118. struct pqi_sas_phy *pqi_sas_phy;
  119. struct pqi_sas_phy *next;
  120. list_for_each_entry_safe(pqi_sas_phy, next,
  121. &pqi_sas_port->phy_list_head, phy_list_entry)
  122. pqi_free_sas_phy(pqi_sas_phy);
  123. sas_port_delete(pqi_sas_port->port);
  124. list_del(&pqi_sas_port->port_list_entry);
  125. kfree(pqi_sas_port);
  126. }
  127. static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev)
  128. {
  129. struct pqi_sas_node *pqi_sas_node;
  130. pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL);
  131. if (pqi_sas_node) {
  132. pqi_sas_node->parent_dev = parent_dev;
  133. INIT_LIST_HEAD(&pqi_sas_node->port_list_head);
  134. }
  135. return pqi_sas_node;
  136. }
  137. static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node)
  138. {
  139. struct pqi_sas_port *pqi_sas_port;
  140. struct pqi_sas_port *next;
  141. if (!pqi_sas_node)
  142. return;
  143. list_for_each_entry_safe(pqi_sas_port, next,
  144. &pqi_sas_node->port_list_head, port_list_entry)
  145. pqi_free_sas_port(pqi_sas_port);
  146. kfree(pqi_sas_node);
  147. }
  148. struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
  149. struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy)
  150. {
  151. struct pqi_scsi_dev *device;
  152. list_for_each_entry(device, &ctrl_info->scsi_device_list,
  153. scsi_device_list_entry) {
  154. if (!device->sas_port)
  155. continue;
  156. if (device->sas_port->rphy == rphy)
  157. return device;
  158. }
  159. return NULL;
  160. }
  161. int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info)
  162. {
  163. int rc;
  164. struct device *parent_dev;
  165. struct pqi_sas_node *pqi_sas_node;
  166. struct pqi_sas_port *pqi_sas_port;
  167. struct pqi_sas_phy *pqi_sas_phy;
  168. parent_dev = &shost->shost_gendev;
  169. pqi_sas_node = pqi_alloc_sas_node(parent_dev);
  170. if (!pqi_sas_node)
  171. return -ENOMEM;
  172. pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, ctrl_info->sas_address);
  173. if (!pqi_sas_port) {
  174. rc = -ENODEV;
  175. goto free_sas_node;
  176. }
  177. pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port);
  178. if (!pqi_sas_phy) {
  179. rc = -ENODEV;
  180. goto free_sas_port;
  181. }
  182. rc = pqi_sas_port_add_phy(pqi_sas_phy);
  183. if (rc)
  184. goto free_sas_phy;
  185. ctrl_info->sas_host = pqi_sas_node;
  186. return 0;
  187. free_sas_phy:
  188. pqi_free_sas_phy(pqi_sas_phy);
  189. free_sas_port:
  190. pqi_free_sas_port(pqi_sas_port);
  191. free_sas_node:
  192. pqi_free_sas_node(pqi_sas_node);
  193. return rc;
  194. }
  195. void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info)
  196. {
  197. pqi_free_sas_node(ctrl_info->sas_host);
  198. }
  199. int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
  200. struct pqi_scsi_dev *device)
  201. {
  202. int rc;
  203. struct pqi_sas_port *pqi_sas_port;
  204. struct sas_rphy *rphy;
  205. pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, device->sas_address);
  206. if (!pqi_sas_port)
  207. return -ENOMEM;
  208. rphy = sas_end_device_alloc(pqi_sas_port->port);
  209. if (!rphy) {
  210. rc = -ENODEV;
  211. goto free_sas_port;
  212. }
  213. pqi_sas_port->rphy = rphy;
  214. device->sas_port = pqi_sas_port;
  215. rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy);
  216. if (rc)
  217. goto free_sas_port;
  218. return 0;
  219. free_sas_port:
  220. pqi_free_sas_port(pqi_sas_port);
  221. device->sas_port = NULL;
  222. return rc;
  223. }
  224. void pqi_remove_sas_device(struct pqi_scsi_dev *device)
  225. {
  226. if (device->sas_port) {
  227. pqi_free_sas_port(device->sas_port);
  228. device->sas_port = NULL;
  229. }
  230. }
  231. static int pqi_sas_get_linkerrors(struct sas_phy *phy)
  232. {
  233. return 0;
  234. }
  235. static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
  236. u64 *identifier)
  237. {
  238. return 0;
  239. }
  240. static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
  241. {
  242. return -ENXIO;
  243. }
  244. static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset)
  245. {
  246. return 0;
  247. }
  248. static int pqi_sas_phy_enable(struct sas_phy *phy, int enable)
  249. {
  250. return 0;
  251. }
  252. static int pqi_sas_phy_setup(struct sas_phy *phy)
  253. {
  254. return 0;
  255. }
  256. static void pqi_sas_phy_release(struct sas_phy *phy)
  257. {
  258. }
  259. static int pqi_sas_phy_speed(struct sas_phy *phy,
  260. struct sas_phy_linkrates *rates)
  261. {
  262. return -EINVAL;
  263. }
  264. struct sas_function_template pqi_sas_transport_functions = {
  265. .get_linkerrors = pqi_sas_get_linkerrors,
  266. .get_enclosure_identifier = pqi_sas_get_enclosure_identifier,
  267. .get_bay_identifier = pqi_sas_get_bay_identifier,
  268. .phy_reset = pqi_sas_phy_reset,
  269. .phy_enable = pqi_sas_phy_enable,
  270. .phy_setup = pqi_sas_phy_setup,
  271. .phy_release = pqi_sas_phy_release,
  272. .set_phy_speed = pqi_sas_phy_speed,
  273. };