1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* PMC 8x6G IOMB Definitions
*/
#ifndef _PMCS_IOMB_H
#define _PMCS_IOMB_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* An IOMB (IO Message Buffer) is the principle means of communication
* between the PMC and the HOST. The host places IOMBs on the Inbound
* Queues (IQ) which are in HOST memory and updates a producer index
* within the PMC. The PMC pulls the IOMB off the IQ and updates a
* consumer index in HOST memory. If appropriate, when the PMC is
* done with the action requested by the IOMB, the PMC writes a
* reply IOMB to host memory and updates its producer index and
* interrupts the HOST.
*/
/*
* The first word of all IOMBs is always laid out thusly:
*
* |Byte 3 |Byte 2 |Byte 1 |Byte 0 |
* +-------------+-------------+----------------------+
* |V Resvd BC|Resvd OBID |CAT | OPCODE |
* +--------------------------------------------------+
*
* V == Valid
* BC = Buffer Count
* OBID = Outbound Queue ID
* CAT = Category
* OPCODE = Well, uh, OPCODE.
*/
#define PMCS_IOMB_VALID (1U << 31)
#define PMCS_IOMB_HIPRI (1U << 30)
#define PMCS_IOMB_BC_SHIFT (24)
#define PMCS_IOMB_BC_MASK (0xf << PMCS_IOMB_BC_SHIFT)
#define PMCS_IOMB_OBID_SHIFT (16)
#define PMCS_IOMB_OBID_MASK (0xf << PMCS_IOMB_OBID_SHIFT)
#define PMCS_IOMB_CAT_SHIFT (12)
#define PMCS_IOMB_CAT_MASK (0xf << PMCS_IOMB_CAT_SHIFT)
#define PMCS_IOMB_OPCODE_MASK (0xfff)
#define PMCS_IOMB_CAT_NET 0
#define PMCS_IOMB_CAT_FC 1
#define PMCS_IOMB_CAT_SAS 2
#define PMCS_IOMB_CAT_SCSI 3
/*
* Shorthand
*/
#define PMCS_IOMB_IN_SAS(q, opcode) \
(PMCS_IOMB_VALID | (1 << PMCS_IOMB_BC_SHIFT) | \
(PMCS_IOMB_CAT_SAS << PMCS_IOMB_CAT_SHIFT) | \
((q << PMCS_IOMB_OBID_SHIFT) & PMCS_IOMB_OBID_MASK) | \
(opcode & PMCS_IOMB_OPCODE_MASK))
/*
* PMC IOMB Inbound Queue Opcodes
*/
#define PMCIN_ECHO 0x01
#define PMCIN_GET_INFO 0x02
#define PMCIN_GET_VPD 0x03
#define PMCIN_PHY_START 0x04
#define PMCIN_PHY_STOP 0x05
#define PMCIN_SSP_INI_IO_START 0x06
#define PMCIN_SSP_INI_TM_START 0x07
#define PMCIN_SSP_INI_EXT_IO_START 0x08
#define PMCIN_DEVICE_HANDLE_ACCEPT 0x09
#define PMCIN_SSP_TGT_IO_START 0x0A
#define PMCIN_SSP_TGT_RESPONSE_START 0x0B
#define PMCIN_SSP_INI_EDC_EXT_IO_START 0x0C
#define PMCIN_SSP_INI_EDC_EXT_IO_START1 0x0D
#define PMCIN_SSP_TGT_EDC_IO_START 0x0E
#define PMCIN_SSP_ABORT 0x0F
#define PMCIN_DEREGISTER_DEVICE_HANDLE 0x10
#define PMCIN_GET_DEVICE_HANDLE 0x11
#define PMCIN_SMP_REQUEST 0x12
#define PMCIN_SMP_RESPONSE 0x13
#define PMCIN_SMP_ABORT 0x14
#define PMCIN_ASSISTED_DISCOVERY 0x15
#define PMCIN_REGISTER_DEVICE 0x16
#define PMCIN_SATA_HOST_IO_START 0x17
#define PMCIN_SATA_ABORT 0x18
#define PMCIN_LOCAL_PHY_CONTROL 0x19
#define PMCIN_GET_DEVICE_INFO 0x1A
#define PMCIN_TWI 0x1B
#define PMCIN_FW_FLASH_UPDATE 0x20
#define PMCIN_SET_VPD 0x21
#define PMCIN_GPIO 0x22
#define PMCIN_SAS_DIAG_MODE_START_END 0x23
#define PMCIN_SAS_DIAG_EXECUTE 0x24
#define PMCIN_SAS_HW_EVENT_ACK 0x25
#define PMCIN_GET_TIME_STAMP 0x26
#define PMCIN_PORT_CONTROL 0x27
#define PMCIN_GET_NVMD_DATA 0x28
#define PMCIN_SET_NVMD_DATA 0x29
#define PMCIN_SET_DEVICE_STATE 0x2A
#define PMCIN_GET_DEVICE_STATE 0x2B
/*
* General Inbound Queue related parameters (DWORD 4)
*/
#define PMCIN_MESSAGE_REPORT (1 << 2)
#define PMCIN_DS_ABORT_TASK (1 << 3)
#define PMCIN_DS_IN_RECOVERY (1 << 4)
#define PMCIN_DATADIR_NONE (0x00 << 8)
#define PMCIN_DATADIR_2_INI (0x01 << 8)
#define PMCIN_DATADIR_2_DEV (0x02 << 8)
/*
* SATA Host IO Start ATA Protocol Types
* (placed into DWORD 4)
*/
#define SATA_PROTOCOL_SRST_ASSERT (0x01 << 10)
#define SATA_PROTOCOL_SRT_DEASSERT (0x02 << 10)
#define SATA_PROTOCOL_EXECDEVDIAG (0x03 << 10)
#define SATA_PROTOCOL_NONDATA (0x04 << 10)
#define SATA_PROTOCOL_PIO (0x05 << 10)
#define SATA_PROTOCOL_DMA (0x06 << 10)
#define SATA_PROTOCOL_FPDMA (0x07 << 10)
/*
* SAS Host IO Start TLR definitions
* (placed into DWORD 4)
*/
#define SAS_TLR_ALL 0 /* SAS 1.1 and SAS 2.0 per device mode page */
#define SAS_TLR_ON 1 /* unconditionally on */
#define SAS_TLR_OFF 2 /* unconditionally off */
#define SAS_TLR_SAS2 3 /* SAS 2.0 per device mode page */
/*
* IOP SMP Request Information
*/
#define SMP_INDIRECT_RESPONSE 0x01
#define SMP_INDIRECT_REQUEST 0x02
#define SMP_PHY_OVERRIDE 0x04
#define SMP_REQUEST_LENGTH_SHIFT 16
/*
* PHY Start related definitions
*/
#define PHY_LINK_1_5 0x01
#define PHY_LINK_3 0x02
#define PHY_LINK_6 0x04
#define PHY_LINK_ALL (PHY_LINK_1_5 | PHY_LINK_3 | PHY_LINK_6)
#define PHY_LINK_SHIFT 8
#define PHY_LM_SAS 1
#define PHY_LM_SATA 2
#define PHY_LM_AUTO 3
#define PHY_MODE_SHIFT 12
#define PHY_SPINUP_HOLD (1 << 14)
/*
* LOCAL PHY CONTROL related definitions
*/
/*
* Device Registration related definitions
*/
#define PMCS_DEVREG_LINK_RATE_SHIFT 24
#define PMCS_DEVREG_TYPE_SATA 0
#define PMCS_DEVREG_TYPE_SAS (1 << 28)
#define PMCS_DEVREG_TYPE_SATA_DIRECT (1 << 29)
#define PMCS_PHYID_SHIFT 4 /* level 0 registration only */
#define PMCS_DEVREG_TLR 0x1 /* Transport Layer Retry */
#define PMCS_DEVREG_IT_NEXUS_TIMEOUT 2000U
#define PMCS_DEVREG_HA 0x2 /* Host Assigned upper 16 */
/* bits for device ID. */
/*
* These are used for getting/setting data in the NVRAM (SEEPROM, VPD, etc.)
*/
typedef struct pmcs_get_nvmd_cmd_s {
uint32_t header; /* DWORD 0 */
uint32_t htag; /* DWORD 1 */
uint8_t tdas_nvmd; /* DWORD 2 */
uint8_t tbn_tdps;
uint8_t tda;
uint8_t ip;
uint8_t doa[3]; /* DWORD 3 Data Offset Addr */
uint8_t d_len; /* Direct Pld Data Len */
uint32_t rsvd[8]; /* DWORDS 4-11 */
uint32_t ipbal; /* 12 - Ind Pld buf addr low */
uint32_t ipbah; /* 13 - Ind Pld buf addr high */
uint32_t ipdl; /* 14 - Ind Pld data length */
uint32_t rsvd3;
} pmcs_get_nvmd_cmd_t;
typedef struct pmcs_set_nvmd_cmd_s {
uint32_t header; /* DWORD 0 */
uint32_t htag; /* DWORD 1 */
uint8_t tdas_nvmd; /* DWORD 2 */
uint8_t tbn_tdps;
uint8_t tda;
uint8_t ip;
uint8_t doa[3]; /* DWORD 3 Data Offset Addr */
uint8_t d_len; /* Direct Pld Data Len */
uint32_t signature; /* DWORD 4 */
uint32_t rsvd[7]; /* DWORDS 5-11 */
uint32_t ipbal; /* 12 - Ind Pld buf addr low */
uint32_t ipbah; /* 13 - Ind Pld buf addr high */
uint32_t ipdl; /* 14 - Ind Pld data length */
uint32_t rsvd2;
} pmcs_set_nvmd_cmd_t;
#define PMCIN_NVMD_DIRECT_PLD 0x00
#define PMCIN_NVMD_INDIRECT_PLD 0x80
/* TWI bus number is upper 4 bits of tbn_tdps */
#define PMCIN_NVMD_TBN(x) (x << 4)
/* TWI Device Page Size bits (lower 4 bits of tbn_tdps */
#define PMCIN_NVMD_TDPS_1 0 /* 1 byte */
#define PMCIN_NVMD_TDPS_8 1 /* 8 bytes */
#define PMCIN_NVMD_TDPS_16 2 /* 16 bytes */
#define PMCIN_NVMD_TDPS_32 3 /* 32 bytes */
/* TWI Device Address Size (upper 4 bits of tdas_nvmd) */
#define PMCIN_NVMD_TDAS_1 (0 << 4) /* 1 byte */
#define PMCIN_NVMD_TDAS_2 (1 << 4) /* 2 bytes */
/*
* TWI Device Address
* The address used to access TWI device for the 2Kb SEEPROM device is
* arranged as follows:
* Bits 7-4 are fixed (0xA)
* Bits 3-1 are page numbers for each 256 byte page
* Bit 0: Set to "1" to read, "0" to write
* Bit 0 is set/reset by the firmware based on whether the command is a
* SET or a GET.
*/
#define PMCIN_TDA_BASE 0xA0
#define PMCIN_TDA_PAGE(x) (PMCIN_TDA_BASE | (x << 1))
/* NVM Device bits (lower 4 bits of tdas_nvmd) */
#define PMCIN_NVMD_TWI 0 /* TWI Device */
#define PMCIN_NVMD_SEEPROM 1 /* SEEPROM Device */
#define PMCIN_NVMD_VPD 4 /* VPD Flash Memory */
#define PMCIN_NVMD_AAP1 5 /* AAP1 Register Dump */
#define PMCIN_NVMD_IOP 6 /* IOP Register Dump */
#define PMCS_SEEPROM_PAGE_SIZE 256
/*
* Minimum and maximum sizes of SPCBoot image
*/
#define PMCS_SPCBOOT_MIN_SIZE 64
#define PMCS_SPCBOOT_MAX_SIZE 512
#define PMCS_SEEPROM_SIGNATURE 0xFEDCBA98
/*
* Register dump information
*
* There are two 16KB regions for register dump information
*/
#define PMCS_REGISTER_DUMP_FLASH_SIZE (1024 * 16)
#define PMCS_REGISTER_DUMP_BLOCK_SIZE 4096 /* Must be read 4K at a time */
#define PMCS_FLASH_CHUNK_SIZE 4096 /* Must be read 4K at a time */
#define PMCS_REG_DUMP_SIZE (1024 * 1024 * 12)
#define PMCS_NVMD_EVENT_LOG_OFFSET 0x10000
#define PMCS_IQP_TRACE_BUFFER_SIZE (1024 * 512)
/*
* The list of items we can retrieve via the GET_NVMD_DATA command
*/
typedef enum {
PMCS_NVMD_VPD = 0,
PMCS_NVMD_REG_DUMP,
PMCS_NVMD_EVENT_LOG,
PMCS_NVMD_SPCBOOT
} pmcs_nvmd_type_t;
/*
* Command types, descriptors and offsets for SAS_DIAG_EXECUTE.
*/
#define PMCS_DIAG_CMD_DESC_SHIFT 8
#define PMCS_DIAG_CMD_SHIFT 13
#define PMCS_DIAG_REPORT_GET 0x04 /* Get counters */
#define PMCS_ERR_CNT_RESET 0x05 /* Clear counters */
#define PMCS_DISPARITY_ERR_CNT 0x02 /* Disparity error count */
#define PMCS_LOST_DWORD_SYNC_CNT 0x05 /* Lost DWord sync count */
#define PMCS_INVALID_DWORD_CNT 0x06 /* Invalid DWord count */
#define PMCS_RESET_FAILED_CNT 0x0C /* PHY reset failed count */
/*
* VPD data layout
*/
#define PMCS_EEPROM_INT_VERSION 1 /* supported version for Thebe INT */
#define PMCS_EEPROM_EXT_VERSION 2 /* supported version for Thebe EXT */
#define PMCS_VPD_DATA_PAGE 2 /* VPD starts at offset 512 */
#define PMCS_VPD_RO_BYTE 0x90 /* Start of "read-only" data */
#define PMCS_VPD_START 0x82 /* VPD start byte */
#define PMCS_VPD_END 0x78 /* VPD end byte */
#define PMCS_EEPROM_INT_SSID_BYTE1 0x02 /* Byte 1 of Thebe INT SSID */
#define PMCS_EEPROM_INT_SSID_BYTE2 0x02 /* Byte 2 of Thebe INT SSID */
#define PMCS_EEPROM_EXT_SSID_BYTE1 0x00 /* Byte 1 of Thebe EXT SSID */
#define PMCS_EEPROM_EXT_SSID_BYTE2 0x22 /* Byte 2 of Thebe EXT SSID */
/*
* This structure defines the "header" for the VPD data. Everything
* following this structure is self-defining. The consumer just needs
* to allocate a buffer large enough for vpd_length + 3 bytes of data.
*/
typedef struct {
uint8_t eeprom_version;
uint8_t vpd_length[2]; /* # bytes that follow, little-endian */
uint8_t hba_sas_wwid[8];
uint8_t subsys_pid[2];
uint8_t subsys_vid[2];
uint8_t vpd_start_byte; /* 0x82 */
uint8_t strid_length[2]; /* little-endian */
/* strid_length bytes follow */
} pmcs_vpd_header_t;
typedef struct {
char keyword[2];
uint8_t value_length;
char value[1]; /* Length is actually value_length */
} pmcs_vpd_kv_t;
/*
* From here on out are definitions related to Outbound Queues
* (completions of Inbound Queue requests and async events)
*/
/*
* PMC IOMB Outbound Queue Opcodes
*/
#define PMCOUT_ECHO 0x01
#define PMCOUT_GET_INFO 0x02
#define PMCOUT_GET_VPD 0x03
#define PMCOUT_SAS_HW_EVENT 0x04
#define PMCOUT_SSP_COMPLETION 0x05
#define PMCOUT_SMP_COMPLETION 0x06
#define PMCOUT_LOCAL_PHY_CONTROL 0x07
#define PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT 0x08
#define PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT 0x09
#define PMCOUT_DEVICE_REGISTRATION 0x0A
#define PMCOUT_DEREGISTER_DEVICE_HANDLE 0x0B
#define PMCOUT_GET_DEVICE_HANDLE 0x0C
#define PMCOUT_SATA_COMPLETION 0x0D
#define PMCOUT_SATA_EVENT 0x0E
#define PMCOUT_SSP_EVENT 0x0F
#define PMCOUT_DEVICE_HANDLE_ARRIVED 0x10
#define PMCOUT_SSP_REQUEST_RECEIVED 0x12
#define PMCOUT_DEVICE_INFO 0x13
#define PMCOUT_FW_FLASH_UPDATE 0x14
#define PMCOUT_SET_VPD 0x15
#define PMCOUT_GPIO 0x16
#define PMCOUT_GPIO_EVENT 0x17
#define PMCOUT_GENERAL_EVENT 0x18
#define PMCOUT_TWI 0x19
#define PMCOUT_SSP_ABORT 0x1A
#define PMCOUT_SATA_ABORT 0x1B
#define PMCOUT_SAS_DIAG_MODE_START_END 0x1C
#define PMCOUT_SAS_DIAG_EXECUTE 0x1D
#define PMCOUT_GET_TIME_STAMP 0x1E
#define PMCOUT_SAS_HW_EVENT_ACK_ACK 0x1F
#define PMCOUT_PORT_CONTROL 0x20
#define PMCOUT_SKIP_ENTRIES 0x21
#define PMCOUT_SMP_ABORT 0x22
#define PMCOUT_GET_NVMD_DATA 0x23
#define PMCOUT_SET_NVMD_DATA 0x24
#define PMCOUT_DEVICE_HANDLE_REMOVED 0x25
#define PMCOUT_SET_DEVICE_STATE 0x26
#define PMCOUT_GET_DEVICE_STATE 0x27
#define PMCOUT_SET_DEVICE_INFO 0x28
/*
* General Outbound Status Definitions
*/
#define PMCOUT_STATUS_OK 0x00
#define PMCOUT_STATUS_ABORTED 0x01
#define PMCOUT_STATUS_OVERFLOW 0x02
#define PMCOUT_STATUS_UNDERFLOW 0x03
#define PMCOUT_STATUS_FAILED 0x04
#define PMCOUT_STATUS_ABORT_RESET 0x05
#define PMCOUT_STATUS_IO_NOT_VALID 0x06
#define PMCOUT_STATUS_NO_DEVICE 0x07
#define PMCOUT_STATUS_ILLEGAL_PARAMETER 0x08
#define PMCOUT_STATUS_LINK_FAILURE 0x09
#define PMCOUT_STATUS_PROG_ERROR 0x0A
#define PMCOUT_STATUS_EDC_IN_ERROR 0x0B
#define PMCOUT_STATUS_EDC_OUT_ERROR 0x0C
#define PMCOUT_STATUS_ERROR_HW_TIMEOUT 0x0D
#define PMCOUT_STATUS_XFER_ERR_BREAK 0x0E
#define PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY 0x0F
#define PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED 0x10
#define PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION 0x11
#define PMCOUT_STATUS_OPEN_CNX_ERROR_BREAK 0x12
#define PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS 0x13
#define PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION 0x14
#define PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED 0x15
#define PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY 0x16
#define PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION 0x17
#define PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_ERROR 0x18
#define PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED 0x19
#define PMCOUT_STATUS_XFER_ERROR_ACK_NAK_TIMEOUT 0x1A
#define PMCOUT_STATUS_XFER_ERROR_PEER_ABORTED 0x1B
#define PMCOUT_STATUS_XFER_ERROR_RX_FRAME 0x1C
#define PMCOUT_STATUS_IO_XFER_ERROR_DMA 0x1D
#define PMCOUT_STATUS_XFER_ERROR_CREDIT_TIMEOUT 0x1E
#define PMCOUT_STATUS_XFER_ERROR_SATA_LINK_TIMEOUT 0x1F
#define PMCOUT_STATUS_XFER_ERROR_SATA 0x20
#define PMCOUT_STATUS_XFER_ERROR_REJECTED_NCQ_MODE 0x21
#define PMCOUT_STATUS_XFER_ERROR_ABORTED_DUE_TO_SRST 0x22
#define PMCOUT_STATUS_XFER_ERROR_ABORTED_NCQ_MODE 0x23
#define PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT 0x24
#define PMCOUT_STATUS_SMP_RESP_CONNECTION_ERROR 0x25
#define PMCOUT_STATUS_XFER_ERROR_UNEXPECTED_PHASE 0x26
#define PMCOUT_STATUS_XFER_ERROR_RDY_OVERRUN 0x27
#define PMCOUT_STATUS_XFER_ERROR_RDY_NOT_EXPECTED 0x28
/* 0x29 */
/* 0x2A */
/* 0x2B */
/* 0x2C */
/* 0x2D */
/* 0x2E */
/* 0x2F */
#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT 0x30
#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK 0x31
#define PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK 0x32
/* 0x33 */
#define PMCOUT_STATUS_XFER_ERROR_OFFSET_MISMATCH 0x34
#define PMCOUT_STATUS_XFER_ERROR_ZERO_DATA_LEN 0x35
#define PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED 0x36
#define PMCOUT_STATUS_ERROR_INTERNAL_SMP_RESOURCE 0x37
#define PMCOUT_STATUS_IO_PORT_IN_RESET 0x38
#define PMCOUT_STATUS_IO_DS_NON_OPERATIONAL 0x39
#define PMCOUT_STATUS_IO_DS_IN_RECOVERY 0x3A
#define PMCOUT_STATUS_IO_TM_TAG_NOT_FOUND 0x3B
#define PMCOUT_STATUS_IO_SSP_EXT_IU_ZERO_LEN_ERROR 0x3D
#define PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY 0x3F
#define PMCOUT_STATUS_IO_ABORT_IN_PROGRESS 0x40
/*
* IOMB formats
*
* NOTE: All IOMBs are little-endian with exceptions to certain parts of
* some IOMBs. For example, the SSP_RESPONSE_IU in the SSP_COMPLETION
* outbound IOMB is big-endian (SAS).
*/
/* Common IOMB header */
typedef struct pmcs_iomb_header {
uint8_t opcode_lo;
DECL_BITFIELD2(opcode_hi: 4,
cat : 4);
DECL_BITFIELD2(obid : 6,
rsvd1 : 2);
DECL_BITFIELD4(buf_count: 5,
rsvd2 : 1,
h_bit : 1,
v_bit : 1);
} pmcs_iomb_header_t;
/* PMCOUT_SSP_COMPLETION */
typedef struct pmcout_ssp_comp {
pmcs_iomb_header_t header;
uint32_t htag;
uint32_t status;
uint32_t param;
uint16_t ssp_tag;
DECL_BITFIELD3(resc_v : 1,
resc_pad : 2,
rsvd1 : 5);
uint8_t rsvd2;
/* SSP_RESPONSE_IU (if it exists) */
/* Residual count (if resc_v is set) */
} pmcout_ssp_comp_t;
/*
* Device State definitions
*/
#define PMCS_DEVICE_STATE_NOT_AVAILABLE 0x0 /* Unconfigured tgt */
#define PMCS_DEVICE_STATE_OPERATIONAL 0x1
#define PMCS_DEVICE_STATE_PORT_IN_RESET 0x2
#define PMCS_DEVICE_STATE_IN_RECOVERY 0x3
#define PMCS_DEVICE_STATE_IN_ERROR 0x4
#define PMCS_DEVICE_STATE_NON_OPERATIONAL 0x7
/*
* Reset Types
*/
#define PMCS_SSP_LINK_RESET 0x1
#define PMCS_SSP_HARD_RESET 0x2
#define PMCS_SMP_HARD_RESET 0x3
/*
* PHYOP for LOCAL_PHY_CONTROL Command
*/
#define PMCS_PHYOP_LINK_RESET 0x01
#define PMCS_PHYOP_HARD_RESET 0x02
/*
* Specialized status values
*/
/* PHY Stop Status Results */
#define IOP_PHY_STOP_OK 0x0
#define IOP_PHY_STOP_INVALID 0x1
#define IOP_PHY_STOP_ERROR 0x3
#define IOP_PHY_STOP_ALREADY 0x4
/* PHY Start Status Results */
#define IOP_PHY_START_OK 0
#define IOP_PHY_START_INVALID 1
#define IOP_PHY_START_ALREADY 2
#define IOP_PHY_START_ERROR 3
/* SET/GET_NVMD status results */
#define PMCS_NVMD_STAT_SUCCESS 0x0000
#define PMCS_NVMD_STAT_PLD_NVMD_COMB_ERR 0x0001
#define PMCS_NVMD_STAT_PLD_LEN_ERR 0x0002
#define PMCS_NVMD_STAT_TWI_DEV_NACK 0x2001
#define PMCS_NVMD_STAT_TWI_DEV_LOST_ARB 0x2002
#define PMCS_NVMD_STAT_TWI_TIMEOUT 0x2021
#define PMCS_NVMD_STAT_TWI_BUS_NACK 0x2081
#define PMCS_NVMD_STAT_TWI_DEV_ARB_FAIL 0x2082
#define PMCS_NVMD_STAT_TWI_BUS_SER_TIMEO 0x20FF
#define PMCS_NVMD_STAT_PART_NOT_IN_FLASH 0x9001
#define PMCS_NVMD_STAT_LEN_TOO_LARGE 0x9002
#define PMCS_NVMD_STAT_FLASH_PRGRM_FAIL 0x9003
#define PMCS_NVMD_STAT_DEVID_MATCH_FAIL 0x9004
#define PMCS_NVMD_STAT_VENDID_MATCH_FAIL 0x9005
#define PMCS_NVMD_STAT_SEC_ERASE_TIMEO 0x9006
#define PMCS_NVMD_STAT_SEC_ERASE_CWE 0x9007
#define PMCS_NVMD_STAT_FLASH_DEV_BUSY 0x9008
#define PMCS_NVMD_STAT_FLASH_DEV_NOT_SUP 0x9009
#define PMCS_NVMD_STAT_FLASH_NO_CFI 0x900A
#define PMCS_NVMD_STAT_ERASE_BLOCKS 0x900B
#define PMCS_NVMD_STAT_PART_READ_ONLY 0x900C
#define PMCS_NVMD_STAT_PART_INV_MAP_TYPE 0x900D
#define PMCS_NVMD_STAT_PART_INIT_STR_DIS 0x900E
/*
* General Event Status Codes
*/
#define INBOUND_IOMB_V_BIT_NOT_SET 0x1
#define INBOUND_IOMB_OPC_NOT_SUPPORTED 0x2
/* Device Register Status Results */
#define PMCS_DEVREG_OK 0x0
#define PMCS_DEVREG_DEVICE_ALREADY_REGISTERED 0x2
#define PMCS_DEVREG_PHY_ALREADY_REGISTERED 0x4
/*
* Flash Update responses
*/
#define FLASH_UPDATE_COMPLETE_PENDING_REBOOT 0x0
#define FLASH_UPDATE_IN_PROGRESS 0x1
#define FLASH_UPDATE_HDR_ERR 0x2
#define FLASH_UPDATE_OFFSET_ERR 0x3
#define FLASH_UPDATE_UPDATE_CRC_ERR 0x4
#define FLASH_UPDATE_LENGTH_ERR 0x5
#define FLASH_UPDATE_HW_ERR 0x6
#define FLASH_UPDATE_DNLD_NOT_SUPPORTED 0x10
#define FLASH_UPDATE_DISABLED 0x11
/*
* IOP SAS HW Event Related definitions
*/
#define IOP_EVENT_LINK_RATE(x) ((x >> 28) & 0xf)
#define IOP_EVENT_STATUS(x) ((x >> 24) & 0xf)
#define IOP_EVENT_EVENT(x) ((x >> 8) & 0xffff)
#define IOP_EVENT_PHYNUM(x) ((x >> 4) & 0xf)
#define IOP_EVENT_PORTID(x) ((x) & 0xf)
#define IOP_EVENT_PHY_STOP_STATUS 0x03
#define IOP_EVENT_SAS_PHY_UP 0x04
#define IOP_EVENT_SATA_PHY_UP 0x05
#define IOP_EVENT_SATA_SPINUP_HOLD 0x06
#define IOP_EVENT_PHY_DOWN 0x07
#define IOP_EVENT_PORT_INVALID 0x08 /* < fw 1.6 */
#define IOP_EVENT_BROADCAST_CHANGE 0x09
#define IOP_EVENT_BROADCAST_SES 0x0B
#define IOP_EVENT_PHY_ERR_INBOUND_CRC 0x0C
#define IOP_EVENT_HARD_RESET_RECEIVED 0x0D
#define IOP_EVENT_EVENT_ID_FRAME_TIMO 0x0F
#define IOP_EVENT_BROADCAST_EXP 0x10
#define IOP_EVENT_PHY_START_STATUS 0x11
#define IOP_EVENT_PHY_ERR_INVALID_DWORD 0x12
#define IOP_EVENT_PHY_ERR_DISPARITY_ERROR 0x13
#define IOP_EVENT_PHY_ERR_CODE_VIOLATION 0x14
#define IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN 0x15
#define IOP_EVENT_PHY_ERR_PHY_RESET_FAILD 0x16
#define IOP_EVENT_PORT_RECOVERY_TIMER_TMO 0x17
#define IOP_EVENT_PORT_RECOVER 0x18
#define IOP_EVENT_PORT_RESET_TIMER_TMO 0x19
#define IOP_EVENT_PORT_RESET_COMPLETE 0x20
#define IOP_EVENT_BROADCAST_ASYNC_EVENT 0x21
#define IOP_EVENT_IT_NEXUS_LOSS 0x22
#define IOP_EVENT_PORT_STATE(x) ((x) & 0xf)
#define IOP_EVENT_NPIP(x) (((x) >> 4) & 0xf)
#define IOP_EVENT_PS_NIL 0x0 /* PORT_ID not valid yet */
#define IOP_EVENT_PS_VALID 0x1 /* PORT_ID now valid */
#define IOP_EVENT_PS_LOSTCOMM 0x2 /* Link temporarily down */
#define IOP_EVENT_PS_IN_RESET 0x4 /* Port in reset */
#define IOP_EVENT_PS_INVALID 0x8 /* PORT_ID now dead */
/*
* HW Event Acknowledge Response Values
*/
#define SAS_HW_EVENT_ACK_OK 0x0
#define SAS_HW_EVENT_ACK_INVALID_SEA 0x1
#define SAS_HW_EVENT_ACK_INVALID_PHY 0x2
#define SAS_HW_EVENT_ACK_INVALID_PORT 0x4
#define SAS_HW_EVENT_ACK_INVALID_PARAM 0x8
/*
* IOMB Queue definitions and Macros
*/
#define ADDQI(ix, n, qd) ((ix + n) & (qd - 1))
#define INCQI(ix, qd) ix = ADDQI(ix, 1, qd)
#define QI2O(ix, n, qd) (ADDQI(ix, n, qd) * PMCS_QENTRY_SIZE)
/*
* Inbound Queue Producer Indices live inside the PMC card.
*
* Inbound Queue Consumer indices live in host memory. We use the Consumer
* Index to return a pointer to an Inbound Queue entry. We then can fill
* it with an IOMB. We then update the the Producer index which kicks
* card to read the IOMB we just wrote.
*
* There is one mutex for each inbound queue that is held from the time
* we get an entry until we increment the producer index, or released
* manually if we don't actually send the message.
*/
/*
* NB: the appropriate iqp_lock must be held
*/
#define GET_IQ_ENTRY(hwp, qnum) \
((ADDQI(hwp->shadow_iqpi[qnum], 1, hwp->ioq_depth) == \
pmcs_rd_iqci(hwp, qnum)) ? NULL : \
&hwp->iqp[qnum][hwp->shadow_iqpi[qnum] * (PMCS_QENTRY_SIZE >> 2)])
/*
* NB: This releases the lock on the Inbound Queue that GET_IO_IQ_ENTRY
* acquired below.
*/
#ifdef DEBUG
#define INC_IQ_ENTRY(hwp, qnum) \
{ \
uint32_t htag; \
ASSERT(mutex_owned(&(hwp)->iqp_lock[qnum])); \
htag = hwp->iqp[qnum][(hwp->shadow_iqpi[qnum] * \
(PMCS_QENTRY_SIZE >> 2)) + 1]; \
mutex_enter(&(hwp)->dbglock); \
pmcs_iqp_trace(hwp, qnum); \
mutex_exit(&(hwp)->dbglock); \
INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth); \
if (ddi_dma_sync(hwp->cip_handles, 0, 0, \
DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) { \
pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition " \
"failed at %s():%d", __func__, __LINE__); \
} \
hwp->ftime[hwp->fti] = gethrtime(); \
pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]); \
mutex_exit(&(hwp)->iqp_lock[qnum]); \
mutex_enter(&(hwp)->dbglock); \
hwp->ftag_lines[hwp->fti] = __LINE__; \
hwp->ftags[hwp->fti++] = htag; \
mutex_exit(&(hwp)->dbglock); \
}
#else
#define INC_IQ_ENTRY(hwp, qnum) \
INCQI(hwp->shadow_iqpi[qnum], hwp->ioq_depth); \
if (ddi_dma_sync(hwp->cip_handles, 0, 0, \
DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) { \
pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Condition " \
"failed at %s():%d", __func__, __LINE__); \
} \
pmcs_wr_iqpi(hwp, qnum, hwp->shadow_iqpi[qnum]); \
mutex_exit(&(hwp)->iqp_lock[qnum])
#endif
/*
* NB: sucessfull acquisition of an IO Inbound Queue
* entry leaves the lock on that Inbound Queue held.
*/
#define GET_IO_IQ_ENTRY(pwp, msg, did, iq) \
iq = did & PMCS_IO_IQ_MASK; \
mutex_enter(&(pwp)->iqp_lock[iq]); \
msg = GET_IQ_ENTRY(pwp, iq); \
if (msg == NULL) { \
mutex_exit(&(pwp)->iqp_lock[iq]); \
for (iq = 0; iq <= PMCS_NON_HIPRI_QUEUES; iq++) { \
mutex_enter(&(pwp)->iqp_lock[iq]); \
msg = GET_IQ_ENTRY(pwp, iq); \
if (msg) { \
break; \
} \
mutex_exit(&(pwp->iqp_lock[iq])); \
} \
}
/*
* Outbound Queue Macros
*
* Outbound Queue Consumer indices live inside the card.
*
* Outbound Queue Producer indices live in host memory. When the card
* wants to send an IOMB, it uses the producer index to find the spot
* to write the IOMB. After it's done it updates the producer index
* and interrupts the host. The host reads the producer index (from
* host memory) and reads IOMBs up to but not including that index.
* It writes that index back to the consumer index on the card,
* signifying that it has read up to that which the card has sent.
*/
#define GET_OQ_ENTRY(hwp, qn, ix, o) \
&hwp->oqp[qn][QI2O(ix, o, hwp->ioq_depth) >> 2]
#define STEP_OQ_ENTRY(hwp, qn, ix, n) ix = ADDQI(ix, n, hwp->ioq_depth)
#define SYNC_OQ_ENTRY(hwp, qn, ci, pi) \
pmcs_wr_oqci(hwp, qn, ci); \
(hwp)->oqci[qn] = ci; \
(hwp)->oqpi[qn] = pi
#ifdef __cplusplus
}
#endif
#endif /* _PMCS_IOMB_H */
|