summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/scsi/adapters/smrt/smrt.h
blob: 5aba7438340fe121dfce26bc1bdd5503d082c2e4 (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
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright (c) 2017, Joyent, Inc.
 */

#ifndef	_SMRT_H
#define	_SMRT_H

#include <sys/types.h>
#include <sys/pci.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/map.h>
#include <sys/modctl.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/stat.h>
#include <sys/scsi/scsi.h>
#include <sys/scsi/impl/spc3_types.h>
#include <sys/devops.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sdt.h>
#include <sys/policy.h>
#include <sys/ctype.h>

#if !defined(_LITTLE_ENDIAN) || !defined(_BIT_FIELDS_LTOH)
/*
 * This driver contains a number of multi-byte bit fields and other structs
 * that are only correct on a system with the same ordering as x86.
 */
#error "smrt: driver works only on little endian systems"
#endif

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * Some structures are statically sized based on the expected number of logical
 * drives and controllers in the system.  These definitions are used throughout
 * other driver-specific header files, and must appear prior to their
 * inclusion.
 */
#define	SMRT_MAX_LOGDRV		64	/* Maximum number of logical drives */
#define	SMRT_MAX_PHYSDEV	128	/* Maximum number of physical devices */

#include <sys/scsi/adapters/smrt/smrt_ciss.h>
#include <sys/scsi/adapters/smrt/smrt_scsi.h>

#ifdef	__cplusplus
extern "C" {
#endif

extern ddi_device_acc_attr_t smrt_dev_attributes;

typedef enum smrt_init_level {
	SMRT_INITLEVEL_BASIC =			(0x1 << 0),
	SMRT_INITLEVEL_I2O_MAPPED =		(0x1 << 1),
	SMRT_INITLEVEL_CFGTBL_MAPPED =		(0x1 << 2),
	SMRT_INITLEVEL_PERIODIC =		(0x1 << 3),
	SMRT_INITLEVEL_INT_ALLOC =		(0x1 << 4),
	SMRT_INITLEVEL_INT_ADDED =		(0x1 << 5),
	SMRT_INITLEVEL_INT_ENABLED =		(0x1 << 6),
	SMRT_INITLEVEL_SCSA =			(0x1 << 7),
	SMRT_INITLEVEL_MUTEX =			(0x1 << 8),
	SMRT_INITLEVEL_TASKQ =			(0x1 << 9),
	SMRT_INITLEVEL_ASYNC_EVENT =		(0x1 << 10),
} smrt_init_level_t;

/*
 * Commands issued to the controller carry a (generally 32-bit, though with
 * two reserved signalling bits) identifying tag number.  In order to avoid
 * having the controller confuse us by double-reporting the completion of a
 * particular tag, we try to reuse them as infrequently as possible.  In
 * practice, this means looping through a range of values.  The minimum and
 * maximum value are defined below.  A single command tag value is set aside
 * for polled commands sent prior to full initialisation of the driver.
 */
#define	SMRT_PRE_TAG_NUMBER			0x00000bad
#define	SMRT_MIN_TAG_NUMBER			0x00001000
#define	SMRT_MAX_TAG_NUMBER			0x0fffffff

/*
 * Character strings that represent the names of the iports used for both
 * physical and virtual volumes.
 */
#define	SMRT_IPORT_PHYS				"p0"
#define	SMRT_IPORT_VIRT				"v0"

/*
 * Definitions to support waiting for the controller to converge on a
 * particular state: ready or not ready.  These are used with
 * smrt_ctlr_wait_for_state().
 */
#define	SMRT_WAIT_DELAY_SECONDS			120
typedef enum smrt_wait_state {
	SMRT_WAIT_STATE_READY = 1,
	SMRT_WAIT_STATE_UNREADY
} smrt_wait_state_t;

typedef enum smrt_ctlr_mode {
	SMRT_CTLR_MODE_UNKNOWN = 0,
	SMRT_CTLR_MODE_SIMPLE
} smrt_ctlr_mode_t;

/*
 * In addition to Logical Volumes, we also expose the controller at a
 * pseudo target address on the SCSI bus we are essentially pretending to be.
 */
#define	SMRT_CONTROLLER_TARGET			128

/*
 * When waiting for volume discovery to complete, we wait for a maximum
 * duration (in seconds) before giving up.
 */
#define	SMRT_DISCOVER_TIMEOUT			30

/*
 * The maintenance routine which checks for controller lockup and aborts
 * commands that have passed their timeout runs periodically.  The time is
 * expressed in seconds.
 */
#define	SMRT_PERIODIC_RATE			5

/*
 * At times, we need to check if the controller is still responding.  To do
 * that, we send a Nop message to the controller and make sure it completes
 * successfully.  So that we don't wait forever, we set a timeout (in seconds).
 */
#define	SMRT_PING_CHECK_TIMEOUT			60

/*
 * When detaching the device, we may need to have an asynchronous event
 * cancellation be issued.  While this should be relatively smooth, we don't
 * want to wait forever for it.  As such we set a timeout in seconds.
 */
#define	SMRT_ASYNC_CANCEL_TIMEOUT		60

/*
 * HP PCI vendor ID and Generation 9 device ID. Used to identify generations of
 * supported controllers.
 */
#define	SMRT_VENDOR_HP				0x103c
#define	SMRT_DEVICE_GEN9			0x3238

typedef enum smrt_controller_status {
	/*
	 * An attempt is being made to detach the controller instance.
	 */
	SMRT_CTLR_STATUS_DETACHING =		(0x1 << 0),

	/*
	 * The controller is believed to be functioning correctly.  The driver
	 * is to allow command submission, process interrupts, and perform
	 * periodic background maintenance.
	 */
	SMRT_CTLR_STATUS_RUNNING =		(0x1 << 1),

	/*
	 * The controller is currently being reset.
	 */
	SMRT_CTLR_STATUS_RESETTING =		(0x1 << 2),

	/*
	 * Our async event notification command is currently in need of help
	 * from the broader driver.  This will be set by smrt_event_complete()
	 * to indicate that the command is not being processed due to a
	 * controller reset or because another fatal error occurred.  The
	 * periodic will have to pick up and recover this for us.  It is only
	 * safe for the driver to manipulate the event command outside of
	 * smrt_event_complete() if this flag is set.
	 */
	SMRT_CTLR_ASYNC_INTERVENTION =		(0x1 << 3),

	/*
	 * See the theory statement on discovery and resets in smrt_ciss.c for
	 * an explanation of these values.
	 */
	SMRT_CTLR_DISCOVERY_REQUESTED =		(0x1 << 4),
	SMRT_CTLR_DISCOVERY_RUNNING =		(0x1 << 5),
	SMRT_CTLR_DISCOVERY_PERIODIC =		(0x1 << 6),
	SMRT_CTLR_DISCOVERY_REQUIRED =		(0x1 << 7),
} smrt_controller_status_t;

#define	SMRT_CTLR_DISCOVERY_MASK	(SMRT_CTLR_DISCOVERY_REQUESTED | \
    SMRT_CTLR_DISCOVERY_RUNNING | SMRT_CTLR_DISCOVERY_PERIODIC)

typedef struct smrt_stats {
	uint64_t smrts_tran_aborts;
	uint64_t smrts_tran_resets;
	uint64_t smrts_tran_starts;
	uint64_t smrts_ctlr_resets;
	unsigned smrts_max_inflight;
	uint64_t smrts_unclaimed_interrupts;
	uint64_t smrts_claimed_interrupts;
	uint64_t smrts_ignored_scsi_cmds;
	uint64_t smrts_events_received;
	uint64_t smrts_events_errors;
	uint64_t smrts_events_intervened;
	uint64_t smrts_discovery_tq_errors;
} smrt_stats_t;

typedef struct smrt_versions {
	uint8_t smrtv_hardware_version;

	/*
	 * These strings must be large enough to hold the 4 byte version string
	 * retrieved from an IDENTIFY CONTROLLER response, as well as the
	 * terminating NUL byte:
	 */
	char smrtv_firmware_rev[5];
	char smrtv_recovery_rev[5];
	char smrtv_bootblock_rev[5];
} smrt_versions_t;

typedef struct smrt smrt_t;
typedef struct smrt_command smrt_command_t;
typedef struct smrt_command_internal smrt_command_internal_t;
typedef struct smrt_command_scsa smrt_command_scsa_t;
typedef struct smrt_pkt smrt_pkt_t;

/*
 * Per-Controller Structure
 */
struct smrt {
	dev_info_t *smrt_dip;
	int smrt_instance;
	smrt_controller_status_t smrt_status;
	smrt_stats_t smrt_stats;

	/*
	 * Controller configuration discovered during initialisation.
	 */
	uint32_t smrt_host_support;
	uint32_t smrt_bus_support;
	uint32_t smrt_maxcmds;
	uint32_t smrt_sg_cnt;
	smrt_versions_t smrt_versions;
	uint16_t smrt_pci_vendor;
	uint16_t smrt_pci_device;

	/*
	 * iport specific data
	 */
	dev_info_t *smrt_virt_iport;
	dev_info_t *smrt_phys_iport;
	scsi_hba_tgtmap_t *smrt_virt_tgtmap;
	scsi_hba_tgtmap_t *smrt_phys_tgtmap;

	/*
	 * The transport mode of the controller.
	 */
	smrt_ctlr_mode_t smrt_ctlr_mode;

	/*
	 * The current initialisation level of the driver.  Bits in this field
	 * are set during initialisation and unset during cleanup of the
	 * allocated resources.
	 */
	smrt_init_level_t smrt_init_level;

	/*
	 * Essentially everything is protected by "smrt_mutex".  When the
	 * completion queue is updated, threads sleeping on "smrt_cv_finishq"
	 * are awoken.
	 */
	kmutex_t smrt_mutex;
	kcondvar_t smrt_cv_finishq;

	/*
	 * List of enumerated logical volumes (smrt_volume_t).
	 */
	list_t smrt_volumes;

	/*
	 * List of enumerated physical devices (smrt_physical_t).
	 */
	list_t smrt_physicals;

	/*
	 * List of attached SCSA target drivers (smrt_target_t).
	 */
	list_t smrt_targets;

	/*
	 * Controller Heartbeat Tracking
	 */
	uint32_t smrt_last_heartbeat;
	hrtime_t smrt_last_heartbeat_time;

	hrtime_t smrt_last_interrupt_claimed;
	hrtime_t smrt_last_interrupt_unclaimed;
	hrtime_t smrt_last_reset_start;
	hrtime_t smrt_last_reset_finish;

	/*
	 * Command object tracking.  These lists, and all commands within the
	 * lists, are protected by "smrt_mutex".
	 */
	uint32_t smrt_next_tag;
	avl_tree_t smrt_inflight;
	list_t smrt_commands;		/* List of all commands. */
	list_t smrt_finishq;		/* List of completed commands. */
	list_t smrt_abortq;		/* List of commands to abort. */

	/*
	 * Discovery coordination
	 */
	ddi_taskq_t *smrt_discover_taskq;
	hrtime_t smrt_last_phys_discovery;
	hrtime_t smrt_last_log_discovery;
	uint64_t smrt_discover_gen;

	/*
	 * Controller interrupt handler registration.
	 */
	int smrt_interrupt_type;
	int smrt_interrupt_cap;
	uint_t smrt_interrupt_pri;
	ddi_intr_handle_t smrt_interrupts[1];
	int smrt_ninterrupts;

	ddi_periodic_t smrt_periodic;

	scsi_hba_tran_t *smrt_hba_tran;

	ddi_dma_attr_t smrt_dma_attr;

	/*
	 * Access to the I2O Registers:
	 */
	unsigned smrt_i2o_bar;
	caddr_t smrt_i2o_space;
	ddi_acc_handle_t smrt_i2o_handle;

	/*
	 * Access to the Configuration Table:
	 */
	unsigned smrt_ct_bar;
	uint32_t smrt_ct_baseaddr;
	CfgTable_t *smrt_ct;
	ddi_acc_handle_t smrt_ct_handle;

	/*
	 * Asynchronous Event State
	 */
	uint32_t smrt_event_count;
	smrt_command_t *smrt_event_cmd;
	smrt_command_t *smrt_event_cancel_cmd;
	kcondvar_t smrt_event_queue;
};

/*
 * Logical Volume Structure
 */
typedef enum smrt_volume_flags {
	SMRT_VOL_FLAG_WWN =			(0x1 << 0),
} smrt_volume_flags_t;

typedef struct smrt_volume {
	LUNAddr_t smlv_addr;
	smrt_volume_flags_t smlv_flags;

	uint8_t smlv_wwn[16];
	uint64_t smlv_gen;

	smrt_t *smlv_ctlr;
	list_node_t smlv_link;

	/*
	 * List of SCSA targets currently attached to this Logical Volume:
	 */
	list_t smlv_targets;
} smrt_volume_t;

typedef struct smrt_physical {
	LUNAddr_t smpt_addr;
	uint64_t smpt_wwn;
	uint8_t smpt_dtype;
	uint16_t smpt_bmic;
	uint64_t smpt_gen;
	boolean_t smpt_supported;
	boolean_t smpt_visible;
	boolean_t smpt_unsup_warn;
	list_node_t smpt_link;
	list_t smpt_targets;
	smrt_t *smpt_ctlr;
	smrt_identify_physical_drive_t *smpt_info;
} smrt_physical_t;

/*
 * Per-Target Structure
 */
typedef struct smrt_target {
	struct scsi_device *smtg_scsi_dev;

	boolean_t smtg_physical;

	/*
	 * This is only used when performing discovery during panic, as we need
	 * a mechanism to determine if the set of drives has shifted.
	 */
	boolean_t smtg_gone;

	/*
	 * Linkage back to the device that this target represents. This may be
	 * either a smrt_volume_t or a smrt_physical_t. We keep a pointer to the
	 * address, as that's the one thing we generally care about.
	 */
	union {
		smrt_physical_t *smtg_phys;
		smrt_volume_t *smtg_vol;
	} smtg_lun;
	list_node_t smtg_link_lun;
	LUNAddr_t *smtg_addr;

	/*
	 * Linkage back to the controller:
	 */
	smrt_t *smtg_ctlr;
	list_node_t smtg_link_ctlr;
} smrt_target_t;

/*
 * DMA Resource Tracking Structure
 */
typedef enum smrt_dma_level {
	SMRT_DMALEVEL_HANDLE_ALLOC =		(0x1 << 0),
	SMRT_DMALEVEL_MEMORY_ALLOC =		(0x1 << 1),
	SMRT_DMALEVEL_HANDLE_BOUND =		(0x1 << 2),
} smrt_dma_level_t;

typedef struct smrt_dma {
	smrt_dma_level_t smdma_level;
	size_t smdma_real_size;
	ddi_dma_handle_t smdma_dma_handle;
	ddi_acc_handle_t smdma_acc_handle;
	ddi_dma_cookie_t smdma_dma_cookies[1];
	uint_t smdma_dma_ncookies;
} smrt_dma_t;


typedef enum smrt_command_status {
	/*
	 * When a command is submitted to the controller, it is marked USED
	 * to avoid accidental reuse of the command without reinitialising
	 * critical fields.  The submitted command is also marked INFLIGHT
	 * to reflect its inclusion in the "smrt_inflight" AVL tree.  When
	 * the command is completed by the controller, INFLIGHT is unset.
	 */
	SMRT_CMD_STATUS_USED =			(0x1 << 0),
	SMRT_CMD_STATUS_INFLIGHT =		(0x1 << 1),

	/*
	 * This flag is set during abort queue processing to record that this
	 * command was aborted in response to an expired timeout, and not some
	 * other cancellation.  If the controller is able to abort the command,
	 * we use this flag to let the SCSI framework know that the command
	 * timed out.
	 */
	SMRT_CMD_STATUS_TIMEOUT =		(0x1 << 2),

	/*
	 * The controller set the error bit when completing this command.
	 * Details of the particular fault may be read from the error
	 * information written by the controller.
	 */
	SMRT_CMD_STATUS_ERROR =			(0x1 << 3),

	/*
	 * This command has been abandoned by the original submitter.  This
	 * could happen if the command did not complete in a timely fashion.
	 * When it reaches the finish queue it will be freed without further
	 * processing.
	 */
	SMRT_CMD_STATUS_ABANDONED =		(0x1 << 4),

	/*
	 * This command has made it through the completion queue and had final
	 * processing performed.
	 */
	SMRT_CMD_STATUS_COMPLETE =		(0x1 << 5),

	/*
	 * A polled message will be ignored by the regular processing of the
	 * completion queue.  The blocking function doing the polling is
	 * responsible for watching the command on which it has set the POLLED
	 * flag.  Regular completion queue processing (which might happen in
	 * the polling function, or it might happen in the interrupt handler)
	 * will set POLL_COMPLETE once it is out of the finish queue
	 * altogether.
	 */
	SMRT_CMD_STATUS_POLLED =		(0x1 << 6),
	SMRT_CMD_STATUS_POLL_COMPLETE =		(0x1 << 7),

	/*
	 * An abort message has been sent to the controller in an attempt to
	 * cancel this command.
	 */
	SMRT_CMD_STATUS_ABORT_SENT =		(0x1 << 8),

	/*
	 * This command has been passed to our tran_start(9E) handler.
	 */
	SMRT_CMD_STATUS_TRAN_START =		(0x1 << 9),

	/*
	 * This command was for a SCSI command that we are explicitly avoiding
	 * sending to the controller.
	 */
	SMRT_CMD_STATUS_TRAN_IGNORED =		(0x1 << 10),

	/*
	 * This command has been submitted once, and subsequently passed to
	 * smrt_command_reuse().
	 */
	SMRT_CMD_STATUS_REUSED =		(0x1 << 11),

	/*
	 * A controller reset has been issued, so a response for this command
	 * is not expected.  If one arrives before the controller reset has
	 * taken effect, it likely cannot be trusted.
	 */
	SMRT_CMD_STATUS_RESET_SENT =		(0x1 << 12),

	/*
	 * Certain commands related to discovery and pinging need to be run
	 * during the context after a reset has occurred, but before the
	 * controller is considered.  Such commands can use this flag to bypass
	 * the normal smrt_submit() check.
	 */
	SMRT_CMD_IGNORE_RUNNING =		(0x1 << 13),
} smrt_command_status_t;

typedef enum smrt_command_type {
	SMRT_CMDTYPE_INTERNAL = 1,
	SMRT_CMDTYPE_EVENT,
	SMRT_CMDTYPE_ABORTQ,
	SMRT_CMDTYPE_SCSA,
	SMRT_CMDTYPE_PREINIT,
} smrt_command_type_t;

struct smrt_command {
	uint32_t smcm_tag;
	smrt_command_type_t smcm_type;
	smrt_command_status_t smcm_status;

	smrt_t *smcm_ctlr;
	smrt_target_t *smcm_target;

	list_node_t smcm_link;		/* Linkage for allocated list. */
	list_node_t smcm_link_finish;	/* Linkage for completion list. */
	list_node_t smcm_link_abort;	/* Linkage for abort list. */
	avl_node_t smcm_node;		/* Inflight AVL membership. */

	hrtime_t smcm_time_submit;
	hrtime_t smcm_time_complete;

	hrtime_t smcm_expiry;

	/*
	 * The time at which an abort message was sent to try and terminate
	 * this command, as well as the tag of the abort message itself:
	 */
	hrtime_t smcm_abort_time;
	uint32_t smcm_abort_tag;

	/*
	 * Ancillary data objects.  Only one of these will be allocated for any
	 * given command, but we nonetheless resist the temptation to use a
	 * union of pointers in order to make incorrect usage obvious.
	 */
	smrt_command_scsa_t *smcm_scsa;
	smrt_command_internal_t *smcm_internal;

	/*
	 * Physical allocation tracking for the actual command to send to the
	 * controller.
	 */
	smrt_dma_t smcm_contig;

	CommandList_t *smcm_va_cmd;
	uint32_t smcm_pa_cmd;

	ErrorInfo_t *smcm_va_err;
	uint32_t smcm_pa_err;
};

/*
 * Commands issued internally to the driver (as opposed to by the HBA
 * framework) generally require a buffer in which to assemble the command body,
 * and for receiving the response from the controller.  The following object
 * tracks this (optional) extra buffer.
 */
struct smrt_command_internal {
	smrt_dma_t smcmi_contig;

	void *smcmi_va;
	uint32_t smcmi_pa;
	size_t smcmi_len;
};

/*
 * Commands issued via the SCSI framework have a number of additional
 * properties.
 */
struct smrt_command_scsa {
	struct scsi_pkt *smcms_pkt;
	smrt_command_t *smcms_command;
};


/*
 * CISS transport routines.
 */
void smrt_periodic(void *);
void smrt_lockup_check(smrt_t *);
int smrt_submit(smrt_t *, smrt_command_t *);
void smrt_submit_simple(smrt_t *, smrt_command_t *);
int smrt_retrieve(smrt_t *);
void smrt_retrieve_simple(smrt_t *);
int smrt_poll_for(smrt_t *, smrt_command_t *);
int smrt_preinit_command_simple(smrt_t *, smrt_command_t *);

/*
 * Interrupt service routines.
 */
int smrt_interrupts_setup(smrt_t *);
int smrt_interrupts_enable(smrt_t *);
void smrt_interrupts_teardown(smrt_t *);
uint32_t smrt_isr_hw_simple(caddr_t, caddr_t);

/*
 * Interrupt enable/disable routines.
 */
void smrt_intr_set(smrt_t *, boolean_t);

/*
 * Controller initialisation routines.
 */
int smrt_ctlr_init(smrt_t *);
void smrt_ctlr_teardown(smrt_t *);
int smrt_ctlr_reset(smrt_t *);
int smrt_ctlr_wait_for_state(smrt_t *, smrt_wait_state_t);
int smrt_ctlr_init_simple(smrt_t *);
void smrt_ctlr_teardown_simple(smrt_t *);
int smrt_cfgtbl_flush(smrt_t *);
int smrt_cfgtbl_transport_has_support(smrt_t *, int);
void smrt_cfgtbl_transport_set(smrt_t *, int);
int smrt_cfgtbl_transport_confirm(smrt_t *, int);
uint32_t smrt_ctlr_get_cmdsoutmax(smrt_t *);
uint32_t smrt_ctlr_get_maxsgelements(smrt_t *);

/*
 * Device enumeration and lookup routines.
 */
void smrt_discover_request(smrt_t *);

int smrt_logvol_discover(smrt_t *, uint16_t, uint64_t);
void smrt_logvol_teardown(smrt_t *);
smrt_volume_t *smrt_logvol_lookup_by_id(smrt_t *, unsigned long);
void smrt_logvol_tgtmap_activate(void *, char *, scsi_tgtmap_tgt_type_t,
    void **);
boolean_t smrt_logvol_tgtmap_deactivate(void *, char *, scsi_tgtmap_tgt_type_t,
    void *, scsi_tgtmap_deact_rsn_t);

int smrt_phys_discover(smrt_t *, uint16_t, uint64_t);
smrt_physical_t *smrt_phys_lookup_by_ua(smrt_t *, const char *);
void smrt_phys_teardown(smrt_t *);
void smrt_phys_tgtmap_activate(void *, char *, scsi_tgtmap_tgt_type_t,
    void **);
boolean_t smrt_phys_tgtmap_deactivate(void *, char *, scsi_tgtmap_tgt_type_t,
    void *, scsi_tgtmap_deact_rsn_t);

/*
 * SCSI framework routines.
 */
int smrt_ctrl_hba_setup(smrt_t *);
void smrt_ctrl_hba_teardown(smrt_t *);

int smrt_logvol_hba_setup(smrt_t *, dev_info_t *);
void smrt_logvol_hba_teardown(smrt_t *, dev_info_t *);
int smrt_phys_hba_setup(smrt_t *, dev_info_t *);
void smrt_phys_hba_teardown(smrt_t *, dev_info_t *);

void smrt_hba_complete(smrt_command_t *);

void smrt_process_finishq(smrt_t *);
void smrt_process_abortq(smrt_t *);

/*
 * Command block management.
 */
smrt_command_t *smrt_command_alloc(smrt_t *, smrt_command_type_t,
    int);
smrt_command_t *smrt_command_alloc_preinit(smrt_t *, size_t, int);
int smrt_command_attach_internal(smrt_t *, smrt_command_t *, size_t,
    int);
void smrt_command_free(smrt_command_t *);
smrt_command_t *smrt_lookup_inflight(smrt_t *, uint32_t);
void smrt_command_reuse(smrt_command_t *);

/*
 * Device message construction routines.
 */
void smrt_write_lun_addr_phys(LUNAddr_t *, boolean_t, unsigned, unsigned);
void smrt_write_controller_lun_addr(LUNAddr_t *);
uint16_t smrt_lun_addr_to_bmic(PhysDevAddr_t *);
void smrt_write_message_abort_one(smrt_command_t *, uint32_t);
void smrt_write_message_abort_all(smrt_command_t *, LUNAddr_t *);
void smrt_write_message_nop(smrt_command_t *, int);
void smrt_write_message_event_notify(smrt_command_t *);

/*
 * Device management routines.
 */
int smrt_device_setup(smrt_t *);
void smrt_device_teardown(smrt_t *);
uint32_t smrt_get32(smrt_t *, offset_t);
void smrt_put32(smrt_t *, offset_t, uint32_t);

/*
 * SATA related routines.
 */
int smrt_sata_determine_wwn(smrt_t *, PhysDevAddr_t *, uint64_t *, uint16_t);

/*
 * Asynchronous Event Notification
 */
int smrt_event_init(smrt_t *);
void smrt_event_fini(smrt_t *);
void smrt_event_complete(smrt_command_t *);

#ifdef	__cplusplus
}
#endif

#endif	/* _SMRT_H */