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