subsys.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * QEMU NVM Express Subsystem: nvme-subsys
  3. *
  4. * Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com>
  5. *
  6. * This code is licensed under the GNU GPL v2. Refer COPYING.
  7. */
  8. #include "qemu/osdep.h"
  9. #include "qemu/units.h"
  10. #include "qapi/error.h"
  11. #include "nvme.h"
  12. #define NVME_DEFAULT_RU_SIZE (96 * MiB)
  13. static int nvme_subsys_reserve_cntlids(NvmeCtrl *n, int start, int num)
  14. {
  15. NvmeSubsystem *subsys = n->subsys;
  16. NvmeSecCtrlEntry *list = n->sec_ctrl_list;
  17. NvmeSecCtrlEntry *sctrl;
  18. int i, cnt = 0;
  19. for (i = start; i < ARRAY_SIZE(subsys->ctrls) && cnt < num; i++) {
  20. if (!subsys->ctrls[i]) {
  21. sctrl = &list[cnt];
  22. sctrl->scid = cpu_to_le16(i);
  23. subsys->ctrls[i] = SUBSYS_SLOT_RSVD;
  24. cnt++;
  25. }
  26. }
  27. return cnt;
  28. }
  29. static void nvme_subsys_unreserve_cntlids(NvmeCtrl *n)
  30. {
  31. NvmeSubsystem *subsys = n->subsys;
  32. NvmeSecCtrlEntry *list = n->sec_ctrl_list;
  33. NvmeSecCtrlEntry *sctrl;
  34. int i, cntlid;
  35. for (i = 0; i < n->params.sriov_max_vfs; i++) {
  36. sctrl = &list[i];
  37. cntlid = le16_to_cpu(sctrl->scid);
  38. if (cntlid) {
  39. assert(subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD);
  40. subsys->ctrls[cntlid] = NULL;
  41. sctrl->scid = 0;
  42. }
  43. }
  44. }
  45. int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
  46. {
  47. NvmeSubsystem *subsys = n->subsys;
  48. NvmeSecCtrlEntry *sctrl = nvme_sctrl(n);
  49. int cntlid, num_rsvd, num_vfs = n->params.sriov_max_vfs;
  50. if (pci_is_vf(&n->parent_obj)) {
  51. cntlid = le16_to_cpu(sctrl->scid);
  52. } else {
  53. n->sec_ctrl_list = g_new0(NvmeSecCtrlEntry, num_vfs);
  54. for (cntlid = 0; cntlid < ARRAY_SIZE(subsys->ctrls); cntlid++) {
  55. if (!subsys->ctrls[cntlid]) {
  56. break;
  57. }
  58. }
  59. if (cntlid == ARRAY_SIZE(subsys->ctrls)) {
  60. error_setg(errp, "no more free controller id");
  61. return -1;
  62. }
  63. num_rsvd = nvme_subsys_reserve_cntlids(n, cntlid + 1, num_vfs);
  64. if (num_rsvd != num_vfs) {
  65. nvme_subsys_unreserve_cntlids(n);
  66. error_setg(errp,
  67. "no more free controller ids for secondary controllers");
  68. return -1;
  69. }
  70. }
  71. if (!subsys->serial) {
  72. subsys->serial = g_strdup(n->params.serial);
  73. } else if (strcmp(subsys->serial, n->params.serial)) {
  74. error_setg(errp, "invalid controller serial");
  75. return -1;
  76. }
  77. subsys->ctrls[cntlid] = n;
  78. return cntlid;
  79. }
  80. void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n)
  81. {
  82. if (pci_is_vf(&n->parent_obj)) {
  83. subsys->ctrls[n->cntlid] = SUBSYS_SLOT_RSVD;
  84. } else {
  85. subsys->ctrls[n->cntlid] = NULL;
  86. nvme_subsys_unreserve_cntlids(n);
  87. }
  88. n->cntlid = -1;
  89. }
  90. static bool nvme_calc_rgif(uint16_t nruh, uint16_t nrg, uint8_t *rgif)
  91. {
  92. uint16_t val;
  93. unsigned int i;
  94. if (unlikely(nrg == 1)) {
  95. /* PIDRG_NORGI scenario, all of pid is used for PHID */
  96. *rgif = 0;
  97. return true;
  98. }
  99. val = nrg;
  100. i = 0;
  101. while (val) {
  102. val >>= 1;
  103. i++;
  104. }
  105. *rgif = i;
  106. /* ensure remaining bits suffice to represent number of phids in a RG */
  107. if (unlikely((UINT16_MAX >> i) < nruh)) {
  108. *rgif = 0;
  109. return false;
  110. }
  111. return true;
  112. }
  113. static bool nvme_subsys_setup_fdp(NvmeSubsystem *subsys, Error **errp)
  114. {
  115. NvmeEnduranceGroup *endgrp = &subsys->endgrp;
  116. if (!subsys->params.fdp.runs) {
  117. error_setg(errp, "fdp.runs must be non-zero");
  118. return false;
  119. }
  120. endgrp->fdp.runs = subsys->params.fdp.runs;
  121. if (!subsys->params.fdp.nrg) {
  122. error_setg(errp, "fdp.nrg must be non-zero");
  123. return false;
  124. }
  125. endgrp->fdp.nrg = subsys->params.fdp.nrg;
  126. if (!subsys->params.fdp.nruh ||
  127. subsys->params.fdp.nruh > NVME_FDP_MAXPIDS) {
  128. error_setg(errp, "fdp.nruh must be non-zero and less than %u",
  129. NVME_FDP_MAXPIDS);
  130. return false;
  131. }
  132. endgrp->fdp.nruh = subsys->params.fdp.nruh;
  133. if (!nvme_calc_rgif(endgrp->fdp.nruh, endgrp->fdp.nrg, &endgrp->fdp.rgif)) {
  134. error_setg(errp,
  135. "cannot derive a valid rgif (nruh %"PRIu16" nrg %"PRIu32")",
  136. endgrp->fdp.nruh, endgrp->fdp.nrg);
  137. return false;
  138. }
  139. endgrp->fdp.ruhs = g_new(NvmeRuHandle, endgrp->fdp.nruh);
  140. for (uint16_t ruhid = 0; ruhid < endgrp->fdp.nruh; ruhid++) {
  141. endgrp->fdp.ruhs[ruhid] = (NvmeRuHandle) {
  142. .ruht = NVME_RUHT_INITIALLY_ISOLATED,
  143. .ruha = NVME_RUHA_UNUSED,
  144. };
  145. endgrp->fdp.ruhs[ruhid].rus = g_new(NvmeReclaimUnit, endgrp->fdp.nrg);
  146. }
  147. endgrp->fdp.enabled = true;
  148. return true;
  149. }
  150. static bool nvme_subsys_setup(NvmeSubsystem *subsys, Error **errp)
  151. {
  152. const char *nqn = subsys->params.nqn ?
  153. subsys->params.nqn : subsys->parent_obj.id;
  154. snprintf((char *)subsys->subnqn, sizeof(subsys->subnqn),
  155. "nqn.2019-08.org.qemu:%s", nqn);
  156. if (subsys->params.fdp.enabled && !nvme_subsys_setup_fdp(subsys, errp)) {
  157. return false;
  158. }
  159. return true;
  160. }
  161. static void nvme_subsys_realize(DeviceState *dev, Error **errp)
  162. {
  163. NvmeSubsystem *subsys = NVME_SUBSYS(dev);
  164. qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id);
  165. nvme_subsys_setup(subsys, errp);
  166. }
  167. static const Property nvme_subsystem_props[] = {
  168. DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn),
  169. DEFINE_PROP_BOOL("fdp", NvmeSubsystem, params.fdp.enabled, false),
  170. DEFINE_PROP_SIZE("fdp.runs", NvmeSubsystem, params.fdp.runs,
  171. NVME_DEFAULT_RU_SIZE),
  172. DEFINE_PROP_UINT32("fdp.nrg", NvmeSubsystem, params.fdp.nrg, 1),
  173. DEFINE_PROP_UINT16("fdp.nruh", NvmeSubsystem, params.fdp.nruh, 0),
  174. };
  175. static void nvme_subsys_class_init(ObjectClass *oc, void *data)
  176. {
  177. DeviceClass *dc = DEVICE_CLASS(oc);
  178. set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
  179. dc->realize = nvme_subsys_realize;
  180. dc->desc = "Virtual NVMe subsystem";
  181. device_class_set_props(dc, nvme_subsystem_props);
  182. }
  183. static const TypeInfo nvme_subsys_info = {
  184. .name = TYPE_NVME_SUBSYS,
  185. .parent = TYPE_DEVICE,
  186. .class_init = nvme_subsys_class_init,
  187. .instance_size = sizeof(NvmeSubsystem),
  188. };
  189. static void nvme_subsys_register_types(void)
  190. {
  191. type_register_static(&nvme_subsys_info);
  192. }
  193. type_init(nvme_subsys_register_types)