lunmgt.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * CXL Flash Device Driver
  4. *
  5. * Written by: Manoj N. Kumar <[email protected]>, IBM Corporation
  6. * Matthew R. Ochs <[email protected]>, IBM Corporation
  7. *
  8. * Copyright (C) 2015 IBM Corporation
  9. */
  10. #include <asm/unaligned.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/pci.h>
  13. #include <scsi/scsi_host.h>
  14. #include <uapi/scsi/cxlflash_ioctl.h>
  15. #include "sislite.h"
  16. #include "common.h"
  17. #include "vlun.h"
  18. #include "superpipe.h"
  19. /**
  20. * create_local() - allocate and initialize a local LUN information structure
  21. * @sdev: SCSI device associated with LUN.
  22. * @wwid: World Wide Node Name for LUN.
  23. *
  24. * Return: Allocated local llun_info structure on success, NULL on failure
  25. */
  26. static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid)
  27. {
  28. struct cxlflash_cfg *cfg = shost_priv(sdev->host);
  29. struct device *dev = &cfg->dev->dev;
  30. struct llun_info *lli = NULL;
  31. lli = kzalloc(sizeof(*lli), GFP_KERNEL);
  32. if (unlikely(!lli)) {
  33. dev_err(dev, "%s: could not allocate lli\n", __func__);
  34. goto out;
  35. }
  36. lli->sdev = sdev;
  37. lli->host_no = sdev->host->host_no;
  38. lli->in_table = false;
  39. memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
  40. out:
  41. return lli;
  42. }
  43. /**
  44. * create_global() - allocate and initialize a global LUN information structure
  45. * @sdev: SCSI device associated with LUN.
  46. * @wwid: World Wide Node Name for LUN.
  47. *
  48. * Return: Allocated global glun_info structure on success, NULL on failure
  49. */
  50. static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid)
  51. {
  52. struct cxlflash_cfg *cfg = shost_priv(sdev->host);
  53. struct device *dev = &cfg->dev->dev;
  54. struct glun_info *gli = NULL;
  55. gli = kzalloc(sizeof(*gli), GFP_KERNEL);
  56. if (unlikely(!gli)) {
  57. dev_err(dev, "%s: could not allocate gli\n", __func__);
  58. goto out;
  59. }
  60. mutex_init(&gli->mutex);
  61. memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
  62. out:
  63. return gli;
  64. }
  65. /**
  66. * lookup_local() - find a local LUN information structure by WWID
  67. * @cfg: Internal structure associated with the host.
  68. * @wwid: WWID associated with LUN.
  69. *
  70. * Return: Found local lun_info structure on success, NULL on failure
  71. */
  72. static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid)
  73. {
  74. struct llun_info *lli, *temp;
  75. list_for_each_entry_safe(lli, temp, &cfg->lluns, list)
  76. if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
  77. return lli;
  78. return NULL;
  79. }
  80. /**
  81. * lookup_global() - find a global LUN information structure by WWID
  82. * @wwid: WWID associated with LUN.
  83. *
  84. * Return: Found global lun_info structure on success, NULL on failure
  85. */
  86. static struct glun_info *lookup_global(u8 *wwid)
  87. {
  88. struct glun_info *gli, *temp;
  89. list_for_each_entry_safe(gli, temp, &global.gluns, list)
  90. if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
  91. return gli;
  92. return NULL;
  93. }
  94. /**
  95. * find_and_create_lun() - find or create a local LUN information structure
  96. * @sdev: SCSI device associated with LUN.
  97. * @wwid: WWID associated with LUN.
  98. *
  99. * The LUN is kept both in a local list (per adapter) and in a global list
  100. * (across all adapters). Certain attributes of the LUN are local to the
  101. * adapter (such as index, port selection mask, etc.).
  102. *
  103. * The block allocation map is shared across all adapters (i.e. associated
  104. * wih the global list). Since different attributes are associated with
  105. * the per adapter and global entries, allocate two separate structures for each
  106. * LUN (one local, one global).
  107. *
  108. * Keep a pointer back from the local to the global entry.
  109. *
  110. * This routine assumes the caller holds the global mutex.
  111. *
  112. * Return: Found/Allocated local lun_info structure on success, NULL on failure
  113. */
  114. static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
  115. {
  116. struct cxlflash_cfg *cfg = shost_priv(sdev->host);
  117. struct device *dev = &cfg->dev->dev;
  118. struct llun_info *lli = NULL;
  119. struct glun_info *gli = NULL;
  120. if (unlikely(!wwid))
  121. goto out;
  122. lli = lookup_local(cfg, wwid);
  123. if (lli)
  124. goto out;
  125. lli = create_local(sdev, wwid);
  126. if (unlikely(!lli))
  127. goto out;
  128. gli = lookup_global(wwid);
  129. if (gli) {
  130. lli->parent = gli;
  131. list_add(&lli->list, &cfg->lluns);
  132. goto out;
  133. }
  134. gli = create_global(sdev, wwid);
  135. if (unlikely(!gli)) {
  136. kfree(lli);
  137. lli = NULL;
  138. goto out;
  139. }
  140. lli->parent = gli;
  141. list_add(&lli->list, &cfg->lluns);
  142. list_add(&gli->list, &global.gluns);
  143. out:
  144. dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli);
  145. return lli;
  146. }
  147. /**
  148. * cxlflash_term_local_luns() - Delete all entries from local LUN list, free.
  149. * @cfg: Internal structure associated with the host.
  150. */
  151. void cxlflash_term_local_luns(struct cxlflash_cfg *cfg)
  152. {
  153. struct llun_info *lli, *temp;
  154. mutex_lock(&global.mutex);
  155. list_for_each_entry_safe(lli, temp, &cfg->lluns, list) {
  156. list_del(&lli->list);
  157. kfree(lli);
  158. }
  159. mutex_unlock(&global.mutex);
  160. }
  161. /**
  162. * cxlflash_list_init() - initializes the global LUN list
  163. */
  164. void cxlflash_list_init(void)
  165. {
  166. INIT_LIST_HEAD(&global.gluns);
  167. mutex_init(&global.mutex);
  168. global.err_page = NULL;
  169. }
  170. /**
  171. * cxlflash_term_global_luns() - frees resources associated with global LUN list
  172. */
  173. void cxlflash_term_global_luns(void)
  174. {
  175. struct glun_info *gli, *temp;
  176. mutex_lock(&global.mutex);
  177. list_for_each_entry_safe(gli, temp, &global.gluns, list) {
  178. list_del(&gli->list);
  179. cxlflash_ba_terminate(&gli->blka.ba_lun);
  180. kfree(gli);
  181. }
  182. mutex_unlock(&global.mutex);
  183. }
  184. /**
  185. * cxlflash_manage_lun() - handles LUN management activities
  186. * @sdev: SCSI device associated with LUN.
  187. * @manage: Manage ioctl data structure.
  188. *
  189. * This routine is used to notify the driver about a LUN's WWID and associate
  190. * SCSI devices (sdev) with a global LUN instance. Additionally it serves to
  191. * change a LUN's operating mode: legacy or superpipe.
  192. *
  193. * Return: 0 on success, -errno on failure
  194. */
  195. int cxlflash_manage_lun(struct scsi_device *sdev,
  196. struct dk_cxlflash_manage_lun *manage)
  197. {
  198. struct cxlflash_cfg *cfg = shost_priv(sdev->host);
  199. struct device *dev = &cfg->dev->dev;
  200. struct llun_info *lli = NULL;
  201. int rc = 0;
  202. u64 flags = manage->hdr.flags;
  203. u32 chan = sdev->channel;
  204. mutex_lock(&global.mutex);
  205. lli = find_and_create_lun(sdev, manage->wwid);
  206. dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n",
  207. __func__, get_unaligned_be64(&manage->wwid[0]),
  208. get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli);
  209. if (unlikely(!lli)) {
  210. rc = -ENOMEM;
  211. goto out;
  212. }
  213. if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) {
  214. /*
  215. * Update port selection mask based upon channel, store off LUN
  216. * in unpacked, AFU-friendly format, and hang LUN reference in
  217. * the sdev.
  218. */
  219. lli->port_sel |= CHAN2PORTMASK(chan);
  220. lli->lun_id[chan] = lun_to_lunid(sdev->lun);
  221. sdev->hostdata = lli;
  222. } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) {
  223. if (lli->parent->mode != MODE_NONE)
  224. rc = -EBUSY;
  225. else {
  226. /*
  227. * Clean up local LUN for this port and reset table
  228. * tracking when no more references exist.
  229. */
  230. sdev->hostdata = NULL;
  231. lli->port_sel &= ~CHAN2PORTMASK(chan);
  232. if (lli->port_sel == 0U)
  233. lli->in_table = false;
  234. }
  235. }
  236. dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n",
  237. __func__, lli->port_sel, chan, lli->lun_id[chan]);
  238. out:
  239. mutex_unlock(&global.mutex);
  240. dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
  241. return rc;
  242. }