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