summaryrefslogtreecommitdiffstats
path: root/sys/dev/ciss/cissreg.h
blob: 982df2fa92c47de75548c4def37991c9444e8a8e (plain)
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
/*-
 * Copyright (c) 2001 Michael Smith
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	$FreeBSD$
 */

/*
 * Structure and I/O definitions for the Command Interface for SCSI-3 Support.
 *
 * Data in command CDBs are in big-endian format.  All other data is little-endian.
 * This header only supports little-endian hosts at this time.
 */

union ciss_device_address
{
    struct 				/* MODE_PERIPHERAL and MODE_MASK_PERIPHERAL */
    {
	u_int32_t	target:24;	/* SCSI target */
	u_int32_t	bus:6;		/* SCSI bus */
	u_int32_t	mode:2;		/* CISS_HDR_ADDRESS_MODE_* */
	u_int32_t	extra_address;	/* SCSI-3 level-2 and level-3 address bytes */
    } physical;
    struct 				/* MODE_LOGICAL */
    {
	u_int32_t	lun:30;		/* logical device ID */
	u_int32_t	mode:2;		/* CISS_HDR_ADDRESS_MODE_LOGICAL */
	u_int32_t	:32;		/* reserved */
    } logical;
    struct
    {
	u_int32_t	:30;
	u_int32_t	mode:2;
	u_int32_t	:32;
    } mode;
};
#define CISS_HDR_ADDRESS_MODE_PERIPHERAL	0x0
#define CISS_HDR_ADDRESS_MODE_LOGICAL		0x1
#define CISS_HDR_ADDRESS_MODE_MASK_PERIPHERAL	0x3

#define CISS_EXTRA_MODE2(extra)		((extra & 0xc0000000) >> 30)
#define CISS_EXTRA_BUS2(extra)		((extra & 0x3f000000) >> 24)
#define CISS_EXTRA_TARGET2(extra)	((extra & 0x00ff0000) >> 16)
#define CISS_EXTRA_MODE3(extra)		((extra & 0x0000c000) >> 14)
#define CISS_EXTRA_BUS3(extra)		((extra & 0x00003f00) >> 8)
#define CISS_EXTRA_TARGET3(extra)	((extra & 0x000000ff))

struct ciss_header
{
    u_int8_t	:8;			/* reserved */
    u_int8_t	sg_in_list;		/* SG's in the command structure */
    u_int16_t	sg_total;		/* total count of SGs for this command */
    u_int32_t	host_tag;		/* host identifier, bits 0&1 must be clear */
#define CISS_HDR_HOST_TAG_ERROR	(1<<1)
    u_int32_t	host_tag_zeroes;	/* tag is 64 bits, but interface only supports 32 */
    union ciss_device_address address;
} __packed;

struct ciss_cdb
{
    u_int8_t	cdb_length;		/* valid CDB bytes */
    u_int8_t	type:3;
#define CISS_CDB_TYPE_COMMAND			0
#define CISS_CDB_TYPE_MESSAGE			1
    u_int8_t	attribute:3;
#define CISS_CDB_ATTRIBUTE_UNTAGGED		0
#define CISS_CDB_ATTRIBUTE_SIMPLE		4
#define CISS_CDB_ATTRIBUTE_HEAD_OF_QUEUE	5
#define CISS_CDB_ATTRIBUTE_ORDERED		6
#define CISS_CDB_ATTRIBUTE_AUTO_CONTINGENT	7
    u_int8_t	direction:2;
#define CISS_CDB_DIRECTION_NONE			0
#define CISS_CDB_DIRECTION_WRITE		1
#define CISS_CDB_DIRECTION_READ			2
    u_int16_t	timeout;		/* seconds */
#define CISS_CDB_BUFFER_SIZE	16
    u_int8_t	cdb[CISS_CDB_BUFFER_SIZE];
} __packed;

struct ciss_error_info_pointer
{
    u_int64_t	error_info_address;	/* points to ciss_error_info structure */
    u_int32_t	error_info_length;
} __packed;

struct ciss_error_info
{
    u_int8_t	scsi_status;
#define CISS_SCSI_STATUS_GOOD			0x00	/* these are scsi-standard values */
#define CISS_SCSI_STATUS_CHECK_CONDITION	0x02
#define CISS_SCSI_STATUS_CONDITION_MET		0x04
#define CISS_SCSI_STATUS_BUSY			0x08
#define CISS_SCSI_STATUS_INDETERMINATE		0x10
#define CISS_SCSI_STATUS_INDETERMINATE_CM	0x14
#define CISS_SCSI_STATUS_RESERVATION_CONFLICT	0x18
#define CISS_SCSI_STATUS_COMMAND_TERMINATED	0x22
#define CISS_SCSI_STATUS_QUEUE_FULL		0x28
#define CISS_SCSI_STATUS_ACA_ACTIVE		0x30
    u_int8_t	sense_length;
    u_int16_t	command_status;
#define CISS_CMD_STATUS_SUCCESS			0
#define CISS_CMD_STATUS_TARGET_STATUS		1
#define CISS_CMD_STATUS_DATA_UNDERRUN		2
#define CISS_CMD_STATUS_DATA_OVERRUN		3
#define CISS_CMD_STATUS_INVALID_COMMAND		4
#define CISS_CMD_STATUS_PROTOCOL_ERROR		5
#define CISS_CMD_STATUS_HARDWARE_ERROR		6
#define CISS_CMD_STATUS_CONNECTION_LOST		7
#define CISS_CMD_STATUS_ABORTED			8
#define CISS_CMD_STATUS_ABORT_FAILED		9
#define CISS_CMD_STATUS_UNSOLICITED_ABORT	10
#define CISS_CMD_STATUS_TIMEOUT			11
#define CISS_CMD_STATUS_UNABORTABLE		12
    u_int32_t	residual_count;
    union {
	struct {
	    u_int8_t	res1[3];
	    u_int8_t	type;
	    u_int32_t	error_info;
	} __packed common_info;
	struct {
	    u_int8_t	res1[2];
	    u_int8_t	offense_size;
	    u_int8_t	offense_offset;
	    u_int32_t	offense_value;
	} __packed invalid_command;
    } additional_error_info;
    u_int8_t	sense_info[0];
} __packed;

struct ciss_sg_entry
{
    u_int64_t	address;
#define CISS_SG_ADDRESS_BITBUCKET	(~(u_int64_t)0)
    u_int32_t	length;
    u_int32_t	:31;
    u_int32_t	extension:1;		/* address points to another s/g chain */
} __packed;

struct ciss_command
{
    struct ciss_header			header;
    struct ciss_cdb			cdb;
    struct ciss_error_info_pointer	error_info;
    struct ciss_sg_entry		sg[0];
} __packed;

#define CISS_OPCODE_REPORT_LOGICAL_LUNS		0xc2
#define CISS_OPCODE_REPORT_PHYSICAL_LUNS	0xc3

struct ciss_lun_report
{
    u_int32_t	list_size;		/* big-endian */
    u_int32_t	:32;
    union ciss_device_address lun[0];
} __packed;

#define	CISS_VPD_LOGICAL_DRIVE_GEOMETRY		0xc1
struct ciss_ldrive_geometry
{
    u_int8_t	periph_qualifier:3;
    u_int8_t	periph_devtype:5;
    u_int8_t	page_code;
    u_int8_t	res1;
    u_int8_t	page_length;
    u_int16_t	cylinders;		/* big-endian */
    u_int8_t	heads;
    u_int8_t	sectors;
    u_int8_t	fault_tolerance;
    u_int8_t	res2[3];
} __attribute__ ((packed));

struct ciss_report_cdb
{
    u_int8_t	opcode;
    u_int8_t	reserved[5];
    u_int32_t	length;			/* big-endian */
    u_int8_t	:8;
    u_int8_t	control;
} __packed;

/*
 * Note that it's not clear whether we have to set the detail field to
 * the tag of the command to be aborted, or the tag field in the command itself;
 * documentation conflicts on this.
 */
#define CISS_OPCODE_MESSAGE_ABORT		0x00
#define CISS_MESSAGE_ABORT_TASK			0x00
#define CISS_MESSAGE_ABORT_TASK_SET		0x01
#define CISS_MESSAGE_ABORT_CLEAR_ACA		0x02
#define CISS_MESSAGE_ABORT_CLEAR_TASK_SET	0x03

#define CISS_OPCODE_MESSAGE_RESET		0x01
#define CISS_MESSAGE_RESET_CONTROLLER		0x00
#define CISS_MESSAGE_RESET_BUS			0x01
#define CISS_MESSAGE_RESET_TARGET		0x03
#define CISS_MESSAGE_RESET_LOGICAL_UNIT		0x04

#define CISS_OPCODE_MESSAGE_SCAN		0x02
#define CISS_MESSAGE_SCAN_CONTROLLER		0x00
#define CISS_MESSAGE_SCAN_BUS			0x01
#define CISS_MESSAGE_SCAN_TARGET		0x03
#define CISS_MESSAGE_SCAN_LOGICAL_UNIT		0x04

#define CISS_OPCODE_MESSAGE_NOP			0x03

struct ciss_message_cdb
{
    u_int8_t	opcode;
    u_int8_t	type;
    u_int16_t	:16;
    u_int32_t	abort_tag;					/* XXX endianness? */
    u_int8_t	reserved[8];
} __packed;

/*
 * CISS vendor-specific commands/messages.
 *
 * Note that while messages and vendor-specific commands are
 * differentiated, they are handled in basically the same way and can
 * be considered to be basically the same thing, as long as the cdb
 * type field is set correctly.
 */
#define CISS_OPCODE_READ		0xc0
#define CISS_OPCODE_WRITE		0xc1
#define CISS_COMMAND_NOTIFY_ON_EVENT	0xd0
#define CISS_COMMAND_ABORT_NOTIFY	0xd1

struct ciss_notify_cdb
{
    u_int8_t	opcode;
    u_int8_t	command;
    u_int8_t	res1[2];
    u_int16_t	timeout;		/* seconds, little-endian */
    u_int8_t	res2;			/* reserved */
    u_int8_t	synchronous:1;		/* return immediately */
    u_int8_t	ordered:1;		/* return events in recorded order */
    u_int8_t	seek_to_oldest:1;	/* reset read counter to oldest event */
    u_int8_t	new_only:1;		/* ignore any queued events */
    u_int8_t	:4;
    u_int32_t	length;			/* must be 512, little-endian */
#define CISS_NOTIFY_DATA_SIZE	512
    u_int8_t	control;
} __packed;

#define CISS_NOTIFY_NOTIFIER		0
#define CISS_NOTIFY_NOTIFIER_STATUS		0
#define CISS_NOTIFY_NOTIFIER_PROTOCOL		1

#define CISS_NOTIFY_HOTPLUG		1
#define CISS_NOTIFY_HOTPLUG_PHYSICAL		0
#define CISS_NOTIFY_HOTPLUG_POWERSUPPLY		1
#define CISS_NOTIFY_HOTPLUG_FAN			2
#define CISS_NOTIFY_HOTPLUG_POWER		3
#define CISS_NOTIFY_HOTPLUG_REDUNDANT		4
#define CISS_NOTIFY_HOTPLUG_NONDISK		5

#define CISS_NOTIFY_HARDWARE		2
#define CISS_NOTIFY_HARDWARE_CABLES		0
#define CISS_NOTIFY_HARDWARE_MEMORY		1
#define CISS_NOTIFY_HARDWARE_FAN		2
#define CISS_NOTIFY_HARDWARE_VRM		3

#define CISS_NOTIFY_ENVIRONMENT		3
#define CISS_NOTIFY_ENVIRONMENT_TEMPERATURE	0
#define CISS_NOTIFY_ENVIRONMENT_POWERSUPPLY	1
#define CISS_NOTIFY_ENVIRONMENT_CHASSIS		2
#define CISS_NOTIFY_ENVIRONMENT_POWER		3

#define CISS_NOTIFY_PHYSICAL		4
#define CISS_NOTIFY_PHYSICAL_STATE		0

#define CISS_NOTIFY_LOGICAL		5
#define CISS_NOTIFY_LOGICAL_STATUS		0
#define CISS_NOTIFY_LOGICAL_ERROR		1
#define CISS_NOTIFY_LOGICAL_SURFACE		2

#define CISS_NOTIFY_REDUNDANT		6
#define CISS_NOTIFY_REDUNDANT_STATUS		0

#define CISS_NOTIFY_CISS		8
#define CISS_NOTIFY_CISS_REDUNDANT_CHANGE	0
#define CISS_NOTIFY_CISS_PATH_STATUS		1
#define CISS_NOTIFY_CISS_HARDWARE_ERROR		2
#define CISS_NOTIFY_CISS_LOGICAL		3

struct ciss_notify_drive
{
    u_int16_t	physical_drive_number;
    u_int8_t	configured_drive_flag;
    u_int8_t	spare_drive_flag;
    u_int8_t	big_physical_drive_number;
    u_int8_t	enclosure_bay_number;
} __packed;

struct ciss_notify_locator
{
    u_int16_t	port;
    u_int16_t	id;
    u_int16_t	box;
} __packed;

struct ciss_notify_redundant_controller
{
    u_int16_t	slot;
} __packed;

struct ciss_notify_logical_status
{
    u_int16_t	logical_drive;
    u_int8_t	previous_state;
    u_int8_t	new_state;
    u_int8_t	spare_state;
} __packed;

struct ciss_notify_rebuild_aborted
{
    u_int16_t	logical_drive;
    u_int8_t	replacement_drive;
    u_int8_t	error_drive;
    u_int8_t	big_replacement_drive;
    u_int8_t	big_error_drive;
} __packed;

struct ciss_notify_io_error
{
    u_int16_t	logical_drive;
    u_int32_t	lba;
    u_int16_t	block_count;
    u_int8_t	command;
    u_int8_t	failure_bus;
    u_int8_t	failure_drive;
    u_int64_t	big_lba;
} __packed;

struct ciss_notify_consistency_completed
{
    u_int16_t	logical_drive;
} __packed;

struct ciss_notify
{
    u_int32_t	timestamp;		/* seconds since controller power-on */
    u_int16_t	class;
    u_int16_t	subclass;
    u_int16_t	detail;
    union
    {
	struct ciss_notify_drive		drive;
	struct ciss_notify_locator		location;
	struct ciss_notify_redundant_controller	redundant_controller;
	struct ciss_notify_logical_status	logical_status;
	struct ciss_notify_rebuild_aborted	rebuild_aborted;
	struct ciss_notify_io_error		io_error;
	struct ciss_notify_consistency_completed consistency_completed;
	u_int8_t	data[64];
    } data;
    char	message[80];
    u_int32_t	tag;
    u_int16_t	date;
    u_int16_t	year;
    u_int32_t	time;
    u_int16_t	pre_power_up_time;
    union ciss_device_address	device;
    /* XXX pads to 512 bytes */
} __packed;

/*
 * CISS config table, which describes the controller's
 * supported interface(s) and capabilities.
 *
 * This is mapped directly via PCI.
 */
struct ciss_config_table
{
    char	signature[4];		/* "CISS" */
    u_int32_t	valence;
    u_int32_t	supported_methods;
#define CISS_TRANSPORT_METHOD_READY	(1<<0)
#define CISS_TRANSPORT_METHOD_SIMPLE	(1<<1)
#define CISS_TRANSPORT_METHOD_PERF	(1<<2)
    u_int32_t	active_method;
    u_int32_t	requested_method;
    u_int32_t	command_physlimit;
    u_int32_t	interrupt_coalesce_delay;
    u_int32_t	interrupt_coalesce_count;
    u_int32_t	max_outstanding_commands;
    u_int32_t	bus_types;
#define CISS_TRANSPORT_BUS_TYPE_ULTRA2	(1<<0)
#define CISS_TRANSPORT_BUS_TYPE_ULTRA3	(1<<1)
#define CISS_TRANSPORT_BUS_TYPE_FIBRE1	(1<<8)
#define CISS_TRANSPORT_BUS_TYPE_FIBRE2	(1<<9)
    u_int32_t	transport_offset;
    char	server_name[16];
    u_int32_t	heartbeat;
    u_int32_t	host_driver;
#define CISS_DRIVER_SUPPORT_UNIT_ATTENTION	(1<<0)
#define CISS_DRIVER_QUICK_INIT			(1<<1)
#define CISS_DRIVER_INTERRUPT_ON_LOCKUP		(1<<2)
#define CISS_DRIVER_SUPPORT_MIXED_Q_TAGS	(1<<3)
#define CISS_DRIVER_HOST_IS_ALPHA		(1<<4)
#define CISS_DRIVER_MULTI_LUN_SUPPORT		(1<<5)
#define CISS_DRIVER_MESSAGE_REQUESTS_SUPPORTED	(1<<7)
#define CISS_DRIVER_DAUGHTER_ATTACHED		(1<<8)
#define CISS_DRIVER_SCSI_PREFETCH		(1<<9)
    u_int32_t	max_sg_length;		/* 31 in older firmware */
} __packed;

/*
 * Configuration table for the Performant transport.  Only 4 request queues
 * are mentioned in this table, though apparently up to 256 can exist.
 */
struct ciss_perf_config {
    uint32_t	fetch_count[8];
#define CISS_SG_FETCH_MAX	0
#define CISS_SG_FETCH_1		1
#define CISS_SG_FETCH_2		2
#define CISS_SG_FETCH_4		3
#define CISS_SG_FETCH_8		4
#define CISS_SG_FETCH_16	5
#define CISS_SG_FETCH_32	6
#define CISS_SG_FETCH_NONE	7
    uint32_t	rq_size;
    uint32_t	rq_count;
    uint32_t	rq_bank_lo;
    uint32_t	rq_bank_hi;
    struct {
	uint32_t	rq_addr_lo;
	uint32_t	rq_addr_hi;
    } __packed rq[4];
} __packed;

/*
 * In a flagrant violation of what CISS seems to be meant to be about,
 * Compaq recycle a goodly portion of their previous generation's
 * command set (and all the legacy baggage related to a design
 * originally aimed at narrow SCSI) through the Array Controller Read
 * and Array Controller Write interface.
 *
 * Command ID values here can be looked up for in the
 * publically-available documentation for the older controllers; note
 * that the command layout is necessarily different to fit within the
 * CDB.
 */
#define CISS_ARRAY_CONTROLLER_READ	0x26
#define CISS_ARRAY_CONTROLLER_WRITE	0x27

#define CISS_BMIC_ID_LDRIVE		0x10
#define CISS_BMIC_ID_CTLR		0x11
#define CISS_BMIC_ID_LSTATUS		0x12
#define CISS_BMIC_ID_PDRIVE		0x15
#define CISS_BMIC_BLINK_PDRIVE		0x16
#define CISS_BMIC_SENSE_BLINK_PDRIVE	0x17
#define CISS_BMIC_SOFT_RESET		0x40
#define CISS_BMIC_FLUSH_CACHE		0xc2
#define CISS_BMIC_ACCEPT_MEDIA		0xe0

/*
 * When numbering drives, the original design assumed that
 * drives 0-7 are on the first SCSI bus, 8-15 on the second,
 * and so forth.  In order to handle modern SCSI configurations,
 * the MSB is set in the drive ID field, in which case the
 * modulus changes from 8 to the number of supported drives
 * per SCSI bus (as obtained from the ID_CTLR command).
 * This feature is referred to as BIG_MAP support, and we assume
 * that all CISS controllers support it.
 */

#define CISS_BIG_MAP_ID(sc, bus, target)		\
	(0x80 | 					\
	 ((sc)->ciss_id->drives_per_scsi_bus * (bus)) |	\
	 (target))

#define CISS_BIG_MAP_BUS(sc, id)			\
	(((id) & 0x80) ? (((id) & ~0x80) / (sc)->ciss_id->drives_per_scsi_bus) : -1)

#define CISS_BIG_MAP_TARGET(sc, id)			\
	(((id) & 0x80) ? (((id) & ~0x80) % (sc)->ciss_id->drives_per_scsi_bus) : -1)

#define CISS_BIG_MAP_ENTRIES	128	/* number of entries in a BIG_MAP */

/*
 * In the device address of a logical volume, the bus number
 * is encoded into the logical lun volume number starting
 * at the second byte, with the first byte defining the
 * logical drive number.
 */
#define CISS_LUN_TO_BUS(x)    (((x) >> 16) & 0xFF)
#define CISS_LUN_TO_TARGET(x) ((x) & 0xFF)

/*
 * BMIC CDB
 *
 * Note that the phys_drive/res1 field is nominally the 32-bit
 * "block number" field, but the only BMIC command(s) of interest
 * implemented overload the MSB (note big-endian format here)
 * to be the physical drive ID, so we define accordingly.
 */
struct ciss_bmic_cdb {
    u_int8_t	opcode;
    u_int8_t	log_drive;
    u_int8_t	phys_drive;
    u_int8_t	res1[3];
    u_int8_t	bmic_opcode;
    u_int16_t	size;			/* big-endian */
    u_int8_t	res2;
} __packed;

/*
 * BMIC command command/return structures.
 */

/* CISS_BMIC_ID_LDRIVE */
struct ciss_bmic_id_ldrive {
    u_int16_t	block_size;
    u_int32_t	blocks_available;
    u_int8_t	drive_parameter_table[16];	/* XXX define */
    u_int8_t	fault_tolerance;
#define CISS_LDRIVE_RAID0	0
#define CISS_LDRIVE_RAID4	1
#define CISS_LDRIVE_RAID1	2
#define CISS_LDRIVE_RAID5	3
#define CISS_LDRIVE_RAID51	4
#define CISS_LDRIVE_RAIDADG	5
    u_int8_t	res1;
    u_int8_t	bios_disable_flag;
    u_int8_t	res2;
    u_int32_t	logical_drive_identifier;
    char	logical_drive_label[64];
    u_int64_t	big_blocks_available;
    u_int8_t	res3[410];
} __packed;

/* CISS_BMIC_ID_LSTATUS */
struct ciss_bmic_id_lstatus {
    u_int8_t	status;
#define CISS_LSTATUS_OK				0
#define CISS_LSTATUS_FAILED			1
#define CISS_LSTATUS_NOT_CONFIGURED		2
#define CISS_LSTATUS_INTERIM_RECOVERY		3
#define CISS_LSTATUS_READY_RECOVERY		4
#define CISS_LSTATUS_RECOVERING			5
#define CISS_LSTATUS_WRONG_PDRIVE		6
#define CISS_LSTATUS_MISSING_PDRIVE		7
#define CISS_LSTATUS_EXPANDING			10
#define CISS_LSTATUS_BECOMING_READY		11
#define CISS_LSTATUS_QUEUED_FOR_EXPANSION	12
    u_int32_t	deprecated_drive_failure_map;
    u_int8_t	res1[416];
    u_int32_t	blocks_to_recover;
    u_int8_t	deprecated_drive_rebuilding;
    u_int16_t	deprecated_remap_count[32];
    u_int32_t	deprecated_replacement_map;
    u_int32_t	deprecated_active_spare_map;
    u_int8_t	spare_configured:1;
    u_int8_t	spare_rebuilding:1;
    u_int8_t	spare_rebuilt:1;
    u_int8_t	spare_failed:1;
    u_int8_t	spare_switched:1;
    u_int8_t	spare_available:1;
    u_int8_t	res2:2;
    u_int8_t	deprecated_spare_to_replace_map[32];
    u_int32_t	deprecated_replaced_marked_ok_map;
    u_int8_t	media_exchanged;
    u_int8_t	cache_failure;
    u_int8_t	expand_failure;
    u_int8_t	rebuild_read_failure:1;
    u_int8_t	rebuild_write_failure:1;
    u_int8_t	res3:6;
    u_int8_t	drive_failure_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int16_t	remap_count[CISS_BIG_MAP_ENTRIES];
    u_int8_t	replacement_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int8_t	active_spare_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int8_t	spare_to_replace_map[CISS_BIG_MAP_ENTRIES];
    u_int8_t	replaced_marked_ok_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int8_t	drive_rebuilding;
    u_int64_t	big_blocks_to_recover;
    u_int8_t	res4[28];
} __packed;

/* CISS_BMIC_ID_CTLR */
struct ciss_bmic_id_table {
    u_int8_t	configured_logical_drives;
    u_int32_t	config_signature;
    char	running_firmware_revision[4];
    char	stored_firmware_revision[4];
    u_int8_t	hardware_revision;
    u_int8_t	res1[4];
    u_int32_t	deprecated_drive_present_map;
    u_int32_t	deprecated_external_drive_present_map;
    u_int32_t	board_id;
    u_int8_t	res2;
    u_int32_t	deprecated_non_disk_map;
    u_int8_t	res3[5];
    char	marketting_revision;
    u_int8_t	res4:3;
    u_int8_t	more_than_seven_supported:1;
    u_int8_t	res5:3;
    u_int8_t	big_map_supported:1;		/* must be set! */
    u_int8_t	res6[2];
    u_int8_t	scsi_bus_count;
    u_int32_t	res7;
    u_int32_t	controller_clock;
    u_int8_t	drives_per_scsi_bus;
    u_int8_t	big_drive_present_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int8_t	big_external_drive_present_map[CISS_BIG_MAP_ENTRIES / 8];
    u_int8_t	big_non_disk_map[CISS_BIG_MAP_ENTRIES / 8];
} __packed;

/* CISS_BMIC_ID_PDRIVE */
struct ciss_bmic_id_pdrive {
    u_int8_t	scsi_bus;
    u_int8_t	scsi_id;
    u_int16_t	block_size;
    u_int32_t	total_blocks;
    u_int32_t	reserved_blocks;
    char	model[40];
    char	serial[40];
    char	revision[8];
    u_int8_t	inquiry_bits;
    u_int8_t	res1[2];
    u_int8_t	drive_present:1;
    u_int8_t	non_disk:1;
    u_int8_t	wide:1;
    u_int8_t	synchronous:1;
    u_int8_t	narrow:1;
    u_int8_t	wide_downgraded_to_narrow:1;
    u_int8_t	ultra:1;
    u_int8_t	ultra2:1;
    u_int8_t	SMART:1;
    u_int8_t	SMART_errors_recorded:1;
    u_int8_t	SMART_errors_enabled:1;
    u_int8_t	SMART_errors_detected:1;
    u_int8_t	external:1;
    u_int8_t	configured:1;
    u_int8_t	configured_spare:1;
    u_int8_t	cache_saved_enabled:1;
    u_int8_t	res2;
    u_int8_t	res3:6;
    u_int8_t	cache_currently_enabled:1;
    u_int8_t	cache_safe:1;
    u_int8_t	res4[5];
    char	connector[2];
    u_int8_t	res5;
    u_int8_t	bay;
    u_int16_t	rpm;
    u_int8_t	drive_type;
    u_int8_t	res6[393];
} __packed;

/* CISS_BMIC_BLINK_PDRIVE */
/* CISS_BMIC_SENSE_BLINK_PDRIVE */
struct ciss_bmic_blink_pdrive {
    u_int32_t	blink_duration;		/* 10ths of a second */
    u_int32_t	duration_elapsed;	/* only for sense command  */
    u_int8_t	blinktab[256];
#define CISS_BMIC_BLINK_ALL	1
#define CISS_BMIC_BLINK_TIMED	2
    u_int8_t	res2[248];
} __packed;

/* CISS_BMIC_FLUSH_CACHE */
struct ciss_bmic_flush_cache {
    u_int16_t	flag;
#define CISS_BMIC_FLUSH_AND_ENABLE	0
#define CISS_BMIC_FLUSH_AND_DISABLE	1
    u_int8_t	res1[510];
} __packed;

#ifdef _KERNEL
/*
 * CISS "simple" transport layer.
 *
 * Note that there are two slightly different versions of this interface
 * with different interrupt mask bits.  There's nothing like consistency...
 */
#define CISS_TL_SIMPLE_BAR_REGS	0x10	/* BAR pointing to register space */
#define CISS_TL_SIMPLE_BAR_CFG	0x14	/* BAR pointing to space containing config table */

#define CISS_TL_SIMPLE_IDBR	0x20	/* inbound doorbell register */
#define CISS_TL_SIMPLE_IDBR_CFG_TABLE	(1<<0)	/* notify controller of config table update */

#define CISS_TL_SIMPLE_ISR	0x30	/* interrupt status register */
#define CISS_TL_SIMPLE_IMR	0x34	/* interrupt mask register */
#define CISS_TL_SIMPLE_INTR_OPQ_SA5	(1<<3)	/* OPQ not empty interrupt, SA5 boards */
#define CISS_TL_SIMPLE_INTR_OPQ_SA5B	(1<<2)	/* OPQ not empty interrupt, SA5B boards */

#define CISS_TL_SIMPLE_IPQ	0x40	/* inbound post queue */
#define CISS_TL_SIMPLE_OPQ	0x44	/* outbound post queue */
#define CISS_TL_SIMPLE_OPQ_EMPTY	(~(u_int32_t)0)

#define CISS_TL_SIMPLE_OSR	0x9c	/* outbound status register */
#define CISS_TL_SIMPLE_ODC	0xa0	/* outbound doorbell clear register */
#define CISS_TL_SIMPLE_ODC_CLEAR	(0x1)

#define CISS_TL_SIMPLE_CFG_BAR	0xb4	/* should be 0x14 */
#define CISS_TL_SIMPLE_CFG_OFF	0xb8	/* offset in BAR at which config table is located */

/*
 * Register access primitives.
 */
#define CISS_TL_SIMPLE_READ(sc, ofs) \
	bus_space_read_4(sc->ciss_regs_btag, sc->ciss_regs_bhandle, ofs)
#define CISS_TL_SIMPLE_WRITE(sc, ofs, val) \
	bus_space_write_4(sc->ciss_regs_btag, sc->ciss_regs_bhandle, ofs, val)

#define CISS_TL_SIMPLE_POST_CMD(sc, phys)	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IPQ, phys)
#define CISS_TL_SIMPLE_FETCH_CMD(sc)		CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_OPQ)

#define CISS_TL_PERF_POST_CMD(sc, cr)		CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IPQ, CISS_FIND_COMMANDPHYS(cr) | (cr)->cr_sg_tag)
#define CISS_TL_PERF_FLUSH_INT(sc)		CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_OSR)
#define CISS_TL_PERF_CLEAR_INT(sc)		CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_ODC, CISS_TL_SIMPLE_ODC_CLEAR)
#define CISS_CYCLE_MASK		0x00000001

#define CISS_MSI_COUNT	4

/*
 * XXX Here we effectively trust the BIOS to set the IMR correctly.  But if
 * we don't trust it, will we get into trouble with wrongly assuming what it
 * should be?
 */
#define CISS_TL_SIMPLE_DISABLE_INTERRUPTS(sc)				\
    do {								\
	(sc)->ciss_interrupt_mask =					\
	     CISS_TL_SIMPLE_READ(sc, CISS_TL_SIMPLE_IMR);		\
	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IMR, ~0);		\
    } while (0)
#define CISS_TL_SIMPLE_ENABLE_INTERRUPTS(sc)				\
	CISS_TL_SIMPLE_WRITE(sc, CISS_TL_SIMPLE_IMR, (sc)->ciss_interrupt_mask)

#endif /* _KERNEL */
OpenPOWER on IntegriCloud