mptconfig.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. /*
  2. * QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages
  3. *
  4. * Copyright (c) 2016 Red Hat, Inc.
  5. *
  6. * Author: Paolo Bonzini
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. */
  18. #include "qemu/osdep.h"
  19. #include "hw/pci/pci.h"
  20. #include "hw/scsi/scsi.h"
  21. #include "mptsas.h"
  22. #include "mpi.h"
  23. #include "trace.h"
  24. /* Generic functions for marshaling and unmarshaling. */
  25. #define repl1(x) x
  26. #define repl2(x) x x
  27. #define repl3(x) x x x
  28. #define repl4(x) x x x x
  29. #define repl5(x) x x x x x
  30. #define repl6(x) x x x x x x
  31. #define repl7(x) x x x x x x x
  32. #define repl8(x) x x x x x x x x
  33. #define repl(n, x) glue(repl, n)(x)
  34. typedef union PackValue {
  35. uint64_t ll;
  36. char *str;
  37. } PackValue;
  38. static size_t vfill(uint8_t *data, size_t size, const char *fmt, va_list ap)
  39. {
  40. size_t ofs;
  41. PackValue val;
  42. const char *p;
  43. ofs = 0;
  44. p = fmt;
  45. while (*p) {
  46. memset(&val, 0, sizeof(val));
  47. switch (*p) {
  48. case '*':
  49. p++;
  50. break;
  51. case 'b':
  52. case 'w':
  53. case 'l':
  54. val.ll = va_arg(ap, int);
  55. break;
  56. case 'q':
  57. val.ll = va_arg(ap, int64_t);
  58. break;
  59. case 's':
  60. val.str = va_arg(ap, void *);
  61. break;
  62. }
  63. switch (*p++) {
  64. case 'b':
  65. if (data) {
  66. stb_p(data + ofs, val.ll);
  67. }
  68. ofs++;
  69. break;
  70. case 'w':
  71. if (data) {
  72. stw_le_p(data + ofs, val.ll);
  73. }
  74. ofs += 2;
  75. break;
  76. case 'l':
  77. if (data) {
  78. stl_le_p(data + ofs, val.ll);
  79. }
  80. ofs += 4;
  81. break;
  82. case 'q':
  83. if (data) {
  84. stq_le_p(data + ofs, val.ll);
  85. }
  86. ofs += 8;
  87. break;
  88. case 's':
  89. {
  90. int cnt = atoi(p);
  91. if (data) {
  92. if (val.str) {
  93. strncpy((void *)data + ofs, val.str, cnt);
  94. } else {
  95. memset((void *)data + ofs, 0, cnt);
  96. }
  97. }
  98. ofs += cnt;
  99. break;
  100. }
  101. }
  102. }
  103. return ofs;
  104. }
  105. static size_t vpack(uint8_t **p_data, const char *fmt, va_list ap1)
  106. {
  107. size_t size = 0;
  108. uint8_t *data = NULL;
  109. if (p_data) {
  110. va_list ap2;
  111. va_copy(ap2, ap1);
  112. size = vfill(NULL, 0, fmt, ap2);
  113. *p_data = data = g_malloc(size);
  114. va_end(ap2);
  115. }
  116. return vfill(data, size, fmt, ap1);
  117. }
  118. static size_t fill(uint8_t *data, size_t size, const char *fmt, ...)
  119. {
  120. va_list ap;
  121. size_t ret;
  122. va_start(ap, fmt);
  123. ret = vfill(data, size, fmt, ap);
  124. va_end(ap);
  125. return ret;
  126. }
  127. /* Functions to build the page header and fill in the length, always used
  128. * through the macros.
  129. */
  130. #define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...) \
  131. mptsas_config_pack(data, "b*bbb" fmt, version, number, type, \
  132. ## __VA_ARGS__)
  133. static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...)
  134. {
  135. va_list ap;
  136. size_t ret;
  137. va_start(ap, fmt);
  138. ret = vpack(data, fmt, ap);
  139. va_end(ap);
  140. if (data) {
  141. assert(ret / 4 < 256 && (ret % 4) == 0);
  142. stb_p(*data + 1, ret / 4);
  143. }
  144. return ret;
  145. }
  146. #define MPTSAS_CONFIG_PACK_EXT(number, type, version, fmt, ...) \
  147. mptsas_config_pack_ext(data, "b*bbb*wb*b" fmt, version, number, \
  148. MPI_CONFIG_PAGETYPE_EXTENDED, type, ## __VA_ARGS__)
  149. static size_t mptsas_config_pack_ext(uint8_t **data, const char *fmt, ...)
  150. {
  151. va_list ap;
  152. size_t ret;
  153. va_start(ap, fmt);
  154. ret = vpack(data, fmt, ap);
  155. va_end(ap);
  156. if (data) {
  157. assert(ret < 65536 && (ret % 4) == 0);
  158. stw_le_p(*data + 4, ret / 4);
  159. }
  160. return ret;
  161. }
  162. /* Manufacturing pages */
  163. static
  164. size_t mptsas_config_manufacturing_0(MPTSASState *s, uint8_t **data, int address)
  165. {
  166. return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  167. "s16s8s16s16s16",
  168. "QEMU MPT Fusion",
  169. "2.5",
  170. "QEMU MPT Fusion",
  171. "QEMU",
  172. "0000111122223333");
  173. }
  174. static
  175. size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address)
  176. {
  177. /* VPD - all zeros */
  178. return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  179. "*s256");
  180. }
  181. static
  182. size_t mptsas_config_manufacturing_2(MPTSASState *s, uint8_t **data, int address)
  183. {
  184. PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
  185. return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  186. "wb*b*l",
  187. pcic->device_id, pcic->revision);
  188. }
  189. static
  190. size_t mptsas_config_manufacturing_3(MPTSASState *s, uint8_t **data, int address)
  191. {
  192. PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
  193. return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  194. "wb*b*l",
  195. pcic->device_id, pcic->revision);
  196. }
  197. static
  198. size_t mptsas_config_manufacturing_4(MPTSASState *s, uint8_t **data, int address)
  199. {
  200. /* All zeros */
  201. return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x05,
  202. "*l*b*b*b*b*b*b*w*s56*l*l*l*l*l*l"
  203. "*b*b*w*b*b*w*l*l");
  204. }
  205. static
  206. size_t mptsas_config_manufacturing_5(MPTSASState *s, uint8_t **data, int address)
  207. {
  208. return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x02,
  209. "q*b*b*w*l*l", s->sas_addr);
  210. }
  211. static
  212. size_t mptsas_config_manufacturing_6(MPTSASState *s, uint8_t **data, int address)
  213. {
  214. return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  215. "*l");
  216. }
  217. static
  218. size_t mptsas_config_manufacturing_7(MPTSASState *s, uint8_t **data, int address)
  219. {
  220. return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  221. "*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS);
  222. }
  223. static
  224. size_t mptsas_config_manufacturing_8(MPTSASState *s, uint8_t **data, int address)
  225. {
  226. return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  227. "*l");
  228. }
  229. static
  230. size_t mptsas_config_manufacturing_9(MPTSASState *s, uint8_t **data, int address)
  231. {
  232. return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  233. "*l");
  234. }
  235. static
  236. size_t mptsas_config_manufacturing_10(MPTSASState *s, uint8_t **data, int address)
  237. {
  238. return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
  239. "*l");
  240. }
  241. /* I/O unit pages */
  242. static
  243. size_t mptsas_config_io_unit_0(MPTSASState *s, uint8_t **data, int address)
  244. {
  245. PCIDevice *pci = PCI_DEVICE(s);
  246. uint64_t unique_value = 0x53504D554D4551LL; /* "QEMUMPTx" */
  247. unique_value |= (uint64_t)pci->devfn << 56;
  248. return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00,
  249. "q", unique_value);
  250. }
  251. static
  252. size_t mptsas_config_io_unit_1(MPTSASState *s, uint8_t **data, int address)
  253. {
  254. return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02, "l",
  255. 0x41 /* single function, RAID disabled */ );
  256. }
  257. static
  258. size_t mptsas_config_io_unit_2(MPTSASState *s, uint8_t **data, int address)
  259. {
  260. PCIDevice *pci = PCI_DEVICE(s);
  261. uint8_t devfn = pci->devfn;
  262. return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02,
  263. "llbbw*b*b*w*b*b*w*b*b*w*l",
  264. 0, 0x100, 0 /* pci bus? */, devfn, 0);
  265. }
  266. static
  267. size_t mptsas_config_io_unit_3(MPTSASState *s, uint8_t **data, int address)
  268. {
  269. return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x01,
  270. "*b*b*w*l");
  271. }
  272. static
  273. size_t mptsas_config_io_unit_4(MPTSASState *s, uint8_t **data, int address)
  274. {
  275. return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00, "*l*l*q");
  276. }
  277. /* I/O controller pages */
  278. static
  279. size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address)
  280. {
  281. PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
  282. return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01,
  283. "*l*lwwb*b*b*blww",
  284. pcic->vendor_id, pcic->device_id, pcic->revision,
  285. pcic->class_id, pcic->subsystem_vendor_id,
  286. pcic->subsystem_id);
  287. }
  288. static
  289. size_t mptsas_config_ioc_1(MPTSASState *s, uint8_t **data, int address)
  290. {
  291. return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC, 0x03,
  292. "*l*l*b*b*b*b");
  293. }
  294. static
  295. size_t mptsas_config_ioc_2(MPTSASState *s, uint8_t **data, int address)
  296. {
  297. return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC, 0x04,
  298. "*l*b*b*b*b");
  299. }
  300. static
  301. size_t mptsas_config_ioc_3(MPTSASState *s, uint8_t **data, int address)
  302. {
  303. return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC, 0x00,
  304. "*b*b*w");
  305. }
  306. static
  307. size_t mptsas_config_ioc_4(MPTSASState *s, uint8_t **data, int address)
  308. {
  309. return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC, 0x00,
  310. "*b*b*w");
  311. }
  312. static
  313. size_t mptsas_config_ioc_5(MPTSASState *s, uint8_t **data, int address)
  314. {
  315. return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC, 0x00,
  316. "*l*b*b*w");
  317. }
  318. static
  319. size_t mptsas_config_ioc_6(MPTSASState *s, uint8_t **data, int address)
  320. {
  321. return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_IOC, 0x01,
  322. "*l*b*b*b*b*b*b*b*b*b*b*w*l*l*l*l*b*b*w"
  323. "*w*w*w*w*l*l*l");
  324. }
  325. /* SAS I/O unit pages (extended) */
  326. #define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16
  327. #define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION 0x02
  328. #define MPI_SAS_IOUNIT0_RATE_1_5 0x08
  329. #define MPI_SAS_IOUNIT0_RATE_3_0 0x09
  330. #define MPI_SAS_DEVICE_INFO_NO_DEVICE 0x00000000
  331. #define MPI_SAS_DEVICE_INFO_END_DEVICE 0x00000001
  332. #define MPI_SAS_DEVICE_INFO_SSP_TARGET 0x00000400
  333. #define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS 0x00
  334. #define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT 0x0001
  335. #define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED 0x0002
  336. #define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT 0x0004
  337. static SCSIDevice *mptsas_phy_get_device(MPTSASState *s, int i,
  338. int *phy_handle, int *dev_handle)
  339. {
  340. SCSIDevice *d = scsi_device_find(&s->bus, 0, i, 0);
  341. if (phy_handle) {
  342. *phy_handle = i + 1;
  343. }
  344. if (dev_handle) {
  345. *dev_handle = d ? i + 1 + MPTSAS_NUM_PORTS : 0;
  346. }
  347. return d;
  348. }
  349. static
  350. size_t mptsas_config_sas_io_unit_0(MPTSASState *s, uint8_t **data, int address)
  351. {
  352. size_t size = MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x04,
  353. "*w*wb*b*w"
  354. repl(MPTSAS_NUM_PORTS, "*s16"),
  355. MPTSAS_NUM_PORTS);
  356. if (data) {
  357. size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
  358. int i;
  359. for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
  360. int phy_handle, dev_handle;
  361. SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  362. fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE,
  363. "bbbblwwl", i, 0, 0,
  364. (dev
  365. ? MPI_SAS_IOUNIT0_RATE_3_0
  366. : MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION),
  367. (dev
  368. ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
  369. : MPI_SAS_DEVICE_INFO_NO_DEVICE),
  370. dev_handle,
  371. dev_handle,
  372. 0);
  373. ofs += MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
  374. }
  375. assert(ofs == size);
  376. }
  377. return size;
  378. }
  379. #define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12
  380. static
  381. size_t mptsas_config_sas_io_unit_1(MPTSASState *s, uint8_t **data, int address)
  382. {
  383. size_t size = MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x07,
  384. "*w*w*w*wb*b*b*b"
  385. repl(MPTSAS_NUM_PORTS, "*s12"),
  386. MPTSAS_NUM_PORTS);
  387. if (data) {
  388. size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
  389. int i;
  390. for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
  391. SCSIDevice *dev = mptsas_phy_get_device(s, i, NULL, NULL);
  392. fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE,
  393. "bbbblww", i, 0, 0,
  394. (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
  395. (dev
  396. ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
  397. : MPI_SAS_DEVICE_INFO_NO_DEVICE),
  398. 0, 0);
  399. ofs += MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
  400. }
  401. assert(ofs == size);
  402. }
  403. return size;
  404. }
  405. static
  406. size_t mptsas_config_sas_io_unit_2(MPTSASState *s, uint8_t **data, int address)
  407. {
  408. return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
  409. "*b*b*w*w*w*b*b*w");
  410. }
  411. static
  412. size_t mptsas_config_sas_io_unit_3(MPTSASState *s, uint8_t **data, int address)
  413. {
  414. return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
  415. "*l*l*l*l*l*l*l*l*l");
  416. }
  417. /* SAS PHY pages (extended) */
  418. static int mptsas_phy_addr_get(MPTSASState *s, int address)
  419. {
  420. int i;
  421. if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 0) {
  422. i = address & 255;
  423. } else if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 1) {
  424. i = address & 65535;
  425. } else {
  426. return -EINVAL;
  427. }
  428. if (i >= MPTSAS_NUM_PORTS) {
  429. return -EINVAL;
  430. }
  431. return i;
  432. }
  433. static
  434. size_t mptsas_config_phy_0(MPTSASState *s, uint8_t **data, int address)
  435. {
  436. int phy_handle = -1;
  437. int dev_handle = -1;
  438. int i = mptsas_phy_addr_get(s, address);
  439. SCSIDevice *dev;
  440. if (i < 0) {
  441. trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
  442. return i;
  443. }
  444. dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  445. trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
  446. return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
  447. "w*wqwb*blbb*b*b*l",
  448. dev_handle, s->sas_addr, dev_handle, i,
  449. (dev
  450. ? MPI_SAS_DEVICE_INFO_END_DEVICE /* | MPI_SAS_DEVICE_INFO_SSP_TARGET?? */
  451. : MPI_SAS_DEVICE_INFO_NO_DEVICE),
  452. (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
  453. (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5);
  454. }
  455. static
  456. size_t mptsas_config_phy_1(MPTSASState *s, uint8_t **data, int address)
  457. {
  458. int phy_handle = -1;
  459. int dev_handle = -1;
  460. int i = mptsas_phy_addr_get(s, address);
  461. if (i < 0) {
  462. trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
  463. return i;
  464. }
  465. (void) mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  466. trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
  467. return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
  468. "*l*l*l*l*l");
  469. }
  470. /* SAS device pages (extended) */
  471. static int mptsas_device_addr_get(MPTSASState *s, int address)
  472. {
  473. uint32_t handle, i;
  474. uint32_t form = address >> MPI_SAS_PHY_PGAD_FORM_SHIFT;
  475. if (form == MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
  476. handle = address & MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK;
  477. do {
  478. if (handle == 65535) {
  479. handle = MPTSAS_NUM_PORTS + 1;
  480. } else {
  481. ++handle;
  482. }
  483. i = handle - 1 - MPTSAS_NUM_PORTS;
  484. } while (i < MPTSAS_NUM_PORTS && !scsi_device_find(&s->bus, 0, i, 0));
  485. } else if (form == MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID) {
  486. if (address & MPI_SAS_DEVICE_PGAD_BT_BUS_MASK) {
  487. return -EINVAL;
  488. }
  489. i = address & MPI_SAS_DEVICE_PGAD_BT_TID_MASK;
  490. } else if (form == MPI_SAS_DEVICE_PGAD_FORM_HANDLE) {
  491. handle = address & MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK;
  492. i = handle - 1 - MPTSAS_NUM_PORTS;
  493. } else {
  494. return -EINVAL;
  495. }
  496. if (i >= MPTSAS_NUM_PORTS) {
  497. return -EINVAL;
  498. }
  499. return i;
  500. }
  501. static
  502. size_t mptsas_config_sas_device_0(MPTSASState *s, uint8_t **data, int address)
  503. {
  504. int phy_handle = -1;
  505. int dev_handle = -1;
  506. int i = mptsas_device_addr_get(s, address);
  507. SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  508. trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 0);
  509. if (!dev) {
  510. return -ENOENT;
  511. }
  512. return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x05,
  513. "*w*wqwbbwbblwb*b",
  514. dev->wwn, phy_handle, i,
  515. MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS,
  516. dev_handle, i, 0,
  517. MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET,
  518. (MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT |
  519. MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED |
  520. MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT), i);
  521. }
  522. static
  523. size_t mptsas_config_sas_device_1(MPTSASState *s, uint8_t **data, int address)
  524. {
  525. int phy_handle = -1;
  526. int dev_handle = -1;
  527. int i = mptsas_device_addr_get(s, address);
  528. SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  529. trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 1);
  530. if (!dev) {
  531. return -ENOENT;
  532. }
  533. return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x00,
  534. "*lq*lwbb*s20",
  535. dev->wwn, dev_handle, i, 0);
  536. }
  537. static
  538. size_t mptsas_config_sas_device_2(MPTSASState *s, uint8_t **data, int address)
  539. {
  540. int phy_handle = -1;
  541. int dev_handle = -1;
  542. int i = mptsas_device_addr_get(s, address);
  543. SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
  544. trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 2);
  545. if (!dev) {
  546. return -ENOENT;
  547. }
  548. return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x01,
  549. "ql", dev->wwn, 0);
  550. }
  551. typedef struct MPTSASConfigPage {
  552. uint8_t number;
  553. uint8_t type;
  554. size_t (*mpt_config_build)(MPTSASState *s, uint8_t **data, int address);
  555. } MPTSASConfigPage;
  556. static const MPTSASConfigPage mptsas_config_pages[] = {
  557. {
  558. 0, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  559. mptsas_config_manufacturing_0,
  560. }, {
  561. 1, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  562. mptsas_config_manufacturing_1,
  563. }, {
  564. 2, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  565. mptsas_config_manufacturing_2,
  566. }, {
  567. 3, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  568. mptsas_config_manufacturing_3,
  569. }, {
  570. 4, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  571. mptsas_config_manufacturing_4,
  572. }, {
  573. 5, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  574. mptsas_config_manufacturing_5,
  575. }, {
  576. 6, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  577. mptsas_config_manufacturing_6,
  578. }, {
  579. 7, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  580. mptsas_config_manufacturing_7,
  581. }, {
  582. 8, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  583. mptsas_config_manufacturing_8,
  584. }, {
  585. 9, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  586. mptsas_config_manufacturing_9,
  587. }, {
  588. 10, MPI_CONFIG_PAGETYPE_MANUFACTURING,
  589. mptsas_config_manufacturing_10,
  590. }, {
  591. 0, MPI_CONFIG_PAGETYPE_IO_UNIT,
  592. mptsas_config_io_unit_0,
  593. }, {
  594. 1, MPI_CONFIG_PAGETYPE_IO_UNIT,
  595. mptsas_config_io_unit_1,
  596. }, {
  597. 2, MPI_CONFIG_PAGETYPE_IO_UNIT,
  598. mptsas_config_io_unit_2,
  599. }, {
  600. 3, MPI_CONFIG_PAGETYPE_IO_UNIT,
  601. mptsas_config_io_unit_3,
  602. }, {
  603. 4, MPI_CONFIG_PAGETYPE_IO_UNIT,
  604. mptsas_config_io_unit_4,
  605. }, {
  606. 0, MPI_CONFIG_PAGETYPE_IOC,
  607. mptsas_config_ioc_0,
  608. }, {
  609. 1, MPI_CONFIG_PAGETYPE_IOC,
  610. mptsas_config_ioc_1,
  611. }, {
  612. 2, MPI_CONFIG_PAGETYPE_IOC,
  613. mptsas_config_ioc_2,
  614. }, {
  615. 3, MPI_CONFIG_PAGETYPE_IOC,
  616. mptsas_config_ioc_3,
  617. }, {
  618. 4, MPI_CONFIG_PAGETYPE_IOC,
  619. mptsas_config_ioc_4,
  620. }, {
  621. 5, MPI_CONFIG_PAGETYPE_IOC,
  622. mptsas_config_ioc_5,
  623. }, {
  624. 6, MPI_CONFIG_PAGETYPE_IOC,
  625. mptsas_config_ioc_6,
  626. }, {
  627. 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
  628. mptsas_config_sas_io_unit_0,
  629. }, {
  630. 1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
  631. mptsas_config_sas_io_unit_1,
  632. }, {
  633. 2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
  634. mptsas_config_sas_io_unit_2,
  635. }, {
  636. 3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
  637. mptsas_config_sas_io_unit_3,
  638. }, {
  639. 0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
  640. mptsas_config_phy_0,
  641. }, {
  642. 1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
  643. mptsas_config_phy_1,
  644. }, {
  645. 0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
  646. mptsas_config_sas_device_0,
  647. }, {
  648. 1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
  649. mptsas_config_sas_device_1,
  650. }, {
  651. 2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
  652. mptsas_config_sas_device_2,
  653. }
  654. };
  655. static const MPTSASConfigPage *mptsas_find_config_page(int type, int number)
  656. {
  657. const MPTSASConfigPage *page;
  658. int i;
  659. for (i = 0; i < ARRAY_SIZE(mptsas_config_pages); i++) {
  660. page = &mptsas_config_pages[i];
  661. if (page->type == type && page->number == number) {
  662. return page;
  663. }
  664. }
  665. return NULL;
  666. }
  667. void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req)
  668. {
  669. PCIDevice *pci = PCI_DEVICE(s);
  670. MPIMsgConfigReply reply;
  671. const MPTSASConfigPage *page;
  672. size_t length;
  673. uint8_t type;
  674. uint8_t *data = NULL;
  675. uint32_t flags_and_length;
  676. uint32_t dmalen;
  677. uint64_t pa;
  678. mptsas_fix_config_endianness(req);
  679. QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
  680. QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
  681. /* Copy common bits from the request into the reply. */
  682. memset(&reply, 0, sizeof(reply));
  683. reply.Action = req->Action;
  684. reply.Function = req->Function;
  685. reply.MsgContext = req->MsgContext;
  686. reply.MsgLength = sizeof(reply) / 4;
  687. reply.PageType = req->PageType;
  688. reply.PageNumber = req->PageNumber;
  689. reply.PageLength = req->PageLength;
  690. reply.PageVersion = req->PageVersion;
  691. type = req->PageType & MPI_CONFIG_PAGETYPE_MASK;
  692. if (type == MPI_CONFIG_PAGETYPE_EXTENDED) {
  693. type = req->ExtPageType;
  694. if (type <= MPI_CONFIG_PAGETYPE_MASK) {
  695. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
  696. goto out;
  697. }
  698. reply.ExtPageType = req->ExtPageType;
  699. }
  700. page = mptsas_find_config_page(type, req->PageNumber);
  701. switch(req->Action) {
  702. case MPI_CONFIG_ACTION_PAGE_DEFAULT:
  703. case MPI_CONFIG_ACTION_PAGE_HEADER:
  704. case MPI_CONFIG_ACTION_PAGE_READ_NVRAM:
  705. case MPI_CONFIG_ACTION_PAGE_READ_CURRENT:
  706. case MPI_CONFIG_ACTION_PAGE_READ_DEFAULT:
  707. case MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT:
  708. case MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM:
  709. break;
  710. default:
  711. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_ACTION;
  712. goto out;
  713. }
  714. if (!page) {
  715. page = mptsas_find_config_page(type, 1);
  716. if (page) {
  717. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
  718. } else {
  719. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
  720. }
  721. goto out;
  722. }
  723. if (req->Action == MPI_CONFIG_ACTION_PAGE_DEFAULT ||
  724. req->Action == MPI_CONFIG_ACTION_PAGE_HEADER) {
  725. length = page->mpt_config_build(s, NULL, req->PageAddress);
  726. if ((ssize_t)length < 0) {
  727. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
  728. goto out;
  729. } else {
  730. goto done;
  731. }
  732. }
  733. if (req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
  734. req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
  735. length = page->mpt_config_build(s, NULL, req->PageAddress);
  736. if ((ssize_t)length < 0) {
  737. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
  738. } else {
  739. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_CANT_COMMIT;
  740. }
  741. goto out;
  742. }
  743. flags_and_length = req->PageBufferSGE.FlagsLength;
  744. dmalen = flags_and_length & MPI_SGE_LENGTH_MASK;
  745. if (dmalen == 0) {
  746. length = page->mpt_config_build(s, NULL, req->PageAddress);
  747. if ((ssize_t)length < 0) {
  748. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
  749. goto out;
  750. } else {
  751. goto done;
  752. }
  753. }
  754. if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
  755. pa = req->PageBufferSGE.u.Address64;
  756. } else {
  757. pa = req->PageBufferSGE.u.Address32;
  758. }
  759. /* Only read actions left. */
  760. length = page->mpt_config_build(s, &data, req->PageAddress);
  761. if ((ssize_t)length < 0) {
  762. reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
  763. goto out;
  764. } else {
  765. assert(data[2] == page->number);
  766. pci_dma_write(pci, pa, data, MIN(length, dmalen));
  767. goto done;
  768. }
  769. abort();
  770. done:
  771. if (type > MPI_CONFIG_PAGETYPE_MASK) {
  772. reply.ExtPageLength = length / 4;
  773. reply.ExtPageType = req->ExtPageType;
  774. } else {
  775. reply.PageLength = length / 4;
  776. }
  777. out:
  778. mptsas_fix_config_reply_endianness(&reply);
  779. mptsas_reply(s, (MPIDefaultReply *)&reply);
  780. g_free(data);
  781. }