lunmgt.c 6.9 KB

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