xref: /titanic_50/usr/src/uts/common/io/aac/aac.c (revision 0b5ce10aee80822ecc7df77df92a5e24078ba196)
1 /*
2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright 2005-08 Adaptec, Inc.
7  * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
8  * Copyright (c) 2000 Michael Smith
9  * Copyright (c) 2001 Scott Long
10  * Copyright (c) 2000 BSDi
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/modctl.h>
35 #include <sys/conf.h>
36 #include <sys/cmn_err.h>
37 #include <sys/ddi.h>
38 #include <sys/devops.h>
39 #include <sys/pci.h>
40 #include <sys/types.h>
41 #include <sys/ddidmareq.h>
42 #include <sys/scsi/scsi.h>
43 #include <sys/ksynch.h>
44 #include <sys/sunddi.h>
45 #include <sys/byteorder.h>
46 #include "aac_regs.h"
47 #include "aac.h"
48 
49 /*
50  * FMA header files
51  */
52 #include <sys/ddifm.h>
53 #include <sys/fm/protocol.h>
54 #include <sys/fm/util.h>
55 #include <sys/fm/io/ddi.h>
56 
57 /*
58  * For minor nodes created by the SCSA framework, minor numbers are
59  * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
60  * number less than 64.
61  *
62  * To support cfgadm, need to confirm the SCSA framework by creating
63  * devctl/scsi and driver specific minor nodes under SCSA format,
64  * and calling scsi_hba_xxx() functions aacordingly.
65  */
66 
67 #define	AAC_MINOR		32
68 #define	INST2AAC(x)		(((x) << INST_MINOR_SHIFT) | AAC_MINOR)
69 #define	AAC_SCSA_MINOR(x)	((x) & TRAN_MINOR_MASK)
70 #define	AAC_IS_SCSA_NODE(x)	((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
71 
72 #define	SD2TRAN(sd)		((sd)->sd_address.a_hba_tran)
73 #define	AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
74 #define	AAC_DIP2TRAN(dip)	((scsi_hba_tran_t *)ddi_get_driver_private(dip))
75 #define	AAC_DIP2SOFTS(dip)	(AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
76 #define	SD2AAC(sd)		(AAC_TRAN2SOFTS(SD2TRAN(sd)))
77 #define	AAC_PD(t)		((t) - AAC_MAX_LD)
78 #define	AAC_DEV(softs, t)	(((t) < AAC_MAX_LD) ? \
79 				&(softs)->containers[(t)].dev : \
80 				((t) < AAC_MAX_DEV(softs)) ? \
81 				&(softs)->nondasds[AAC_PD(t)].dev : NULL)
82 #define	AAC_DEVCFG_BEGIN(softs, tgt) \
83 				aac_devcfg((softs), (tgt), 1)
84 #define	AAC_DEVCFG_END(softs, tgt) \
85 				aac_devcfg((softs), (tgt), 0)
86 #define	PKT2AC(pkt)		((struct aac_cmd *)(pkt)->pkt_ha_private)
87 #define	AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
88 		if (!(cond)) { \
89 			int count = (timeout) * 10; \
90 			while (count) { \
91 				drv_usecwait(100); \
92 				if (cond) \
93 					break; \
94 				count--; \
95 			} \
96 			(timeout) = (count + 9) / 10; \
97 		} \
98 	}
99 
100 #define	AAC_SENSE_DATA_DESCR_LEN \
101 	(sizeof (struct scsi_descr_sense_hdr) + \
102 	sizeof (struct scsi_information_sense_descr))
103 #define	AAC_ARQ64_LENGTH \
104 	(sizeof (struct scsi_arq_status) + \
105 	AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
106 
107 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
108 #define	AAC_GETGXADDR(cmdlen, cdbp) \
109 	((cmdlen == 6) ? GETG0ADDR(cdbp) : \
110 	(cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
111 	((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
112 
113 #define	AAC_CDB_INQUIRY_CMDDT	0x02
114 #define	AAC_CDB_INQUIRY_EVPD	0x01
115 #define	AAC_VPD_PAGE_CODE	1
116 #define	AAC_VPD_PAGE_LENGTH	3
117 #define	AAC_VPD_PAGE_DATA	4
118 #define	AAC_VPD_ID_CODESET	0
119 #define	AAC_VPD_ID_TYPE		1
120 #define	AAC_VPD_ID_LENGTH	3
121 #define	AAC_VPD_ID_DATA		4
122 
123 #define	AAC_SCSI_RPTLUNS_HEAD_SIZE			0x08
124 #define	AAC_SCSI_RPTLUNS_ADDR_SIZE			0x08
125 #define	AAC_SCSI_RPTLUNS_ADDR_MASK			0xC0
126 /* 00b - peripheral device addressing method */
127 #define	AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL		0x00
128 /* 01b - flat space addressing method */
129 #define	AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE		0x40
130 /* 10b - logical unit addressing method */
131 #define	AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT		0x80
132 
133 /* Return the size of FIB with data part type data_type */
134 #define	AAC_FIB_SIZEOF(data_type) \
135 	(sizeof (struct aac_fib_header) + sizeof (data_type))
136 /* Return the container size defined in mir */
137 #define	AAC_MIR_SIZE(softs, acc, mir) \
138 	(((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
139 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
140 	((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
141 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
142 
143 /* The last entry of aac_cards[] is for unknown cards */
144 #define	AAC_UNKNOWN_CARD \
145 	(sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
146 #define	CARD_IS_UNKNOWN(i)	(i == AAC_UNKNOWN_CARD)
147 #define	BUF_IS_READ(bp)		((bp)->b_flags & B_READ)
148 #define	AAC_IS_Q_EMPTY(q)	((q)->q_head == NULL)
149 #define	AAC_CMDQ(acp)		(!((acp)->flags & AAC_CMD_SYNC))
150 
151 #define	PCI_MEM_GET32(softs, off) \
152 	ddi_get32((softs)->pci_mem_handle, \
153 	    (void *)((softs)->pci_mem_base_vaddr + (off)))
154 #define	PCI_MEM_PUT32(softs, off, val) \
155 	ddi_put32((softs)->pci_mem_handle, \
156 	    (void *)((softs)->pci_mem_base_vaddr + (off)), \
157 	    (uint32_t)(val))
158 #define	PCI_MEM_GET16(softs, off) \
159 	ddi_get16((softs)->pci_mem_handle, \
160 	(void *)((softs)->pci_mem_base_vaddr + (off)))
161 #define	PCI_MEM_PUT16(softs, off, val) \
162 	ddi_put16((softs)->pci_mem_handle, \
163 	(void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
164 /* Write host data at valp to device mem[off] repeatedly count times */
165 #define	PCI_MEM_REP_PUT8(softs, off, valp, count) \
166 	ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
167 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
168 	    count, DDI_DEV_AUTOINCR)
169 /* Read device data at mem[off] to host addr valp repeatedly count times */
170 #define	PCI_MEM_REP_GET8(softs, off, valp, count) \
171 	ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
172 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
173 	    count, DDI_DEV_AUTOINCR)
174 #define	AAC_GET_FIELD8(acc, d, s, field) \
175 	(d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
176 #define	AAC_GET_FIELD32(acc, d, s, field) \
177 	(d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
178 #define	AAC_GET_FIELD64(acc, d, s, field) \
179 	(d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
180 #define	AAC_REP_GET_FIELD8(acc, d, s, field, r) \
181 	ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
182 	    (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
183 #define	AAC_REP_GET_FIELD32(acc, d, s, field, r) \
184 	ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
185 	    (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
186 
187 #define	AAC_ENABLE_INTR(softs) { \
188 		if (softs->flags & AAC_FLAGS_NEW_COMM) \
189 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
190 		else \
191 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
192 		softs->state |= AAC_STATE_INTR; \
193 	}
194 
195 #define	AAC_DISABLE_INTR(softs)	{ \
196 		PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
197 		softs->state &= ~AAC_STATE_INTR; \
198 	}
199 #define	AAC_STATUS_CLR(softs, mask)	PCI_MEM_PUT32(softs, AAC_ODBR, mask)
200 #define	AAC_STATUS_GET(softs)		PCI_MEM_GET32(softs, AAC_ODBR)
201 #define	AAC_NOTIFY(softs, val)		PCI_MEM_PUT32(softs, AAC_IDBR, val)
202 #define	AAC_OUTB_GET(softs)		PCI_MEM_GET32(softs, AAC_OQUE)
203 #define	AAC_OUTB_SET(softs, val)	PCI_MEM_PUT32(softs, AAC_OQUE, val)
204 #define	AAC_FWSTATUS_GET(softs)	\
205 	((softs)->aac_if.aif_get_fwstatus(softs))
206 #define	AAC_MAILBOX_GET(softs, mb) \
207 	((softs)->aac_if.aif_get_mailbox((softs), (mb)))
208 #define	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
209 	((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
210 	    (arg0), (arg1), (arg2), (arg3)))
211 
212 #define	AAC_MGT_SLOT_NUM	2
213 #define	AAC_THROTTLE_DRAIN	-1
214 
215 #define	AAC_QUIESCE_TICK	1	/* 1 second */
216 #define	AAC_QUIESCE_TIMEOUT	180	/* 180 seconds */
217 #define	AAC_DEFAULT_TICK	10	/* 10 seconds */
218 #define	AAC_SYNC_TICK		(30*60)	/* 30 minutes */
219 
220 /* Poll time for aac_do_poll_io() */
221 #define	AAC_POLL_TIME		60	/* 60 seconds */
222 
223 /* IOP reset */
224 #define	AAC_IOP_RESET_SUCCEED		0	/* IOP reset succeed */
225 #define	AAC_IOP_RESET_FAILED		-1	/* IOP reset failed */
226 #define	AAC_IOP_RESET_ABNORMAL		-2	/* Reset operation abnormal */
227 
228 /*
229  * Hardware access functions
230  */
231 static int aac_rx_get_fwstatus(struct aac_softstate *);
232 static int aac_rx_get_mailbox(struct aac_softstate *, int);
233 static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
234     uint32_t, uint32_t, uint32_t);
235 static int aac_rkt_get_fwstatus(struct aac_softstate *);
236 static int aac_rkt_get_mailbox(struct aac_softstate *, int);
237 static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
238     uint32_t, uint32_t, uint32_t);
239 
240 /*
241  * SCSA function prototypes
242  */
243 static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
244 static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
245 static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
246 static int aac_quiesce(dev_info_t *);
247 static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
248 
249 /*
250  * Interrupt handler functions
251  */
252 static int aac_query_intrs(struct aac_softstate *, int);
253 static int aac_add_intrs(struct aac_softstate *);
254 static void aac_remove_intrs(struct aac_softstate *);
255 static int aac_enable_intrs(struct aac_softstate *);
256 static int aac_disable_intrs(struct aac_softstate *);
257 static uint_t aac_intr_old(caddr_t);
258 static uint_t aac_intr_new(caddr_t);
259 static uint_t aac_softintr(caddr_t);
260 
261 /*
262  * Internal functions in attach
263  */
264 static int aac_check_card_type(struct aac_softstate *);
265 static int aac_check_firmware(struct aac_softstate *);
266 static int aac_common_attach(struct aac_softstate *);
267 static void aac_common_detach(struct aac_softstate *);
268 static int aac_probe_containers(struct aac_softstate *);
269 static int aac_alloc_comm_space(struct aac_softstate *);
270 static int aac_setup_comm_space(struct aac_softstate *);
271 static void aac_free_comm_space(struct aac_softstate *);
272 static int aac_hba_setup(struct aac_softstate *);
273 
274 /*
275  * Sync FIB operation functions
276  */
277 int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
278     uint32_t, uint32_t, uint32_t, uint32_t *);
279 static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
280 
281 /*
282  * Command queue operation functions
283  */
284 static void aac_cmd_initq(struct aac_cmd_queue *);
285 static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
286 static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
287 static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
288 
289 /*
290  * FIB queue operation functions
291  */
292 static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
293 static int aac_fib_dequeue(struct aac_softstate *, int, int *);
294 
295 /*
296  * Slot operation functions
297  */
298 static int aac_create_slots(struct aac_softstate *);
299 static void aac_destroy_slots(struct aac_softstate *);
300 static void aac_alloc_fibs(struct aac_softstate *);
301 static void aac_destroy_fibs(struct aac_softstate *);
302 static struct aac_slot *aac_get_slot(struct aac_softstate *);
303 static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
304 static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
305 static void aac_free_fib(struct aac_slot *);
306 
307 /*
308  * Internal functions
309  */
310 static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
311     uint16_t);
312 static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
313 static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
314 static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
315 static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
316 static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
317 static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
318 static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
319 static void aac_start_waiting_io(struct aac_softstate *);
320 static void aac_drain_comp_q(struct aac_softstate *);
321 int aac_do_io(struct aac_softstate *, struct aac_cmd *);
322 static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
323 static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
324 static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
325 static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
326 static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
327 static int aac_send_command(struct aac_softstate *, struct aac_slot *);
328 static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
329 static int aac_dma_sync_ac(struct aac_cmd *);
330 static int aac_shutdown(struct aac_softstate *);
331 static int aac_reset_adapter(struct aac_softstate *);
332 static int aac_do_quiesce(struct aac_softstate *softs);
333 static int aac_do_unquiesce(struct aac_softstate *softs);
334 static void aac_unhold_bus(struct aac_softstate *, int);
335 static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
336     int, int);
337 
338 /*
339  * Adapter Initiated FIB handling function
340  */
341 static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
342     struct aac_fib *, int);
343 static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
344 
345 /*
346  * Event handling related functions
347  */
348 static void aac_timer(void *);
349 static void aac_event_thread(struct aac_softstate *);
350 static void aac_event_disp(struct aac_softstate *, int);
351 
352 /*
353  * IOCTL interface related functions
354  */
355 static int aac_open(dev_t *, int, int, cred_t *);
356 static int aac_close(dev_t, int, int, cred_t *);
357 static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
358 extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
359 
360 /*
361  * FMA Prototypes
362  */
363 static void aac_fm_init(struct aac_softstate *);
364 static void aac_fm_fini(struct aac_softstate *);
365 static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
366 int aac_check_acc_handle(ddi_acc_handle_t);
367 int aac_check_dma_handle(ddi_dma_handle_t);
368 void aac_fm_ereport(struct aac_softstate *, char *);
369 
370 /*
371  * Auto enumeration functions
372  */
373 static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
374 static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
375     void *, dev_info_t **);
376 static int aac_handle_dr(struct aac_softstate *, int, int, int);
377 
378 extern pri_t minclsyspri;
379 
380 #ifdef DEBUG
381 /*
382  * UART	debug output support
383  */
384 
385 #define	AAC_PRINT_BUFFER_SIZE		512
386 #define	AAC_PRINT_TIMEOUT		250	/* 1/4 sec. = 250 msec. */
387 
388 #define	AAC_FW_DBG_STRLEN_OFFSET	0x00
389 #define	AAC_FW_DBG_FLAGS_OFFSET		0x04
390 #define	AAC_FW_DBG_BLED_OFFSET		0x08
391 
392 static int aac_get_fw_debug_buffer(struct aac_softstate *);
393 static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
394 static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
395 
396 static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
397 static char aac_fmt[] = " %s";
398 static char aac_fmt_header[] = " %s.%d: %s";
399 static kmutex_t aac_prt_mutex;
400 
401 /*
402  * Debug flags to be put into the softstate flags field
403  * when initialized
404  */
405 uint32_t aac_debug_flags =
406 /*    AACDB_FLAGS_KERNEL_PRINT | */
407 /*    AACDB_FLAGS_FW_PRINT |	*/
408 /*    AACDB_FLAGS_MISC |	*/
409 /*    AACDB_FLAGS_FUNC1 |	*/
410 /*    AACDB_FLAGS_FUNC2 |	*/
411 /*    AACDB_FLAGS_SCMD |	*/
412 /*    AACDB_FLAGS_AIF |		*/
413 /*    AACDB_FLAGS_FIB |		*/
414 /*    AACDB_FLAGS_IOCTL |	*/
415 0;
416 uint32_t aac_debug_fib_flags =
417 /*    AACDB_FLAGS_FIB_RW |	*/
418 /*    AACDB_FLAGS_FIB_IOCTL |	*/
419 /*    AACDB_FLAGS_FIB_SRB |	*/
420 /*    AACDB_FLAGS_FIB_SYNC |	*/
421 /*    AACDB_FLAGS_FIB_HEADER |	*/
422 /*    AACDB_FLAGS_FIB_TIMEOUT |	*/
423 0;
424 
425 #endif /* DEBUG */
426 
427 static struct cb_ops aac_cb_ops = {
428 	aac_open,	/* open */
429 	aac_close,	/* close */
430 	nodev,		/* strategy */
431 	nodev,		/* print */
432 	nodev,		/* dump */
433 	nodev,		/* read */
434 	nodev,		/* write */
435 	aac_ioctl,	/* ioctl */
436 	nodev,		/* devmap */
437 	nodev,		/* mmap */
438 	nodev,		/* segmap */
439 	nochpoll,	/* poll */
440 	ddi_prop_op,	/* cb_prop_op */
441 	NULL,		/* streamtab */
442 	D_64BIT | D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
443 	CB_REV,		/* cb_rev */
444 	nodev,		/* async I/O read entry point */
445 	nodev		/* async I/O write entry point */
446 };
447 
448 static struct dev_ops aac_dev_ops = {
449 	DEVO_REV,
450 	0,
451 	aac_getinfo,
452 	nulldev,
453 	nulldev,
454 	aac_attach,
455 	aac_detach,
456 	aac_reset,
457 	&aac_cb_ops,
458 	NULL,
459 	NULL,
460 	aac_quiesce,
461 };
462 
463 static struct modldrv aac_modldrv = {
464 	&mod_driverops,
465 	"AAC Driver " AAC_DRIVER_VERSION,
466 	&aac_dev_ops,
467 };
468 
469 static struct modlinkage aac_modlinkage = {
470 	MODREV_1,
471 	&aac_modldrv,
472 	NULL
473 };
474 
475 static struct aac_softstate  *aac_softstatep;
476 
477 /*
478  * Supported card list
479  * ordered in vendor id, subvendor id, subdevice id, and device id
480  */
481 static struct aac_card_type aac_cards[] = {
482 	{0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
483 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
484 	    "Dell", "PERC 3/Di"},
485 	{0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
486 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
487 	    "Dell", "PERC 3/Di"},
488 	{0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
489 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
490 	    "Dell", "PERC 3/Si"},
491 	{0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
492 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
493 	    "Dell", "PERC 3/Di"},
494 	{0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
495 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
496 	    "Dell", "PERC 3/Si"},
497 	{0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
498 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
499 	    "Dell", "PERC 3/Di"},
500 	{0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
501 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
502 	    "Dell", "PERC 3/Di"},
503 	{0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
504 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
505 	    "Dell", "PERC 3/Di"},
506 	{0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
507 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
508 	    "Dell", "PERC 3/Di"},
509 	{0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
510 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
511 	    "Dell", "PERC 3/Di"},
512 	{0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
513 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
514 	    "Dell", "PERC 320/DC"},
515 	{0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
516 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
517 
518 	{0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
519 	    0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
520 	{0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
521 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
522 	{0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
523 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
524 
525 	{0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
526 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
527 	{0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
528 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
529 
530 	{0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
531 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
532 	    "Adaptec", "2200S"},
533 	{0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
534 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
535 	    "Adaptec", "2120S"},
536 	{0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
537 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
538 	    "Adaptec", "2200S"},
539 	{0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
540 	    0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
541 	{0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
542 	    0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
543 	{0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
544 	    0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
545 	{0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
546 	    0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
547 	{0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
548 	    0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
549 	{0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
550 	    0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
551 	{0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
552 	    0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
553 	{0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
554 	    0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
555 	{0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
556 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
557 	{0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
558 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
559 	{0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
560 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
561 	{0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
562 	    0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
563 	{0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
564 	    0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
565 	{0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
566 	    0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
567 	{0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
568 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
569 	{0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
570 	    0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
571 	{0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
572 	    0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
573 	{0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
574 	    0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
575 	{0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
576 	    0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
577 	{0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
578 	    0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
579 	{0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
580 	    0, AAC_TYPE_SATA, "ICP", "9024RO"},
581 	{0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
582 	    0, AAC_TYPE_SATA, "ICP", "9014RO"},
583 	{0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
584 	    0, AAC_TYPE_SATA, "ICP", "9047MA"},
585 	{0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
586 	    0, AAC_TYPE_SATA, "ICP", "9087MA"},
587 	{0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
588 	    0, AAC_TYPE_SAS, "ICP", "9085LI"},
589 	{0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
590 	    0, AAC_TYPE_SAS, "ICP", "5085BR"},
591 	{0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
592 	    0, AAC_TYPE_SATA, "ICP", "9067MA"},
593 	{0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
594 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
595 	{0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
596 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
597 	{0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
598 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
599 	{0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
600 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
601 	{0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
602 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
603 	{0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
604 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
605 
606 	{0, 0, 0, 0, AAC_HWIF_UNKNOWN,
607 	    0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
608 };
609 
610 /*
611  * Hardware access functions for i960 based cards
612  */
613 static struct aac_interface aac_rx_interface = {
614 	aac_rx_get_fwstatus,
615 	aac_rx_get_mailbox,
616 	aac_rx_set_mailbox
617 };
618 
619 /*
620  * Hardware access functions for Rocket based cards
621  */
622 static struct aac_interface aac_rkt_interface = {
623 	aac_rkt_get_fwstatus,
624 	aac_rkt_get_mailbox,
625 	aac_rkt_set_mailbox
626 };
627 
628 ddi_device_acc_attr_t aac_acc_attr = {
629 	DDI_DEVICE_ATTR_V1,
630 	DDI_STRUCTURE_LE_ACC,
631 	DDI_STRICTORDER_ACC,
632 	DDI_DEFAULT_ACC
633 };
634 
635 static struct {
636 	int	size;
637 	int	notify;
638 } aac_qinfo[] = {
639 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
640 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
641 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
642 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
643 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
644 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
645 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
646 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
647 };
648 
649 /*
650  * Default aac dma attributes
651  */
652 static ddi_dma_attr_t aac_dma_attr = {
653 	DMA_ATTR_V0,
654 	0,		/* lowest usable address */
655 	0xffffffffull,	/* high DMA address range */
656 	0xffffffffull,	/* DMA counter register */
657 	AAC_DMA_ALIGN,	/* DMA address alignment */
658 	1,		/* DMA burstsizes */
659 	1,		/* min effective DMA size */
660 	0xffffffffull,	/* max DMA xfer size */
661 	0xffffffffull,	/* segment boundary */
662 	1,		/* s/g list length */
663 	AAC_BLK_SIZE,	/* granularity of device */
664 	0		/* DMA transfer flags */
665 };
666 
667 static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
668 static uint32_t aac_timebase = 0;	/* internal timer in seconds */
669 
670 /*
671  * Warlock directives
672  *
673  * Different variables with the same types have to be protected by the
674  * same mutex; otherwise, warlock will complain with "variables don't
675  * seem to be protected consistently". For example,
676  * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
677  * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
678  * declare them as protected explictly at aac_cmd_dequeue().
679  */
680 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
681     scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
682     mode_format mode_geometry mode_header aac_cmd))
683 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
684     aac_sge))
685 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
686     aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
687     aac_sg_table aac_srb))
688 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
689 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
690 _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
691 
692 int
693 _init(void)
694 {
695 	int rval = 0;
696 
697 #ifdef DEBUG
698 	mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
699 #endif
700 	DBCALLED(NULL, 1);
701 
702 	if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
703 	    sizeof (struct aac_softstate), 0)) != 0)
704 		goto error;
705 
706 	if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
707 		ddi_soft_state_fini((void *)&aac_softstatep);
708 		goto error;
709 	}
710 
711 	if ((rval = mod_install(&aac_modlinkage)) != 0) {
712 		ddi_soft_state_fini((void *)&aac_softstatep);
713 		scsi_hba_fini(&aac_modlinkage);
714 		goto error;
715 	}
716 	return (rval);
717 
718 error:
719 	AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
720 #ifdef DEBUG
721 	mutex_destroy(&aac_prt_mutex);
722 #endif
723 	return (rval);
724 }
725 
726 int
727 _info(struct modinfo *modinfop)
728 {
729 	DBCALLED(NULL, 1);
730 	return (mod_info(&aac_modlinkage, modinfop));
731 }
732 
733 /*
734  * An HBA driver cannot be unload unless you reboot,
735  * so this function will be of no use.
736  */
737 int
738 _fini(void)
739 {
740 	int rval;
741 
742 	DBCALLED(NULL, 1);
743 
744 	if ((rval = mod_remove(&aac_modlinkage)) != 0)
745 		goto error;
746 
747 	scsi_hba_fini(&aac_modlinkage);
748 	ddi_soft_state_fini((void *)&aac_softstatep);
749 #ifdef DEBUG
750 	mutex_destroy(&aac_prt_mutex);
751 #endif
752 	return (0);
753 
754 error:
755 	AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
756 	return (rval);
757 }
758 
759 static int
760 aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
761 {
762 	int instance, i;
763 	struct aac_softstate *softs = NULL;
764 	int attach_state = 0;
765 	char *data;
766 
767 	DBCALLED(NULL, 1);
768 
769 	switch (cmd) {
770 	case DDI_ATTACH:
771 		break;
772 	case DDI_RESUME:
773 		return (DDI_FAILURE);
774 	default:
775 		return (DDI_FAILURE);
776 	}
777 
778 	instance = ddi_get_instance(dip);
779 
780 	/* Get soft state */
781 	if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
782 		AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
783 		goto error;
784 	}
785 	softs = ddi_get_soft_state(aac_softstatep, instance);
786 	attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
787 
788 	softs->instance = instance;
789 	softs->devinfo_p = dip;
790 	softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
791 	softs->addr_dma_attr.dma_attr_granular = 1;
792 	softs->acc_attr = aac_acc_attr;
793 	softs->reg_attr = aac_acc_attr;
794 	softs->card = AAC_UNKNOWN_CARD;
795 #ifdef DEBUG
796 	softs->debug_flags = aac_debug_flags;
797 	softs->debug_fib_flags = aac_debug_fib_flags;
798 #endif
799 
800 	/* Initialize FMA */
801 	aac_fm_init(softs);
802 
803 	/* Check the card type */
804 	if (aac_check_card_type(softs) == AACERR) {
805 		AACDB_PRINT(softs, CE_WARN, "Card not supported");
806 		goto error;
807 	}
808 	/* We have found the right card and everything is OK */
809 	attach_state |= AAC_ATTACH_CARD_DETECTED;
810 
811 	/* Map PCI mem space */
812 	if (ddi_regs_map_setup(dip, 1,
813 	    (caddr_t *)&softs->pci_mem_base_vaddr, 0,
814 	    softs->map_size_min, &softs->reg_attr,
815 	    &softs->pci_mem_handle) != DDI_SUCCESS)
816 		goto error;
817 
818 	softs->map_size = softs->map_size_min;
819 	attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
820 
821 	AAC_DISABLE_INTR(softs);
822 
823 	/* Init mutexes and condvars */
824 	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
825 	    DDI_INTR_PRI(softs->intr_pri));
826 	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
827 	    DDI_INTR_PRI(softs->intr_pri));
828 	mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
829 	    DDI_INTR_PRI(softs->intr_pri));
830 	mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
831 	    DDI_INTR_PRI(softs->intr_pri));
832 	mutex_init(&softs->aifq_mutex, NULL,
833 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
834 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
835 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
836 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
837 	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
838 	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
839 	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
840 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
841 
842 	/* Init the cmd queues */
843 	for (i = 0; i < AAC_CMDQ_NUM; i++)
844 		aac_cmd_initq(&softs->q_wait[i]);
845 	aac_cmd_initq(&softs->q_busy);
846 	aac_cmd_initq(&softs->q_comp);
847 
848 	/* Check for legacy device naming support */
849 	softs->legacy = 1; /* default to use legacy name */
850 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
851 	    "legacy-name-enable", &data) == DDI_SUCCESS)) {
852 		if (strcmp(data, "no") == 0) {
853 			AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
854 			softs->legacy = 0;
855 		}
856 		ddi_prop_free(data);
857 	}
858 
859 	/*
860 	 * Everything has been set up till now,
861 	 * we will do some common attach.
862 	 */
863 	mutex_enter(&softs->io_lock);
864 	if (aac_common_attach(softs) == AACERR) {
865 		mutex_exit(&softs->io_lock);
866 		goto error;
867 	}
868 	mutex_exit(&softs->io_lock);
869 	attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
870 
871 	/* Check for buf breakup support */
872 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
873 	    "breakup-enable", &data) == DDI_SUCCESS)) {
874 		if (strcmp(data, "yes") == 0) {
875 			AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
876 			softs->flags |= AAC_FLAGS_BRKUP;
877 		}
878 		ddi_prop_free(data);
879 	}
880 	softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
881 	if (softs->flags & AAC_FLAGS_BRKUP) {
882 		softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
883 		    DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
884 	}
885 
886 	if (aac_hba_setup(softs) != AACOK)
887 		goto error;
888 	attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
889 
890 	/* Create devctl/scsi nodes for cfgadm */
891 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
892 	    INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
893 		AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
894 		goto error;
895 	}
896 	attach_state |= AAC_ATTACH_CREATE_DEVCTL;
897 
898 	if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
899 	    DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
900 		AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
901 		goto error;
902 	}
903 	attach_state |= AAC_ATTACH_CREATE_SCSI;
904 
905 	/* Create aac node for app. to issue ioctls */
906 	if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
907 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
908 		AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
909 		goto error;
910 	}
911 
912 	/* Common attach is OK, so we are attached! */
913 	softs->state |= AAC_STATE_RUN;
914 
915 	/* Create event thread */
916 	softs->fibctx_p = &softs->aifctx;
917 	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
918 	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
919 		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
920 		softs->state &= ~AAC_STATE_RUN;
921 		goto error;
922 	}
923 
924 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
925 
926 	/* Create a thread for command timeout */
927 	softs->timeout_id = timeout(aac_timer, (void *)softs,
928 	    (aac_tick * drv_usectohz(1000000)));
929 
930 	/* Common attach is OK, so we are attached! */
931 	ddi_report_dev(dip);
932 	AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
933 	return (DDI_SUCCESS);
934 
935 error:
936 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
937 		ddi_remove_minor_node(dip, "scsi");
938 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
939 		ddi_remove_minor_node(dip, "devctl");
940 	if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
941 		aac_common_detach(softs);
942 	if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
943 		(void) scsi_hba_detach(dip);
944 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
945 	}
946 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
947 		mutex_destroy(&softs->io_lock);
948 		mutex_destroy(&softs->q_comp_mutex);
949 		mutex_destroy(&softs->time_mutex);
950 		mutex_destroy(&softs->ev_lock);
951 		mutex_destroy(&softs->aifq_mutex);
952 		cv_destroy(&softs->event);
953 		cv_destroy(&softs->sync_fib_cv);
954 		cv_destroy(&softs->drain_cv);
955 		cv_destroy(&softs->event_wait_cv);
956 		cv_destroy(&softs->event_disp_cv);
957 		cv_destroy(&softs->aifq_cv);
958 	}
959 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
960 		ddi_regs_map_free(&softs->pci_mem_handle);
961 	aac_fm_fini(softs);
962 	if (attach_state & AAC_ATTACH_CARD_DETECTED)
963 		softs->card = AACERR;
964 	if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
965 		ddi_soft_state_free(aac_softstatep, instance);
966 	return (DDI_FAILURE);
967 }
968 
969 static int
970 aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
971 {
972 	scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
973 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
974 
975 	DBCALLED(softs, 1);
976 
977 	switch (cmd) {
978 	case DDI_DETACH:
979 		break;
980 	case DDI_SUSPEND:
981 		return (DDI_FAILURE);
982 	default:
983 		return (DDI_FAILURE);
984 	}
985 
986 	mutex_enter(&softs->io_lock);
987 	AAC_DISABLE_INTR(softs);
988 	softs->state = AAC_STATE_STOPPED;
989 
990 	ddi_remove_minor_node(dip, "aac");
991 	ddi_remove_minor_node(dip, "scsi");
992 	ddi_remove_minor_node(dip, "devctl");
993 	mutex_exit(&softs->io_lock);
994 
995 	aac_common_detach(softs);
996 
997 	mutex_enter(&softs->io_lock);
998 	(void) scsi_hba_detach(dip);
999 	scsi_hba_tran_free(tran);
1000 	mutex_exit(&softs->io_lock);
1001 
1002 	/* Stop timer */
1003 	mutex_enter(&softs->time_mutex);
1004 	if (softs->timeout_id) {
1005 		timeout_id_t tid = softs->timeout_id;
1006 		softs->timeout_id = 0;
1007 
1008 		mutex_exit(&softs->time_mutex);
1009 		(void) untimeout(tid);
1010 		mutex_enter(&softs->time_mutex);
1011 	}
1012 	mutex_exit(&softs->time_mutex);
1013 
1014 	/* Destroy event thread */
1015 	mutex_enter(&softs->ev_lock);
1016 	cv_signal(&softs->event_disp_cv);
1017 	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
1018 	mutex_exit(&softs->ev_lock);
1019 
1020 	cv_destroy(&softs->aifq_cv);
1021 	cv_destroy(&softs->event_disp_cv);
1022 	cv_destroy(&softs->event_wait_cv);
1023 	cv_destroy(&softs->drain_cv);
1024 	cv_destroy(&softs->sync_fib_cv);
1025 	cv_destroy(&softs->event);
1026 	mutex_destroy(&softs->aifq_mutex);
1027 	mutex_destroy(&softs->ev_lock);
1028 	mutex_destroy(&softs->time_mutex);
1029 	mutex_destroy(&softs->q_comp_mutex);
1030 	mutex_destroy(&softs->io_lock);
1031 
1032 	ddi_regs_map_free(&softs->pci_mem_handle);
1033 	aac_fm_fini(softs);
1034 	softs->hwif = AAC_HWIF_UNKNOWN;
1035 	softs->card = AAC_UNKNOWN_CARD;
1036 	ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
1037 
1038 	return (DDI_SUCCESS);
1039 }
1040 
1041 /*ARGSUSED*/
1042 static int
1043 aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
1044 {
1045 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1046 
1047 	DBCALLED(softs, 1);
1048 
1049 	mutex_enter(&softs->io_lock);
1050 	AAC_DISABLE_INTR(softs);
1051 	(void) aac_shutdown(softs);
1052 	mutex_exit(&softs->io_lock);
1053 
1054 	return (DDI_SUCCESS);
1055 }
1056 
1057 /*
1058  * quiesce(9E) entry point.
1059  *
1060  * This function is called when the system is single-threaded at high
1061  * PIL with preemption disabled. Therefore, this function must not be
1062  * blocked.
1063  *
1064  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1065  * DDI_FAILURE indicates an error condition and should almost never happen.
1066  */
1067 static int
1068 aac_quiesce(dev_info_t *dip)
1069 {
1070 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1071 
1072 	if (softs == NULL)
1073 		return (DDI_FAILURE);
1074 
1075 	_NOTE(ASSUMING_PROTECTED(softs->state))
1076 	AAC_DISABLE_INTR(softs);
1077 
1078 	return (DDI_SUCCESS);
1079 }
1080 
1081 /* ARGSUSED */
1082 static int
1083 aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
1084     void **result)
1085 {
1086 	int error = DDI_SUCCESS;
1087 
1088 	switch (infocmd) {
1089 	case DDI_INFO_DEVT2INSTANCE:
1090 		*result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
1091 		break;
1092 	default:
1093 		error = DDI_FAILURE;
1094 	}
1095 	return (error);
1096 }
1097 
1098 /*
1099  * Bring the controller down to a dormant state and detach all child devices.
1100  * This function is called before detach or system shutdown.
1101  * Note: we can assume that the q_wait on the controller is empty, as we
1102  * won't allow shutdown if any device is open.
1103  */
1104 static int
1105 aac_shutdown(struct aac_softstate *softs)
1106 {
1107 	ddi_acc_handle_t acc;
1108 	struct aac_close_command *cc;
1109 	int rval;
1110 
1111 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
1112 	acc = softs->sync_ac.slotp->fib_acc_handle;
1113 
1114 	cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
1115 
1116 	ddi_put32(acc, &cc->Command, VM_CloseAll);
1117 	ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
1118 
1119 	/* Flush all caches, set FW to write through mode */
1120 	rval = aac_sync_fib(softs, ContainerCommand,
1121 	    AAC_FIB_SIZEOF(struct aac_close_command));
1122 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
1123 
1124 	AACDB_PRINT(softs, CE_NOTE,
1125 	    "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
1126 	return (rval);
1127 }
1128 
1129 static uint_t
1130 aac_softintr(caddr_t arg)
1131 {
1132 	struct aac_softstate *softs = (void *)arg;
1133 
1134 	if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
1135 		aac_drain_comp_q(softs);
1136 	}
1137 	return (DDI_INTR_CLAIMED);
1138 }
1139 
1140 /*
1141  * Setup auto sense data for pkt
1142  */
1143 static void
1144 aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
1145     uchar_t add_code, uchar_t qual_code, uint64_t info)
1146 {
1147 	struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
1148 
1149 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
1150 	pkt->pkt_state |= STATE_ARQ_DONE;
1151 
1152 	*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
1153 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
1154 	arqstat->sts_rqpkt_resid = 0;
1155 	arqstat->sts_rqpkt_state =
1156 	    STATE_GOT_BUS |
1157 	    STATE_GOT_TARGET |
1158 	    STATE_SENT_CMD |
1159 	    STATE_XFERRED_DATA;
1160 	arqstat->sts_rqpkt_statistics = 0;
1161 
1162 	if (info <= 0xfffffffful) {
1163 		arqstat->sts_sensedata.es_valid = 1;
1164 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1165 		arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
1166 		arqstat->sts_sensedata.es_key = key;
1167 		arqstat->sts_sensedata.es_add_code = add_code;
1168 		arqstat->sts_sensedata.es_qual_code = qual_code;
1169 
1170 		arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
1171 		arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
1172 		arqstat->sts_sensedata.es_info_3 = (info >>  8) & 0xFF;
1173 		arqstat->sts_sensedata.es_info_4 = info & 0xFF;
1174 	} else { /* 64-bit LBA */
1175 		struct scsi_descr_sense_hdr *dsp;
1176 		struct scsi_information_sense_descr *isd;
1177 
1178 		dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
1179 		dsp->ds_class = CLASS_EXTENDED_SENSE;
1180 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
1181 		dsp->ds_key = key;
1182 		dsp->ds_add_code = add_code;
1183 		dsp->ds_qual_code = qual_code;
1184 		dsp->ds_addl_sense_length =
1185 		    sizeof (struct scsi_information_sense_descr);
1186 
1187 		isd = (struct scsi_information_sense_descr *)(dsp+1);
1188 		isd->isd_descr_type = DESCR_INFORMATION;
1189 		isd->isd_valid = 1;
1190 		isd->isd_information[0] = (info >> 56) & 0xFF;
1191 		isd->isd_information[1] = (info >> 48) & 0xFF;
1192 		isd->isd_information[2] = (info >> 40) & 0xFF;
1193 		isd->isd_information[3] = (info >> 32) & 0xFF;
1194 		isd->isd_information[4] = (info >> 24) & 0xFF;
1195 		isd->isd_information[5] = (info >> 16) & 0xFF;
1196 		isd->isd_information[6] = (info >>  8) & 0xFF;
1197 		isd->isd_information[7] = (info) & 0xFF;
1198 	}
1199 }
1200 
1201 /*
1202  * Setup auto sense data for HARDWARE ERROR
1203  */
1204 static void
1205 aac_set_arq_data_hwerr(struct aac_cmd *acp)
1206 {
1207 	union scsi_cdb *cdbp;
1208 	uint64_t err_blkno;
1209 
1210 	cdbp = (void *)acp->pkt->pkt_cdbp;
1211 	err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
1212 	aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
1213 }
1214 
1215 /*
1216  * Send a command to the adapter in New Comm. interface
1217  */
1218 static int
1219 aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
1220 {
1221 	uint32_t index, device;
1222 
1223 	index = PCI_MEM_GET32(softs, AAC_IQUE);
1224 	if (index == 0xffffffffUL) {
1225 		index = PCI_MEM_GET32(softs, AAC_IQUE);
1226 		if (index == 0xffffffffUL)
1227 			return (AACERR);
1228 	}
1229 
1230 	device = index;
1231 	PCI_MEM_PUT32(softs, device,
1232 	    (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
1233 	device += 4;
1234 	PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
1235 	device += 4;
1236 	PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
1237 	PCI_MEM_PUT32(softs, AAC_IQUE, index);
1238 	return (AACOK);
1239 }
1240 
1241 static void
1242 aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
1243 {
1244 	struct aac_device *dvp = acp->dvp;
1245 	int q = AAC_CMDQ(acp);
1246 
1247 	if (acp->slotp) { /* outstanding cmd */
1248 		if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
1249 			aac_release_slot(softs, acp->slotp);
1250 			acp->slotp = NULL;
1251 		}
1252 		if (dvp) {
1253 			dvp->ncmds[q]--;
1254 			if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
1255 			    dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
1256 				aac_set_throttle(softs, dvp, q,
1257 				    softs->total_slots);
1258 			/*
1259 			 * Setup auto sense data for UNIT ATTENTION
1260 			 * Each lun should generate a unit attention
1261 			 * condition when reset.
1262 			 * Phys. drives are treated as logical ones
1263 			 * during error recovery.
1264 			 */
1265 			if (dvp->type == AAC_DEV_LD) {
1266 				struct aac_container *ctp =
1267 				    (struct aac_container *)dvp;
1268 				if (ctp->reset == 0)
1269 					goto noreset;
1270 
1271 				AACDB_PRINT(softs, CE_NOTE,
1272 				    "Unit attention: reset");
1273 				ctp->reset = 0;
1274 				aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
1275 				    0x29, 0x02, 0);
1276 			}
1277 		}
1278 noreset:
1279 		softs->bus_ncmds[q]--;
1280 		aac_cmd_delete(&softs->q_busy, acp);
1281 	} else { /* cmd in waiting queue */
1282 		aac_cmd_delete(&softs->q_wait[q], acp);
1283 	}
1284 
1285 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
1286 		mutex_enter(&softs->q_comp_mutex);
1287 		aac_cmd_enqueue(&softs->q_comp, acp);
1288 		mutex_exit(&softs->q_comp_mutex);
1289 	} else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
1290 		cv_broadcast(&softs->event);
1291 	}
1292 }
1293 
1294 static void
1295 aac_handle_io(struct aac_softstate *softs, int index)
1296 {
1297 	struct aac_slot *slotp;
1298 	struct aac_cmd *acp;
1299 	uint32_t fast;
1300 
1301 	fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
1302 	index >>= 2;
1303 
1304 	/* Make sure firmware reported index is valid */
1305 	ASSERT(index >= 0 && index < softs->total_slots);
1306 	slotp = &softs->io_slot[index];
1307 	ASSERT(slotp->index == index);
1308 	acp = slotp->acp;
1309 
1310 	if (acp == NULL || acp->slotp != slotp) {
1311 		cmn_err(CE_WARN,
1312 		    "Firmware error: invalid slot index received from FW");
1313 		return;
1314 	}
1315 
1316 	acp->flags |= AAC_CMD_CMPLT;
1317 	(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
1318 
1319 	if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
1320 		/*
1321 		 * For fast response IO, the firmware do not return any FIB
1322 		 * data, so we need to fill in the FIB status and state so that
1323 		 * FIB users can handle it correctly.
1324 		 */
1325 		if (fast) {
1326 			uint32_t state;
1327 
1328 			state = ddi_get32(slotp->fib_acc_handle,
1329 			    &slotp->fibp->Header.XferState);
1330 			/*
1331 			 * Update state for CPU not for device, no DMA sync
1332 			 * needed
1333 			 */
1334 			ddi_put32(slotp->fib_acc_handle,
1335 			    &slotp->fibp->Header.XferState,
1336 			    state | AAC_FIBSTATE_DONEADAP);
1337 			ddi_put32(slotp->fib_acc_handle,
1338 			    (void *)&slotp->fibp->data[0], ST_OK);
1339 		}
1340 
1341 		/* Handle completed ac */
1342 		acp->ac_comp(softs, acp);
1343 	} else {
1344 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1345 		acp->flags |= AAC_CMD_ERR;
1346 		if (acp->pkt) {
1347 			acp->pkt->pkt_reason = CMD_TRAN_ERR;
1348 			acp->pkt->pkt_statistics = 0;
1349 		}
1350 	}
1351 	aac_end_io(softs, acp);
1352 }
1353 
1354 /*
1355  * Interrupt handler for New Comm. interface
1356  * New Comm. interface use a different mechanism for interrupt. No explict
1357  * message queues, and driver need only accesses the mapped PCI mem space to
1358  * find the completed FIB or AIF.
1359  */
1360 static int
1361 aac_process_intr_new(struct aac_softstate *softs)
1362 {
1363 	uint32_t index;
1364 
1365 	index = AAC_OUTB_GET(softs);
1366 	if (index == 0xfffffffful)
1367 		index = AAC_OUTB_GET(softs);
1368 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1369 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1370 		return (0);
1371 	}
1372 	if (index != 0xfffffffful) {
1373 		do {
1374 			if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
1375 				aac_handle_io(softs, index);
1376 			} else if (index != 0xfffffffeul) {
1377 				struct aac_fib *fibp;	/* FIB in AIF queue */
1378 				uint16_t fib_size;
1379 
1380 				/*
1381 				 * 0xfffffffe means that the controller wants
1382 				 * more work, ignore it for now. Otherwise,
1383 				 * AIF received.
1384 				 */
1385 				index &= ~2;
1386 
1387 				fibp = (struct aac_fib *)(softs-> \
1388 				    pci_mem_base_vaddr + index);
1389 				fib_size = PCI_MEM_GET16(softs, index + \
1390 				    offsetof(struct aac_fib, Header.Size));
1391 
1392 				aac_save_aif(softs, softs->pci_mem_handle,
1393 				    fibp, fib_size);
1394 
1395 				/*
1396 				 * AIF memory is owned by the adapter, so let it
1397 				 * know that we are done with it.
1398 				 */
1399 				AAC_OUTB_SET(softs, index);
1400 				AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1401 			}
1402 
1403 			index = AAC_OUTB_GET(softs);
1404 		} while (index != 0xfffffffful);
1405 
1406 		/*
1407 		 * Process waiting cmds before start new ones to
1408 		 * ensure first IOs are serviced first.
1409 		 */
1410 		aac_start_waiting_io(softs);
1411 		return (AAC_DB_COMMAND_READY);
1412 	} else {
1413 		return (0);
1414 	}
1415 }
1416 
1417 static uint_t
1418 aac_intr_new(caddr_t arg)
1419 {
1420 	struct aac_softstate *softs = (void *)arg;
1421 	uint_t rval;
1422 
1423 	mutex_enter(&softs->io_lock);
1424 	if (aac_process_intr_new(softs))
1425 		rval = DDI_INTR_CLAIMED;
1426 	else
1427 		rval = DDI_INTR_UNCLAIMED;
1428 	mutex_exit(&softs->io_lock);
1429 
1430 	aac_drain_comp_q(softs);
1431 	return (rval);
1432 }
1433 
1434 /*
1435  * Interrupt handler for old interface
1436  * Explicit message queues are used to send FIB to and get completed FIB from
1437  * the adapter. Driver and adapter maitain the queues in the producer/consumer
1438  * manner. The driver has to query the queues to find the completed FIB.
1439  */
1440 static int
1441 aac_process_intr_old(struct aac_softstate *softs)
1442 {
1443 	uint16_t status;
1444 
1445 	status = AAC_STATUS_GET(softs);
1446 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1447 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1448 		return (DDI_INTR_UNCLAIMED);
1449 	}
1450 	if (status & AAC_DB_RESPONSE_READY) {
1451 		int slot_idx;
1452 
1453 		/* ACK the intr */
1454 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1455 		(void) AAC_STATUS_GET(softs);
1456 		while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
1457 		    &slot_idx) == AACOK)
1458 			aac_handle_io(softs, slot_idx);
1459 
1460 		/*
1461 		 * Process waiting cmds before start new ones to
1462 		 * ensure first IOs are serviced first.
1463 		 */
1464 		aac_start_waiting_io(softs);
1465 		return (AAC_DB_RESPONSE_READY);
1466 	} else if (status & AAC_DB_COMMAND_READY) {
1467 		int aif_idx;
1468 
1469 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
1470 		(void) AAC_STATUS_GET(softs);
1471 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
1472 		    AACOK) {
1473 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
1474 			struct aac_fib *fibp;	/* FIB in communication space */
1475 			uint16_t fib_size;
1476 			uint32_t fib_xfer_state;
1477 			uint32_t addr, size;
1478 
1479 			ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
1480 
1481 #define	AAC_SYNC_AIF(softs, aif_idx, type) \
1482 	{ (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
1483 	    offsetof(struct aac_comm_space, \
1484 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
1485 	    (type)); }
1486 
1487 			/* Copy AIF from adapter to the empty AIF slot */
1488 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
1489 			fibp = &softs->comm_space->adapter_fibs[aif_idx];
1490 			fib_size = ddi_get16(acc, &fibp->Header.Size);
1491 
1492 			aac_save_aif(softs, acc, fibp, fib_size);
1493 
1494 			/* Complete AIF back to adapter with good status */
1495 			fib_xfer_state = LE_32(fibp->Header.XferState);
1496 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
1497 				ddi_put32(acc, &fibp->Header.XferState,
1498 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
1499 				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
1500 				if (fib_size > AAC_FIB_SIZE)
1501 					ddi_put16(acc, &fibp->Header.Size,
1502 					    AAC_FIB_SIZE);
1503 				AAC_SYNC_AIF(softs, aif_idx,
1504 				    DDI_DMA_SYNC_FORDEV);
1505 			}
1506 
1507 			/* Put the AIF response on the response queue */
1508 			addr = ddi_get32(acc,
1509 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1510 			    Header.SenderFibAddress);
1511 			size = (uint32_t)ddi_get16(acc,
1512 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1513 			    Header.Size);
1514 			ddi_put32(acc,
1515 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1516 			    Header.ReceiverFibAddress, addr);
1517 			if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
1518 			    addr, size) == AACERR)
1519 				cmn_err(CE_NOTE, "!AIF ack failed");
1520 		}
1521 		return (AAC_DB_COMMAND_READY);
1522 	} else if (status & AAC_DB_PRINTF_READY) {
1523 		/* ACK the intr */
1524 		AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
1525 		(void) AAC_STATUS_GET(softs);
1526 		(void) ddi_dma_sync(softs->comm_space_dma_handle,
1527 		    offsetof(struct aac_comm_space, adapter_print_buf),
1528 		    AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
1529 		if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
1530 		    DDI_SUCCESS)
1531 			cmn_err(CE_NOTE, "MSG From Adapter: %s",
1532 			    softs->comm_space->adapter_print_buf);
1533 		else
1534 			ddi_fm_service_impact(softs->devinfo_p,
1535 			    DDI_SERVICE_UNAFFECTED);
1536 		AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
1537 		return (AAC_DB_PRINTF_READY);
1538 	} else if (status & AAC_DB_COMMAND_NOT_FULL) {
1539 		/*
1540 		 * Without these two condition statements, the OS could hang
1541 		 * after a while, especially if there are a lot of AIF's to
1542 		 * handle, for instance if a drive is pulled from an array
1543 		 * under heavy load.
1544 		 */
1545 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1546 		return (AAC_DB_COMMAND_NOT_FULL);
1547 	} else if (status & AAC_DB_RESPONSE_NOT_FULL) {
1548 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1549 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
1550 		return (AAC_DB_RESPONSE_NOT_FULL);
1551 	} else {
1552 		return (0);
1553 	}
1554 }
1555 
1556 static uint_t
1557 aac_intr_old(caddr_t arg)
1558 {
1559 	struct aac_softstate *softs = (void *)arg;
1560 	int rval;
1561 
1562 	mutex_enter(&softs->io_lock);
1563 	if (aac_process_intr_old(softs))
1564 		rval = DDI_INTR_CLAIMED;
1565 	else
1566 		rval = DDI_INTR_UNCLAIMED;
1567 	mutex_exit(&softs->io_lock);
1568 
1569 	aac_drain_comp_q(softs);
1570 	return (rval);
1571 }
1572 
1573 /*
1574  * Query FIXED or MSI interrupts
1575  */
1576 static int
1577 aac_query_intrs(struct aac_softstate *softs, int intr_type)
1578 {
1579 	dev_info_t *dip = softs->devinfo_p;
1580 	int avail, actual, count;
1581 	int i, flag, ret;
1582 
1583 	AACDB_PRINT(softs, CE_NOTE,
1584 	    "aac_query_intrs:interrupt type 0x%x", intr_type);
1585 
1586 	/* Get number of interrupts */
1587 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
1588 	if ((ret != DDI_SUCCESS) || (count == 0)) {
1589 		AACDB_PRINT(softs, CE_WARN,
1590 		    "ddi_intr_get_nintrs() failed, ret %d count %d",
1591 		    ret, count);
1592 		return (DDI_FAILURE);
1593 	}
1594 
1595 	/* Get number of available interrupts */
1596 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
1597 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
1598 		AACDB_PRINT(softs, CE_WARN,
1599 		    "ddi_intr_get_navail() failed, ret %d avail %d",
1600 		    ret, avail);
1601 		return (DDI_FAILURE);
1602 	}
1603 
1604 	AACDB_PRINT(softs, CE_NOTE,
1605 	    "ddi_intr_get_nvail returned %d, navail() returned %d",
1606 	    count, avail);
1607 
1608 	/* Allocate an array of interrupt handles */
1609 	softs->intr_size = count * sizeof (ddi_intr_handle_t);
1610 	softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
1611 
1612 	if (intr_type == DDI_INTR_TYPE_MSI) {
1613 		count = 1; /* only one vector needed by now */
1614 		flag = DDI_INTR_ALLOC_STRICT;
1615 	} else { /* must be DDI_INTR_TYPE_FIXED */
1616 		flag = DDI_INTR_ALLOC_NORMAL;
1617 	}
1618 
1619 	/* Call ddi_intr_alloc() */
1620 	ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
1621 	    count, &actual, flag);
1622 
1623 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
1624 		AACDB_PRINT(softs, CE_WARN,
1625 		    "ddi_intr_alloc() failed, ret = %d", ret);
1626 		actual = 0;
1627 		goto error;
1628 	}
1629 
1630 	if (actual < count) {
1631 		AACDB_PRINT(softs, CE_NOTE,
1632 		    "Requested: %d, Received: %d", count, actual);
1633 		goto error;
1634 	}
1635 
1636 	softs->intr_cnt = actual;
1637 
1638 	/* Get priority for first msi, assume remaining are all the same */
1639 	if ((ret = ddi_intr_get_pri(softs->htable[0],
1640 	    &softs->intr_pri)) != DDI_SUCCESS) {
1641 		AACDB_PRINT(softs, CE_WARN,
1642 		    "ddi_intr_get_pri() failed, ret = %d", ret);
1643 		goto error;
1644 	}
1645 
1646 	/* Test for high level mutex */
1647 	if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
1648 		AACDB_PRINT(softs, CE_WARN,
1649 		    "aac_query_intrs: Hi level interrupt not supported");
1650 		goto error;
1651 	}
1652 
1653 	return (DDI_SUCCESS);
1654 
1655 error:
1656 	/* Free already allocated intr */
1657 	for (i = 0; i < actual; i++)
1658 		(void) ddi_intr_free(softs->htable[i]);
1659 
1660 	kmem_free(softs->htable, softs->intr_size);
1661 	return (DDI_FAILURE);
1662 }
1663 
1664 
1665 /*
1666  * Register FIXED or MSI interrupts, and enable them
1667  */
1668 static int
1669 aac_add_intrs(struct aac_softstate *softs)
1670 {
1671 	int i, ret;
1672 	int actual;
1673 	ddi_intr_handler_t *aac_intr;
1674 
1675 	actual = softs->intr_cnt;
1676 	aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
1677 	    aac_intr_new : aac_intr_old);
1678 
1679 	/* Call ddi_intr_add_handler() */
1680 	for (i = 0; i < actual; i++) {
1681 		if ((ret = ddi_intr_add_handler(softs->htable[i],
1682 		    aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
1683 			cmn_err(CE_WARN,
1684 			    "ddi_intr_add_handler() failed ret = %d", ret);
1685 
1686 			/* Free already allocated intr */
1687 			for (i = 0; i < actual; i++)
1688 				(void) ddi_intr_free(softs->htable[i]);
1689 
1690 			kmem_free(softs->htable, softs->intr_size);
1691 			return (DDI_FAILURE);
1692 		}
1693 	}
1694 
1695 	if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
1696 	    != DDI_SUCCESS) {
1697 		cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
1698 
1699 		/* Free already allocated intr */
1700 		for (i = 0; i < actual; i++)
1701 			(void) ddi_intr_free(softs->htable[i]);
1702 
1703 		kmem_free(softs->htable, softs->intr_size);
1704 		return (DDI_FAILURE);
1705 	}
1706 
1707 	return (DDI_SUCCESS);
1708 }
1709 
1710 /*
1711  * Unregister FIXED or MSI interrupts
1712  */
1713 static void
1714 aac_remove_intrs(struct aac_softstate *softs)
1715 {
1716 	int i;
1717 
1718 	/* Disable all interrupts */
1719 	(void) aac_disable_intrs(softs);
1720 	/* Call ddi_intr_remove_handler() */
1721 	for (i = 0; i < softs->intr_cnt; i++) {
1722 		(void) ddi_intr_remove_handler(softs->htable[i]);
1723 		(void) ddi_intr_free(softs->htable[i]);
1724 	}
1725 
1726 	kmem_free(softs->htable, softs->intr_size);
1727 }
1728 
1729 static int
1730 aac_enable_intrs(struct aac_softstate *softs)
1731 {
1732 	int rval = AACOK;
1733 
1734 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1735 		/* for MSI block enable */
1736 		if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
1737 		    DDI_SUCCESS)
1738 			rval = AACERR;
1739 	} else {
1740 		int i;
1741 
1742 		/* Call ddi_intr_enable() for legacy/MSI non block enable */
1743 		for (i = 0; i < softs->intr_cnt; i++) {
1744 			if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
1745 				rval = AACERR;
1746 		}
1747 	}
1748 	return (rval);
1749 }
1750 
1751 static int
1752 aac_disable_intrs(struct aac_softstate *softs)
1753 {
1754 	int rval = AACOK;
1755 
1756 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1757 		/* Call ddi_intr_block_disable() */
1758 		if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
1759 		    DDI_SUCCESS)
1760 			rval = AACERR;
1761 	} else {
1762 		int i;
1763 
1764 		for (i = 0; i < softs->intr_cnt; i++) {
1765 			if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
1766 				rval = AACERR;
1767 		}
1768 	}
1769 	return (rval);
1770 }
1771 
1772 /*
1773  * Set pkt_reason and OR in pkt_statistics flag
1774  */
1775 static void
1776 aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
1777     uchar_t reason, uint_t stat)
1778 {
1779 #ifndef __lock_lint
1780 	_NOTE(ARGUNUSED(softs))
1781 #endif
1782 	if (acp->pkt->pkt_reason == CMD_CMPLT)
1783 		acp->pkt->pkt_reason = reason;
1784 	acp->pkt->pkt_statistics |= stat;
1785 }
1786 
1787 /*
1788  * Handle a finished pkt of soft SCMD
1789  */
1790 static void
1791 aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
1792 {
1793 	ASSERT(acp->pkt);
1794 
1795 	acp->flags |= AAC_CMD_CMPLT;
1796 
1797 	acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
1798 	    STATE_SENT_CMD | STATE_GOT_STATUS;
1799 	if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
1800 		acp->pkt->pkt_resid = 0;
1801 
1802 	/* AAC_CMD_NO_INTR means no complete callback */
1803 	if (!(acp->flags & AAC_CMD_NO_INTR)) {
1804 		mutex_enter(&softs->q_comp_mutex);
1805 		aac_cmd_enqueue(&softs->q_comp, acp);
1806 		mutex_exit(&softs->q_comp_mutex);
1807 		ddi_trigger_softintr(softs->softint_id);
1808 	}
1809 }
1810 
1811 /*
1812  * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
1813  */
1814 
1815 /*
1816  * Handle completed logical device IO command
1817  */
1818 /*ARGSUSED*/
1819 static void
1820 aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1821 {
1822 	struct aac_slot *slotp = acp->slotp;
1823 	struct aac_blockread_response *resp;
1824 	uint32_t status;
1825 
1826 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1827 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1828 
1829 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
1830 
1831 	/*
1832 	 * block_read/write has a similar response header, use blockread
1833 	 * response for both.
1834 	 */
1835 	resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
1836 	status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
1837 	if (status == ST_OK) {
1838 		acp->pkt->pkt_resid = 0;
1839 		acp->pkt->pkt_state |= STATE_XFERRED_DATA;
1840 	} else {
1841 		aac_set_arq_data_hwerr(acp);
1842 	}
1843 }
1844 
1845 /*
1846  * Handle completed phys. device IO command
1847  */
1848 static void
1849 aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1850 {
1851 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
1852 	struct aac_fib *fibp = acp->slotp->fibp;
1853 	struct scsi_pkt *pkt = acp->pkt;
1854 	struct aac_srb_reply *resp;
1855 	uint32_t resp_status;
1856 
1857 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1858 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1859 
1860 	resp = (struct aac_srb_reply *)&fibp->data[0];
1861 	resp_status = ddi_get32(acc, &resp->status);
1862 
1863 	/* First check FIB status */
1864 	if (resp_status == ST_OK) {
1865 		uint32_t scsi_status;
1866 		uint32_t srb_status;
1867 		uint32_t data_xfer_length;
1868 
1869 		scsi_status = ddi_get32(acc, &resp->scsi_status);
1870 		srb_status = ddi_get32(acc, &resp->srb_status);
1871 		data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
1872 
1873 		*pkt->pkt_scbp = (uint8_t)scsi_status;
1874 		pkt->pkt_state |= STATE_GOT_STATUS;
1875 		if (scsi_status == STATUS_GOOD) {
1876 			uchar_t cmd = ((union scsi_cdb *)(void *)
1877 			    (pkt->pkt_cdbp))->scc_cmd;
1878 
1879 			/* Next check SRB status */
1880 			switch (srb_status & 0x3f) {
1881 			case SRB_STATUS_DATA_OVERRUN:
1882 				AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
1883 				    "scmd=%d, xfer=%d, buflen=%d",
1884 				    (uint32_t)cmd, data_xfer_length,
1885 				    acp->bcount);
1886 
1887 				switch (cmd) {
1888 				case SCMD_READ:
1889 				case SCMD_WRITE:
1890 				case SCMD_READ_G1:
1891 				case SCMD_WRITE_G1:
1892 				case SCMD_READ_G4:
1893 				case SCMD_WRITE_G4:
1894 				case SCMD_READ_G5:
1895 				case SCMD_WRITE_G5:
1896 					aac_set_pkt_reason(softs, acp,
1897 					    CMD_DATA_OVR, 0);
1898 					break;
1899 				}
1900 				/*FALLTHRU*/
1901 			case SRB_STATUS_ERROR_RECOVERY:
1902 			case SRB_STATUS_PENDING:
1903 			case SRB_STATUS_SUCCESS:
1904 				/*
1905 				 * pkt_resid should only be calculated if the
1906 				 * status is ERROR_RECOVERY/PENDING/SUCCESS/
1907 				 * OVERRUN/UNDERRUN
1908 				 */
1909 				if (data_xfer_length) {
1910 					pkt->pkt_state |= STATE_XFERRED_DATA;
1911 					pkt->pkt_resid = acp->bcount - \
1912 					    data_xfer_length;
1913 					ASSERT(pkt->pkt_resid >= 0);
1914 				}
1915 				break;
1916 			case SRB_STATUS_ABORTED:
1917 				AACDB_PRINT(softs, CE_NOTE,
1918 				    "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
1919 				    data_xfer_length, pkt->pkt_resid);
1920 				aac_set_pkt_reason(softs, acp, CMD_ABORTED,
1921 				    STAT_ABORTED);
1922 				break;
1923 			case SRB_STATUS_ABORT_FAILED:
1924 				AACDB_PRINT(softs, CE_NOTE,
1925 				    "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
1926 				    "resid=%d", data_xfer_length,
1927 				    pkt->pkt_resid);
1928 				aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
1929 				    0);
1930 				break;
1931 			case SRB_STATUS_PARITY_ERROR:
1932 				AACDB_PRINT(softs, CE_NOTE,
1933 				    "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
1934 				    "resid=%d", data_xfer_length,
1935 				    pkt->pkt_resid);
1936 				aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
1937 				break;
1938 			case SRB_STATUS_NO_DEVICE:
1939 			case SRB_STATUS_INVALID_PATH_ID:
1940 			case SRB_STATUS_INVALID_TARGET_ID:
1941 			case SRB_STATUS_INVALID_LUN:
1942 			case SRB_STATUS_SELECTION_TIMEOUT:
1943 #ifdef DEBUG
1944 				if (AAC_DEV_IS_VALID(acp->dvp)) {
1945 					AACDB_PRINT(softs, CE_NOTE,
1946 					    "SRB_STATUS_NO_DEVICE(%d), " \
1947 					    "xfer=%d, resid=%d ",
1948 					    srb_status & 0x3f,
1949 					    data_xfer_length, pkt->pkt_resid);
1950 				}
1951 #endif
1952 				aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
1953 				break;
1954 			case SRB_STATUS_COMMAND_TIMEOUT:
1955 			case SRB_STATUS_TIMEOUT:
1956 				AACDB_PRINT(softs, CE_NOTE,
1957 				    "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
1958 				    "resid=%d", data_xfer_length,
1959 				    pkt->pkt_resid);
1960 				aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
1961 				    STAT_TIMEOUT);
1962 				break;
1963 			case SRB_STATUS_BUS_RESET:
1964 				AACDB_PRINT(softs, CE_NOTE,
1965 				    "SRB_STATUS_BUS_RESET, xfer=%d, " \
1966 				    "resid=%d", data_xfer_length,
1967 				    pkt->pkt_resid);
1968 				aac_set_pkt_reason(softs, acp, CMD_RESET,
1969 				    STAT_BUS_RESET);
1970 				break;
1971 			default:
1972 				AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
1973 				    "xfer=%d, resid=%d", srb_status & 0x3f,
1974 				    data_xfer_length, pkt->pkt_resid);
1975 				aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
1976 				break;
1977 			}
1978 		} else if (scsi_status == STATUS_CHECK) {
1979 			/* CHECK CONDITION */
1980 			struct scsi_arq_status *arqstat =
1981 			    (void *)(pkt->pkt_scbp);
1982 			uint32_t sense_data_size;
1983 
1984 			pkt->pkt_state |= STATE_ARQ_DONE;
1985 
1986 			*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
1987 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
1988 			arqstat->sts_rqpkt_resid = 0;
1989 			arqstat->sts_rqpkt_state =
1990 			    STATE_GOT_BUS |
1991 			    STATE_GOT_TARGET |
1992 			    STATE_SENT_CMD |
1993 			    STATE_XFERRED_DATA;
1994 			arqstat->sts_rqpkt_statistics = 0;
1995 
1996 			sense_data_size = ddi_get32(acc,
1997 			    &resp->sense_data_size);
1998 			ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
1999 			AACDB_PRINT(softs, CE_NOTE,
2000 			    "CHECK CONDITION: sense len=%d, xfer len=%d",
2001 			    sense_data_size, data_xfer_length);
2002 
2003 			if (sense_data_size > SENSE_LENGTH)
2004 				sense_data_size = SENSE_LENGTH;
2005 			ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
2006 			    (uint8_t *)resp->sense_data, sense_data_size,
2007 			    DDI_DEV_AUTOINCR);
2008 		} else {
2009 			AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
2010 			    "scsi_status=%d, srb_status=%d",
2011 			    scsi_status, srb_status);
2012 			aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
2013 		}
2014 	} else {
2015 		AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
2016 		    resp_status);
2017 		aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
2018 	}
2019 }
2020 
2021 /*
2022  * Handle completed IOCTL command
2023  */
2024 /*ARGSUSED*/
2025 void
2026 aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2027 {
2028 	struct aac_slot *slotp = acp->slotp;
2029 
2030 	/*
2031 	 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
2032 	 * may wait on softs->event, so use cv_broadcast() instead
2033 	 * of cv_signal().
2034 	 */
2035 	ASSERT(acp->flags & AAC_CMD_SYNC);
2036 	ASSERT(acp->flags & AAC_CMD_NO_CB);
2037 
2038 	/* Get the size of the response FIB from its FIB.Header.Size field */
2039 	acp->fib_size = ddi_get16(slotp->fib_acc_handle,
2040 	    &slotp->fibp->Header.Size);
2041 
2042 	ASSERT(acp->fib_size <= softs->aac_max_fib_size);
2043 	ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
2044 	    (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
2045 }
2046 
2047 /*
2048  * Handle completed sync fib command
2049  */
2050 /*ARGSUSED*/
2051 void
2052 aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2053 {
2054 }
2055 
2056 /*
2057  * Handle completed Flush command
2058  */
2059 /*ARGSUSED*/
2060 static void
2061 aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2062 {
2063 	struct aac_slot *slotp = acp->slotp;
2064 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2065 	struct aac_synchronize_reply *resp;
2066 	uint32_t status;
2067 
2068 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2069 
2070 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2071 
2072 	resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
2073 	status = ddi_get32(acc, &resp->Status);
2074 	if (status != CT_OK)
2075 		aac_set_arq_data_hwerr(acp);
2076 }
2077 
2078 /*ARGSUSED*/
2079 static void
2080 aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2081 {
2082 	struct aac_slot *slotp = acp->slotp;
2083 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2084 	struct aac_Container_resp *resp;
2085 	uint32_t status;
2086 
2087 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2088 
2089 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2090 
2091 	resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
2092 	status = ddi_get32(acc, &resp->Status);
2093 	if (status != 0) {
2094 		AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
2095 		aac_set_arq_data_hwerr(acp);
2096 	}
2097 }
2098 
2099 /*
2100  * Access PCI space to see if the driver can support the card
2101  */
2102 static int
2103 aac_check_card_type(struct aac_softstate *softs)
2104 {
2105 	ddi_acc_handle_t pci_config_handle;
2106 	int card_index;
2107 	uint32_t pci_cmd;
2108 
2109 	/* Map pci configuration space */
2110 	if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
2111 	    DDI_SUCCESS) {
2112 		AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
2113 		return (AACERR);
2114 	}
2115 
2116 	softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
2117 	softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
2118 	softs->subvendid = pci_config_get16(pci_config_handle,
2119 	    PCI_CONF_SUBVENID);
2120 	softs->subsysid = pci_config_get16(pci_config_handle,
2121 	    PCI_CONF_SUBSYSID);
2122 
2123 	card_index = 0;
2124 	while (!CARD_IS_UNKNOWN(card_index)) {
2125 		if ((aac_cards[card_index].vendor == softs->vendid) &&
2126 		    (aac_cards[card_index].device == softs->devid) &&
2127 		    (aac_cards[card_index].subvendor == softs->subvendid) &&
2128 		    (aac_cards[card_index].subsys == softs->subsysid)) {
2129 			break;
2130 		}
2131 		card_index++;
2132 	}
2133 
2134 	softs->card = card_index;
2135 	softs->hwif = aac_cards[card_index].hwif;
2136 
2137 	/*
2138 	 * Unknown aac card
2139 	 * do a generic match based on the VendorID and DeviceID to
2140 	 * support the new cards in the aac family
2141 	 */
2142 	if (CARD_IS_UNKNOWN(card_index)) {
2143 		if (softs->vendid != 0x9005) {
2144 			AACDB_PRINT(softs, CE_WARN,
2145 			    "Unknown vendor 0x%x", softs->vendid);
2146 			goto error;
2147 		}
2148 		switch (softs->devid) {
2149 		case 0x285:
2150 			softs->hwif = AAC_HWIF_I960RX;
2151 			break;
2152 		case 0x286:
2153 			softs->hwif = AAC_HWIF_RKT;
2154 			break;
2155 		default:
2156 			AACDB_PRINT(softs, CE_WARN,
2157 			    "Unknown device \"pci9005,%x\"", softs->devid);
2158 			goto error;
2159 		}
2160 	}
2161 
2162 	/* Set hardware dependent interface */
2163 	switch (softs->hwif) {
2164 	case AAC_HWIF_I960RX:
2165 		softs->aac_if = aac_rx_interface;
2166 		softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
2167 		break;
2168 	case AAC_HWIF_RKT:
2169 		softs->aac_if = aac_rkt_interface;
2170 		softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
2171 		break;
2172 	default:
2173 		AACDB_PRINT(softs, CE_WARN,
2174 		    "Unknown hardware interface %d", softs->hwif);
2175 		goto error;
2176 	}
2177 
2178 	/* Set card names */
2179 	(void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
2180 	    AAC_VENDOR_LEN);
2181 	(void *)strncpy(softs->product_name, aac_cards[card_index].desc,
2182 	    AAC_PRODUCT_LEN);
2183 
2184 	/* Set up quirks */
2185 	softs->flags = aac_cards[card_index].quirks;
2186 
2187 	/* Force the busmaster enable bit on */
2188 	pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2189 	if ((pci_cmd & PCI_COMM_ME) == 0) {
2190 		pci_cmd |= PCI_COMM_ME;
2191 		pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
2192 		pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2193 		if ((pci_cmd & PCI_COMM_ME) == 0) {
2194 			cmn_err(CE_CONT, "?Cannot enable busmaster bit");
2195 			goto error;
2196 		}
2197 	}
2198 
2199 	/* Set memory base to map */
2200 	softs->pci_mem_base_paddr = 0xfffffff0UL & \
2201 	    pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
2202 
2203 	pci_config_teardown(&pci_config_handle);
2204 
2205 	return (AACOK); /* card type detected */
2206 error:
2207 	pci_config_teardown(&pci_config_handle);
2208 	return (AACERR); /* no matched card found */
2209 }
2210 
2211 /*
2212  * Do the usual interrupt handler setup stuff.
2213  */
2214 static int
2215 aac_register_intrs(struct aac_softstate *softs)
2216 {
2217 	dev_info_t *dip;
2218 	int intr_types;
2219 
2220 	ASSERT(softs->devinfo_p);
2221 	dip = softs->devinfo_p;
2222 
2223 	/* Get the type of device intrrupts */
2224 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
2225 		AACDB_PRINT(softs, CE_WARN,
2226 		    "ddi_intr_get_supported_types() failed");
2227 		return (AACERR);
2228 	}
2229 	AACDB_PRINT(softs, CE_NOTE,
2230 	    "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
2231 
2232 	/* Query interrupt, and alloc/init all needed struct */
2233 	if (intr_types & DDI_INTR_TYPE_MSI) {
2234 		if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
2235 		    != DDI_SUCCESS) {
2236 			AACDB_PRINT(softs, CE_WARN,
2237 			    "MSI interrupt query failed");
2238 			return (AACERR);
2239 		}
2240 		softs->intr_type = DDI_INTR_TYPE_MSI;
2241 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
2242 		if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
2243 		    != DDI_SUCCESS) {
2244 			AACDB_PRINT(softs, CE_WARN,
2245 			    "FIXED interrupt query failed");
2246 			return (AACERR);
2247 		}
2248 		softs->intr_type = DDI_INTR_TYPE_FIXED;
2249 	} else {
2250 		AACDB_PRINT(softs, CE_WARN,
2251 		    "Device cannot suppport both FIXED and MSI interrupts");
2252 		return (AACERR);
2253 	}
2254 
2255 	/* Connect interrupt handlers */
2256 	if (aac_add_intrs(softs) != DDI_SUCCESS) {
2257 		AACDB_PRINT(softs, CE_WARN,
2258 		    "Interrupt registration failed, intr type: %s",
2259 		    softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
2260 		return (AACERR);
2261 	}
2262 	(void) aac_enable_intrs(softs);
2263 
2264 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
2265 	    NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
2266 		AACDB_PRINT(softs, CE_WARN,
2267 		    "Can not setup soft interrupt handler!");
2268 		aac_remove_intrs(softs);
2269 		return (AACERR);
2270 	}
2271 
2272 	return (AACOK);
2273 }
2274 
2275 static void
2276 aac_unregister_intrs(struct aac_softstate *softs)
2277 {
2278 	aac_remove_intrs(softs);
2279 	ddi_remove_softintr(softs->softint_id);
2280 }
2281 
2282 /*
2283  * Check the firmware to determine the features to support and the FIB
2284  * parameters to use.
2285  */
2286 static int
2287 aac_check_firmware(struct aac_softstate *softs)
2288 {
2289 	uint32_t options;
2290 	uint32_t atu_size;
2291 	ddi_acc_handle_t pci_handle;
2292 	uint8_t *data;
2293 	uint32_t max_fibs;
2294 	uint32_t max_fib_size;
2295 	uint32_t sg_tablesize;
2296 	uint32_t max_sectors;
2297 	uint32_t status;
2298 
2299 	/* Get supported options */
2300 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
2301 	    &status)) != AACOK) {
2302 		if (status != SRB_STATUS_INVALID_REQUEST) {
2303 			cmn_err(CE_CONT,
2304 			    "?Fatal error: request adapter info error");
2305 			return (AACERR);
2306 		}
2307 		options = 0;
2308 		atu_size = 0;
2309 	} else {
2310 		options = AAC_MAILBOX_GET(softs, 1);
2311 		atu_size = AAC_MAILBOX_GET(softs, 2);
2312 	}
2313 
2314 	if (softs->state & AAC_STATE_RESET) {
2315 		if ((softs->support_opt == options) &&
2316 		    (softs->atu_size == atu_size))
2317 			return (AACOK);
2318 
2319 		cmn_err(CE_WARN,
2320 		    "?Fatal error: firmware changed, system needs reboot");
2321 		return (AACERR);
2322 	}
2323 
2324 	/*
2325 	 * The following critical settings are initialized only once during
2326 	 * driver attachment.
2327 	 */
2328 	softs->support_opt = options;
2329 	softs->atu_size = atu_size;
2330 
2331 	/* Process supported options */
2332 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
2333 	    (softs->flags & AAC_FLAGS_NO4GB) == 0) {
2334 		AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
2335 		softs->flags |= AAC_FLAGS_4GB_WINDOW;
2336 	} else {
2337 		/*
2338 		 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
2339 		 * only. IO is handled by the DMA engine which does not suffer
2340 		 * from the ATU window programming workarounds necessary for
2341 		 * CPU copy operations.
2342 		 */
2343 		softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
2344 		softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
2345 	}
2346 
2347 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
2348 		AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
2349 		softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
2350 		softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
2351 		softs->flags |= AAC_FLAGS_SG_64BIT;
2352 	}
2353 
2354 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
2355 		softs->flags |= AAC_FLAGS_ARRAY_64BIT;
2356 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
2357 	}
2358 
2359 	if (options & AAC_SUPPORTED_NONDASD) {
2360 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
2361 		    "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
2362 			if (strcmp((char *)data, "yes") == 0) {
2363 				AACDB_PRINT(softs, CE_NOTE,
2364 				    "!Enable Non-DASD access");
2365 				softs->flags |= AAC_FLAGS_NONDASD;
2366 			}
2367 			ddi_prop_free(data);
2368 		}
2369 	}
2370 
2371 	/* Read preferred settings */
2372 	max_fib_size = 0;
2373 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
2374 	    0, 0, 0, 0, NULL)) == AACOK) {
2375 		options = AAC_MAILBOX_GET(softs, 1);
2376 		max_fib_size = (options & 0xffff);
2377 		max_sectors = (options >> 16) << 1;
2378 		options = AAC_MAILBOX_GET(softs, 2);
2379 		sg_tablesize = (options >> 16);
2380 		options = AAC_MAILBOX_GET(softs, 3);
2381 		max_fibs = (options & 0xffff);
2382 	}
2383 
2384 	/* Enable new comm. and rawio at the same time */
2385 	if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
2386 	    (max_fib_size != 0)) {
2387 		/* read out and save PCI MBR */
2388 		if ((atu_size > softs->map_size) &&
2389 		    (ddi_regs_map_setup(softs->devinfo_p, 1,
2390 		    (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
2391 		    &pci_handle) == DDI_SUCCESS)) {
2392 			ddi_regs_map_free(&softs->pci_mem_handle);
2393 			softs->pci_mem_handle = pci_handle;
2394 			softs->pci_mem_base_vaddr = data;
2395 			softs->map_size = atu_size;
2396 		}
2397 		if (atu_size == softs->map_size) {
2398 			softs->flags |= AAC_FLAGS_NEW_COMM;
2399 			AACDB_PRINT(softs, CE_NOTE,
2400 			    "!Enable New Comm. interface");
2401 		}
2402 	}
2403 
2404 	/* Set FIB parameters */
2405 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
2406 		softs->aac_max_fibs = max_fibs;
2407 		softs->aac_max_fib_size = max_fib_size;
2408 		softs->aac_max_sectors = max_sectors;
2409 		softs->aac_sg_tablesize = sg_tablesize;
2410 
2411 		softs->flags |= AAC_FLAGS_RAW_IO;
2412 		AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
2413 	} else {
2414 		softs->aac_max_fibs =
2415 		    (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
2416 		softs->aac_max_fib_size = AAC_FIB_SIZE;
2417 		softs->aac_max_sectors = 128;	/* 64K */
2418 		if (softs->flags & AAC_FLAGS_17SG)
2419 			softs->aac_sg_tablesize = 17;
2420 		else if (softs->flags & AAC_FLAGS_34SG)
2421 			softs->aac_sg_tablesize = 34;
2422 		else if (softs->flags & AAC_FLAGS_SG_64BIT)
2423 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2424 			    sizeof (struct aac_blockwrite64) +
2425 			    sizeof (struct aac_sg_entry64)) /
2426 			    sizeof (struct aac_sg_entry64);
2427 		else
2428 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2429 			    sizeof (struct aac_blockwrite) +
2430 			    sizeof (struct aac_sg_entry)) /
2431 			    sizeof (struct aac_sg_entry);
2432 	}
2433 
2434 	if ((softs->flags & AAC_FLAGS_RAW_IO) &&
2435 	    (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
2436 		softs->flags |= AAC_FLAGS_LBA_64BIT;
2437 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
2438 	}
2439 	softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
2440 	softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
2441 	/*
2442 	 * 64K maximum segment size in scatter gather list is controlled by
2443 	 * the NEW_COMM bit in the adapter information. If not set, the card
2444 	 * can only accept a maximum of 64K. It is not recommended to permit
2445 	 * more than 128KB of total transfer size to the adapters because
2446 	 * performance is negatively impacted.
2447 	 *
2448 	 * For new comm, segment size equals max xfer size. For old comm,
2449 	 * we use 64K for both.
2450 	 */
2451 	softs->buf_dma_attr.dma_attr_count_max =
2452 	    softs->buf_dma_attr.dma_attr_maxxfer - 1;
2453 
2454 	/* Setup FIB operations */
2455 	if (softs->flags & AAC_FLAGS_RAW_IO)
2456 		softs->aac_cmd_fib = aac_cmd_fib_rawio;
2457 	else if (softs->flags & AAC_FLAGS_SG_64BIT)
2458 		softs->aac_cmd_fib = aac_cmd_fib_brw64;
2459 	else
2460 		softs->aac_cmd_fib = aac_cmd_fib_brw;
2461 	softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
2462 	    aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
2463 
2464 	/* 64-bit LBA needs descriptor format sense data */
2465 	softs->slen = sizeof (struct scsi_arq_status);
2466 	if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
2467 	    softs->slen < AAC_ARQ64_LENGTH)
2468 		softs->slen = AAC_ARQ64_LENGTH;
2469 
2470 	AACDB_PRINT(softs, CE_NOTE,
2471 	    "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
2472 	    softs->aac_max_fibs, softs->aac_max_fib_size,
2473 	    softs->aac_max_sectors, softs->aac_sg_tablesize);
2474 
2475 	return (AACOK);
2476 }
2477 
2478 static void
2479 aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
2480     struct FsaRev *fsarev1)
2481 {
2482 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
2483 
2484 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
2485 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
2486 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
2487 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
2488 	AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
2489 }
2490 
2491 /*
2492  * The following function comes from Adaptec:
2493  *
2494  * Query adapter information and supplement adapter information
2495  */
2496 static int
2497 aac_get_adapter_info(struct aac_softstate *softs,
2498     struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
2499 {
2500 	struct aac_cmd *acp = &softs->sync_ac;
2501 	ddi_acc_handle_t acc;
2502 	struct aac_fib *fibp;
2503 	struct aac_adapter_info *ainfp;
2504 	struct aac_supplement_adapter_info *sinfp;
2505 	int rval;
2506 
2507 	(void) aac_sync_fib_slot_bind(softs, acp);
2508 	acc = acp->slotp->fib_acc_handle;
2509 	fibp = acp->slotp->fibp;
2510 
2511 	ddi_put8(acc, &fibp->data[0], 0);
2512 	if (aac_sync_fib(softs, RequestAdapterInfo,
2513 	    AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
2514 		AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
2515 		rval = AACERR;
2516 		goto finish;
2517 	}
2518 	ainfp = (struct aac_adapter_info *)fibp->data;
2519 	if (ainfr) {
2520 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2521 		AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
2522 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
2523 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
2524 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
2525 		AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
2526 		AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
2527 		AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
2528 		aac_fsa_rev(softs, &ainfp->KernelRevision,
2529 		    &ainfr->KernelRevision);
2530 		aac_fsa_rev(softs, &ainfp->MonitorRevision,
2531 		    &ainfr->MonitorRevision);
2532 		aac_fsa_rev(softs, &ainfp->HardwareRevision,
2533 		    &ainfr->HardwareRevision);
2534 		aac_fsa_rev(softs, &ainfp->BIOSRevision,
2535 		    &ainfr->BIOSRevision);
2536 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
2537 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
2538 		AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
2539 		AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
2540 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2541 		AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
2542 	}
2543 	if (sinfr) {
2544 		if (!(softs->support_opt &
2545 		    AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
2546 			AACDB_PRINT(softs, CE_WARN,
2547 			    "SupplementAdapterInfo not supported");
2548 			rval = AACERR;
2549 			goto finish;
2550 		}
2551 		ddi_put8(acc, &fibp->data[0], 0);
2552 		if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
2553 		    AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
2554 		    != AACOK) {
2555 			AACDB_PRINT(softs, CE_WARN,
2556 			    "RequestSupplementAdapterInfo failed");
2557 			rval = AACERR;
2558 			goto finish;
2559 		}
2560 		sinfp = (struct aac_supplement_adapter_info *)fibp->data;
2561 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
2562 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
2563 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
2564 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
2565 		AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
2566 		AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
2567 		AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
2568 		AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
2569 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
2570 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
2571 		AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
2572 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
2573 		    sizeof (struct vpd_info));
2574 		aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
2575 		    &sinfr->FlashFirmwareRevision);
2576 		AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
2577 		aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
2578 		    &sinfr->FlashFirmwareBootRevision);
2579 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
2580 		    MFG_PCBA_SERIAL_NUMBER_WIDTH);
2581 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
2582 		    MFG_WWN_WIDTH);
2583 		AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
2584 		AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
2585 		if (sinfr->ExpansionFlag == 1) {
2586 			AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
2587 			AAC_GET_FIELD32(acc, sinfr, sinfp,
2588 			    SupportedPerformanceMode);
2589 			AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
2590 			    ReservedGrowth[0], 80);
2591 		}
2592 	}
2593 	rval = AACOK;
2594 finish:
2595 	aac_sync_fib_slot_release(softs, acp);
2596 	return (rval);
2597 }
2598 
2599 static int
2600 aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
2601     uint32_t *tgt_max)
2602 {
2603 	struct aac_cmd *acp = &softs->sync_ac;
2604 	ddi_acc_handle_t acc;
2605 	struct aac_fib *fibp;
2606 	struct aac_ctcfg *c_cmd;
2607 	struct aac_ctcfg_resp *c_resp;
2608 	uint32_t scsi_method_id;
2609 	struct aac_bus_info *cmd;
2610 	struct aac_bus_info_response *resp;
2611 	int rval;
2612 
2613 	(void) aac_sync_fib_slot_bind(softs, acp);
2614 	acc = acp->slotp->fib_acc_handle;
2615 	fibp = acp->slotp->fibp;
2616 
2617 	/* Detect MethodId */
2618 	c_cmd = (struct aac_ctcfg *)&fibp->data[0];
2619 	ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
2620 	ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
2621 	ddi_put32(acc, &c_cmd->param, 0);
2622 	rval = aac_sync_fib(softs, ContainerCommand,
2623 	    AAC_FIB_SIZEOF(struct aac_ctcfg));
2624 	c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
2625 	if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
2626 		AACDB_PRINT(softs, CE_WARN,
2627 		    "VM_ContainerConfig command fail");
2628 		rval = AACERR;
2629 		goto finish;
2630 	}
2631 	scsi_method_id = ddi_get32(acc, &c_resp->param);
2632 
2633 	/* Detect phys. bus count and max. target id first */
2634 	cmd = (struct aac_bus_info *)&fibp->data[0];
2635 	ddi_put32(acc, &cmd->Command, VM_Ioctl);
2636 	ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
2637 	ddi_put32(acc, &cmd->MethodId, scsi_method_id);
2638 	ddi_put32(acc, &cmd->ObjectId, 0);
2639 	ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
2640 	/*
2641 	 * For VM_Ioctl, the firmware uses the Header.Size filled from the
2642 	 * driver as the size to be returned. Therefore the driver has to use
2643 	 * sizeof (struct aac_bus_info_response) because it is greater than
2644 	 * sizeof (struct aac_bus_info).
2645 	 */
2646 	rval = aac_sync_fib(softs, ContainerCommand,
2647 	    AAC_FIB_SIZEOF(struct aac_bus_info_response));
2648 	resp = (struct aac_bus_info_response *)cmd;
2649 
2650 	/* Scan all coordinates with INQUIRY */
2651 	if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
2652 		AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
2653 		rval = AACERR;
2654 		goto finish;
2655 	}
2656 	*bus_max = ddi_get32(acc, &resp->BusCount);
2657 	*tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
2658 
2659 finish:
2660 	aac_sync_fib_slot_release(softs, acp);
2661 	return (AACOK);
2662 }
2663 
2664 /*
2665  * The following function comes from Adaptec:
2666  *
2667  * Routine to be called during initialization of communications with
2668  * the adapter to handle possible adapter configuration issues. When
2669  * the adapter first boots up, it examines attached drives, etc, and
2670  * potentially comes up with a new or revised configuration (relative to
2671  * what's stored in it's NVRAM). Additionally it may discover problems
2672  * that make the current physical configuration unworkable (currently
2673  * applicable only to cluster configuration issues).
2674  *
2675  * If there are no configuration issues or the issues are considered
2676  * trival by the adapter, it will set it's configuration status to
2677  * "FSACT_CONTINUE" and execute the "commit confiuguration" action
2678  * automatically on it's own.
2679  *
2680  * However, if there are non-trivial issues, the adapter will set it's
2681  * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
2682  * and wait for some agent on the host to issue the "\ContainerCommand
2683  * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
2684  * adapter to commit the new/updated configuration and enable
2685  * un-inhibited operation.  The host agent should first issue the
2686  * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
2687  * command to obtain information about config issues detected by
2688  * the adapter.
2689  *
2690  * Normally the adapter's PC BIOS will execute on the host following
2691  * adapter poweron and reset and will be responsible for querring the
2692  * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
2693  * command if appropriate.
2694  *
2695  * However, with the introduction of IOP reset support, the adapter may
2696  * boot up without the benefit of the adapter's PC BIOS host agent.
2697  * This routine is intended to take care of these issues in situations
2698  * where BIOS doesn't execute following adapter poweron or reset.  The
2699  * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
2700  * there is no harm in doing this when it's already been done.
2701  */
2702 static int
2703 aac_handle_adapter_config_issues(struct aac_softstate *softs)
2704 {
2705 	struct aac_cmd *acp = &softs->sync_ac;
2706 	ddi_acc_handle_t acc;
2707 	struct aac_fib *fibp;
2708 	struct aac_Container *cmd;
2709 	struct aac_Container_resp *resp;
2710 	struct aac_cf_status_header *cfg_sts_hdr;
2711 	uint32_t resp_status;
2712 	uint32_t ct_status;
2713 	uint32_t cfg_stat_action;
2714 	int rval;
2715 
2716 	(void) aac_sync_fib_slot_bind(softs, acp);
2717 	acc = acp->slotp->fib_acc_handle;
2718 	fibp = acp->slotp->fibp;
2719 
2720 	/* Get adapter config status */
2721 	cmd = (struct aac_Container *)&fibp->data[0];
2722 
2723 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2724 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2725 	ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
2726 	ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
2727 	    sizeof (struct aac_cf_status_header));
2728 	rval = aac_sync_fib(softs, ContainerCommand,
2729 	    AAC_FIB_SIZEOF(struct aac_Container));
2730 	resp = (struct aac_Container_resp *)cmd;
2731 	cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
2732 
2733 	resp_status = ddi_get32(acc, &resp->Status);
2734 	ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2735 	if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
2736 		cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
2737 
2738 		/* Commit configuration if it's reasonable to do so. */
2739 		if (cfg_stat_action <= CFACT_PAUSE) {
2740 			bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2741 			ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2742 			ddi_put32(acc, &cmd->CTCommand.command,
2743 			    CT_COMMIT_CONFIG);
2744 			rval = aac_sync_fib(softs, ContainerCommand,
2745 			    AAC_FIB_SIZEOF(struct aac_Container));
2746 
2747 			resp_status = ddi_get32(acc, &resp->Status);
2748 			ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2749 			if ((rval == AACOK) && (resp_status == 0) &&
2750 			    (ct_status == CT_OK))
2751 				/* Successful completion */
2752 				rval = AACMPE_OK;
2753 			else
2754 				/* Auto-commit aborted due to error(s). */
2755 				rval = AACMPE_COMMIT_CONFIG;
2756 		} else {
2757 			/*
2758 			 * Auto-commit aborted due to adapter indicating
2759 			 * configuration issue(s) too dangerous to auto-commit.
2760 			 */
2761 			rval = AACMPE_CONFIG_STATUS;
2762 		}
2763 	} else {
2764 		cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
2765 		rval = AACMPE_CONFIG_STATUS;
2766 	}
2767 
2768 	aac_sync_fib_slot_release(softs, acp);
2769 	return (rval);
2770 }
2771 
2772 /*
2773  * Hardware initialization and resource allocation
2774  */
2775 static int
2776 aac_common_attach(struct aac_softstate *softs)
2777 {
2778 	uint32_t status;
2779 	int i;
2780 	struct aac_supplement_adapter_info sinf;
2781 
2782 	DBCALLED(softs, 1);
2783 
2784 	/*
2785 	 * Do a little check here to make sure there aren't any outstanding
2786 	 * FIBs in the message queue. At this point there should not be and
2787 	 * if there are they are probably left over from another instance of
2788 	 * the driver like when the system crashes and the crash dump driver
2789 	 * gets loaded.
2790 	 */
2791 	while (AAC_OUTB_GET(softs) != 0xfffffffful)
2792 		;
2793 
2794 	/*
2795 	 * Wait the card to complete booting up before do anything that
2796 	 * attempts to communicate with it.
2797 	 */
2798 	status = AAC_FWSTATUS_GET(softs);
2799 	if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
2800 		goto error;
2801 	i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
2802 	AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
2803 	if (i == 0) {
2804 		cmn_err(CE_CONT, "?Fatal error: controller not ready");
2805 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2806 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2807 		goto error;
2808 	}
2809 
2810 	/* Read and set card supported options and settings */
2811 	if (aac_check_firmware(softs) == AACERR) {
2812 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2813 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2814 		goto error;
2815 	}
2816 
2817 	/* Add interrupt handlers */
2818 	if (aac_register_intrs(softs) == AACERR) {
2819 		cmn_err(CE_CONT,
2820 		    "?Fatal error: interrupts register failed");
2821 		goto error;
2822 	}
2823 
2824 	/* Setup communication space with the card */
2825 	if (softs->comm_space_dma_handle == NULL) {
2826 		if (aac_alloc_comm_space(softs) != AACOK)
2827 			goto error;
2828 	}
2829 	if (aac_setup_comm_space(softs) != AACOK) {
2830 		cmn_err(CE_CONT, "?Setup communication space failed");
2831 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2832 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2833 		goto error;
2834 	}
2835 
2836 #ifdef DEBUG
2837 	if (aac_get_fw_debug_buffer(softs) != AACOK)
2838 		cmn_err(CE_CONT, "?firmware UART trace not supported");
2839 #endif
2840 
2841 	/* Allocate slots */
2842 	if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
2843 		cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
2844 		goto error;
2845 	}
2846 	AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
2847 
2848 	/* Allocate FIBs */
2849 	if (softs->total_fibs < softs->total_slots) {
2850 		aac_alloc_fibs(softs);
2851 		if (softs->total_fibs == 0)
2852 			goto error;
2853 		AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
2854 		    softs->total_fibs);
2855 	}
2856 
2857 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
2858 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
2859 
2860 	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
2861 		softs->feature_bits = sinf.FeatureBits;
2862 		softs->support_opt2 = sinf.SupportedOptions2;
2863 
2864 		/* Get adapter names */
2865 		if (CARD_IS_UNKNOWN(softs->card)) {
2866 			char *p, *p0, *p1;
2867 
2868 			/*
2869 			 * Now find the controller name in supp_adapter_info->
2870 			 * AdapterTypeText. Use the first word as the vendor
2871 			 * and the other words as the product name.
2872 			 */
2873 			AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
2874 			    "\"%s\"", sinf.AdapterTypeText);
2875 			p = sinf.AdapterTypeText;
2876 			p0 = p1 = NULL;
2877 			/* Skip heading spaces */
2878 			while (*p && (*p == ' ' || *p == '\t'))
2879 				p++;
2880 			p0 = p;
2881 			while (*p && (*p != ' ' && *p != '\t'))
2882 				p++;
2883 			/* Remove middle spaces */
2884 			while (*p && (*p == ' ' || *p == '\t'))
2885 				*p++ = 0;
2886 			p1 = p;
2887 			/* Remove trailing spaces */
2888 			p = p1 + strlen(p1) - 1;
2889 			while (p > p1 && (*p == ' ' || *p == '\t'))
2890 				*p-- = 0;
2891 			if (*p0 && *p1) {
2892 				(void *)strncpy(softs->vendor_name, p0,
2893 				    AAC_VENDOR_LEN);
2894 				(void *)strncpy(softs->product_name, p1,
2895 				    AAC_PRODUCT_LEN);
2896 			} else {
2897 				cmn_err(CE_WARN,
2898 				    "?adapter name mis-formatted\n");
2899 				if (*p0)
2900 					(void *)strncpy(softs->product_name,
2901 					    p0, AAC_PRODUCT_LEN);
2902 			}
2903 		}
2904 	} else {
2905 		cmn_err(CE_CONT, "?Query adapter information failed");
2906 	}
2907 
2908 
2909 	cmn_err(CE_NOTE,
2910 	    "!aac driver %d.%02d.%02d-%d, found card: " \
2911 	    "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
2912 	    AAC_DRIVER_MAJOR_VERSION,
2913 	    AAC_DRIVER_MINOR_VERSION,
2914 	    AAC_DRIVER_BUGFIX_LEVEL,
2915 	    AAC_DRIVER_BUILD,
2916 	    softs->vendor_name, softs->product_name,
2917 	    softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
2918 	    softs->pci_mem_base_paddr);
2919 
2920 	/* Perform acceptance of adapter-detected config changes if possible */
2921 	if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
2922 		cmn_err(CE_CONT, "?Handle adapter config issues failed");
2923 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2924 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2925 		goto error;
2926 	}
2927 
2928 	/* Setup containers (logical devices) */
2929 	if (aac_probe_containers(softs) != AACOK) {
2930 		cmn_err(CE_CONT, "?Fatal error: get container info error");
2931 		goto error;
2932 	}
2933 
2934 	/* Check for JBOD support. Default disable */
2935 	char *data;
2936 	if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
2937 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
2938 		    0, "jbod-enable", &data) == DDI_SUCCESS)) {
2939 			if (strcmp(data, "yes") == 0) {
2940 				AACDB_PRINT(softs, CE_NOTE,
2941 				    "Enable JBOD access");
2942 				softs->flags |= AAC_FLAGS_JBOD;
2943 			}
2944 			ddi_prop_free(data);
2945 		}
2946 	}
2947 
2948 	/* Setup phys. devices */
2949 	if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
2950 		uint32_t bus_max, tgt_max;
2951 		uint32_t bus, tgt;
2952 		int index;
2953 
2954 		if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
2955 			cmn_err(CE_CONT, "?Fatal error: get bus info error");
2956 			goto error;
2957 		}
2958 		AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
2959 		    bus_max, tgt_max);
2960 		if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
2961 			if (softs->state & AAC_STATE_RESET) {
2962 				cmn_err(CE_WARN,
2963 				    "?Fatal error: bus map changed");
2964 				goto error;
2965 			}
2966 			softs->bus_max = bus_max;
2967 			softs->tgt_max = tgt_max;
2968 			if (softs->nondasds) {
2969 				kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
2970 				    sizeof (struct aac_nondasd));
2971 			}
2972 			softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
2973 			    sizeof (struct aac_nondasd), KM_SLEEP);
2974 
2975 			index = 0;
2976 			for (bus = 0; bus < softs->bus_max; bus++) {
2977 				for (tgt = 0; tgt < softs->tgt_max; tgt++) {
2978 					struct aac_nondasd *dvp =
2979 					    &softs->nondasds[index++];
2980 					dvp->dev.type = AAC_DEV_PD;
2981 					dvp->bus = bus;
2982 					dvp->tid = tgt;
2983 				}
2984 			}
2985 		}
2986 	}
2987 
2988 	/* Check dma & acc handles allocated in attach */
2989 	if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
2990 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2991 		goto error;
2992 	}
2993 
2994 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
2995 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2996 		goto error;
2997 	}
2998 
2999 	for (i = 0; i < softs->total_slots; i++) {
3000 		if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
3001 		    DDI_SUCCESS) {
3002 			ddi_fm_service_impact(softs->devinfo_p,
3003 			    DDI_SERVICE_LOST);
3004 			goto error;
3005 		}
3006 	}
3007 
3008 	return (AACOK);
3009 error:
3010 	if (softs->state & AAC_STATE_RESET)
3011 		return (AACERR);
3012 	if (softs->nondasds) {
3013 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
3014 		    sizeof (struct aac_nondasd));
3015 		softs->nondasds = NULL;
3016 	}
3017 	if (softs->total_fibs > 0)
3018 		aac_destroy_fibs(softs);
3019 	if (softs->total_slots > 0)
3020 		aac_destroy_slots(softs);
3021 	if (softs->comm_space_dma_handle)
3022 		aac_free_comm_space(softs);
3023 	return (AACERR);
3024 }
3025 
3026 /*
3027  * Hardware shutdown and resource release
3028  */
3029 static void
3030 aac_common_detach(struct aac_softstate *softs)
3031 {
3032 	DBCALLED(softs, 1);
3033 
3034 	aac_unregister_intrs(softs);
3035 
3036 	mutex_enter(&softs->io_lock);
3037 	(void) aac_shutdown(softs);
3038 
3039 	if (softs->nondasds) {
3040 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
3041 		    sizeof (struct aac_nondasd));
3042 		softs->nondasds = NULL;
3043 	}
3044 	aac_destroy_fibs(softs);
3045 	aac_destroy_slots(softs);
3046 	aac_free_comm_space(softs);
3047 	mutex_exit(&softs->io_lock);
3048 }
3049 
3050 /*
3051  * Send a synchronous command to the controller and wait for a result.
3052  * Indicate if the controller completed the command with an error status.
3053  */
3054 int
3055 aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
3056     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
3057     uint32_t *statusp)
3058 {
3059 	int timeout;
3060 	uint32_t status;
3061 
3062 	if (statusp != NULL)
3063 		*statusp = SRB_STATUS_SUCCESS;
3064 
3065 	/* Fill in mailbox */
3066 	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
3067 
3068 	/* Ensure the sync command doorbell flag is cleared */
3069 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3070 
3071 	/* Then set it to signal the adapter */
3072 	AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
3073 
3074 	/* Spin waiting for the command to complete */
3075 	timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
3076 	AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
3077 	if (!timeout) {
3078 		AACDB_PRINT(softs, CE_WARN,
3079 		    "Sync command timed out after %d seconds (0x%x)!",
3080 		    AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
3081 		return (AACERR);
3082 	}
3083 
3084 	/* Clear the completion flag */
3085 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3086 
3087 	/* Get the command status */
3088 	status = AAC_MAILBOX_GET(softs, 0);
3089 	if (statusp != NULL)
3090 		*statusp = status;
3091 	if (status != SRB_STATUS_SUCCESS) {
3092 		AACDB_PRINT(softs, CE_WARN,
3093 		    "Sync command fail: status = 0x%x", status);
3094 		return (AACERR);
3095 	}
3096 
3097 	return (AACOK);
3098 }
3099 
3100 /*
3101  * Send a synchronous FIB to the adapter and wait for its completion
3102  */
3103 static int
3104 aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
3105 {
3106 	struct aac_cmd *acp = &softs->sync_ac;
3107 
3108 	acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
3109 	if (softs->state & AAC_STATE_INTR)
3110 		acp->flags |= AAC_CMD_NO_CB;
3111 	else
3112 		acp->flags |= AAC_CMD_NO_INTR;
3113 
3114 	acp->ac_comp = aac_sync_complete;
3115 	acp->timeout = AAC_SYNC_TIMEOUT;
3116 	acp->fib_size = fibsize;
3117 
3118 	/*
3119 	 * Only need to setup sync fib header, caller should have init
3120 	 * fib data
3121 	 */
3122 	aac_cmd_fib_header(softs, acp, cmd);
3123 
3124 	(void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
3125 	    DDI_DMA_SYNC_FORDEV);
3126 
3127 	aac_start_io(softs, acp);
3128 
3129 	if (softs->state & AAC_STATE_INTR)
3130 		return (aac_do_sync_io(softs, acp));
3131 	else
3132 		return (aac_do_poll_io(softs, acp));
3133 }
3134 
3135 static void
3136 aac_cmd_initq(struct aac_cmd_queue *q)
3137 {
3138 	q->q_head = NULL;
3139 	q->q_tail = (struct aac_cmd *)&q->q_head;
3140 }
3141 
3142 /*
3143  * Remove a cmd from the head of q
3144  */
3145 static struct aac_cmd *
3146 aac_cmd_dequeue(struct aac_cmd_queue *q)
3147 {
3148 	struct aac_cmd *acp;
3149 
3150 	_NOTE(ASSUMING_PROTECTED(*q))
3151 
3152 	if ((acp = q->q_head) != NULL) {
3153 		if ((q->q_head = acp->next) != NULL)
3154 			acp->next = NULL;
3155 		else
3156 			q->q_tail = (struct aac_cmd *)&q->q_head;
3157 		acp->prev = NULL;
3158 	}
3159 	return (acp);
3160 }
3161 
3162 /*
3163  * Add a cmd to the tail of q
3164  */
3165 static void
3166 aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
3167 {
3168 	ASSERT(acp->next == NULL);
3169 	acp->prev = q->q_tail;
3170 	q->q_tail->next = acp;
3171 	q->q_tail = acp;
3172 }
3173 
3174 /*
3175  * Remove the cmd ac from q
3176  */
3177 static void
3178 aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
3179 {
3180 	if (acp->prev) {
3181 		if ((acp->prev->next = acp->next) != NULL) {
3182 			acp->next->prev = acp->prev;
3183 			acp->next = NULL;
3184 		} else {
3185 			q->q_tail = acp->prev;
3186 		}
3187 		acp->prev = NULL;
3188 	}
3189 	/* ac is not in the queue */
3190 }
3191 
3192 /*
3193  * Atomically insert an entry into the nominated queue, returns 0 on success or
3194  * AACERR if the queue is full.
3195  *
3196  * Note: it would be more efficient to defer notifying the controller in
3197  *	 the case where we may be inserting several entries in rapid succession,
3198  *	 but implementing this usefully may be difficult (it would involve a
3199  *	 separate queue/notify interface).
3200  */
3201 static int
3202 aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
3203     uint32_t fib_size)
3204 {
3205 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3206 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3207 	uint32_t pi, ci;
3208 
3209 	DBCALLED(softs, 2);
3210 
3211 	ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
3212 
3213 	/* Get the producer/consumer indices */
3214 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3215 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3216 	    DDI_DMA_SYNC_FORCPU);
3217 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3218 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3219 		return (AACERR);
3220 	}
3221 
3222 	pi = ddi_get32(acc,
3223 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3224 	ci = ddi_get32(acc,
3225 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3226 
3227 	/*
3228 	 * Wrap the queue first before we check the queue to see
3229 	 * if it is full
3230 	 */
3231 	if (pi >= aac_qinfo[queue].size)
3232 		pi = 0;
3233 
3234 	/* XXX queue full */
3235 	if ((pi + 1) == ci)
3236 		return (AACERR);
3237 
3238 	/* Fill in queue entry */
3239 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
3240 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
3241 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3242 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3243 	    DDI_DMA_SYNC_FORDEV);
3244 
3245 	/* Update producer index */
3246 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
3247 	    pi + 1);
3248 	(void) ddi_dma_sync(dma,
3249 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
3250 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3251 	    DDI_DMA_SYNC_FORDEV);
3252 
3253 	if (aac_qinfo[queue].notify != 0)
3254 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3255 	return (AACOK);
3256 }
3257 
3258 /*
3259  * Atomically remove one entry from the nominated queue, returns 0 on
3260  * success or AACERR if the queue is empty.
3261  */
3262 static int
3263 aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
3264 {
3265 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3266 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3267 	uint32_t pi, ci;
3268 	int unfull = 0;
3269 
3270 	DBCALLED(softs, 2);
3271 
3272 	ASSERT(idxp);
3273 
3274 	/* Get the producer/consumer indices */
3275 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3276 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3277 	    DDI_DMA_SYNC_FORCPU);
3278 	pi = ddi_get32(acc,
3279 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3280 	ci = ddi_get32(acc,
3281 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3282 
3283 	/* Check for queue empty */
3284 	if (ci == pi)
3285 		return (AACERR);
3286 
3287 	if (pi >= aac_qinfo[queue].size)
3288 		pi = 0;
3289 
3290 	/* Check for queue full */
3291 	if (ci == pi + 1)
3292 		unfull = 1;
3293 
3294 	/*
3295 	 * The controller does not wrap the queue,
3296 	 * so we have to do it by ourselves
3297 	 */
3298 	if (ci >= aac_qinfo[queue].size)
3299 		ci = 0;
3300 
3301 	/* Fetch the entry */
3302 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3303 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3304 	    DDI_DMA_SYNC_FORCPU);
3305 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3306 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3307 		return (AACERR);
3308 	}
3309 
3310 	switch (queue) {
3311 	case AAC_HOST_NORM_RESP_Q:
3312 	case AAC_HOST_HIGH_RESP_Q:
3313 		*idxp = ddi_get32(acc,
3314 		    &(softs->qentries[queue] + ci)->aq_fib_addr);
3315 		break;
3316 
3317 	case AAC_HOST_NORM_CMD_Q:
3318 	case AAC_HOST_HIGH_CMD_Q:
3319 		*idxp = ddi_get32(acc,
3320 		    &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
3321 		break;
3322 
3323 	default:
3324 		cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
3325 		return (AACERR);
3326 	}
3327 
3328 	/* Update consumer index */
3329 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
3330 	    ci + 1);
3331 	(void) ddi_dma_sync(dma,
3332 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
3333 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3334 	    DDI_DMA_SYNC_FORDEV);
3335 
3336 	if (unfull && aac_qinfo[queue].notify != 0)
3337 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3338 	return (AACOK);
3339 }
3340 
3341 static struct aac_mntinforesp *
3342 aac_get_mntinfo(struct aac_softstate *softs, int cid)
3343 {
3344 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3345 	struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
3346 	struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
3347 	struct aac_mntinforesp *mir;
3348 
3349 	ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
3350 	    (softs->flags & AAC_FLAGS_LBA_64BIT) ?
3351 	    VM_NameServe64 : VM_NameServe);
3352 	ddi_put32(acc, &mi->MntType, FT_FILESYS);
3353 	ddi_put32(acc, &mi->MntCount, cid);
3354 
3355 	if (aac_sync_fib(softs, ContainerCommand,
3356 	    AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
3357 		AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
3358 		return (NULL);
3359 	}
3360 
3361 	mir = (struct aac_mntinforesp *)&fibp->data[0];
3362 	if (ddi_get32(acc, &mir->Status) == ST_OK)
3363 		return (mir);
3364 	return (NULL);
3365 }
3366 
3367 static int
3368 aac_get_container_count(struct aac_softstate *softs, int *count)
3369 {
3370 	ddi_acc_handle_t acc;
3371 	struct aac_mntinforesp *mir;
3372 	int rval;
3373 
3374 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3375 	acc = softs->sync_ac.slotp->fib_acc_handle;
3376 
3377 	if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
3378 		rval = AACERR;
3379 		goto finish;
3380 	}
3381 	*count = ddi_get32(acc, &mir->MntRespCount);
3382 	if (*count > AAC_MAX_LD) {
3383 		AACDB_PRINT(softs, CE_CONT,
3384 		    "container count(%d) > AAC_MAX_LD", *count);
3385 		rval = AACERR;
3386 		goto finish;
3387 	}
3388 	rval = AACOK;
3389 
3390 finish:
3391 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3392 	return (rval);
3393 }
3394 
3395 static int
3396 aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
3397 {
3398 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3399 	struct aac_Container *ct = (struct aac_Container *) \
3400 	    &softs->sync_ac.slotp->fibp->data[0];
3401 
3402 	bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
3403 	ddi_put32(acc, &ct->Command, VM_ContainerConfig);
3404 	ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
3405 	ddi_put32(acc, &ct->CTCommand.param[0], cid);
3406 
3407 	if (aac_sync_fib(softs, ContainerCommand,
3408 	    AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
3409 		return (AACERR);
3410 	if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
3411 		return (AACERR);
3412 
3413 	*uid = ddi_get32(acc, &ct->CTCommand.param[1]);
3414 	return (AACOK);
3415 }
3416 
3417 /*
3418  * Request information of the container cid
3419  */
3420 static struct aac_mntinforesp *
3421 aac_get_container_info(struct aac_softstate *softs, int cid)
3422 {
3423 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3424 	struct aac_mntinforesp *mir;
3425 	int rval_uid;
3426 	uint32_t uid;
3427 
3428 	/* Get container UID first so that it will not overwrite mntinfo */
3429 	rval_uid = aac_get_container_uid(softs, cid, &uid);
3430 
3431 	/* Get container basic info */
3432 	if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
3433 		AACDB_PRINT(softs, CE_CONT,
3434 		    "query container %d info failed", cid);
3435 		return (NULL);
3436 	}
3437 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
3438 		return (mir);
3439 	if (rval_uid != AACOK) {
3440 		AACDB_PRINT(softs, CE_CONT,
3441 		    "query container %d uid failed", cid);
3442 		return (NULL);
3443 	}
3444 
3445 	ddi_put32(acc, &mir->Status, uid);
3446 	return (mir);
3447 }
3448 
3449 static enum aac_cfg_event
3450 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
3451 {
3452 	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
3453 	struct aac_container *dvp = &softs->containers[cid];
3454 	struct aac_mntinforesp *mir;
3455 	ddi_acc_handle_t acc;
3456 
3457 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3458 	acc = softs->sync_ac.slotp->fib_acc_handle;
3459 
3460 	/* Get container basic info */
3461 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
3462 		/* AAC_CFG_NULL_NOEXIST */
3463 		goto finish;
3464 	}
3465 
3466 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
3467 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3468 			AACDB_PRINT(softs, CE_NOTE,
3469 			    ">>> Container %d deleted", cid);
3470 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
3471 			event = AAC_CFG_DELETE;
3472 		}
3473 		/* AAC_CFG_NULL_NOEXIST */
3474 	} else {
3475 		uint64_t size;
3476 		uint32_t uid;
3477 
3478 		event = AAC_CFG_NULL_EXIST;
3479 
3480 		size = AAC_MIR_SIZE(softs, acc, mir);
3481 		uid = ddi_get32(acc, &mir->Status);
3482 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3483 			if (dvp->uid != uid) {
3484 				AACDB_PRINT(softs, CE_WARN,
3485 				    ">>> Container %u uid changed to %d",
3486 				    cid, uid);
3487 				dvp->uid = uid;
3488 				event = AAC_CFG_CHANGE;
3489 			}
3490 			if (dvp->size != size) {
3491 				AACDB_PRINT(softs, CE_NOTE,
3492 				    ">>> Container %u size changed to %"PRIu64,
3493 				    cid, size);
3494 				dvp->size = size;
3495 				event = AAC_CFG_CHANGE;
3496 			}
3497 		} else { /* Init new container */
3498 			AACDB_PRINT(softs, CE_NOTE,
3499 			    ">>> Container %d added: " \
3500 			    "size=0x%x.%08x, type=%d, name=%s",
3501 			    cid,
3502 			    ddi_get32(acc, &mir->MntObj.CapacityHigh),
3503 			    ddi_get32(acc, &mir->MntObj.Capacity),
3504 			    ddi_get32(acc, &mir->MntObj.VolType),
3505 			    mir->MntObj.FileSystemName);
3506 			dvp->dev.flags |= AAC_DFLAG_VALID;
3507 			dvp->dev.type = AAC_DEV_LD;
3508 
3509 			dvp->cid = cid;
3510 			dvp->uid = uid;
3511 			dvp->size = size;
3512 			dvp->locked = 0;
3513 			dvp->deleted = 0;
3514 
3515 			event = AAC_CFG_ADD;
3516 		}
3517 	}
3518 
3519 finish:
3520 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3521 	return (event);
3522 }
3523 
3524 /*
3525  * Do a rescan of all the possible containers and update the container list
3526  * with newly online/offline containers, and prepare for autoconfiguration.
3527  */
3528 static int
3529 aac_probe_containers(struct aac_softstate *softs)
3530 {
3531 	int i, count, total;
3532 
3533 	/* Loop over possible containers */
3534 	count = softs->container_count;
3535 	if (aac_get_container_count(softs, &count) == AACERR)
3536 		return (AACERR);
3537 
3538 	for (i = total = 0; i < count; i++) {
3539 		enum aac_cfg_event event = aac_probe_container(softs, i);
3540 		if ((event != AAC_CFG_NULL_NOEXIST) &&
3541 		    (event != AAC_CFG_NULL_EXIST)) {
3542 			(void) aac_handle_dr(softs, i, -1, event);
3543 			total++;
3544 		}
3545 	}
3546 
3547 	if (count < softs->container_count) {
3548 		struct aac_container *dvp;
3549 
3550 		for (dvp = &softs->containers[count];
3551 		    dvp < &softs->containers[softs->container_count]; dvp++) {
3552 			if (!AAC_DEV_IS_VALID(&dvp->dev))
3553 				continue;
3554 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
3555 			    dvp->cid);
3556 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
3557 			(void) aac_handle_dr(softs, dvp->cid, -1,
3558 			    AAC_CFG_DELETE);
3559 		}
3560 	}
3561 
3562 	softs->container_count = count;
3563 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
3564 	return (AACOK);
3565 }
3566 
3567 static int
3568 aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
3569 {
3570 	ASSERT(AAC_MAX_LD <= tgt);
3571 	ASSERT(tgt < AAC_MAX_DEV(softs));
3572 	struct aac_device *dvp;
3573 	dvp = AAC_DEV(softs, tgt);
3574 
3575 	switch (event) {
3576 	case AAC_CFG_ADD:
3577 		AACDB_PRINT(softs, CE_NOTE,
3578 		    ">>> Jbod %d added", tgt - AAC_MAX_LD);
3579 		dvp->flags |= AAC_DFLAG_VALID;
3580 		dvp->type = AAC_DEV_PD;
3581 		break;
3582 	case AAC_CFG_DELETE:
3583 		AACDB_PRINT(softs, CE_NOTE,
3584 		    ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
3585 		dvp->flags &= ~AAC_DFLAG_VALID;
3586 		break;
3587 	default:
3588 		return (AACERR);
3589 	}
3590 	(void) aac_handle_dr(softs, tgt, 0, event);
3591 	return (AACOK);
3592 }
3593 
3594 static int
3595 aac_alloc_comm_space(struct aac_softstate *softs)
3596 {
3597 	size_t rlen;
3598 	ddi_dma_cookie_t cookie;
3599 	uint_t cookien;
3600 
3601 	/* Allocate DMA for comm. space */
3602 	if (ddi_dma_alloc_handle(
3603 	    softs->devinfo_p,
3604 	    &softs->addr_dma_attr,
3605 	    DDI_DMA_SLEEP,
3606 	    NULL,
3607 	    &softs->comm_space_dma_handle) != DDI_SUCCESS) {
3608 		AACDB_PRINT(softs, CE_WARN,
3609 		    "Cannot alloc dma handle for communication area");
3610 		goto error;
3611 	}
3612 	if (ddi_dma_mem_alloc(
3613 	    softs->comm_space_dma_handle,
3614 	    sizeof (struct aac_comm_space),
3615 	    &softs->acc_attr,
3616 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3617 	    DDI_DMA_SLEEP,
3618 	    NULL,
3619 	    (caddr_t *)&softs->comm_space,
3620 	    &rlen,
3621 	    &softs->comm_space_acc_handle) != DDI_SUCCESS) {
3622 		AACDB_PRINT(softs, CE_WARN,
3623 		    "Cannot alloc mem for communication area");
3624 		goto error;
3625 	}
3626 	if (ddi_dma_addr_bind_handle(
3627 	    softs->comm_space_dma_handle,
3628 	    NULL,
3629 	    (caddr_t)softs->comm_space,
3630 	    sizeof (struct aac_comm_space),
3631 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3632 	    DDI_DMA_SLEEP,
3633 	    NULL,
3634 	    &cookie,
3635 	    &cookien) != DDI_DMA_MAPPED) {
3636 		AACDB_PRINT(softs, CE_WARN,
3637 		    "DMA bind failed for communication area");
3638 		goto error;
3639 	}
3640 	softs->comm_space_phyaddr = cookie.dmac_address;
3641 
3642 	return (AACOK);
3643 error:
3644 	if (softs->comm_space_acc_handle) {
3645 		ddi_dma_mem_free(&softs->comm_space_acc_handle);
3646 		softs->comm_space_acc_handle = NULL;
3647 	}
3648 	if (softs->comm_space_dma_handle) {
3649 		ddi_dma_free_handle(&softs->comm_space_dma_handle);
3650 		softs->comm_space_dma_handle = NULL;
3651 	}
3652 	return (AACERR);
3653 }
3654 
3655 static void
3656 aac_free_comm_space(struct aac_softstate *softs)
3657 {
3658 
3659 	(void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
3660 	ddi_dma_mem_free(&softs->comm_space_acc_handle);
3661 	softs->comm_space_acc_handle = NULL;
3662 	ddi_dma_free_handle(&softs->comm_space_dma_handle);
3663 	softs->comm_space_dma_handle = NULL;
3664 	softs->comm_space_phyaddr = NULL;
3665 }
3666 
3667 /*
3668  * Initialize the data structures that are required for the communication
3669  * interface to operate
3670  */
3671 static int
3672 aac_setup_comm_space(struct aac_softstate *softs)
3673 {
3674 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3675 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3676 	uint32_t comm_space_phyaddr;
3677 	struct aac_adapter_init *initp;
3678 	int qoffset;
3679 
3680 	comm_space_phyaddr = softs->comm_space_phyaddr;
3681 
3682 	/* Setup adapter init struct */
3683 	initp = &softs->comm_space->init_data;
3684 	bzero(initp, sizeof (struct aac_adapter_init));
3685 
3686 	ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
3687 	ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
3688 
3689 	/* Setup new/old comm. specific data */
3690 	if (softs->flags & AAC_FLAGS_RAW_IO) {
3691 		uint32_t init_flags = 0;
3692 
3693 		if (softs->flags & AAC_FLAGS_NEW_COMM)
3694 			init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
3695 		/* AAC_SUPPORTED_POWER_MANAGEMENT */
3696 		init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
3697 		init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
3698 
3699 		ddi_put32(acc, &initp->InitStructRevision,
3700 		    AAC_INIT_STRUCT_REVISION_4);
3701 		ddi_put32(acc, &initp->InitFlags, init_flags);
3702 		/* Setup the preferred settings */
3703 		ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
3704 		ddi_put32(acc, &initp->MaxIoSize,
3705 		    (softs->aac_max_sectors << 9));
3706 		ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
3707 	} else {
3708 		/*
3709 		 * Tells the adapter about the physical location of various
3710 		 * important shared data structures
3711 		 */
3712 		ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
3713 		    comm_space_phyaddr + \
3714 		    offsetof(struct aac_comm_space, adapter_fibs));
3715 		ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
3716 		ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
3717 		ddi_put32(acc, &initp->AdapterFibsSize,
3718 		    AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
3719 		ddi_put32(acc, &initp->PrintfBufferAddress,
3720 		    comm_space_phyaddr + \
3721 		    offsetof(struct aac_comm_space, adapter_print_buf));
3722 		ddi_put32(acc, &initp->PrintfBufferSize,
3723 		    AAC_ADAPTER_PRINT_BUFSIZE);
3724 		ddi_put32(acc, &initp->MiniPortRevision,
3725 		    AAC_INIT_STRUCT_MINIPORT_REVISION);
3726 		ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
3727 
3728 		qoffset = (comm_space_phyaddr + \
3729 		    offsetof(struct aac_comm_space, qtable)) % \
3730 		    AAC_QUEUE_ALIGN;
3731 		if (qoffset)
3732 			qoffset = AAC_QUEUE_ALIGN - qoffset;
3733 		softs->qtablep = (struct aac_queue_table *) \
3734 		    ((char *)&softs->comm_space->qtable + qoffset);
3735 		ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
3736 		    offsetof(struct aac_comm_space, qtable) + qoffset);
3737 
3738 		/* Init queue table */
3739 		ddi_put32(acc, &softs->qtablep-> \
3740 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3741 		    AAC_HOST_NORM_CMD_ENTRIES);
3742 		ddi_put32(acc, &softs->qtablep-> \
3743 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3744 		    AAC_HOST_NORM_CMD_ENTRIES);
3745 		ddi_put32(acc, &softs->qtablep-> \
3746 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3747 		    AAC_HOST_HIGH_CMD_ENTRIES);
3748 		ddi_put32(acc, &softs->qtablep-> \
3749 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3750 		    AAC_HOST_HIGH_CMD_ENTRIES);
3751 		ddi_put32(acc, &softs->qtablep-> \
3752 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3753 		    AAC_ADAP_NORM_CMD_ENTRIES);
3754 		ddi_put32(acc, &softs->qtablep-> \
3755 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3756 		    AAC_ADAP_NORM_CMD_ENTRIES);
3757 		ddi_put32(acc, &softs->qtablep-> \
3758 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3759 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3760 		ddi_put32(acc, &softs->qtablep-> \
3761 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3762 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3763 		ddi_put32(acc, &softs->qtablep-> \
3764 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3765 		    AAC_HOST_NORM_RESP_ENTRIES);
3766 		ddi_put32(acc, &softs->qtablep-> \
3767 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3768 		    AAC_HOST_NORM_RESP_ENTRIES);
3769 		ddi_put32(acc, &softs->qtablep-> \
3770 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3771 		    AAC_HOST_HIGH_RESP_ENTRIES);
3772 		ddi_put32(acc, &softs->qtablep-> \
3773 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3774 		    AAC_HOST_HIGH_RESP_ENTRIES);
3775 		ddi_put32(acc, &softs->qtablep-> \
3776 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3777 		    AAC_ADAP_NORM_RESP_ENTRIES);
3778 		ddi_put32(acc, &softs->qtablep-> \
3779 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3780 		    AAC_ADAP_NORM_RESP_ENTRIES);
3781 		ddi_put32(acc, &softs->qtablep-> \
3782 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3783 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3784 		ddi_put32(acc, &softs->qtablep-> \
3785 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3786 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3787 
3788 		/* Init queue entries */
3789 		softs->qentries[AAC_HOST_NORM_CMD_Q] =
3790 		    &softs->qtablep->qt_HostNormCmdQueue[0];
3791 		softs->qentries[AAC_HOST_HIGH_CMD_Q] =
3792 		    &softs->qtablep->qt_HostHighCmdQueue[0];
3793 		softs->qentries[AAC_ADAP_NORM_CMD_Q] =
3794 		    &softs->qtablep->qt_AdapNormCmdQueue[0];
3795 		softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
3796 		    &softs->qtablep->qt_AdapHighCmdQueue[0];
3797 		softs->qentries[AAC_HOST_NORM_RESP_Q] =
3798 		    &softs->qtablep->qt_HostNormRespQueue[0];
3799 		softs->qentries[AAC_HOST_HIGH_RESP_Q] =
3800 		    &softs->qtablep->qt_HostHighRespQueue[0];
3801 		softs->qentries[AAC_ADAP_NORM_RESP_Q] =
3802 		    &softs->qtablep->qt_AdapNormRespQueue[0];
3803 		softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
3804 		    &softs->qtablep->qt_AdapHighRespQueue[0];
3805 	}
3806 	(void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
3807 
3808 	/* Send init structure to the card */
3809 	if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
3810 	    comm_space_phyaddr + \
3811 	    offsetof(struct aac_comm_space, init_data),
3812 	    0, 0, 0, NULL) == AACERR) {
3813 		AACDB_PRINT(softs, CE_WARN,
3814 		    "Cannot send init structure to adapter");
3815 		return (AACERR);
3816 	}
3817 
3818 	return (AACOK);
3819 }
3820 
3821 static uchar_t *
3822 aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
3823 {
3824 	(void) memset(buf, ' ', AAC_VENDOR_LEN);
3825 	bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
3826 	return (buf + AAC_VENDOR_LEN);
3827 }
3828 
3829 static uchar_t *
3830 aac_product_id(struct aac_softstate *softs, uchar_t *buf)
3831 {
3832 	(void) memset(buf, ' ', AAC_PRODUCT_LEN);
3833 	bcopy(softs->product_name, buf, strlen(softs->product_name));
3834 	return (buf + AAC_PRODUCT_LEN);
3835 }
3836 
3837 /*
3838  * Construct unit serial number from container uid
3839  */
3840 static uchar_t *
3841 aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
3842 {
3843 	int i, d;
3844 	uint32_t uid;
3845 
3846 	ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
3847 
3848 	uid = softs->containers[tgt].uid;
3849 	for (i = 7; i >= 0; i--) {
3850 		d = uid & 0xf;
3851 		buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
3852 		uid >>= 4;
3853 	}
3854 	return (buf + 8);
3855 }
3856 
3857 /*
3858  * SPC-3 7.5 INQUIRY command implementation
3859  */
3860 static void
3861 aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
3862     union scsi_cdb *cdbp, struct buf *bp)
3863 {
3864 	int tgt = pkt->pkt_address.a_target;
3865 	char *b_addr = NULL;
3866 	uchar_t page = cdbp->cdb_opaque[2];
3867 
3868 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
3869 		/* Command Support Data is not supported */
3870 		aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
3871 		return;
3872 	}
3873 
3874 	if (bp && bp->b_un.b_addr && bp->b_bcount) {
3875 		if (bp->b_flags & (B_PHYS | B_PAGEIO))
3876 			bp_mapin(bp);
3877 		b_addr = bp->b_un.b_addr;
3878 	}
3879 
3880 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
3881 		uchar_t *vpdp = (uchar_t *)b_addr;
3882 		uchar_t *idp, *sp;
3883 
3884 		/* SPC-3 8.4 Vital product data parameters */
3885 		switch (page) {
3886 		case 0x00:
3887 			/* Supported VPD pages */
3888 			if (vpdp == NULL ||
3889 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
3890 				return;
3891 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3892 			vpdp[AAC_VPD_PAGE_CODE] = 0x00;
3893 			vpdp[AAC_VPD_PAGE_LENGTH] = 3;
3894 
3895 			vpdp[AAC_VPD_PAGE_DATA] = 0x00;
3896 			vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
3897 			vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
3898 
3899 			pkt->pkt_state |= STATE_XFERRED_DATA;
3900 			break;
3901 
3902 		case 0x80:
3903 			/* Unit serial number page */
3904 			if (vpdp == NULL ||
3905 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
3906 				return;
3907 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3908 			vpdp[AAC_VPD_PAGE_CODE] = 0x80;
3909 			vpdp[AAC_VPD_PAGE_LENGTH] = 8;
3910 
3911 			sp = &vpdp[AAC_VPD_PAGE_DATA];
3912 			(void) aac_lun_serialno(softs, tgt, sp);
3913 
3914 			pkt->pkt_state |= STATE_XFERRED_DATA;
3915 			break;
3916 
3917 		case 0x83:
3918 			/* Device identification page */
3919 			if (vpdp == NULL ||
3920 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
3921 				return;
3922 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3923 			vpdp[AAC_VPD_PAGE_CODE] = 0x83;
3924 
3925 			idp = &vpdp[AAC_VPD_PAGE_DATA];
3926 			bzero(idp, AAC_VPD_ID_LENGTH);
3927 			idp[AAC_VPD_ID_CODESET] = 0x02;
3928 			idp[AAC_VPD_ID_TYPE] = 0x01;
3929 
3930 			/*
3931 			 * SPC-3 Table 111 - Identifier type
3932 			 * One recommanded method of constructing the remainder
3933 			 * of identifier field is to concatenate the product
3934 			 * identification field from the standard INQUIRY data
3935 			 * field and the product serial number field from the
3936 			 * unit serial number page.
3937 			 */
3938 			sp = &idp[AAC_VPD_ID_DATA];
3939 			sp = aac_vendor_id(softs, sp);
3940 			sp = aac_product_id(softs, sp);
3941 			sp = aac_lun_serialno(softs, tgt, sp);
3942 			idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
3943 			    (uintptr_t)&idp[AAC_VPD_ID_DATA];
3944 
3945 			vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
3946 			    (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
3947 			pkt->pkt_state |= STATE_XFERRED_DATA;
3948 			break;
3949 
3950 		default:
3951 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3952 			    0x24, 0x00, 0);
3953 			break;
3954 		}
3955 	} else {
3956 		struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
3957 		size_t len = sizeof (struct scsi_inquiry);
3958 
3959 		if (page != 0) {
3960 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3961 			    0x24, 0x00, 0);
3962 			return;
3963 		}
3964 		if (inqp == NULL || bp->b_bcount < len)
3965 			return;
3966 
3967 		bzero(inqp, len);
3968 		inqp->inq_len = AAC_ADDITIONAL_LEN;
3969 		inqp->inq_ansi = AAC_ANSI_VER;
3970 		inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
3971 		(void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
3972 		(void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
3973 		bcopy("V1.0", inqp->inq_revision, 4);
3974 		inqp->inq_cmdque = 1; /* enable tagged-queuing */
3975 		/*
3976 		 * For "sd-max-xfer-size" property which may impact performance
3977 		 * when IO threads increase.
3978 		 */
3979 		inqp->inq_wbus32 = 1;
3980 
3981 		pkt->pkt_state |= STATE_XFERRED_DATA;
3982 	}
3983 }
3984 
3985 /*
3986  * SPC-3 7.10 MODE SENSE command implementation
3987  */
3988 static void
3989 aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
3990     union scsi_cdb *cdbp, struct buf *bp, int capacity)
3991 {
3992 	uchar_t pagecode;
3993 	struct mode_header *headerp;
3994 	struct mode_header_g1 *g1_headerp;
3995 	unsigned int ncyl;
3996 	caddr_t sense_data;
3997 	caddr_t next_page;
3998 	size_t sdata_size;
3999 	size_t pages_size;
4000 	int unsupport_page = 0;
4001 
4002 	ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
4003 	    cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
4004 
4005 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
4006 		return;
4007 
4008 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
4009 		bp_mapin(bp);
4010 	pkt->pkt_state |= STATE_XFERRED_DATA;
4011 	pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
4012 
4013 	/* calculate the size of needed buffer */
4014 	if (cdbp->scc_cmd == SCMD_MODE_SENSE)
4015 		sdata_size = MODE_HEADER_LENGTH;
4016 	else /* must be SCMD_MODE_SENSE_G1 */
4017 		sdata_size = MODE_HEADER_LENGTH_G1;
4018 
4019 	pages_size = 0;
4020 	switch (pagecode) {
4021 	case SD_MODE_SENSE_PAGE3_CODE:
4022 		pages_size += sizeof (struct mode_format);
4023 		break;
4024 
4025 	case SD_MODE_SENSE_PAGE4_CODE:
4026 		pages_size += sizeof (struct mode_geometry);
4027 		break;
4028 
4029 	case MODEPAGE_CTRL_MODE:
4030 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
4031 			pages_size += sizeof (struct mode_control_scsi3);
4032 		} else {
4033 			unsupport_page = 1;
4034 		}
4035 		break;
4036 
4037 	case MODEPAGE_ALLPAGES:
4038 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
4039 			pages_size += sizeof (struct mode_format) +
4040 			    sizeof (struct mode_geometry) +
4041 			    sizeof (struct mode_control_scsi3);
4042 		} else {
4043 			pages_size += sizeof (struct mode_format) +
4044 			    sizeof (struct mode_geometry);
4045 		}
4046 		break;
4047 
4048 	default:
4049 		/* unsupported pages */
4050 		unsupport_page = 1;
4051 	}
4052 
4053 	/* allocate buffer to fill the send data */
4054 	sdata_size += pages_size;
4055 	sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
4056 
4057 	if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
4058 		headerp = (struct mode_header *)sense_data;
4059 		headerp->length = MODE_HEADER_LENGTH + pages_size -
4060 		    sizeof (headerp->length);
4061 		headerp->bdesc_length = 0;
4062 		next_page = sense_data + sizeof (struct mode_header);
4063 	} else {
4064 		g1_headerp = (void *)sense_data;
4065 		g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
4066 		    sizeof (g1_headerp->length));
4067 		g1_headerp->bdesc_length = 0;
4068 		next_page = sense_data + sizeof (struct mode_header_g1);
4069 	}
4070 
4071 	if (unsupport_page)
4072 		goto finish;
4073 
4074 	if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
4075 	    pagecode == MODEPAGE_ALLPAGES) {
4076 		/* SBC-3 7.1.3.3 Format device page */
4077 		struct mode_format *page3p;
4078 
4079 		page3p = (void *)next_page;
4080 		page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
4081 		page3p->mode_page.length = sizeof (struct mode_format);
4082 		page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
4083 		page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
4084 
4085 		next_page += sizeof (struct mode_format);
4086 	}
4087 
4088 	if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
4089 	    pagecode == MODEPAGE_ALLPAGES) {
4090 		/* SBC-3 7.1.3.8 Rigid disk device geometry page */
4091 		struct mode_geometry *page4p;
4092 
4093 		page4p = (void *)next_page;
4094 		page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
4095 		page4p->mode_page.length = sizeof (struct mode_geometry);
4096 		page4p->heads = AAC_NUMBER_OF_HEADS;
4097 		page4p->rpm = BE_16(AAC_ROTATION_SPEED);
4098 		ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
4099 		page4p->cyl_lb = ncyl & 0xff;
4100 		page4p->cyl_mb = (ncyl >> 8) & 0xff;
4101 		page4p->cyl_ub = (ncyl >> 16) & 0xff;
4102 
4103 		next_page += sizeof (struct mode_geometry);
4104 	}
4105 
4106 	if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
4107 	    softs->flags & AAC_FLAGS_LBA_64BIT) {
4108 		/* 64-bit LBA need large sense data */
4109 		struct mode_control_scsi3 *mctl;
4110 
4111 		mctl = (void *)next_page;
4112 		mctl->mode_page.code = MODEPAGE_CTRL_MODE;
4113 		mctl->mode_page.length =
4114 		    sizeof (struct mode_control_scsi3) -
4115 		    sizeof (struct mode_page);
4116 		mctl->d_sense = 1;
4117 	}
4118 
4119 finish:
4120 	/* copyout the valid data. */
4121 	bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
4122 	kmem_free(sense_data, sdata_size);
4123 }
4124 
4125 static int
4126 aac_name_node(dev_info_t *dip, char *name, int len)
4127 {
4128 	int tgt, lun;
4129 
4130 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4131 	    DDI_PROP_DONTPASS, "target", -1);
4132 	if (tgt == -1)
4133 		return (DDI_FAILURE);
4134 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4135 	    DDI_PROP_DONTPASS, "lun", -1);
4136 	if (lun == -1)
4137 		return (DDI_FAILURE);
4138 
4139 	(void) snprintf(name, len, "%x,%x", tgt, lun);
4140 	return (DDI_SUCCESS);
4141 }
4142 
4143 /*ARGSUSED*/
4144 static int
4145 aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4146     scsi_hba_tran_t *tran, struct scsi_device *sd)
4147 {
4148 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
4149 #if defined(DEBUG) || defined(__lock_lint)
4150 	int ctl = ddi_get_instance(softs->devinfo_p);
4151 #endif
4152 	uint16_t tgt = sd->sd_address.a_target;
4153 	uint8_t lun = sd->sd_address.a_lun;
4154 	struct aac_device *dvp;
4155 
4156 	DBCALLED(softs, 2);
4157 
4158 	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
4159 		/*
4160 		 * If no persistent node exist, we don't allow .conf node
4161 		 * to be created.
4162 		 */
4163 		if (aac_find_child(softs, tgt, lun) != NULL) {
4164 			if (ndi_merge_node(tgt_dip, aac_name_node) !=
4165 			    DDI_SUCCESS)
4166 				/* Create this .conf node */
4167 				return (DDI_SUCCESS);
4168 		}
4169 		return (DDI_FAILURE);
4170 	}
4171 
4172 	/*
4173 	 * Only support container/phys. device that has been
4174 	 * detected and valid
4175 	 */
4176 	mutex_enter(&softs->io_lock);
4177 	if (tgt >= AAC_MAX_DEV(softs)) {
4178 		AACDB_PRINT_TRAN(softs,
4179 		    "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
4180 		mutex_exit(&softs->io_lock);
4181 		return (DDI_FAILURE);
4182 	}
4183 
4184 	if (tgt < AAC_MAX_LD) {
4185 		dvp = (struct aac_device *)&softs->containers[tgt];
4186 		if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
4187 			AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
4188 			    ctl, tgt, lun);
4189 			mutex_exit(&softs->io_lock);
4190 			return (DDI_FAILURE);
4191 		}
4192 		/*
4193 		 * Save the tgt_dip for the given target if one doesn't exist
4194 		 * already. Dip's for non-existance tgt's will be cleared in
4195 		 * tgt_free.
4196 		 */
4197 		if (softs->containers[tgt].dev.dip == NULL &&
4198 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4199 			softs->containers[tgt].dev.dip = tgt_dip;
4200 	} else {
4201 		dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
4202 		/*
4203 		 * Save the tgt_dip for the given target if one doesn't exist
4204 		 * already. Dip's for non-existance tgt's will be cleared in
4205 		 * tgt_free.
4206 		 */
4207 
4208 		if (softs->nondasds[AAC_PD(tgt)].dev.dip  == NULL &&
4209 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4210 			softs->nondasds[AAC_PD(tgt)].dev.dip  = tgt_dip;
4211 	}
4212 
4213 	if (softs->flags & AAC_FLAGS_BRKUP) {
4214 		if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
4215 		    "buf_break", 1) != DDI_PROP_SUCCESS) {
4216 			cmn_err(CE_CONT, "unable to create "
4217 			    "property for t%dL%d (buf_break)", tgt, lun);
4218 		}
4219 	}
4220 
4221 	AACDB_PRINT(softs, CE_NOTE,
4222 	    "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
4223 	    (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
4224 	mutex_exit(&softs->io_lock);
4225 	return (DDI_SUCCESS);
4226 }
4227 
4228 static void
4229 aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4230     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
4231 {
4232 #ifndef __lock_lint
4233 	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
4234 #endif
4235 
4236 	struct aac_softstate *softs = SD2AAC(sd);
4237 	int tgt = sd->sd_address.a_target;
4238 
4239 	mutex_enter(&softs->io_lock);
4240 	if (tgt < AAC_MAX_LD) {
4241 		if (softs->containers[tgt].dev.dip == tgt_dip)
4242 			softs->containers[tgt].dev.dip = NULL;
4243 	} else {
4244 		if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
4245 			softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
4246 		softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
4247 	}
4248 	mutex_exit(&softs->io_lock);
4249 }
4250 
4251 /*
4252  * Check if the firmware is Up And Running. If it is in the Kernel Panic
4253  * state, (BlinkLED code + 1) is returned.
4254  *    0 -- firmware up and running
4255  *   -1 -- firmware dead
4256  *   >0 -- firmware kernel panic
4257  */
4258 static int
4259 aac_check_adapter_health(struct aac_softstate *softs)
4260 {
4261 	int rval;
4262 
4263 	rval = PCI_MEM_GET32(softs, AAC_OMR0);
4264 
4265 	if (rval & AAC_KERNEL_UP_AND_RUNNING) {
4266 		rval = 0;
4267 	} else if (rval & AAC_KERNEL_PANIC) {
4268 		cmn_err(CE_WARN, "firmware panic");
4269 		rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
4270 	} else {
4271 		cmn_err(CE_WARN, "firmware dead");
4272 		rval = -1;
4273 	}
4274 	return (rval);
4275 }
4276 
4277 static void
4278 aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
4279     uchar_t reason)
4280 {
4281 	acp->flags |= AAC_CMD_ABORT;
4282 
4283 	if (acp->pkt) {
4284 		if (acp->slotp) { /* outstanding cmd */
4285 			acp->pkt->pkt_state |= STATE_GOT_STATUS;
4286 		}
4287 
4288 		switch (reason) {
4289 		case CMD_TIMEOUT:
4290 			AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
4291 			    acp);
4292 			aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
4293 			    STAT_TIMEOUT | STAT_BUS_RESET);
4294 			break;
4295 		case CMD_RESET:
4296 			/* aac support only RESET_ALL */
4297 			AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
4298 			aac_set_pkt_reason(softs, acp, CMD_RESET,
4299 			    STAT_BUS_RESET);
4300 			break;
4301 		case CMD_ABORTED:
4302 			AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
4303 			    acp);
4304 			aac_set_pkt_reason(softs, acp, CMD_ABORTED,
4305 			    STAT_ABORTED);
4306 			break;
4307 		}
4308 	}
4309 	aac_end_io(softs, acp);
4310 }
4311 
4312 /*
4313  * Abort all the pending commands of type iocmd or just the command pkt
4314  * corresponding to pkt
4315  */
4316 static void
4317 aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
4318     int reason)
4319 {
4320 	struct aac_cmd *ac_arg, *acp;
4321 	int i;
4322 
4323 	if (pkt == NULL) {
4324 		ac_arg = NULL;
4325 	} else {
4326 		ac_arg = PKT2AC(pkt);
4327 		iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
4328 		    AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
4329 	}
4330 
4331 	/*
4332 	 * a) outstanding commands on the controller
4333 	 * Note: should abort outstanding commands only after one
4334 	 * IOP reset has been done.
4335 	 */
4336 	if (iocmd & AAC_IOCMD_OUTSTANDING) {
4337 		struct aac_cmd *acp;
4338 
4339 		for (i = 0; i < AAC_MAX_LD; i++) {
4340 			if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
4341 				softs->containers[i].reset = 1;
4342 		}
4343 		while ((acp = softs->q_busy.q_head) != NULL)
4344 			aac_abort_iocmd(softs, acp, reason);
4345 	}
4346 
4347 	/* b) commands in the waiting queues */
4348 	for (i = 0; i < AAC_CMDQ_NUM; i++) {
4349 		if (iocmd & (1 << i)) {
4350 			if (ac_arg) {
4351 				aac_abort_iocmd(softs, ac_arg, reason);
4352 			} else {
4353 				while ((acp = softs->q_wait[i].q_head) != NULL)
4354 					aac_abort_iocmd(softs, acp, reason);
4355 			}
4356 		}
4357 	}
4358 }
4359 
4360 /*
4361  * The draining thread is shared among quiesce threads. It terminates
4362  * when the adapter is quiesced or stopped by aac_stop_drain().
4363  */
4364 static void
4365 aac_check_drain(void *arg)
4366 {
4367 	struct aac_softstate *softs = arg;
4368 
4369 	mutex_enter(&softs->io_lock);
4370 	if (softs->ndrains) {
4371 		softs->drain_timeid = 0;
4372 		/*
4373 		 * If both ASYNC and SYNC bus throttle are held,
4374 		 * wake up threads only when both are drained out.
4375 		 */
4376 		if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
4377 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
4378 		    (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
4379 		    softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
4380 			cv_broadcast(&softs->drain_cv);
4381 		else
4382 			softs->drain_timeid = timeout(aac_check_drain, softs,
4383 			    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4384 	}
4385 	mutex_exit(&softs->io_lock);
4386 }
4387 
4388 /*
4389  * If not draining the outstanding cmds, drain them. Otherwise,
4390  * only update ndrains.
4391  */
4392 static void
4393 aac_start_drain(struct aac_softstate *softs)
4394 {
4395 	if (softs->ndrains == 0) {
4396 		ASSERT(softs->drain_timeid == 0);
4397 		softs->drain_timeid = timeout(aac_check_drain, softs,
4398 		    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4399 	}
4400 	softs->ndrains++;
4401 }
4402 
4403 /*
4404  * Stop the draining thread when no other threads use it any longer.
4405  * Side effect: io_lock may be released in the middle.
4406  */
4407 static void
4408 aac_stop_drain(struct aac_softstate *softs)
4409 {
4410 	softs->ndrains--;
4411 	if (softs->ndrains == 0) {
4412 		if (softs->drain_timeid != 0) {
4413 			timeout_id_t tid = softs->drain_timeid;
4414 
4415 			softs->drain_timeid = 0;
4416 			mutex_exit(&softs->io_lock);
4417 			(void) untimeout(tid);
4418 			mutex_enter(&softs->io_lock);
4419 		}
4420 	}
4421 }
4422 
4423 /*
4424  * The following function comes from Adaptec:
4425  *
4426  * Once do an IOP reset, basically the driver have to re-initialize the card
4427  * as if up from a cold boot, and the driver is responsible for any IO that
4428  * is outstanding to the adapter at the time of the IOP RESET. And prepare
4429  * for IOP RESET by making the init code modular with the ability to call it
4430  * from multiple places.
4431  */
4432 static int
4433 aac_reset_adapter(struct aac_softstate *softs)
4434 {
4435 	int health;
4436 	uint32_t status;
4437 	int rval = AAC_IOP_RESET_FAILED;
4438 
4439 	DBCALLED(softs, 1);
4440 
4441 	ASSERT(softs->state & AAC_STATE_RESET);
4442 
4443 	ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
4444 	/* Disable interrupt */
4445 	AAC_DISABLE_INTR(softs);
4446 
4447 	health = aac_check_adapter_health(softs);
4448 	if (health == -1) {
4449 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
4450 		goto finish;
4451 	}
4452 	if (health == 0) /* flush drives if possible */
4453 		(void) aac_shutdown(softs);
4454 
4455 	/* Execute IOP reset */
4456 	if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
4457 	    &status)) != AACOK) {
4458 		ddi_acc_handle_t acc;
4459 		struct aac_fib *fibp;
4460 		struct aac_pause_command *pc;
4461 
4462 		if ((status & 0xf) == 0xf) {
4463 			uint32_t wait_count;
4464 
4465 			/*
4466 			 * Sunrise Lake has dual cores and we must drag the
4467 			 * other core with us to reset simultaneously. There
4468 			 * are 2 bits in the Inbound Reset Control and Status
4469 			 * Register (offset 0x38) of the Sunrise Lake to reset
4470 			 * the chip without clearing out the PCI configuration
4471 			 * info (COMMAND & BARS).
4472 			 */
4473 			PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
4474 
4475 			/*
4476 			 * We need to wait for 5 seconds before accessing the MU
4477 			 * again 10000 * 100us = 1000,000us = 1000ms = 1s
4478 			 */
4479 			wait_count = 5 * 10000;
4480 			while (wait_count) {
4481 				drv_usecwait(100); /* delay 100 microseconds */
4482 				wait_count--;
4483 			}
4484 		} else {
4485 			if (status == SRB_STATUS_INVALID_REQUEST)
4486 				cmn_err(CE_WARN, "!IOP_RESET not supported");
4487 			else /* probably timeout */
4488 				cmn_err(CE_WARN, "!IOP_RESET failed");
4489 
4490 			/* Unwind aac_shutdown() */
4491 			(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
4492 			acc = softs->sync_ac.slotp->fib_acc_handle;
4493 
4494 			fibp = softs->sync_ac.slotp->fibp;
4495 			pc = (struct aac_pause_command *)&fibp->data[0];
4496 
4497 			bzero(pc, sizeof (*pc));
4498 			ddi_put32(acc, &pc->Command, VM_ContainerConfig);
4499 			ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
4500 			ddi_put32(acc, &pc->Timeout, 1);
4501 			ddi_put32(acc, &pc->Min, 1);
4502 			ddi_put32(acc, &pc->NoRescan, 1);
4503 
4504 			(void) aac_sync_fib(softs, ContainerCommand,
4505 			    AAC_FIB_SIZEOF(struct aac_pause_command));
4506 			aac_sync_fib_slot_release(softs, &softs->sync_ac);
4507 
4508 			if (aac_check_adapter_health(softs) != 0)
4509 				ddi_fm_service_impact(softs->devinfo_p,
4510 				    DDI_SERVICE_LOST);
4511 			else
4512 				/*
4513 				 * IOP reset not supported or IOP not reseted
4514 				 */
4515 				rval = AAC_IOP_RESET_ABNORMAL;
4516 			goto finish;
4517 		}
4518 	}
4519 
4520 	/*
4521 	 * Re-read and renegotiate the FIB parameters, as one of the actions
4522 	 * that can result from an IOP reset is the running of a new firmware
4523 	 * image.
4524 	 */
4525 	if (aac_common_attach(softs) != AACOK)
4526 		goto finish;
4527 
4528 	rval = AAC_IOP_RESET_SUCCEED;
4529 
4530 finish:
4531 	AAC_ENABLE_INTR(softs);
4532 	return (rval);
4533 }
4534 
4535 static void
4536 aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
4537     int throttle)
4538 {
4539 	/*
4540 	 * If the bus is draining/quiesced, no changes to the throttles
4541 	 * are allowed. All throttles should have been set to 0.
4542 	 */
4543 	if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
4544 		return;
4545 	dvp->throttle[q] = throttle;
4546 }
4547 
4548 static void
4549 aac_hold_bus(struct aac_softstate *softs, int iocmds)
4550 {
4551 	int i, q;
4552 
4553 	/* Hold bus by holding every device on the bus */
4554 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4555 		if (iocmds & (1 << q)) {
4556 			softs->bus_throttle[q] = 0;
4557 			for (i = 0; i < AAC_MAX_LD; i++)
4558 				aac_set_throttle(softs,
4559 				    &softs->containers[i].dev, q, 0);
4560 			for (i = 0; i < AAC_MAX_PD(softs); i++)
4561 				aac_set_throttle(softs,
4562 				    &softs->nondasds[i].dev, q, 0);
4563 		}
4564 	}
4565 }
4566 
4567 static void
4568 aac_unhold_bus(struct aac_softstate *softs, int iocmds)
4569 {
4570 	int i, q, max_throttle;
4571 
4572 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4573 		if (iocmds & (1 << q)) {
4574 			/*
4575 			 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
4576 			 * quiesced or being drained by possibly some quiesce
4577 			 * threads.
4578 			 */
4579 			if (q == AAC_CMDQ_ASYNC && ((softs->state &
4580 			    AAC_STATE_QUIESCED) || softs->ndrains))
4581 				continue;
4582 			if (q == AAC_CMDQ_ASYNC)
4583 				max_throttle = softs->total_slots -
4584 				    AAC_MGT_SLOT_NUM;
4585 			else
4586 				max_throttle = softs->total_slots - 1;
4587 			softs->bus_throttle[q] = max_throttle;
4588 			for (i = 0; i < AAC_MAX_LD; i++)
4589 				aac_set_throttle(softs,
4590 				    &softs->containers[i].dev,
4591 				    q, max_throttle);
4592 			for (i = 0; i < AAC_MAX_PD(softs); i++)
4593 				aac_set_throttle(softs, &softs->nondasds[i].dev,
4594 				    q, max_throttle);
4595 		}
4596 	}
4597 }
4598 
4599 static int
4600 aac_do_reset(struct aac_softstate *softs)
4601 {
4602 	int health;
4603 	int rval;
4604 
4605 	softs->state |= AAC_STATE_RESET;
4606 	health = aac_check_adapter_health(softs);
4607 
4608 	/*
4609 	 * Hold off new io commands and wait all outstanding io
4610 	 * commands to complete.
4611 	 */
4612 	if (health == 0) {
4613 		int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
4614 		int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
4615 
4616 		if (sync_cmds == 0 && async_cmds == 0) {
4617 			rval = AAC_IOP_RESET_SUCCEED;
4618 			goto finish;
4619 		}
4620 		/*
4621 		 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
4622 		 * to complete the outstanding io commands
4623 		 */
4624 		int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
4625 		int (*intr_handler)(struct aac_softstate *);
4626 
4627 		aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4628 		/*
4629 		 * Poll the adapter by ourselves in case interrupt is disabled
4630 		 * and to avoid releasing the io_lock.
4631 		 */
4632 		intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
4633 		    aac_process_intr_new : aac_process_intr_old;
4634 		while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
4635 		    softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
4636 			drv_usecwait(100);
4637 			(void) intr_handler(softs);
4638 			timeout--;
4639 		}
4640 		aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4641 
4642 		if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
4643 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
4644 			/* Cmds drained out */
4645 			rval = AAC_IOP_RESET_SUCCEED;
4646 			goto finish;
4647 		} else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
4648 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
4649 			/* Cmds not drained out, adapter overloaded */
4650 			rval = AAC_IOP_RESET_ABNORMAL;
4651 			goto finish;
4652 		}
4653 	}
4654 
4655 	/*
4656 	 * If a longer waiting time still can't drain any outstanding io
4657 	 * commands, do IOP reset.
4658 	 */
4659 	if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
4660 		softs->state |= AAC_STATE_DEAD;
4661 
4662 finish:
4663 	softs->state &= ~AAC_STATE_RESET;
4664 	return (rval);
4665 }
4666 
4667 static int
4668 aac_tran_reset(struct scsi_address *ap, int level)
4669 {
4670 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4671 	int rval;
4672 
4673 	DBCALLED(softs, 1);
4674 
4675 	if (level != RESET_ALL) {
4676 		cmn_err(CE_NOTE, "!reset target/lun not supported");
4677 		return (0);
4678 	}
4679 
4680 	mutex_enter(&softs->io_lock);
4681 	switch (rval = aac_do_reset(softs)) {
4682 	case AAC_IOP_RESET_SUCCEED:
4683 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
4684 		    NULL, CMD_RESET);
4685 		aac_start_waiting_io(softs);
4686 		break;
4687 	case AAC_IOP_RESET_FAILED:
4688 		/* Abort IOCTL cmds when adapter is dead */
4689 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
4690 		break;
4691 	case AAC_IOP_RESET_ABNORMAL:
4692 		aac_start_waiting_io(softs);
4693 	}
4694 	mutex_exit(&softs->io_lock);
4695 
4696 	aac_drain_comp_q(softs);
4697 	return (rval == 0);
4698 }
4699 
4700 static int
4701 aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
4702 {
4703 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4704 
4705 	DBCALLED(softs, 1);
4706 
4707 	mutex_enter(&softs->io_lock);
4708 	aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
4709 	mutex_exit(&softs->io_lock);
4710 
4711 	aac_drain_comp_q(softs);
4712 	return (1);
4713 }
4714 
4715 void
4716 aac_free_dmamap(struct aac_cmd *acp)
4717 {
4718 	/* Free dma mapping */
4719 	if (acp->flags & AAC_CMD_DMA_VALID) {
4720 		ASSERT(acp->buf_dma_handle);
4721 		(void) ddi_dma_unbind_handle(acp->buf_dma_handle);
4722 		acp->flags &= ~AAC_CMD_DMA_VALID;
4723 	}
4724 
4725 	if (acp->abp != NULL) { /* free non-aligned buf DMA */
4726 		ASSERT(acp->buf_dma_handle);
4727 		if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
4728 			ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
4729 			    (uint8_t *)acp->abp, acp->bp->b_bcount,
4730 			    DDI_DEV_AUTOINCR);
4731 		ddi_dma_mem_free(&acp->abh);
4732 		acp->abp = NULL;
4733 	}
4734 
4735 	if (acp->buf_dma_handle) {
4736 		ddi_dma_free_handle(&acp->buf_dma_handle);
4737 		acp->buf_dma_handle = NULL;
4738 	}
4739 }
4740 
4741 static void
4742 aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
4743 {
4744 	AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
4745 	    ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
4746 	aac_free_dmamap(acp);
4747 	aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
4748 	aac_soft_callback(softs, acp);
4749 }
4750 
4751 /*
4752  * Handle command to logical device
4753  */
4754 static int
4755 aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
4756 {
4757 	struct aac_container *dvp;
4758 	struct scsi_pkt *pkt;
4759 	union scsi_cdb *cdbp;
4760 	struct buf *bp;
4761 	int rval;
4762 
4763 	dvp = (struct aac_container *)acp->dvp;
4764 	pkt = acp->pkt;
4765 	cdbp = (void *)pkt->pkt_cdbp;
4766 	bp = acp->bp;
4767 
4768 	switch (cdbp->scc_cmd) {
4769 	case SCMD_INQUIRY: /* inquiry */
4770 		aac_free_dmamap(acp);
4771 		aac_inquiry(softs, pkt, cdbp, bp);
4772 		aac_soft_callback(softs, acp);
4773 		rval = TRAN_ACCEPT;
4774 		break;
4775 
4776 	case SCMD_READ_CAPACITY: /* read capacity */
4777 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4778 			struct scsi_capacity cap;
4779 			uint64_t last_lba;
4780 
4781 			/* check 64-bit LBA */
4782 			last_lba = dvp->size - 1;
4783 			if (last_lba > 0xffffffffull) {
4784 				cap.capacity = 0xfffffffful;
4785 			} else {
4786 				cap.capacity = BE_32(last_lba);
4787 			}
4788 			cap.lbasize = BE_32(AAC_SECTOR_SIZE);
4789 
4790 			aac_free_dmamap(acp);
4791 			if (bp->b_flags & (B_PHYS|B_PAGEIO))
4792 				bp_mapin(bp);
4793 			bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
4794 			pkt->pkt_state |= STATE_XFERRED_DATA;
4795 		}
4796 		aac_soft_callback(softs, acp);
4797 		rval = TRAN_ACCEPT;
4798 		break;
4799 
4800 	case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
4801 		/* Check if containers need 64-bit LBA support */
4802 		if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
4803 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
4804 				struct scsi_capacity_16 cap16;
4805 				int cap_len = sizeof (struct scsi_capacity_16);
4806 
4807 				bzero(&cap16, cap_len);
4808 				cap16.sc_capacity = BE_64(dvp->size - 1);
4809 				cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
4810 
4811 				aac_free_dmamap(acp);
4812 				if (bp->b_flags & (B_PHYS | B_PAGEIO))
4813 					bp_mapin(bp);
4814 				bcopy(&cap16, bp->b_un.b_addr,
4815 				    min(bp->b_bcount, cap_len));
4816 				pkt->pkt_state |= STATE_XFERRED_DATA;
4817 			}
4818 			aac_soft_callback(softs, acp);
4819 		} else {
4820 			aac_unknown_scmd(softs, acp);
4821 		}
4822 		rval = TRAN_ACCEPT;
4823 		break;
4824 
4825 	case SCMD_READ_G4: /* read_16 */
4826 	case SCMD_WRITE_G4: /* write_16 */
4827 		if (softs->flags & AAC_FLAGS_RAW_IO) {
4828 			/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
4829 			acp->blkno = ((uint64_t) \
4830 			    GETG4ADDR(cdbp) << 32) | \
4831 			    (uint32_t)GETG4ADDRTL(cdbp);
4832 			goto do_io;
4833 		}
4834 		AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
4835 		aac_unknown_scmd(softs, acp);
4836 		rval = TRAN_ACCEPT;
4837 		break;
4838 
4839 	case SCMD_READ: /* read_6 */
4840 	case SCMD_WRITE: /* write_6 */
4841 		acp->blkno = GETG0ADDR(cdbp);
4842 		goto do_io;
4843 
4844 	case SCMD_READ_G5: /* read_12 */
4845 	case SCMD_WRITE_G5: /* write_12 */
4846 		acp->blkno = GETG5ADDR(cdbp);
4847 		goto do_io;
4848 
4849 	case SCMD_READ_G1: /* read_10 */
4850 	case SCMD_WRITE_G1: /* write_10 */
4851 		acp->blkno = (uint32_t)GETG1ADDR(cdbp);
4852 do_io:
4853 		if (acp->flags & AAC_CMD_DMA_VALID) {
4854 			uint64_t cnt_size = dvp->size;
4855 
4856 			/*
4857 			 * If LBA > array size AND rawio, the
4858 			 * adapter may hang. So check it before
4859 			 * sending.
4860 			 * NOTE: (blkno + blkcnt) may overflow
4861 			 */
4862 			if ((acp->blkno < cnt_size) &&
4863 			    ((acp->blkno + acp->bcount /
4864 			    AAC_BLK_SIZE) <= cnt_size)) {
4865 				rval = aac_do_io(softs, acp);
4866 			} else {
4867 			/*
4868 			 * Request exceeds the capacity of disk,
4869 			 * set error block number to last LBA
4870 			 * + 1.
4871 			 */
4872 				aac_set_arq_data(pkt,
4873 				    KEY_ILLEGAL_REQUEST, 0x21,
4874 				    0x00, cnt_size);
4875 				aac_soft_callback(softs, acp);
4876 				rval = TRAN_ACCEPT;
4877 			}
4878 		} else if (acp->bcount == 0) {
4879 			/* For 0 length IO, just return ok */
4880 			aac_soft_callback(softs, acp);
4881 			rval = TRAN_ACCEPT;
4882 		} else {
4883 			rval = TRAN_BADPKT;
4884 		}
4885 		break;
4886 
4887 	case SCMD_MODE_SENSE: /* mode_sense_6 */
4888 	case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
4889 		int capacity;
4890 
4891 		aac_free_dmamap(acp);
4892 		if (dvp->size > 0xffffffffull)
4893 			capacity = 0xfffffffful; /* 64-bit LBA */
4894 		else
4895 			capacity = dvp->size;
4896 		aac_mode_sense(softs, pkt, cdbp, bp, capacity);
4897 		aac_soft_callback(softs, acp);
4898 		rval = TRAN_ACCEPT;
4899 		break;
4900 	}
4901 
4902 	case SCMD_START_STOP:
4903 		if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
4904 			acp->aac_cmd_fib = aac_cmd_fib_startstop;
4905 			acp->ac_comp = aac_startstop_complete;
4906 			rval = aac_do_io(softs, acp);
4907 			break;
4908 		}
4909 	/* FALLTHRU */
4910 	case SCMD_TEST_UNIT_READY:
4911 	case SCMD_REQUEST_SENSE:
4912 	case SCMD_FORMAT:
4913 		aac_free_dmamap(acp);
4914 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4915 			if (acp->flags & AAC_CMD_BUF_READ) {
4916 				if (bp->b_flags & (B_PHYS|B_PAGEIO))
4917 					bp_mapin(bp);
4918 				bzero(bp->b_un.b_addr, bp->b_bcount);
4919 			}
4920 			pkt->pkt_state |= STATE_XFERRED_DATA;
4921 		}
4922 		aac_soft_callback(softs, acp);
4923 		rval = TRAN_ACCEPT;
4924 		break;
4925 
4926 	case SCMD_SYNCHRONIZE_CACHE:
4927 		acp->flags |= AAC_CMD_NTAG;
4928 		acp->aac_cmd_fib = aac_cmd_fib_sync;
4929 		acp->ac_comp = aac_synccache_complete;
4930 		rval = aac_do_io(softs, acp);
4931 		break;
4932 
4933 	case SCMD_DOORLOCK:
4934 		aac_free_dmamap(acp);
4935 		dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
4936 		aac_soft_callback(softs, acp);
4937 		rval = TRAN_ACCEPT;
4938 		break;
4939 
4940 	default: /* unknown command */
4941 		aac_unknown_scmd(softs, acp);
4942 		rval = TRAN_ACCEPT;
4943 		break;
4944 	}
4945 
4946 	return (rval);
4947 }
4948 
4949 static int
4950 aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
4951 {
4952 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4953 	struct aac_cmd *acp = PKT2AC(pkt);
4954 	struct aac_device *dvp = acp->dvp;
4955 	int rval;
4956 
4957 	DBCALLED(softs, 2);
4958 
4959 	/*
4960 	 * Reinitialize some fields of ac and pkt; the packet may
4961 	 * have been resubmitted
4962 	 */
4963 	acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
4964 	    AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
4965 	acp->timeout = acp->pkt->pkt_time;
4966 	if (pkt->pkt_flags & FLAG_NOINTR)
4967 		acp->flags |= AAC_CMD_NO_INTR;
4968 #ifdef DEBUG
4969 	acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
4970 #endif
4971 	pkt->pkt_reason = CMD_CMPLT;
4972 	pkt->pkt_state = 0;
4973 	pkt->pkt_statistics = 0;
4974 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
4975 
4976 	if (acp->flags & AAC_CMD_DMA_VALID) {
4977 		pkt->pkt_resid = acp->bcount;
4978 		/* Consistent packets need to be sync'ed first */
4979 		if ((acp->flags & AAC_CMD_CONSISTENT) &&
4980 		    (acp->flags & AAC_CMD_BUF_WRITE))
4981 			if (aac_dma_sync_ac(acp) != AACOK) {
4982 				ddi_fm_service_impact(softs->devinfo_p,
4983 				    DDI_SERVICE_UNAFFECTED);
4984 				return (TRAN_BADPKT);
4985 			}
4986 	} else {
4987 		pkt->pkt_resid = 0;
4988 	}
4989 
4990 	mutex_enter(&softs->io_lock);
4991 	AACDB_PRINT_SCMD(softs, acp);
4992 	if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
4993 	    !(softs->state & AAC_STATE_DEAD)) {
4994 		if (dvp->type == AAC_DEV_LD) {
4995 			if (ap->a_lun == 0)
4996 				rval = aac_tran_start_ld(softs, acp);
4997 			else
4998 				goto error;
4999 		} else {
5000 			rval = aac_do_io(softs, acp);
5001 		}
5002 	} else {
5003 error:
5004 #ifdef DEBUG
5005 		if (!(softs->state & AAC_STATE_DEAD)) {
5006 			AACDB_PRINT_TRAN(softs,
5007 			    "Cannot send cmd to target t%dL%d: %s",
5008 			    ap->a_target, ap->a_lun,
5009 			    "target invalid");
5010 		} else {
5011 			AACDB_PRINT(softs, CE_WARN,
5012 			    "Cannot send cmd to target t%dL%d: %s",
5013 			    ap->a_target, ap->a_lun,
5014 			    "adapter dead");
5015 		}
5016 #endif
5017 		rval = TRAN_FATAL_ERROR;
5018 	}
5019 	mutex_exit(&softs->io_lock);
5020 	return (rval);
5021 }
5022 
5023 static int
5024 aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
5025 {
5026 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5027 	struct aac_device *dvp;
5028 	int rval;
5029 
5030 	DBCALLED(softs, 2);
5031 
5032 	/* We don't allow inquiring about capabilities for other targets */
5033 	if (cap == NULL || whom == 0) {
5034 		AACDB_PRINT(softs, CE_WARN,
5035 		    "GetCap> %s not supported: whom=%d", cap, whom);
5036 		return (-1);
5037 	}
5038 
5039 	mutex_enter(&softs->io_lock);
5040 	dvp = AAC_DEV(softs, ap->a_target);
5041 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5042 		mutex_exit(&softs->io_lock);
5043 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
5044 		    ap->a_target, ap->a_lun);
5045 		return (-1);
5046 	}
5047 
5048 	switch (scsi_hba_lookup_capstr(cap)) {
5049 	case SCSI_CAP_ARQ: /* auto request sense */
5050 		rval = 1;
5051 		break;
5052 	case SCSI_CAP_UNTAGGED_QING:
5053 	case SCSI_CAP_TAGGED_QING:
5054 		rval = 1;
5055 		break;
5056 	case SCSI_CAP_DMA_MAX:
5057 		rval = softs->dma_max;
5058 		break;
5059 	default:
5060 		rval = -1;
5061 		break;
5062 	}
5063 	mutex_exit(&softs->io_lock);
5064 
5065 	AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
5066 	    cap, ap->a_target, ap->a_lun, rval);
5067 	return (rval);
5068 }
5069 
5070 /*ARGSUSED*/
5071 static int
5072 aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
5073 {
5074 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5075 	struct aac_device *dvp;
5076 	int rval;
5077 
5078 	DBCALLED(softs, 2);
5079 
5080 	/* We don't allow inquiring about capabilities for other targets */
5081 	if (cap == NULL || whom == 0) {
5082 		AACDB_PRINT(softs, CE_WARN,
5083 		    "SetCap> %s not supported: whom=%d", cap, whom);
5084 		return (-1);
5085 	}
5086 
5087 	mutex_enter(&softs->io_lock);
5088 	dvp = AAC_DEV(softs, ap->a_target);
5089 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5090 		mutex_exit(&softs->io_lock);
5091 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
5092 		    ap->a_target, ap->a_lun);
5093 		return (-1);
5094 	}
5095 
5096 	switch (scsi_hba_lookup_capstr(cap)) {
5097 	case SCSI_CAP_ARQ:
5098 		/* Force auto request sense */
5099 		rval = (value == 1) ? 1 : 0;
5100 		break;
5101 	case SCSI_CAP_UNTAGGED_QING:
5102 	case SCSI_CAP_TAGGED_QING:
5103 		rval = (value == 1) ? 1 : 0;
5104 		break;
5105 	default:
5106 		rval = -1;
5107 		break;
5108 	}
5109 	mutex_exit(&softs->io_lock);
5110 
5111 	AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
5112 	    cap, ap->a_target, ap->a_lun, value, rval);
5113 	return (rval);
5114 }
5115 
5116 static void
5117 aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5118 {
5119 	struct aac_cmd *acp = PKT2AC(pkt);
5120 
5121 	DBCALLED(NULL, 2);
5122 
5123 	if (acp->sgt) {
5124 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5125 		    acp->left_cookien);
5126 	}
5127 	aac_free_dmamap(acp);
5128 	ASSERT(acp->slotp == NULL);
5129 	scsi_hba_pkt_free(ap, pkt);
5130 }
5131 
5132 int
5133 aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
5134     struct buf *bp, int flags, int (*cb)(), caddr_t arg)
5135 {
5136 	int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
5137 	uint_t oldcookiec;
5138 	int bioerr;
5139 	int rval;
5140 
5141 	oldcookiec = acp->left_cookien;
5142 
5143 	/* Move window to build s/g map */
5144 	if (acp->total_nwin > 0) {
5145 		if (++acp->cur_win < acp->total_nwin) {
5146 			off_t off;
5147 			size_t len;
5148 
5149 			rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
5150 			    &off, &len, &acp->cookie, &acp->left_cookien);
5151 			if (rval == DDI_SUCCESS)
5152 				goto get_dma_cookies;
5153 			AACDB_PRINT(softs, CE_WARN,
5154 			    "ddi_dma_getwin() fail %d", rval);
5155 			return (AACERR);
5156 		}
5157 		AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
5158 		return (AACERR);
5159 	}
5160 
5161 	/* We need to transfer data, so we alloc DMA resources for this pkt */
5162 	if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
5163 		uint_t dma_flags = 0;
5164 		struct aac_sge *sge;
5165 
5166 		/*
5167 		 * We will still use this point to fake some
5168 		 * infomation in tran_start
5169 		 */
5170 		acp->bp = bp;
5171 
5172 		/* Set dma flags */
5173 		if (BUF_IS_READ(bp)) {
5174 			dma_flags |= DDI_DMA_READ;
5175 			acp->flags |= AAC_CMD_BUF_READ;
5176 		} else {
5177 			dma_flags |= DDI_DMA_WRITE;
5178 			acp->flags |= AAC_CMD_BUF_WRITE;
5179 		}
5180 		if (flags & PKT_CONSISTENT)
5181 			dma_flags |= DDI_DMA_CONSISTENT;
5182 		if (flags & PKT_DMA_PARTIAL)
5183 			dma_flags |= DDI_DMA_PARTIAL;
5184 
5185 		/* Alloc buf dma handle */
5186 		if (!acp->buf_dma_handle) {
5187 			rval = ddi_dma_alloc_handle(softs->devinfo_p,
5188 			    &softs->buf_dma_attr, cb, arg,
5189 			    &acp->buf_dma_handle);
5190 			if (rval != DDI_SUCCESS) {
5191 				AACDB_PRINT(softs, CE_WARN,
5192 				    "Can't allocate DMA handle, errno=%d",
5193 				    rval);
5194 				goto error_out;
5195 			}
5196 		}
5197 
5198 		/* Bind buf */
5199 		if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
5200 			rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
5201 			    bp, dma_flags, cb, arg, &acp->cookie,
5202 			    &acp->left_cookien);
5203 		} else {
5204 			size_t bufsz;
5205 
5206 			AACDB_PRINT_TRAN(softs,
5207 			    "non-aligned buffer: addr=0x%p, cnt=%lu",
5208 			    (void *)bp->b_un.b_addr, bp->b_bcount);
5209 			if (bp->b_flags & (B_PAGEIO|B_PHYS))
5210 				bp_mapin(bp);
5211 
5212 			rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
5213 			    AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
5214 			    &softs->acc_attr, DDI_DMA_STREAMING,
5215 			    cb, arg, &acp->abp, &bufsz, &acp->abh);
5216 
5217 			if (rval != DDI_SUCCESS) {
5218 				AACDB_PRINT(softs, CE_NOTE,
5219 				    "Cannot alloc DMA to non-aligned buf");
5220 				bioerr = 0;
5221 				goto error_out;
5222 			}
5223 
5224 			if (acp->flags & AAC_CMD_BUF_WRITE)
5225 				ddi_rep_put8(acp->abh,
5226 				    (uint8_t *)bp->b_un.b_addr,
5227 				    (uint8_t *)acp->abp, bp->b_bcount,
5228 				    DDI_DEV_AUTOINCR);
5229 
5230 			rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
5231 			    NULL, acp->abp, bufsz, dma_flags, cb, arg,
5232 			    &acp->cookie, &acp->left_cookien);
5233 		}
5234 
5235 		switch (rval) {
5236 		case DDI_DMA_PARTIAL_MAP:
5237 			if (ddi_dma_numwin(acp->buf_dma_handle,
5238 			    &acp->total_nwin) == DDI_FAILURE) {
5239 				AACDB_PRINT(softs, CE_WARN,
5240 				    "Cannot get number of DMA windows");
5241 				bioerr = 0;
5242 				goto error_out;
5243 			}
5244 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5245 			    acp->left_cookien);
5246 			acp->cur_win = 0;
5247 			break;
5248 
5249 		case DDI_DMA_MAPPED:
5250 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5251 			    acp->left_cookien);
5252 			acp->cur_win = 0;
5253 			acp->total_nwin = 1;
5254 			break;
5255 
5256 		case DDI_DMA_NORESOURCES:
5257 			bioerr = 0;
5258 			AACDB_PRINT(softs, CE_WARN,
5259 			    "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
5260 			goto error_out;
5261 		case DDI_DMA_BADATTR:
5262 		case DDI_DMA_NOMAPPING:
5263 			bioerr = EFAULT;
5264 			AACDB_PRINT(softs, CE_WARN,
5265 			    "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
5266 			goto error_out;
5267 		case DDI_DMA_TOOBIG:
5268 			bioerr = EINVAL;
5269 			AACDB_PRINT(softs, CE_WARN,
5270 			    "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
5271 			    bp->b_bcount);
5272 			goto error_out;
5273 		default:
5274 			bioerr = EINVAL;
5275 			AACDB_PRINT(softs, CE_WARN,
5276 			    "Cannot bind buf for DMA: %d", rval);
5277 			goto error_out;
5278 		}
5279 		acp->flags |= AAC_CMD_DMA_VALID;
5280 
5281 get_dma_cookies:
5282 		ASSERT(acp->left_cookien > 0);
5283 		if (acp->left_cookien > softs->aac_sg_tablesize) {
5284 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
5285 			    acp->left_cookien);
5286 			bioerr = EINVAL;
5287 			goto error_out;
5288 		}
5289 		if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
5290 			kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5291 			    oldcookiec);
5292 			acp->sgt = NULL;
5293 		}
5294 		if (acp->sgt == NULL) {
5295 			acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
5296 			    acp->left_cookien, kf);
5297 			if (acp->sgt == NULL) {
5298 				AACDB_PRINT(softs, CE_WARN,
5299 				    "sgt kmem_alloc fail");
5300 				bioerr = ENOMEM;
5301 				goto error_out;
5302 			}
5303 		}
5304 
5305 		sge = &acp->sgt[0];
5306 		sge->bcount = acp->cookie.dmac_size;
5307 		sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5308 		sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5309 		acp->bcount = acp->cookie.dmac_size;
5310 		for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
5311 			ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
5312 			sge->bcount = acp->cookie.dmac_size;
5313 			sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5314 			sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5315 			acp->bcount += acp->cookie.dmac_size;
5316 		}
5317 
5318 		/*
5319 		 * Note: The old DMA engine do not correctly handle
5320 		 * dma_attr_maxxfer attribute. So we have to ensure
5321 		 * it by ourself.
5322 		 */
5323 		if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
5324 			AACDB_PRINT(softs, CE_NOTE,
5325 			    "large xfer size received %d\n", acp->bcount);
5326 			bioerr = EINVAL;
5327 			goto error_out;
5328 		}
5329 
5330 		acp->total_xfer += acp->bcount;
5331 
5332 		if (acp->pkt) {
5333 			/* Return remaining byte count */
5334 			if (acp->total_xfer <= bp->b_bcount) {
5335 				acp->pkt->pkt_resid = bp->b_bcount - \
5336 				    acp->total_xfer;
5337 			} else {
5338 				/*
5339 				 * Allocated DMA size is greater than the buf
5340 				 * size of bp. This is caused by devices like
5341 				 * tape. we have extra bytes allocated, but
5342 				 * the packet residual has to stay correct.
5343 				 */
5344 				acp->pkt->pkt_resid = 0;
5345 			}
5346 			AACDB_PRINT_TRAN(softs,
5347 			    "bp=0x%p, xfered=%d/%d, resid=%d",
5348 			    (void *)bp->b_un.b_addr, (int)acp->total_xfer,
5349 			    (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
5350 		}
5351 	}
5352 	return (AACOK);
5353 
5354 error_out:
5355 	bioerror(bp, bioerr);
5356 	return (AACERR);
5357 }
5358 
5359 static struct scsi_pkt *
5360 aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
5361     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
5362     int (*callback)(), caddr_t arg)
5363 {
5364 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5365 	struct aac_cmd *acp, *new_acp;
5366 
5367 	DBCALLED(softs, 2);
5368 
5369 	/* Allocate pkt */
5370 	if (pkt == NULL) {
5371 		int slen;
5372 
5373 		/* Force auto request sense */
5374 		slen = (statuslen > softs->slen) ? statuslen : softs->slen;
5375 		pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
5376 		    slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
5377 		if (pkt == NULL) {
5378 			AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
5379 			return (NULL);
5380 		}
5381 		acp = new_acp = PKT2AC(pkt);
5382 		acp->pkt = pkt;
5383 		acp->cmdlen = cmdlen;
5384 
5385 		if (ap->a_target < AAC_MAX_LD) {
5386 			acp->dvp = &softs->containers[ap->a_target].dev;
5387 			acp->aac_cmd_fib = softs->aac_cmd_fib;
5388 			acp->ac_comp = aac_ld_complete;
5389 		} else {
5390 			_NOTE(ASSUMING_PROTECTED(softs->nondasds))
5391 
5392 			acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
5393 			acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
5394 			acp->ac_comp = aac_pd_complete;
5395 		}
5396 	} else {
5397 		acp = PKT2AC(pkt);
5398 		new_acp = NULL;
5399 	}
5400 
5401 	if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
5402 		return (pkt);
5403 
5404 	if (new_acp)
5405 		aac_tran_destroy_pkt(ap, pkt);
5406 	return (NULL);
5407 }
5408 
5409 /*
5410  * tran_sync_pkt(9E) - explicit DMA synchronization
5411  */
5412 /*ARGSUSED*/
5413 static void
5414 aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5415 {
5416 	struct aac_cmd *acp = PKT2AC(pkt);
5417 
5418 	DBCALLED(NULL, 2);
5419 
5420 	if (aac_dma_sync_ac(acp) != AACOK)
5421 		ddi_fm_service_impact(
5422 		    (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
5423 		    DDI_SERVICE_UNAFFECTED);
5424 }
5425 
5426 /*
5427  * tran_dmafree(9E) - deallocate DMA resources allocated for command
5428  */
5429 /*ARGSUSED*/
5430 static void
5431 aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
5432 {
5433 	struct aac_cmd *acp = PKT2AC(pkt);
5434 
5435 	DBCALLED(NULL, 2);
5436 
5437 	aac_free_dmamap(acp);
5438 }
5439 
5440 static int
5441 aac_do_quiesce(struct aac_softstate *softs)
5442 {
5443 	aac_hold_bus(softs, AAC_IOCMD_ASYNC);
5444 	if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
5445 		aac_start_drain(softs);
5446 		do {
5447 			if (cv_wait_sig(&softs->drain_cv,
5448 			    &softs->io_lock) == 0) {
5449 				/* Quiesce has been interrupted */
5450 				aac_stop_drain(softs);
5451 				aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5452 				aac_start_waiting_io(softs);
5453 				return (AACERR);
5454 			}
5455 		} while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
5456 		aac_stop_drain(softs);
5457 	}
5458 
5459 	softs->state |= AAC_STATE_QUIESCED;
5460 	return (AACOK);
5461 }
5462 
5463 static int
5464 aac_tran_quiesce(dev_info_t *dip)
5465 {
5466 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5467 	int rval;
5468 
5469 	DBCALLED(softs, 1);
5470 
5471 	mutex_enter(&softs->io_lock);
5472 	if (aac_do_quiesce(softs) == AACOK)
5473 		rval = 0;
5474 	else
5475 		rval = 1;
5476 	mutex_exit(&softs->io_lock);
5477 	return (rval);
5478 }
5479 
5480 static int
5481 aac_do_unquiesce(struct aac_softstate *softs)
5482 {
5483 	softs->state &= ~AAC_STATE_QUIESCED;
5484 	aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5485 
5486 	aac_start_waiting_io(softs);
5487 	return (AACOK);
5488 }
5489 
5490 static int
5491 aac_tran_unquiesce(dev_info_t *dip)
5492 {
5493 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5494 	int rval;
5495 
5496 	DBCALLED(softs, 1);
5497 
5498 	mutex_enter(&softs->io_lock);
5499 	if (aac_do_unquiesce(softs) == AACOK)
5500 		rval = 0;
5501 	else
5502 		rval = 1;
5503 	mutex_exit(&softs->io_lock);
5504 	return (rval);
5505 }
5506 
5507 static int
5508 aac_hba_setup(struct aac_softstate *softs)
5509 {
5510 	scsi_hba_tran_t *hba_tran;
5511 	int rval;
5512 
5513 	hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
5514 	if (hba_tran == NULL)
5515 		return (AACERR);
5516 	hba_tran->tran_hba_private = softs;
5517 	hba_tran->tran_tgt_init = aac_tran_tgt_init;
5518 	hba_tran->tran_tgt_free = aac_tran_tgt_free;
5519 	hba_tran->tran_tgt_probe = scsi_hba_probe;
5520 	hba_tran->tran_start = aac_tran_start;
5521 	hba_tran->tran_getcap = aac_tran_getcap;
5522 	hba_tran->tran_setcap = aac_tran_setcap;
5523 	hba_tran->tran_init_pkt = aac_tran_init_pkt;
5524 	hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
5525 	hba_tran->tran_reset = aac_tran_reset;
5526 	hba_tran->tran_abort = aac_tran_abort;
5527 	hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
5528 	hba_tran->tran_dmafree = aac_tran_dmafree;
5529 	hba_tran->tran_quiesce = aac_tran_quiesce;
5530 	hba_tran->tran_unquiesce = aac_tran_unquiesce;
5531 	hba_tran->tran_bus_config = aac_tran_bus_config;
5532 	rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
5533 	    hba_tran, 0);
5534 	if (rval != DDI_SUCCESS) {
5535 		scsi_hba_tran_free(hba_tran);
5536 		AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
5537 		return (AACERR);
5538 	}
5539 
5540 	softs->hba_tran = hba_tran;
5541 	return (AACOK);
5542 }
5543 
5544 /*
5545  * FIB setup operations
5546  */
5547 
5548 /*
5549  * Init FIB header
5550  */
5551 static void
5552 aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
5553     uint16_t cmd)
5554 {
5555 	struct aac_slot *slotp = acp->slotp;
5556 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5557 	struct aac_fib *fibp = slotp->fibp;
5558 	uint32_t xfer_state;
5559 
5560 	xfer_state =
5561 	    AAC_FIBSTATE_HOSTOWNED |
5562 	    AAC_FIBSTATE_INITIALISED |
5563 	    AAC_FIBSTATE_EMPTY |
5564 	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
5565 	    AAC_FIBSTATE_FROMHOST |
5566 	    AAC_FIBSTATE_REXPECTED |
5567 	    AAC_FIBSTATE_NORM;
5568 
5569 	if (!(acp->flags & AAC_CMD_SYNC))
5570 		xfer_state |= AAC_FIBSTATE_ASYNC;
5571 
5572 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
5573 	ddi_put16(acc, &fibp->Header.Command, cmd);
5574 	ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
5575 	ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
5576 	ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
5577 	ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
5578 	ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
5579 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5580 	ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
5581 }
5582 
5583 /*
5584  * Init FIB for raw IO command
5585  */
5586 static void
5587 aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
5588 {
5589 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5590 	struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
5591 	struct aac_sg_entryraw *sgp;
5592 	struct aac_sge *sge;
5593 
5594 	/* Calculate FIB size */
5595 	acp->fib_size = sizeof (struct aac_fib_header) + \
5596 	    sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
5597 	    sizeof (struct aac_sg_entryraw);
5598 
5599 	aac_cmd_fib_header(softs, acp, RawIo);
5600 
5601 	ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
5602 	ddi_put16(acc, &io->BpTotal, 0);
5603 	ddi_put16(acc, &io->BpComplete, 0);
5604 
5605 	ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
5606 	ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
5607 	ddi_put16(acc, &io->ContainerId,
5608 	    ((struct aac_container *)acp->dvp)->cid);
5609 
5610 	/* Fill SG table */
5611 	ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
5612 	ddi_put32(acc, &io->ByteCount, acp->bcount);
5613 
5614 	for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
5615 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5616 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5617 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5618 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5619 		sgp->Next = 0;
5620 		sgp->Prev = 0;
5621 		sgp->Flags = 0;
5622 	}
5623 }
5624 
5625 /* Init FIB for 64-bit block IO command */
5626 static void
5627 aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
5628 {
5629 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5630 	struct aac_blockread64 *br = (struct aac_blockread64 *) \
5631 	    &acp->slotp->fibp->data[0];
5632 	struct aac_sg_entry64 *sgp;
5633 	struct aac_sge *sge;
5634 
5635 	acp->fib_size = sizeof (struct aac_fib_header) + \
5636 	    sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
5637 	    sizeof (struct aac_sg_entry64);
5638 
5639 	aac_cmd_fib_header(softs, acp, ContainerCommand64);
5640 
5641 	/*
5642 	 * The definitions for aac_blockread64 and aac_blockwrite64
5643 	 * are the same.
5644 	 */
5645 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5646 	ddi_put16(acc, &br->ContainerId,
5647 	    ((struct aac_container *)acp->dvp)->cid);
5648 	ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
5649 	    VM_CtHostRead64 : VM_CtHostWrite64);
5650 	ddi_put16(acc, &br->Pad, 0);
5651 	ddi_put16(acc, &br->Flags, 0);
5652 
5653 	/* Fill SG table */
5654 	ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
5655 	ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
5656 
5657 	for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
5658 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5659 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5660 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5661 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5662 	}
5663 }
5664 
5665 /* Init FIB for block IO command */
5666 static void
5667 aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
5668 {
5669 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5670 	struct aac_blockread *br = (struct aac_blockread *) \
5671 	    &acp->slotp->fibp->data[0];
5672 	struct aac_sg_entry *sgp;
5673 	struct aac_sge *sge = &acp->sgt[0];
5674 
5675 	if (acp->flags & AAC_CMD_BUF_READ) {
5676 		acp->fib_size = sizeof (struct aac_fib_header) + \
5677 		    sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
5678 		    sizeof (struct aac_sg_entry);
5679 
5680 		ddi_put32(acc, &br->Command, VM_CtBlockRead);
5681 		ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
5682 		sgp = &br->SgMap.SgEntry[0];
5683 	} else {
5684 		struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
5685 
5686 		acp->fib_size = sizeof (struct aac_fib_header) + \
5687 		    sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
5688 		    sizeof (struct aac_sg_entry);
5689 
5690 		ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
5691 		ddi_put32(acc, &bw->Stable, CUNSTABLE);
5692 		ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
5693 		sgp = &bw->SgMap.SgEntry[0];
5694 	}
5695 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5696 
5697 	/*
5698 	 * aac_blockread and aac_blockwrite have the similar
5699 	 * structure head, so use br for bw here
5700 	 */
5701 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5702 	ddi_put32(acc, &br->ContainerId,
5703 	    ((struct aac_container *)acp->dvp)->cid);
5704 	ddi_put32(acc, &br->ByteCount, acp->bcount);
5705 
5706 	/* Fill SG table */
5707 	for (sge = &acp->sgt[0];
5708 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5709 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5710 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5711 	}
5712 }
5713 
5714 /*ARGSUSED*/
5715 void
5716 aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
5717 {
5718 	struct aac_slot *slotp = acp->slotp;
5719 	struct aac_fib *fibp = slotp->fibp;
5720 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5721 
5722 	ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
5723 	    acp->fib_size,   /* only copy data of needed length */
5724 	    DDI_DEV_AUTOINCR);
5725 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5726 	ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
5727 }
5728 
5729 static void
5730 aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
5731 {
5732 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5733 	struct aac_synchronize_command *sync =
5734 	    (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
5735 
5736 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
5737 
5738 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5739 	ddi_put32(acc, &sync->Command, VM_ContainerConfig);
5740 	ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
5741 	ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
5742 	ddi_put32(acc, &sync->Count,
5743 	    sizeof (((struct aac_synchronize_reply *)0)->Data));
5744 }
5745 
5746 /*
5747  * Start/Stop unit (Power Management)
5748  */
5749 static void
5750 aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
5751 {
5752 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5753 	struct aac_Container *cmd =
5754 	    (struct aac_Container *)&acp->slotp->fibp->data[0];
5755 	union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
5756 
5757 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
5758 
5759 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5760 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
5761 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
5762 	ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
5763 	ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
5764 	    AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
5765 	ddi_put32(acc, &cmd->CTCommand.param[1],
5766 	    ((struct aac_container *)acp->dvp)->cid);
5767 	ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
5768 }
5769 
5770 /*
5771  * Init FIB for pass-through SCMD
5772  */
5773 static void
5774 aac_cmd_fib_srb(struct aac_cmd *acp)
5775 {
5776 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5777 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5778 	uint8_t *cdb;
5779 
5780 	ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
5781 	ddi_put32(acc, &srb->retry_limit, 0);
5782 	ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
5783 	ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
5784 	if (acp->fibp == NULL) {
5785 		if (acp->flags & AAC_CMD_BUF_READ)
5786 			ddi_put32(acc, &srb->flags, SRB_DataIn);
5787 		else if (acp->flags & AAC_CMD_BUF_WRITE)
5788 			ddi_put32(acc, &srb->flags, SRB_DataOut);
5789 		ddi_put32(acc, &srb->channel,
5790 		    ((struct aac_nondasd *)acp->dvp)->bus);
5791 		ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
5792 		ddi_put32(acc, &srb->lun, 0);
5793 		cdb = acp->pkt->pkt_cdbp;
5794 	} else {
5795 		struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
5796 
5797 		ddi_put32(acc, &srb->flags, srb0->flags);
5798 		ddi_put32(acc, &srb->channel, srb0->channel);
5799 		ddi_put32(acc, &srb->id, srb0->id);
5800 		ddi_put32(acc, &srb->lun, srb0->lun);
5801 		cdb = srb0->cdb;
5802 	}
5803 	ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
5804 }
5805 
5806 static void
5807 aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
5808 {
5809 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5810 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5811 	struct aac_sg_entry *sgp;
5812 	struct aac_sge *sge;
5813 
5814 	acp->fib_size = sizeof (struct aac_fib_header) + \
5815 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5816 	    acp->left_cookien * sizeof (struct aac_sg_entry);
5817 
5818 	/* Fill FIB and SRB headers, and copy cdb */
5819 	aac_cmd_fib_header(softs, acp, ScsiPortCommand);
5820 	aac_cmd_fib_srb(acp);
5821 
5822 	/* Fill SG table */
5823 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5824 	ddi_put32(acc, &srb->count, acp->bcount);
5825 
5826 	for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
5827 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5828 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5829 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5830 	}
5831 }
5832 
5833 static void
5834 aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
5835 {
5836 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5837 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5838 	struct aac_sg_entry64 *sgp;
5839 	struct aac_sge *sge;
5840 
5841 	acp->fib_size = sizeof (struct aac_fib_header) + \
5842 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5843 	    acp->left_cookien * sizeof (struct aac_sg_entry64);
5844 
5845 	/* Fill FIB and SRB headers, and copy cdb */
5846 	aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
5847 	aac_cmd_fib_srb(acp);
5848 
5849 	/* Fill SG table */
5850 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5851 	ddi_put32(acc, &srb->count, acp->bcount);
5852 
5853 	for (sge = &acp->sgt[0],
5854 	    sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
5855 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5856 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5857 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5858 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5859 	}
5860 }
5861 
5862 static int
5863 aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5864 {
5865 	struct aac_slot *slotp;
5866 
5867 	if (slotp = aac_get_slot(softs)) {
5868 		acp->slotp = slotp;
5869 		slotp->acp = acp;
5870 		acp->aac_cmd_fib(softs, acp);
5871 		(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
5872 		    DDI_DMA_SYNC_FORDEV);
5873 		return (AACOK);
5874 	}
5875 	return (AACERR);
5876 }
5877 
5878 static int
5879 aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
5880 {
5881 	struct aac_device *dvp = acp->dvp;
5882 	int q = AAC_CMDQ(acp);
5883 
5884 	if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
5885 		if (dvp) {
5886 			if (dvp->ncmds[q] < dvp->throttle[q]) {
5887 				if (!(acp->flags & AAC_CMD_NTAG) ||
5888 				    dvp->ncmds[q] == 0) {
5889 					return (aac_cmd_slot_bind(softs, acp));
5890 				}
5891 				ASSERT(q == AAC_CMDQ_ASYNC);
5892 				aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
5893 				    AAC_THROTTLE_DRAIN);
5894 			}
5895 		} else {
5896 			return (aac_cmd_slot_bind(softs, acp));
5897 		}
5898 	}
5899 	return (AACERR);
5900 }
5901 
5902 static int
5903 aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5904 {
5905 	struct aac_slot *slotp;
5906 
5907 	while (softs->sync_ac.slotp)
5908 		cv_wait(&softs->sync_fib_cv, &softs->io_lock);
5909 
5910 	if (slotp = aac_get_slot(softs)) {
5911 		ASSERT(acp->slotp == NULL);
5912 
5913 		acp->slotp = slotp;
5914 		slotp->acp = acp;
5915 		return (AACOK);
5916 	}
5917 	return (AACERR);
5918 }
5919 
5920 static void
5921 aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
5922 {
5923 	ASSERT(acp->slotp);
5924 
5925 	aac_release_slot(softs, acp->slotp);
5926 	acp->slotp->acp = NULL;
5927 	acp->slotp = NULL;
5928 
5929 	cv_signal(&softs->sync_fib_cv);
5930 }
5931 
5932 static void
5933 aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
5934 {
5935 	struct aac_slot *slotp = acp->slotp;
5936 	int q = AAC_CMDQ(acp);
5937 	int rval;
5938 
5939 	/* Set ac and pkt */
5940 	if (acp->pkt) { /* ac from ioctl has no pkt */
5941 		acp->pkt->pkt_state |=
5942 		    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
5943 	}
5944 	if (acp->timeout) /* 0 indicates no timeout */
5945 		acp->timeout += aac_timebase + aac_tick;
5946 
5947 	if (acp->dvp)
5948 		acp->dvp->ncmds[q]++;
5949 	softs->bus_ncmds[q]++;
5950 	aac_cmd_enqueue(&softs->q_busy, acp);
5951 
5952 	AACDB_PRINT_FIB(softs, slotp);
5953 
5954 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
5955 		rval = aac_send_command(softs, slotp);
5956 	} else {
5957 		/*
5958 		 * If fib can not be enqueued, the adapter is in an abnormal
5959 		 * state, there will be no interrupt to us.
5960 		 */
5961 		rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
5962 		    slotp->fib_phyaddr, acp->fib_size);
5963 	}
5964 
5965 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
5966 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
5967 
5968 	/*
5969 	 * NOTE: We send command only when slots availabe, so should never
5970 	 * reach here.
5971 	 */
5972 	if (rval != AACOK) {
5973 		AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
5974 		if (acp->pkt) {
5975 			acp->pkt->pkt_state &= ~STATE_SENT_CMD;
5976 			aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
5977 		}
5978 		aac_end_io(softs, acp);
5979 		if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
5980 			ddi_trigger_softintr(softs->softint_id);
5981 	}
5982 }
5983 
5984 static void
5985 aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
5986 {
5987 	struct aac_cmd *acp, *next_acp;
5988 
5989 	/* Serve as many waiting io's as possible */
5990 	for (acp = q->q_head; acp; acp = next_acp) {
5991 		next_acp = acp->next;
5992 		if (aac_bind_io(softs, acp) == AACOK) {
5993 			aac_cmd_delete(q, acp);
5994 			aac_start_io(softs, acp);
5995 		}
5996 		if (softs->free_io_slot_head == NULL)
5997 			break;
5998 	}
5999 }
6000 
6001 static void
6002 aac_start_waiting_io(struct aac_softstate *softs)
6003 {
6004 	/*
6005 	 * Sync FIB io is served before async FIB io so that io requests
6006 	 * sent by interactive userland commands get responded asap.
6007 	 */
6008 	if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
6009 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
6010 	if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
6011 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
6012 }
6013 
6014 static void
6015 aac_drain_comp_q(struct aac_softstate *softs)
6016 {
6017 	struct aac_cmd *acp;
6018 	struct scsi_pkt *pkt;
6019 
6020 	/*CONSTCOND*/
6021 	while (1) {
6022 		mutex_enter(&softs->q_comp_mutex);
6023 		acp = aac_cmd_dequeue(&softs->q_comp);
6024 		mutex_exit(&softs->q_comp_mutex);
6025 		if (acp != NULL) {
6026 			ASSERT(acp->pkt != NULL);
6027 			pkt = acp->pkt;
6028 
6029 			if (pkt->pkt_reason == CMD_CMPLT) {
6030 				/*
6031 				 * Consistent packets need to be sync'ed first
6032 				 */
6033 				if ((acp->flags & AAC_CMD_CONSISTENT) &&
6034 				    (acp->flags & AAC_CMD_BUF_READ)) {
6035 					if (aac_dma_sync_ac(acp) != AACOK) {
6036 						ddi_fm_service_impact(
6037 						    softs->devinfo_p,
6038 						    DDI_SERVICE_UNAFFECTED);
6039 						pkt->pkt_reason = CMD_TRAN_ERR;
6040 						pkt->pkt_statistics = 0;
6041 					}
6042 				}
6043 				if ((aac_check_acc_handle(softs-> \
6044 				    comm_space_acc_handle) != DDI_SUCCESS) ||
6045 				    (aac_check_acc_handle(softs-> \
6046 				    pci_mem_handle) != DDI_SUCCESS)) {
6047 					ddi_fm_service_impact(softs->devinfo_p,
6048 					    DDI_SERVICE_UNAFFECTED);
6049 					ddi_fm_acc_err_clear(softs-> \
6050 					    pci_mem_handle, DDI_FME_VER0);
6051 					pkt->pkt_reason = CMD_TRAN_ERR;
6052 					pkt->pkt_statistics = 0;
6053 				}
6054 				if (aac_check_dma_handle(softs-> \
6055 				    comm_space_dma_handle) != DDI_SUCCESS) {
6056 					ddi_fm_service_impact(softs->devinfo_p,
6057 					    DDI_SERVICE_UNAFFECTED);
6058 					pkt->pkt_reason = CMD_TRAN_ERR;
6059 					pkt->pkt_statistics = 0;
6060 				}
6061 			}
6062 			scsi_hba_pkt_comp(pkt);
6063 		} else {
6064 			break;
6065 		}
6066 	}
6067 }
6068 
6069 static int
6070 aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
6071 {
6072 	size_t rlen;
6073 	ddi_dma_cookie_t cookie;
6074 	uint_t cookien;
6075 
6076 	/* Allocate FIB dma resource */
6077 	if (ddi_dma_alloc_handle(
6078 	    softs->devinfo_p,
6079 	    &softs->addr_dma_attr,
6080 	    DDI_DMA_SLEEP,
6081 	    NULL,
6082 	    &slotp->fib_dma_handle) != DDI_SUCCESS) {
6083 		AACDB_PRINT(softs, CE_WARN,
6084 		    "Cannot alloc dma handle for slot fib area");
6085 		goto error;
6086 	}
6087 	if (ddi_dma_mem_alloc(
6088 	    slotp->fib_dma_handle,
6089 	    softs->aac_max_fib_size,
6090 	    &softs->acc_attr,
6091 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6092 	    DDI_DMA_SLEEP,
6093 	    NULL,
6094 	    (caddr_t *)&slotp->fibp,
6095 	    &rlen,
6096 	    &slotp->fib_acc_handle) != DDI_SUCCESS) {
6097 		AACDB_PRINT(softs, CE_WARN,
6098 		    "Cannot alloc mem for slot fib area");
6099 		goto error;
6100 	}
6101 	if (ddi_dma_addr_bind_handle(
6102 	    slotp->fib_dma_handle,
6103 	    NULL,
6104 	    (caddr_t)slotp->fibp,
6105 	    softs->aac_max_fib_size,
6106 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6107 	    DDI_DMA_SLEEP,
6108 	    NULL,
6109 	    &cookie,
6110 	    &cookien) != DDI_DMA_MAPPED) {
6111 		AACDB_PRINT(softs, CE_WARN,
6112 		    "dma bind failed for slot fib area");
6113 		goto error;
6114 	}
6115 
6116 	/* Check dma handles allocated in fib attach */
6117 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
6118 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6119 		goto error;
6120 	}
6121 
6122 	/* Check acc handles allocated in fib attach */
6123 	if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
6124 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6125 		goto error;
6126 	}
6127 
6128 	slotp->fib_phyaddr = cookie.dmac_laddress;
6129 	return (AACOK);
6130 
6131 error:
6132 	if (slotp->fib_acc_handle) {
6133 		ddi_dma_mem_free(&slotp->fib_acc_handle);
6134 		slotp->fib_acc_handle = NULL;
6135 	}
6136 	if (slotp->fib_dma_handle) {
6137 		ddi_dma_free_handle(&slotp->fib_dma_handle);
6138 		slotp->fib_dma_handle = NULL;
6139 	}
6140 	return (AACERR);
6141 }
6142 
6143 static void
6144 aac_free_fib(struct aac_slot *slotp)
6145 {
6146 	(void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
6147 	ddi_dma_mem_free(&slotp->fib_acc_handle);
6148 	slotp->fib_acc_handle = NULL;
6149 	ddi_dma_free_handle(&slotp->fib_dma_handle);
6150 	slotp->fib_dma_handle = NULL;
6151 	slotp->fib_phyaddr = 0;
6152 }
6153 
6154 static void
6155 aac_alloc_fibs(struct aac_softstate *softs)
6156 {
6157 	int i;
6158 	struct aac_slot *slotp;
6159 
6160 	for (i = 0; i < softs->total_slots &&
6161 	    softs->total_fibs < softs->total_slots; i++) {
6162 		slotp = &(softs->io_slot[i]);
6163 		if (slotp->fib_phyaddr)
6164 			continue;
6165 		if (aac_alloc_fib(softs, slotp) != AACOK)
6166 			break;
6167 
6168 		/* Insert the slot to the free slot list */
6169 		aac_release_slot(softs, slotp);
6170 		softs->total_fibs++;
6171 	}
6172 }
6173 
6174 static void
6175 aac_destroy_fibs(struct aac_softstate *softs)
6176 {
6177 	struct aac_slot *slotp;
6178 
6179 	while ((slotp = softs->free_io_slot_head) != NULL) {
6180 		ASSERT(slotp->fib_phyaddr);
6181 		softs->free_io_slot_head = slotp->next;
6182 		aac_free_fib(slotp);
6183 		ASSERT(slotp->index == (slotp - softs->io_slot));
6184 		softs->total_fibs--;
6185 	}
6186 	ASSERT(softs->total_fibs == 0);
6187 }
6188 
6189 static int
6190 aac_create_slots(struct aac_softstate *softs)
6191 {
6192 	int i;
6193 
6194 	softs->total_slots = softs->aac_max_fibs;
6195 	softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
6196 	    softs->total_slots, KM_SLEEP);
6197 	if (softs->io_slot == NULL) {
6198 		AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
6199 		return (AACERR);
6200 	}
6201 	for (i = 0; i < softs->total_slots; i++)
6202 		softs->io_slot[i].index = i;
6203 	softs->free_io_slot_head = NULL;
6204 	softs->total_fibs = 0;
6205 	return (AACOK);
6206 }
6207 
6208 static void
6209 aac_destroy_slots(struct aac_softstate *softs)
6210 {
6211 	ASSERT(softs->free_io_slot_head == NULL);
6212 
6213 	kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
6214 	    softs->total_slots);
6215 	softs->io_slot = NULL;
6216 	softs->total_slots = 0;
6217 }
6218 
6219 struct aac_slot *
6220 aac_get_slot(struct aac_softstate *softs)
6221 {
6222 	struct aac_slot *slotp;
6223 
6224 	if ((slotp = softs->free_io_slot_head) != NULL) {
6225 		softs->free_io_slot_head = slotp->next;
6226 		slotp->next = NULL;
6227 	}
6228 	return (slotp);
6229 }
6230 
6231 static void
6232 aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
6233 {
6234 	ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
6235 	ASSERT(slotp == &softs->io_slot[slotp->index]);
6236 
6237 	slotp->acp = NULL;
6238 	slotp->next = softs->free_io_slot_head;
6239 	softs->free_io_slot_head = slotp;
6240 }
6241 
6242 int
6243 aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
6244 {
6245 	if (aac_bind_io(softs, acp) == AACOK)
6246 		aac_start_io(softs, acp);
6247 	else
6248 		aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
6249 
6250 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
6251 		return (TRAN_ACCEPT);
6252 	/*
6253 	 * Because sync FIB is always 512 bytes and used for critical
6254 	 * functions, async FIB is used for poll IO.
6255 	 */
6256 	if (acp->flags & AAC_CMD_NO_INTR) {
6257 		if (aac_do_poll_io(softs, acp) == AACOK)
6258 			return (TRAN_ACCEPT);
6259 	} else {
6260 		if (aac_do_sync_io(softs, acp) == AACOK)
6261 			return (TRAN_ACCEPT);
6262 	}
6263 	return (TRAN_BADPKT);
6264 }
6265 
6266 static int
6267 aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
6268 {
6269 	int (*intr_handler)(struct aac_softstate *);
6270 
6271 	/*
6272 	 * Interrupt is disabled, we have to poll the adapter by ourselves.
6273 	 */
6274 	intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
6275 	    aac_process_intr_new : aac_process_intr_old;
6276 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
6277 		int i = AAC_POLL_TIME * 1000;
6278 
6279 		AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
6280 		if (i == 0)
6281 			aac_cmd_timeout(softs, acp);
6282 	}
6283 
6284 	ddi_trigger_softintr(softs->softint_id);
6285 
6286 	if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
6287 		return (AACOK);
6288 	return (AACERR);
6289 }
6290 
6291 static int
6292 aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
6293 {
6294 	ASSERT(softs && acp);
6295 
6296 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
6297 		cv_wait(&softs->event, &softs->io_lock);
6298 
6299 	if (acp->flags & AAC_CMD_CMPLT)
6300 		return (AACOK);
6301 	return (AACERR);
6302 }
6303 
6304 static int
6305 aac_dma_sync_ac(struct aac_cmd *acp)
6306 {
6307 	if (acp->buf_dma_handle) {
6308 		if (acp->flags & AAC_CMD_BUF_WRITE) {
6309 			if (acp->abp != NULL)
6310 				ddi_rep_put8(acp->abh,
6311 				    (uint8_t *)acp->bp->b_un.b_addr,
6312 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6313 				    DDI_DEV_AUTOINCR);
6314 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6315 			    DDI_DMA_SYNC_FORDEV);
6316 		} else {
6317 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6318 			    DDI_DMA_SYNC_FORCPU);
6319 			if (aac_check_dma_handle(acp->buf_dma_handle) !=
6320 			    DDI_SUCCESS)
6321 				return (AACERR);
6322 			if (acp->abp != NULL)
6323 				ddi_rep_get8(acp->abh,
6324 				    (uint8_t *)acp->bp->b_un.b_addr,
6325 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6326 				    DDI_DEV_AUTOINCR);
6327 		}
6328 	}
6329 	return (AACOK);
6330 }
6331 
6332 /*
6333  * Copy AIF from adapter to the empty AIF slot and inform AIF threads
6334  */
6335 static void
6336 aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
6337     struct aac_fib *fibp0, int fib_size0)
6338 {
6339 	struct aac_fib *fibp;	/* FIB in AIF queue */
6340 	int fib_size;
6341 	uint16_t fib_command;
6342 	int current, next;
6343 
6344 	/* Ignore non AIF messages */
6345 	fib_command = ddi_get16(acc, &fibp0->Header.Command);
6346 	if (fib_command != AifRequest) {
6347 		cmn_err(CE_WARN, "!Unknown command from controller");
6348 		return;
6349 	}
6350 
6351 	mutex_enter(&softs->aifq_mutex);
6352 
6353 	/* Save AIF */
6354 	fibp = &softs->aifq[softs->aifq_idx].d;
6355 	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
6356 	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
6357 	    DDI_DEV_AUTOINCR);
6358 
6359 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
6360 		ddi_fm_service_impact(softs->devinfo_p,
6361 		    DDI_SERVICE_UNAFFECTED);
6362 		mutex_exit(&softs->aifq_mutex);
6363 		return;
6364 	}
6365 
6366 	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
6367 
6368 	/* Modify AIF contexts */
6369 	current = softs->aifq_idx;
6370 	next = (current + 1) % AAC_AIFQ_LENGTH;
6371 	if (next == 0) {
6372 		struct aac_fib_context *ctx_p;
6373 
6374 		softs->aifq_wrap = 1;
6375 		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
6376 			if (next == ctx_p->ctx_idx) {
6377 				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
6378 			} else if (current == ctx_p->ctx_idx &&
6379 			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
6380 				ctx_p->ctx_idx = next;
6381 				ctx_p->ctx_overrun++;
6382 			}
6383 		}
6384 	}
6385 	softs->aifq_idx = next;
6386 
6387 	/* Wakeup AIF threads */
6388 	cv_broadcast(&softs->aifq_cv);
6389 	mutex_exit(&softs->aifq_mutex);
6390 
6391 	/* Wakeup event thread to handle aif */
6392 	aac_event_disp(softs, AAC_EVENT_AIF);
6393 }
6394 
6395 static int
6396 aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
6397     struct aac_fib **fibpp)
6398 {
6399 	int current;
6400 
6401 	current = ctx->ctx_idx;
6402 	if (current == softs->aifq_idx &&
6403 	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
6404 		return (EAGAIN); /* Empty */
6405 
6406 	*fibpp = &softs->aifq[current].d;
6407 
6408 	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
6409 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
6410 	return (0);
6411 }
6412 
6413 int
6414 aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
6415     struct aac_fib **fibpp)
6416 {
6417 	int rval;
6418 
6419 	mutex_enter(&softs->aifq_mutex);
6420 	rval = aac_return_aif_common(softs, ctx, fibpp);
6421 	mutex_exit(&softs->aifq_mutex);
6422 	return (rval);
6423 }
6424 
6425 int
6426 aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
6427     struct aac_fib **fibpp)
6428 {
6429 	int rval;
6430 
6431 	mutex_enter(&softs->aifq_mutex);
6432 	rval = aac_return_aif_common(softs, ctx, fibpp);
6433 	if (rval == EAGAIN) {
6434 		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
6435 		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
6436 	}
6437 	mutex_exit(&softs->aifq_mutex);
6438 	return ((rval > 0) ? 0 : EINTR);
6439 }
6440 
6441 /*
6442  * The following function comes from Adaptec:
6443  *
6444  * When driver sees a particular event that means containers are changed, it
6445  * will rescan containers. However a change may not be complete until some
6446  * other event is received. For example, creating or deleting an array will
6447  * incur as many as six AifEnConfigChange events which would generate six
6448  * container rescans. To diminish rescans, driver set a flag to wait for
6449  * another particular event. When sees that events come in, it will do rescan.
6450  */
6451 static int
6452 aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
6453 {
6454 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
6455 	int en_type;
6456 	int devcfg_needed;
6457 	int cid;
6458 	uint32_t bus_id, tgt_id;
6459 	enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
6460 
6461 	devcfg_needed = 0;
6462 	en_type = LE_32((uint32_t)aif->data.EN.type);
6463 
6464 	switch (LE_32((uint32_t)aif->command)) {
6465 	case AifCmdDriverNotify: {
6466 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6467 
6468 		switch (en_type) {
6469 		case AifDenMorphComplete:
6470 		case AifDenVolumeExtendComplete:
6471 			if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
6472 				softs->devcfg_wait_on = AifEnConfigChange;
6473 			break;
6474 		}
6475 		if (softs->devcfg_wait_on == en_type)
6476 			devcfg_needed = 1;
6477 		break;
6478 	}
6479 
6480 	case AifCmdEventNotify:
6481 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6482 		switch (en_type) {
6483 		case AifEnAddContainer:
6484 		case AifEnDeleteContainer:
6485 			softs->devcfg_wait_on = AifEnConfigChange;
6486 			break;
6487 		case AifEnContainerChange:
6488 			if (!softs->devcfg_wait_on)
6489 				softs->devcfg_wait_on = AifEnConfigChange;
6490 			break;
6491 		case AifEnContainerEvent:
6492 			if (ddi_get32(acc, &aif-> \
6493 			    data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
6494 				devcfg_needed = 1;
6495 			break;
6496 		case AifEnAddJBOD:
6497 			if (!(softs->flags & AAC_FLAGS_JBOD))
6498 				return (AACERR);
6499 			event = AAC_CFG_ADD;
6500 			bus_id = (cid >> 24) & 0xf;
6501 			tgt_id = cid & 0xffff;
6502 			break;
6503 		case AifEnDeleteJBOD:
6504 			if (!(softs->flags & AAC_FLAGS_JBOD))
6505 				return (AACERR);
6506 			event = AAC_CFG_DELETE;
6507 			bus_id = (cid >> 24) & 0xf;
6508 			tgt_id = cid & 0xffff;
6509 			break;
6510 		}
6511 		if (softs->devcfg_wait_on == en_type)
6512 			devcfg_needed = 1;
6513 		break;
6514 
6515 	case AifCmdJobProgress:
6516 		if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
6517 			int pr_status;
6518 			uint32_t pr_ftick, pr_ctick;
6519 
6520 			pr_status = LE_32((uint32_t)aif->data.PR[0].status);
6521 			pr_ctick = LE_32(aif->data.PR[0].currentTick);
6522 			pr_ftick = LE_32(aif->data.PR[0].finalTick);
6523 
6524 			if ((pr_ctick == pr_ftick) ||
6525 			    (pr_status == AifJobStsSuccess))
6526 				softs->devcfg_wait_on = AifEnContainerChange;
6527 			else if ((pr_ctick == 0) &&
6528 			    (pr_status == AifJobStsRunning))
6529 				softs->devcfg_wait_on = AifEnContainerChange;
6530 		}
6531 		break;
6532 	}
6533 
6534 	if (devcfg_needed) {
6535 		softs->devcfg_wait_on = 0;
6536 		(void) aac_probe_containers(softs);
6537 	}
6538 
6539 	if (event != AAC_CFG_NULL_EXIST) {
6540 		ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
6541 		(void) aac_probe_jbod(softs,
6542 		    AAC_P2VTGT(softs, bus_id, tgt_id), event);
6543 	}
6544 	return (AACOK);
6545 }
6546 
6547 
6548 /*
6549  * Check and handle AIF events
6550  */
6551 static void
6552 aac_aif_event(struct aac_softstate *softs)
6553 {
6554 	struct aac_fib *fibp;
6555 
6556 	/*CONSTCOND*/
6557 	while (1) {
6558 		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
6559 			break; /* No more AIFs to handle, end loop */
6560 
6561 		/* AIF overrun, array create/delete may missed. */
6562 		if (softs->aifctx.ctx_overrun) {
6563 			softs->aifctx.ctx_overrun = 0;
6564 		}
6565 
6566 		/* AIF received, handle it */
6567 		struct aac_aif_command *aifp =
6568 		    (struct aac_aif_command *)&fibp->data[0];
6569 		uint32_t aif_command = LE_32((uint32_t)aifp->command);
6570 
6571 		if (aif_command == AifCmdDriverNotify ||
6572 		    aif_command == AifCmdEventNotify ||
6573 		    aif_command == AifCmdJobProgress)
6574 			(void) aac_handle_aif(softs, aifp);
6575 	}
6576 }
6577 
6578 /*
6579  * Timeout recovery
6580  */
6581 /*ARGSUSED*/
6582 static void
6583 aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
6584 {
6585 #ifdef DEBUG
6586 	acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
6587 	AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
6588 	AACDB_PRINT_FIB(softs, acp->slotp);
6589 #endif
6590 
6591 	/*
6592 	 * Besides the firmware in unhealthy state, an overloaded
6593 	 * adapter may also incur pkt timeout.
6594 	 * There is a chance for an adapter with a slower IOP to take
6595 	 * longer than 60 seconds to process the commands, such as when
6596 	 * to perform IOs. So the adapter is doing a build on a RAID-5
6597 	 * while being required longer completion times should be
6598 	 * tolerated.
6599 	 */
6600 	switch (aac_do_reset(softs)) {
6601 	case AAC_IOP_RESET_SUCCEED:
6602 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
6603 		aac_start_waiting_io(softs);
6604 		break;
6605 	case AAC_IOP_RESET_FAILED:
6606 		/* Abort all waiting cmds when adapter is dead */
6607 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
6608 		break;
6609 	case AAC_IOP_RESET_ABNORMAL:
6610 		aac_start_waiting_io(softs);
6611 	}
6612 }
6613 
6614 /*
6615  * The following function comes from Adaptec:
6616  *
6617  * Time sync. command added to synchronize time with firmware every 30
6618  * minutes (required for correct AIF timestamps etc.)
6619  */
6620 static void
6621 aac_sync_tick(struct aac_softstate *softs)
6622 {
6623 	ddi_acc_handle_t acc;
6624 	int rval;
6625 
6626 	mutex_enter(&softs->time_mutex);
6627 	ASSERT(softs->time_sync <= softs->timebase);
6628 	softs->time_sync = 0;
6629 	mutex_exit(&softs->time_mutex);
6630 
6631 	/* Time sync. with firmware every AAC_SYNC_TICK */
6632 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
6633 	acc = softs->sync_ac.slotp->fib_acc_handle;
6634 
6635 	ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
6636 	    ddi_get_time());
6637 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
6638 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
6639 
6640 	mutex_enter(&softs->time_mutex);
6641 	softs->time_sync = softs->timebase;
6642 	if (rval != AACOK)
6643 		/* retry shortly */
6644 		softs->time_sync += aac_tick << 1;
6645 	else
6646 		softs->time_sync += AAC_SYNC_TICK;
6647 	mutex_exit(&softs->time_mutex);
6648 }
6649 
6650 /*
6651  * Timeout checking and handling
6652  */
6653 static void
6654 aac_daemon(struct aac_softstate *softs)
6655 {
6656 	int time_out; /* set if timeout happened */
6657 	int time_adjust;
6658 	uint32_t softs_timebase;
6659 
6660 	mutex_enter(&softs->time_mutex);
6661 	ASSERT(softs->time_out <= softs->timebase);
6662 	softs->time_out = 0;
6663 	softs_timebase = softs->timebase;
6664 	mutex_exit(&softs->time_mutex);
6665 
6666 	/* Check slots for timeout pkts */
6667 	time_adjust = 0;
6668 	do {
6669 		struct aac_cmd *acp;
6670 
6671 		time_out = 0;
6672 		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
6673 			if (acp->timeout == 0)
6674 				continue;
6675 
6676 			/*
6677 			 * If timeout happened, update outstanding cmds
6678 			 * to be checked later again.
6679 			 */
6680 			if (time_adjust) {
6681 				acp->timeout += time_adjust;
6682 				continue;
6683 			}
6684 
6685 			if (acp->timeout <= softs_timebase) {
6686 				aac_cmd_timeout(softs, acp);
6687 				time_out = 1;
6688 				time_adjust = aac_tick * drv_usectohz(1000000);
6689 				break; /* timeout happened */
6690 			} else {
6691 				break; /* no timeout */
6692 			}
6693 		}
6694 	} while (time_out);
6695 
6696 	mutex_enter(&softs->time_mutex);
6697 	softs->time_out = softs->timebase + aac_tick;
6698 	mutex_exit(&softs->time_mutex);
6699 }
6700 
6701 /*
6702  * The event thread handles various tasks serially for the other parts of
6703  * the driver, so that they can run fast.
6704  */
6705 static void
6706 aac_event_thread(struct aac_softstate *softs)
6707 {
6708 	int run = 1;
6709 
6710 	DBCALLED(softs, 1);
6711 
6712 	mutex_enter(&softs->ev_lock);
6713 	while (run) {
6714 		int events;
6715 
6716 		if ((events = softs->events) == 0) {
6717 			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
6718 			events = softs->events;
6719 		}
6720 		softs->events = 0;
6721 		mutex_exit(&softs->ev_lock);
6722 
6723 		mutex_enter(&softs->io_lock);
6724 		if ((softs->state & AAC_STATE_RUN) &&
6725 		    (softs->state & AAC_STATE_DEAD) == 0) {
6726 			if (events & AAC_EVENT_TIMEOUT)
6727 				aac_daemon(softs);
6728 			if (events & AAC_EVENT_SYNCTICK)
6729 				aac_sync_tick(softs);
6730 			if (events & AAC_EVENT_AIF)
6731 				aac_aif_event(softs);
6732 		} else {
6733 			run = 0;
6734 		}
6735 		mutex_exit(&softs->io_lock);
6736 
6737 		mutex_enter(&softs->ev_lock);
6738 	}
6739 
6740 	cv_signal(&softs->event_wait_cv);
6741 	mutex_exit(&softs->ev_lock);
6742 }
6743 
6744 /*
6745  * Internal timer. It is only responsbile for time counting and report time
6746  * related events. Events handling is done by aac_event_thread(), so that
6747  * the timer itself could be as precise as possible.
6748  */
6749 static void
6750 aac_timer(void *arg)
6751 {
6752 	struct aac_softstate *softs = arg;
6753 	int events = 0;
6754 
6755 	mutex_enter(&softs->time_mutex);
6756 
6757 	/* If timer is being stopped, exit */
6758 	if (softs->timeout_id) {
6759 		softs->timeout_id = timeout(aac_timer, (void *)softs,
6760 		    (aac_tick * drv_usectohz(1000000)));
6761 	} else {
6762 		mutex_exit(&softs->time_mutex);
6763 		return;
6764 	}
6765 
6766 	/* Time counting */
6767 	softs->timebase += aac_tick;
6768 
6769 	/* Check time related events */
6770 	if (softs->time_out && softs->time_out <= softs->timebase)
6771 		events |= AAC_EVENT_TIMEOUT;
6772 	if (softs->time_sync && softs->time_sync <= softs->timebase)
6773 		events |= AAC_EVENT_SYNCTICK;
6774 
6775 	mutex_exit(&softs->time_mutex);
6776 
6777 	if (events)
6778 		aac_event_disp(softs, events);
6779 }
6780 
6781 /*
6782  * Dispatch events to daemon thread for handling
6783  */
6784 static void
6785 aac_event_disp(struct aac_softstate *softs, int events)
6786 {
6787 	mutex_enter(&softs->ev_lock);
6788 	softs->events |= events;
6789 	cv_broadcast(&softs->event_disp_cv);
6790 	mutex_exit(&softs->ev_lock);
6791 }
6792 
6793 /*
6794  * Architecture dependent functions
6795  */
6796 static int
6797 aac_rx_get_fwstatus(struct aac_softstate *softs)
6798 {
6799 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6800 }
6801 
6802 static int
6803 aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
6804 {
6805 	return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
6806 }
6807 
6808 static void
6809 aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6810     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6811 {
6812 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
6813 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
6814 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
6815 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
6816 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
6817 }
6818 
6819 static int
6820 aac_rkt_get_fwstatus(struct aac_softstate *softs)
6821 {
6822 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6823 }
6824 
6825 static int
6826 aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
6827 {
6828 	return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
6829 }
6830 
6831 static void
6832 aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6833     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6834 {
6835 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
6836 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
6837 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
6838 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
6839 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
6840 }
6841 
6842 /*
6843  * cb_ops functions
6844  */
6845 static int
6846 aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
6847 {
6848 	struct aac_softstate *softs;
6849 	int minor0, minor;
6850 	int instance;
6851 
6852 	DBCALLED(NULL, 2);
6853 
6854 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6855 		return (EINVAL);
6856 
6857 	minor0 = getminor(*devp);
6858 	minor = AAC_SCSA_MINOR(minor0);
6859 
6860 	if (AAC_IS_SCSA_NODE(minor))
6861 		return (scsi_hba_open(devp, flag, otyp, cred));
6862 
6863 	instance = MINOR2INST(minor0);
6864 	if (instance >= AAC_MAX_ADAPTERS)
6865 		return (ENXIO);
6866 
6867 	softs = ddi_get_soft_state(aac_softstatep, instance);
6868 	if (softs == NULL)
6869 		return (ENXIO);
6870 
6871 	return (0);
6872 }
6873 
6874 /*ARGSUSED*/
6875 static int
6876 aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
6877 {
6878 	int minor0, minor;
6879 	int instance;
6880 
6881 	DBCALLED(NULL, 2);
6882 
6883 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6884 		return (EINVAL);
6885 
6886 	minor0 = getminor(dev);
6887 	minor = AAC_SCSA_MINOR(minor0);
6888 
6889 	if (AAC_IS_SCSA_NODE(minor))
6890 		return (scsi_hba_close(dev, flag, otyp, cred));
6891 
6892 	instance = MINOR2INST(minor0);
6893 	if (instance >= AAC_MAX_ADAPTERS)
6894 		return (ENXIO);
6895 
6896 	return (0);
6897 }
6898 
6899 static int
6900 aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
6901     int *rval_p)
6902 {
6903 	struct aac_softstate *softs;
6904 	int minor0, minor;
6905 	int instance;
6906 
6907 	DBCALLED(NULL, 2);
6908 
6909 	if (drv_priv(cred_p) != 0)
6910 		return (EPERM);
6911 
6912 	minor0 = getminor(dev);
6913 	minor = AAC_SCSA_MINOR(minor0);
6914 
6915 	if (AAC_IS_SCSA_NODE(minor))
6916 		return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
6917 
6918 	instance = MINOR2INST(minor0);
6919 	if (instance < AAC_MAX_ADAPTERS) {
6920 		softs = ddi_get_soft_state(aac_softstatep, instance);
6921 		return (aac_do_ioctl(softs, dev, cmd, arg, flag));
6922 	}
6923 	return (ENXIO);
6924 }
6925 
6926 /*
6927  * The IO fault service error handling callback function
6928  */
6929 /*ARGSUSED*/
6930 static int
6931 aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
6932 {
6933 	/*
6934 	 * as the driver can always deal with an error in any dma or
6935 	 * access handle, we can just return the fme_status value.
6936 	 */
6937 	pci_ereport_post(dip, err, NULL);
6938 	return (err->fme_status);
6939 }
6940 
6941 /*
6942  * aac_fm_init - initialize fma capabilities and register with IO
6943  *               fault services.
6944  */
6945 static void
6946 aac_fm_init(struct aac_softstate *softs)
6947 {
6948 	/*
6949 	 * Need to change iblock to priority for new MSI intr
6950 	 */
6951 	ddi_iblock_cookie_t fm_ibc;
6952 
6953 	softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
6954 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
6955 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
6956 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
6957 
6958 	/* Only register with IO Fault Services if we have some capability */
6959 	if (softs->fm_capabilities) {
6960 		/* Adjust access and dma attributes for FMA */
6961 		softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
6962 		softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
6963 		softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
6964 
6965 		/*
6966 		 * Register capabilities with IO Fault Services.
6967 		 * fm_capabilities will be updated to indicate
6968 		 * capabilities actually supported (not requested.)
6969 		 */
6970 		ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
6971 
6972 		/*
6973 		 * Initialize pci ereport capabilities if ereport
6974 		 * capable (should always be.)
6975 		 */
6976 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
6977 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6978 			pci_ereport_setup(softs->devinfo_p);
6979 		}
6980 
6981 		/*
6982 		 * Register error callback if error callback capable.
6983 		 */
6984 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6985 			ddi_fm_handler_register(softs->devinfo_p,
6986 			    aac_fm_error_cb, (void *) softs);
6987 		}
6988 	}
6989 }
6990 
6991 /*
6992  * aac_fm_fini - Releases fma capabilities and un-registers with IO
6993  *               fault services.
6994  */
6995 static void
6996 aac_fm_fini(struct aac_softstate *softs)
6997 {
6998 	/* Only unregister FMA capabilities if registered */
6999 	if (softs->fm_capabilities) {
7000 		/*
7001 		 * Un-register error callback if error callback capable.
7002 		 */
7003 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7004 			ddi_fm_handler_unregister(softs->devinfo_p);
7005 		}
7006 
7007 		/*
7008 		 * Release any resources allocated by pci_ereport_setup()
7009 		 */
7010 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
7011 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7012 			pci_ereport_teardown(softs->devinfo_p);
7013 		}
7014 
7015 		/* Unregister from IO Fault Services */
7016 		ddi_fm_fini(softs->devinfo_p);
7017 
7018 		/* Adjust access and dma attributes for FMA */
7019 		softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
7020 		softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
7021 		softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
7022 	}
7023 }
7024 
7025 int
7026 aac_check_acc_handle(ddi_acc_handle_t handle)
7027 {
7028 	ddi_fm_error_t de;
7029 
7030 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
7031 	return (de.fme_status);
7032 }
7033 
7034 int
7035 aac_check_dma_handle(ddi_dma_handle_t handle)
7036 {
7037 	ddi_fm_error_t de;
7038 
7039 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
7040 	return (de.fme_status);
7041 }
7042 
7043 void
7044 aac_fm_ereport(struct aac_softstate *softs, char *detail)
7045 {
7046 	uint64_t ena;
7047 	char buf[FM_MAX_CLASS];
7048 
7049 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
7050 	ena = fm_ena_generate(0, FM_ENA_FMT1);
7051 	if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
7052 		ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
7053 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
7054 	}
7055 }
7056 
7057 /*
7058  * Autoconfiguration support
7059  */
7060 static int
7061 aac_parse_devname(char *devnm, int *tgt, int *lun)
7062 {
7063 	char devbuf[SCSI_MAXNAMELEN];
7064 	char *addr;
7065 	char *p,  *tp, *lp;
7066 	long num;
7067 
7068 	/* Parse dev name and address */
7069 	(void) strcpy(devbuf, devnm);
7070 	addr = "";
7071 	for (p = devbuf; *p != '\0'; p++) {
7072 		if (*p == '@') {
7073 			addr = p + 1;
7074 			*p = '\0';
7075 		} else if (*p == ':') {
7076 			*p = '\0';
7077 			break;
7078 		}
7079 	}
7080 
7081 	/* Parse taget and lun */
7082 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
7083 		if (*p == ',') {
7084 			lp = p + 1;
7085 			*p = '\0';
7086 			break;
7087 		}
7088 	}
7089 	if (tgt && tp) {
7090 		if (ddi_strtol(tp, NULL, 0x10, &num))
7091 			return (AACERR);
7092 		*tgt = (int)num;
7093 	}
7094 	if (lun && lp) {
7095 		if (ddi_strtol(lp, NULL, 0x10, &num))
7096 			return (AACERR);
7097 		*lun = (int)num;
7098 	}
7099 	return (AACOK);
7100 }
7101 
7102 static dev_info_t *
7103 aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
7104 {
7105 	dev_info_t *child = NULL;
7106 	char addr[SCSI_MAXNAMELEN];
7107 	char tmp[MAXNAMELEN];
7108 
7109 	if (tgt < AAC_MAX_LD) {
7110 		if (lun == 0) {
7111 			struct aac_device *dvp = &softs->containers[tgt].dev;
7112 
7113 			child = dvp->dip;
7114 		}
7115 	} else {
7116 		(void) sprintf(addr, "%x,%x", tgt, lun);
7117 		for (child = ddi_get_child(softs->devinfo_p);
7118 		    child; child = ddi_get_next_sibling(child)) {
7119 			/* We don't care about non-persistent node */
7120 			if (ndi_dev_is_persistent_node(child) == 0)
7121 				continue;
7122 
7123 			if (aac_name_node(child, tmp, MAXNAMELEN) !=
7124 			    DDI_SUCCESS)
7125 				continue;
7126 			if (strcmp(addr, tmp) == 0)
7127 				break;
7128 		}
7129 	}
7130 	return (child);
7131 }
7132 
7133 static int
7134 aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
7135     dev_info_t **dipp)
7136 {
7137 	char *nodename = NULL;
7138 	char **compatible = NULL;
7139 	int ncompatible = 0;
7140 	char *childname;
7141 	dev_info_t *ldip = NULL;
7142 	int tgt = sd->sd_address.a_target;
7143 	int lun = sd->sd_address.a_lun;
7144 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7145 	int rval;
7146 
7147 	DBCALLED(softs, 2);
7148 
7149 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
7150 	    NULL, &nodename, &compatible, &ncompatible);
7151 	if (nodename == NULL) {
7152 		AACDB_PRINT(softs, CE_WARN,
7153 		    "found no comptible driver for t%dL%d", tgt, lun);
7154 		rval = NDI_FAILURE;
7155 		goto finish;
7156 	}
7157 	childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
7158 
7159 	/* Create dev node */
7160 	rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
7161 	    &ldip);
7162 	if (rval == NDI_SUCCESS) {
7163 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
7164 		    != DDI_PROP_SUCCESS) {
7165 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7166 			    "property for t%dL%d (target)", tgt, lun);
7167 			rval = NDI_FAILURE;
7168 			goto finish;
7169 		}
7170 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
7171 		    != DDI_PROP_SUCCESS) {
7172 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7173 			    "property for t%dL%d (lun)", tgt, lun);
7174 			rval = NDI_FAILURE;
7175 			goto finish;
7176 		}
7177 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
7178 		    "compatible", compatible, ncompatible)
7179 		    != DDI_PROP_SUCCESS) {
7180 			AACDB_PRINT(softs, CE_WARN, "unable to create "
7181 			    "property for t%dL%d (compatible)", tgt, lun);
7182 			rval = NDI_FAILURE;
7183 			goto finish;
7184 		}
7185 
7186 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
7187 		if (rval != NDI_SUCCESS) {
7188 			AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
7189 			    tgt, lun);
7190 			ndi_prop_remove_all(ldip);
7191 			(void) ndi_devi_free(ldip);
7192 		}
7193 	}
7194 finish:
7195 	if (dipp)
7196 		*dipp = ldip;
7197 
7198 	scsi_hba_nodename_compatible_free(nodename, compatible);
7199 	return (rval);
7200 }
7201 
7202 /*ARGSUSED*/
7203 static int
7204 aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
7205 {
7206 	int tgt = sd->sd_address.a_target;
7207 	int lun = sd->sd_address.a_lun;
7208 
7209 	DBCALLED(softs, 2);
7210 
7211 	if (tgt < AAC_MAX_LD) {
7212 		enum aac_cfg_event event;
7213 
7214 		if (lun == 0) {
7215 			mutex_enter(&softs->io_lock);
7216 			event = aac_probe_container(softs, tgt);
7217 			mutex_exit(&softs->io_lock);
7218 			if ((event != AAC_CFG_NULL_NOEXIST) &&
7219 			    (event != AAC_CFG_DELETE)) {
7220 				if (scsi_hba_probe(sd, NULL) ==
7221 				    SCSIPROBE_EXISTS)
7222 					return (NDI_SUCCESS);
7223 			}
7224 		}
7225 		return (NDI_FAILURE);
7226 	} else {
7227 		int dtype;
7228 		int qual; /* device qualifier */
7229 
7230 		if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
7231 			return (NDI_FAILURE);
7232 
7233 		dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7234 		qual = dtype >> 5;
7235 
7236 		AACDB_PRINT(softs, CE_NOTE,
7237 		    "Phys. device found: tgt %d dtype %d: %s",
7238 		    tgt, dtype, sd->sd_inq->inq_vid);
7239 
7240 		/* Only non-DASD and JBOD mode DASD are allowed exposed */
7241 		if (dtype == DTYPE_RODIRECT /* CDROM */ ||
7242 		    dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
7243 		    dtype == DTYPE_ESI /* SES */) {
7244 			if (!(softs->flags & AAC_FLAGS_NONDASD))
7245 				return (NDI_FAILURE);
7246 			AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
7247 
7248 		} else if (dtype == DTYPE_DIRECT) {
7249 			if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
7250 				return (NDI_FAILURE);
7251 			AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
7252 		}
7253 
7254 		mutex_enter(&softs->io_lock);
7255 		softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
7256 		mutex_exit(&softs->io_lock);
7257 		return (NDI_SUCCESS);
7258 	}
7259 }
7260 
7261 static int
7262 aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
7263     dev_info_t **ldip)
7264 {
7265 	struct scsi_device sd;
7266 	dev_info_t *child;
7267 	int rval;
7268 
7269 	DBCALLED(softs, 2);
7270 
7271 	if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
7272 		if (ldip)
7273 			*ldip = child;
7274 		return (NDI_SUCCESS);
7275 	}
7276 
7277 	bzero(&sd, sizeof (struct scsi_device));
7278 	sd.sd_address.a_hba_tran = softs->hba_tran;
7279 	sd.sd_address.a_target = (uint16_t)tgt;
7280 	sd.sd_address.a_lun = (uint8_t)lun;
7281 	if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
7282 		rval = aac_config_child(softs, &sd, ldip);
7283 	/* scsi_unprobe is blank now. Free buffer manually */
7284 	if (sd.sd_inq) {
7285 		kmem_free(sd.sd_inq, SUN_INQSIZE);
7286 		sd.sd_inq = (struct scsi_inquiry *)NULL;
7287 	}
7288 	return (rval);
7289 }
7290 
7291 static int
7292 aac_config_tgt(struct aac_softstate *softs, int tgt)
7293 {
7294 	struct scsi_address ap;
7295 	struct buf *bp = NULL;
7296 	int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
7297 	int list_len = 0;
7298 	int lun_total = 0;
7299 	dev_info_t *ldip;
7300 	int i;
7301 
7302 	ap.a_hba_tran = softs->hba_tran;
7303 	ap.a_target = (uint16_t)tgt;
7304 	ap.a_lun = 0;
7305 
7306 	for (i = 0; i < 2; i++) {
7307 		struct scsi_pkt *pkt;
7308 		uchar_t *cdb;
7309 		uchar_t *p;
7310 		uint32_t data;
7311 
7312 		if (bp == NULL) {
7313 			if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
7314 			    buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
7315 			return (AACERR);
7316 		}
7317 		if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
7318 		    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
7319 		    NULL, NULL)) == NULL) {
7320 			scsi_free_consistent_buf(bp);
7321 			return (AACERR);
7322 		}
7323 		cdb = pkt->pkt_cdbp;
7324 		bzero(cdb, CDB_GROUP5);
7325 		cdb[0] = SCMD_REPORT_LUNS;
7326 
7327 		/* Convert buffer len from local to LE_32 */
7328 		data = buf_len;
7329 		for (p = &cdb[9]; p > &cdb[5]; p--) {
7330 			*p = data & 0xff;
7331 			data >>= 8;
7332 		}
7333 
7334 		if (scsi_poll(pkt) < 0 ||
7335 		    ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
7336 			scsi_destroy_pkt(pkt);
7337 			break;
7338 		}
7339 
7340 		/* Convert list_len from LE_32 to local */
7341 		for (p = (uchar_t *)bp->b_un.b_addr;
7342 		    p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
7343 			data <<= 8;
7344 			data |= *p;
7345 		}
7346 		list_len = data;
7347 		if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
7348 			scsi_free_consistent_buf(bp);
7349 			bp = NULL;
7350 			buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
7351 		}
7352 		scsi_destroy_pkt(pkt);
7353 	}
7354 	if (i >= 2) {
7355 		uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
7356 		    AAC_SCSI_RPTLUNS_HEAD_SIZE);
7357 
7358 		for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
7359 			uint16_t lun;
7360 
7361 			/* Determine report luns addressing type */
7362 			switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
7363 			/*
7364 			 * Vendors in the field have been found to be
7365 			 * concatenating bus/target/lun to equal the
7366 			 * complete lun value instead of switching to
7367 			 * flat space addressing
7368 			 */
7369 			case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
7370 			case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
7371 			case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
7372 				lun = ((buf[0] & 0x3f) << 8) | buf[1];
7373 				if (lun > UINT8_MAX) {
7374 					AACDB_PRINT(softs, CE_WARN,
7375 					    "abnormal lun number: %d", lun);
7376 					break;
7377 				}
7378 				if (aac_config_lun(softs, tgt, lun, &ldip) ==
7379 				    NDI_SUCCESS)
7380 					lun_total++;
7381 				break;
7382 			}
7383 
7384 			buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
7385 		}
7386 	} else {
7387 		/* The target may do not support SCMD_REPORT_LUNS. */
7388 		if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
7389 			lun_total++;
7390 	}
7391 	scsi_free_consistent_buf(bp);
7392 	return (lun_total);
7393 }
7394 
7395 static void
7396 aac_devcfg(struct aac_softstate *softs, int tgt, int en)
7397 {
7398 	struct aac_device *dvp;
7399 
7400 	mutex_enter(&softs->io_lock);
7401 	dvp = AAC_DEV(softs, tgt);
7402 	if (en)
7403 		dvp->flags |= AAC_DFLAG_CONFIGURING;
7404 	else
7405 		dvp->flags &= ~AAC_DFLAG_CONFIGURING;
7406 	mutex_exit(&softs->io_lock);
7407 }
7408 
7409 static int
7410 aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
7411     void *arg, dev_info_t **childp)
7412 {
7413 	struct aac_softstate *softs;
7414 	int circ = 0;
7415 	int rval;
7416 
7417 	if ((softs = ddi_get_soft_state(aac_softstatep,
7418 	    ddi_get_instance(parent))) == NULL)
7419 		return (NDI_FAILURE);
7420 
7421 	/* Commands for bus config should be blocked as the bus is quiesced */
7422 	mutex_enter(&softs->io_lock);
7423 	if (softs->state & AAC_STATE_QUIESCED) {
7424 		AACDB_PRINT(softs, CE_NOTE,
7425 		    "bus_config abroted because bus is quiesced");
7426 		mutex_exit(&softs->io_lock);
7427 		return (NDI_FAILURE);
7428 	}
7429 	mutex_exit(&softs->io_lock);
7430 
7431 	DBCALLED(softs, 1);
7432 
7433 	/* Hold the nexus across the bus_config */
7434 	ndi_devi_enter(parent, &circ);
7435 	switch (op) {
7436 	case BUS_CONFIG_ONE: {
7437 		int tgt, lun;
7438 
7439 		if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
7440 			rval = NDI_FAILURE;
7441 			break;
7442 		}
7443 		if (tgt >= AAC_MAX_LD) {
7444 			if (tgt >= AAC_MAX_DEV(softs)) {
7445 				rval = NDI_FAILURE;
7446 				break;
7447 			}
7448 		}
7449 
7450 		AAC_DEVCFG_BEGIN(softs, tgt);
7451 		rval = aac_config_lun(softs, tgt, lun, childp);
7452 		AAC_DEVCFG_END(softs, tgt);
7453 		break;
7454 	}
7455 
7456 	case BUS_CONFIG_DRIVER:
7457 	case BUS_CONFIG_ALL: {
7458 		uint32_t bus, tgt;
7459 		int index, total;
7460 
7461 		for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
7462 			AAC_DEVCFG_BEGIN(softs, tgt);
7463 			(void) aac_config_lun(softs, tgt, 0, NULL);
7464 			AAC_DEVCFG_END(softs, tgt);
7465 		}
7466 
7467 		/* Config the non-DASD devices connected to the card */
7468 		total = 0;
7469 		index = AAC_MAX_LD;
7470 		for (bus = 0; bus < softs->bus_max; bus++) {
7471 			AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
7472 			for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
7473 				AAC_DEVCFG_BEGIN(softs, index);
7474 				if (aac_config_tgt(softs, index))
7475 					total++;
7476 				AAC_DEVCFG_END(softs, index);
7477 			}
7478 		}
7479 		AACDB_PRINT(softs, CE_CONT,
7480 		    "?Total %d phys. device(s) found", total);
7481 		rval = NDI_SUCCESS;
7482 		break;
7483 	}
7484 	}
7485 
7486 	if (rval == NDI_SUCCESS)
7487 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
7488 	ndi_devi_exit(parent, circ);
7489 	return (rval);
7490 }
7491 
7492 /*ARGSUSED*/
7493 static int
7494 aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
7495 {
7496 	struct aac_device *dvp;
7497 	dev_info_t *dip;
7498 	int valid;
7499 	int circ1 = 0;
7500 
7501 	DBCALLED(softs, 1);
7502 
7503 	/* Hold the nexus across the bus_config */
7504 	dvp = AAC_DEV(softs, tgt);
7505 	valid = AAC_DEV_IS_VALID(dvp);
7506 	dip = dvp->dip;
7507 	if (!(softs->state & AAC_STATE_RUN))
7508 		return (AACERR);
7509 	mutex_exit(&softs->io_lock);
7510 
7511 	switch (event) {
7512 	case AAC_CFG_ADD:
7513 	case AAC_CFG_DELETE:
7514 		/* Device onlined */
7515 		if (dip == NULL && valid) {
7516 			ndi_devi_enter(softs->devinfo_p, &circ1);
7517 			(void) aac_config_lun(softs, tgt, 0, NULL);
7518 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
7519 			    softs->instance, tgt, lun);
7520 			ndi_devi_exit(softs->devinfo_p, circ1);
7521 		}
7522 		/* Device offlined */
7523 		if (dip && !valid) {
7524 			mutex_enter(&softs->io_lock);
7525 			(void) aac_do_reset(softs);
7526 			mutex_exit(&softs->io_lock);
7527 
7528 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
7529 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
7530 			    softs->instance, tgt, lun);
7531 		}
7532 		break;
7533 	}
7534 
7535 	mutex_enter(&softs->io_lock);
7536 	return (AACOK);
7537 }
7538 
7539 #ifdef DEBUG
7540 
7541 /* -------------------------debug aid functions-------------------------- */
7542 
7543 #define	AAC_FIB_CMD_KEY_STRINGS \
7544 	TestCommandResponse, "TestCommandResponse", \
7545 	TestAdapterCommand, "TestAdapterCommand", \
7546 	LastTestCommand, "LastTestCommand", \
7547 	ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
7548 	ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
7549 	ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
7550 	ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
7551 	ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
7552 	ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
7553 	ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
7554 	ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
7555 	InterfaceShutdown, "InterfaceShutdown", \
7556 	DmaCommandFib, "DmaCommandFib", \
7557 	StartProfile, "StartProfile", \
7558 	TermProfile, "TermProfile", \
7559 	SpeedTest, "SpeedTest", \
7560 	TakeABreakPt, "TakeABreakPt", \
7561 	RequestPerfData, "RequestPerfData", \
7562 	SetInterruptDefTimer, "SetInterruptDefTimer", \
7563 	SetInterruptDefCount, "SetInterruptDefCount", \
7564 	GetInterruptDefStatus, "GetInterruptDefStatus", \
7565 	LastCommCommand, "LastCommCommand", \
7566 	NuFileSystem, "NuFileSystem", \
7567 	UFS, "UFS", \
7568 	HostFileSystem, "HostFileSystem", \
7569 	LastFileSystemCommand, "LastFileSystemCommand", \
7570 	ContainerCommand, "ContainerCommand", \
7571 	ContainerCommand64, "ContainerCommand64", \
7572 	ClusterCommand, "ClusterCommand", \
7573 	ScsiPortCommand, "ScsiPortCommand", \
7574 	ScsiPortCommandU64, "ScsiPortCommandU64", \
7575 	AifRequest, "AifRequest", \
7576 	CheckRevision, "CheckRevision", \
7577 	FsaHostShutdown, "FsaHostShutdown", \
7578 	RequestAdapterInfo, "RequestAdapterInfo", \
7579 	IsAdapterPaused, "IsAdapterPaused", \
7580 	SendHostTime, "SendHostTime", \
7581 	LastMiscCommand, "LastMiscCommand"
7582 
7583 #define	AAC_CTVM_SUBCMD_KEY_STRINGS \
7584 	VM_Null, "VM_Null", \
7585 	VM_NameServe, "VM_NameServe", \
7586 	VM_ContainerConfig, "VM_ContainerConfig", \
7587 	VM_Ioctl, "VM_Ioctl", \
7588 	VM_FilesystemIoctl, "VM_FilesystemIoctl", \
7589 	VM_CloseAll, "VM_CloseAll", \
7590 	VM_CtBlockRead, "VM_CtBlockRead", \
7591 	VM_CtBlockWrite, "VM_CtBlockWrite", \
7592 	VM_SliceBlockRead, "VM_SliceBlockRead", \
7593 	VM_SliceBlockWrite, "VM_SliceBlockWrite", \
7594 	VM_DriveBlockRead, "VM_DriveBlockRead", \
7595 	VM_DriveBlockWrite, "VM_DriveBlockWrite", \
7596 	VM_EnclosureMgt, "VM_EnclosureMgt", \
7597 	VM_Unused, "VM_Unused", \
7598 	VM_CtBlockVerify, "VM_CtBlockVerify", \
7599 	VM_CtPerf, "VM_CtPerf", \
7600 	VM_CtBlockRead64, "VM_CtBlockRead64", \
7601 	VM_CtBlockWrite64, "VM_CtBlockWrite64", \
7602 	VM_CtBlockVerify64, "VM_CtBlockVerify64", \
7603 	VM_CtHostRead64, "VM_CtHostRead64", \
7604 	VM_CtHostWrite64, "VM_CtHostWrite64", \
7605 	VM_NameServe64, "VM_NameServe64"
7606 
7607 #define	AAC_CT_SUBCMD_KEY_STRINGS \
7608 	CT_Null, "CT_Null", \
7609 	CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
7610 	CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
7611 	CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
7612 	CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
7613 	CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
7614 	CT_WRITE_MBR, "CT_WRITE_MBR", \
7615 	CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
7616 	CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
7617 	CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
7618 	CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
7619 	CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
7620 	CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
7621 	CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
7622 	CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
7623 	CT_READ_MBR, "CT_READ_MBR", \
7624 	CT_READ_PARTITION, "CT_READ_PARTITION", \
7625 	CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
7626 	CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
7627 	CT_SLICE_SIZE, "CT_SLICE_SIZE", \
7628 	CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
7629 	CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
7630 	CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
7631 	CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
7632 	CT_UNMIRROR, "CT_UNMIRROR", \
7633 	CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
7634 	CT_GEN_MIRROR, "CT_GEN_MIRROR", \
7635 	CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
7636 	CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
7637 	CT_MOVE2, "CT_MOVE2", \
7638 	CT_SPLIT, "CT_SPLIT", \
7639 	CT_SPLIT2, "CT_SPLIT2", \
7640 	CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
7641 	CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
7642 	CT_RECONFIG, "CT_RECONFIG", \
7643 	CT_BREAK2, "CT_BREAK2", \
7644 	CT_BREAK, "CT_BREAK", \
7645 	CT_MERGE2, "CT_MERGE2", \
7646 	CT_MERGE, "CT_MERGE", \
7647 	CT_FORCE_ERROR, "CT_FORCE_ERROR", \
7648 	CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
7649 	CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
7650 	CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
7651 	CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
7652 	CT_VOLUME_ADD, "CT_VOLUME_ADD", \
7653 	CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
7654 	CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
7655 	CT_COPY_STATUS, "CT_COPY_STATUS", \
7656 	CT_COPY, "CT_COPY", \
7657 	CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
7658 	CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
7659 	CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
7660 	CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
7661 	CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
7662 	CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
7663 	CT_SET, "CT_SET", \
7664 	CT_GET, "CT_GET", \
7665 	CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
7666 	CT_GET_DELAY, "CT_GET_DELAY", \
7667 	CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
7668 	CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
7669 	CT_SCRUB, "CT_SCRUB", \
7670 	CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
7671 	CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
7672 	CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
7673 	CT_PAUSE_IO, "CT_PAUSE_IO", \
7674 	CT_RELEASE_IO, "CT_RELEASE_IO", \
7675 	CT_SCRUB2, "CT_SCRUB2", \
7676 	CT_MCHECK, "CT_MCHECK", \
7677 	CT_CORRUPT, "CT_CORRUPT", \
7678 	CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
7679 	CT_PROMOTE, "CT_PROMOTE", \
7680 	CT_SET_DEAD, "CT_SET_DEAD", \
7681 	CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
7682 	CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
7683 	CT_GET_PARAM, "CT_GET_PARAM", \
7684 	CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
7685 	CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
7686 	CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
7687 	CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
7688 	CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
7689 	CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
7690 	CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
7691 	CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
7692 	CT_STOP_DATA, "CT_STOP_DATA", \
7693 	CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
7694 	CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
7695 	CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
7696 	CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
7697 	CT_GET_TIME, "CT_GET_TIME", \
7698 	CT_READ_DATA, "CT_READ_DATA", \
7699 	CT_CTR, "CT_CTR", \
7700 	CT_CTL, "CT_CTL", \
7701 	CT_DRAINIO, "CT_DRAINIO", \
7702 	CT_RELEASEIO, "CT_RELEASEIO", \
7703 	CT_GET_NVRAM, "CT_GET_NVRAM", \
7704 	CT_GET_MEMORY, "CT_GET_MEMORY", \
7705 	CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
7706 	CT_ADD_LEVEL, "CT_ADD_LEVEL", \
7707 	CT_NV_ZERO, "CT_NV_ZERO", \
7708 	CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
7709 	CT_THROTTLE_ON, "CT_THROTTLE_ON", \
7710 	CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
7711 	CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
7712 	CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
7713 	CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
7714 	CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
7715 	CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
7716 	CT_MONITOR, "CT_MONITOR", \
7717 	CT_GEN_MORPH, "CT_GEN_MORPH", \
7718 	CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
7719 	CT_CACHE_SET, "CT_CACHE_SET", \
7720 	CT_CACHE_STAT, "CT_CACHE_STAT", \
7721 	CT_TRACE_START, "CT_TRACE_START", \
7722 	CT_TRACE_STOP, "CT_TRACE_STOP", \
7723 	CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
7724 	CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
7725 	CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
7726 	CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
7727 	CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
7728 	CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
7729 	CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
7730 	CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
7731 	CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
7732 	CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
7733 	CT_STOP_DUMPS, "CT_STOP_DUMPS", \
7734 	CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
7735 	CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
7736 	CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
7737 	CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
7738 	CT_READ_NAME, "CT_READ_NAME", \
7739 	CT_WRITE_NAME, "CT_WRITE_NAME", \
7740 	CT_TOSS_CACHE, "CT_TOSS_CACHE", \
7741 	CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
7742 	CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
7743 	CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
7744 	CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
7745 	CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
7746 	CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
7747 	CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
7748 	CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
7749 	CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
7750 	CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
7751 	CT_FLUSH, "CT_FLUSH", \
7752 	CT_REBUILD, "CT_REBUILD", \
7753 	CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
7754 	CT_RESTART, "CT_RESTART", \
7755 	CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
7756 	CT_TRACE_FLAG, "CT_TRACE_FLAG", \
7757 	CT_RESTART_MORPH, "CT_RESTART_MORPH", \
7758 	CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
7759 	CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
7760 	CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
7761 	CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
7762 	CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
7763 	CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
7764 	CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
7765 	CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
7766 	CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
7767 	CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
7768 	CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
7769 	CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
7770 	CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
7771 	CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
7772 	CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
7773 	CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
7774 	CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
7775 	CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
7776 	CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
7777 	CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
7778 	CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
7779 	CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
7780 	CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
7781 	CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
7782 	CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
7783 	CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
7784 	CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
7785 	CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
7786 	CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
7787 	CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
7788 	CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
7789 	CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
7790 	CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
7791 	CT_IS_CONTAINER_MEATADATA_STANDARD, \
7792 	    "CT_IS_CONTAINER_MEATADATA_STANDARD", \
7793 	CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
7794 	CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
7795 	CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
7796 	CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
7797 	CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
7798 	CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
7799 	CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
7800 	CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
7801 	CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
7802 	CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
7803 	CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
7804 	CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
7805 	CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
7806 	CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
7807 	CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
7808 	CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
7809 	CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
7810 	CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
7811 	CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
7812 
7813 #define	AAC_CL_SUBCMD_KEY_STRINGS \
7814 	CL_NULL, "CL_NULL", \
7815 	DS_INIT, "DS_INIT", \
7816 	DS_RESCAN, "DS_RESCAN", \
7817 	DS_CREATE, "DS_CREATE", \
7818 	DS_DELETE, "DS_DELETE", \
7819 	DS_ADD_DISK, "DS_ADD_DISK", \
7820 	DS_REMOVE_DISK, "DS_REMOVE_DISK", \
7821 	DS_MOVE_DISK, "DS_MOVE_DISK", \
7822 	DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
7823 	DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
7824 	DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
7825 	DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
7826 	DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
7827 	DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
7828 	DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
7829 	DS_GET_DRIVES, "DS_GET_DRIVES", \
7830 	DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
7831 	DS_ONLINE, "DS_ONLINE", \
7832 	DS_OFFLINE, "DS_OFFLINE", \
7833 	DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
7834 	DS_FSAPRINT, "DS_FSAPRINT", \
7835 	CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
7836 	CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
7837 	CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
7838 	CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
7839 	CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
7840 	CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
7841 	CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
7842 	CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
7843 	CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
7844 	CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
7845 	CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
7846 	CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
7847 	CC_GET_BUSINFO, "CC_GET_BUSINFO", \
7848 	CC_GET_PORTINFO, "CC_GET_PORTINFO", \
7849 	CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
7850 	CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
7851 	CQ_QUORUM_OP, "CQ_QUORUM_OP"
7852 
7853 #define	AAC_AIF_SUBCMD_KEY_STRINGS \
7854 	AifCmdEventNotify, "AifCmdEventNotify", \
7855 	AifCmdJobProgress, "AifCmdJobProgress", \
7856 	AifCmdAPIReport, "AifCmdAPIReport", \
7857 	AifCmdDriverNotify, "AifCmdDriverNotify", \
7858 	AifReqJobList, "AifReqJobList", \
7859 	AifReqJobsForCtr, "AifReqJobsForCtr", \
7860 	AifReqJobsForScsi, "AifReqJobsForScsi", \
7861 	AifReqJobReport, "AifReqJobReport", \
7862 	AifReqTerminateJob, "AifReqTerminateJob", \
7863 	AifReqSuspendJob, "AifReqSuspendJob", \
7864 	AifReqResumeJob, "AifReqResumeJob", \
7865 	AifReqSendAPIReport, "AifReqSendAPIReport", \
7866 	AifReqAPIJobStart, "AifReqAPIJobStart", \
7867 	AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
7868 	AifReqAPIJobFinish, "AifReqAPIJobFinish"
7869 
7870 #define	AAC_IOCTL_SUBCMD_KEY_STRINGS \
7871 	Reserved_IOCTL, "Reserved_IOCTL", \
7872 	GetDeviceHandle, "GetDeviceHandle", \
7873 	BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
7874 	DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
7875 	RescanBus, "RescanBus", \
7876 	GetDeviceProbeInfo, "GetDeviceProbeInfo", \
7877 	GetDeviceCapacity, "GetDeviceCapacity", \
7878 	GetContainerProbeInfo, "GetContainerProbeInfo", \
7879 	GetRequestedMemorySize, "GetRequestedMemorySize", \
7880 	GetBusInfo, "GetBusInfo", \
7881 	GetVendorSpecific, "GetVendorSpecific", \
7882 	EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
7883 	EnhancedGetBusInfo, "EnhancedGetBusInfo", \
7884 	SetupExtendedCounters, "SetupExtendedCounters", \
7885 	GetPerformanceCounters, "GetPerformanceCounters", \
7886 	ResetPerformanceCounters, "ResetPerformanceCounters", \
7887 	ReadModePage, "ReadModePage", \
7888 	WriteModePage, "WriteModePage", \
7889 	ReadDriveParameter, "ReadDriveParameter", \
7890 	WriteDriveParameter, "WriteDriveParameter", \
7891 	ResetAdapter, "ResetAdapter", \
7892 	ResetBus, "ResetBus", \
7893 	ResetBusDevice, "ResetBusDevice", \
7894 	ExecuteSrb, "ExecuteSrb", \
7895 	Create_IO_Task, "Create_IO_Task", \
7896 	Delete_IO_Task, "Delete_IO_Task", \
7897 	Get_IO_Task_Info, "Get_IO_Task_Info", \
7898 	Check_Task_Progress, "Check_Task_Progress", \
7899 	InjectError, "InjectError", \
7900 	GetDeviceDefectCounts, "GetDeviceDefectCounts", \
7901 	GetDeviceDefectInfo, "GetDeviceDefectInfo", \
7902 	GetDeviceStatus, "GetDeviceStatus", \
7903 	ClearDeviceStatus, "ClearDeviceStatus", \
7904 	DiskSpinControl, "DiskSpinControl", \
7905 	DiskSmartControl, "DiskSmartControl", \
7906 	WriteSame, "WriteSame", \
7907 	ReadWriteLong, "ReadWriteLong", \
7908 	FormatUnit, "FormatUnit", \
7909 	TargetDeviceControl, "TargetDeviceControl", \
7910 	TargetChannelControl, "TargetChannelControl", \
7911 	FlashNewCode, "FlashNewCode", \
7912 	DiskCheck, "DiskCheck", \
7913 	RequestSense, "RequestSense", \
7914 	DiskPERControl, "DiskPERControl", \
7915 	Read10, "Read10", \
7916 	Write10, "Write10"
7917 
7918 #define	AAC_AIFEN_KEY_STRINGS \
7919 	AifEnGeneric, "Generic", \
7920 	AifEnTaskComplete, "TaskComplete", \
7921 	AifEnConfigChange, "Config change", \
7922 	AifEnContainerChange, "Container change", \
7923 	AifEnDeviceFailure, "device failed", \
7924 	AifEnMirrorFailover, "Mirror failover", \
7925 	AifEnContainerEvent, "container event", \
7926 	AifEnFileSystemChange, "File system changed", \
7927 	AifEnConfigPause, "Container pause event", \
7928 	AifEnConfigResume, "Container resume event", \
7929 	AifEnFailoverChange, "Failover space assignment changed", \
7930 	AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
7931 	AifEnEnclosureManagement, "Enclosure management event", \
7932 	AifEnBatteryEvent, "battery event", \
7933 	AifEnAddContainer, "Add container", \
7934 	AifEnDeleteContainer, "Delete container", \
7935 	AifEnSMARTEvent, "SMART Event", \
7936 	AifEnBatteryNeedsRecond, "battery needs reconditioning", \
7937 	AifEnClusterEvent, "cluster event", \
7938 	AifEnDiskSetEvent, "disk set event occured", \
7939 	AifDenMorphComplete, "morph operation completed", \
7940 	AifDenVolumeExtendComplete, "VolumeExtendComplete"
7941 
7942 struct aac_key_strings {
7943 	int key;
7944 	char *message;
7945 };
7946 
7947 extern struct scsi_key_strings scsi_cmds[];
7948 
7949 static struct aac_key_strings aac_fib_cmds[] = {
7950 	AAC_FIB_CMD_KEY_STRINGS,
7951 	-1,			NULL
7952 };
7953 
7954 static struct aac_key_strings aac_ctvm_subcmds[] = {
7955 	AAC_CTVM_SUBCMD_KEY_STRINGS,
7956 	-1,			NULL
7957 };
7958 
7959 static struct aac_key_strings aac_ct_subcmds[] = {
7960 	AAC_CT_SUBCMD_KEY_STRINGS,
7961 	-1,			NULL
7962 };
7963 
7964 static struct aac_key_strings aac_cl_subcmds[] = {
7965 	AAC_CL_SUBCMD_KEY_STRINGS,
7966 	-1,			NULL
7967 };
7968 
7969 static struct aac_key_strings aac_aif_subcmds[] = {
7970 	AAC_AIF_SUBCMD_KEY_STRINGS,
7971 	-1,			NULL
7972 };
7973 
7974 static struct aac_key_strings aac_ioctl_subcmds[] = {
7975 	AAC_IOCTL_SUBCMD_KEY_STRINGS,
7976 	-1,			NULL
7977 };
7978 
7979 static struct aac_key_strings aac_aifens[] = {
7980 	AAC_AIFEN_KEY_STRINGS,
7981 	-1,			NULL
7982 };
7983 
7984 /*
7985  * The following function comes from Adaptec:
7986  *
7987  * Get the firmware print buffer parameters from the firmware,
7988  * if the command was successful map in the address.
7989  */
7990 static int
7991 aac_get_fw_debug_buffer(struct aac_softstate *softs)
7992 {
7993 	if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
7994 	    0, 0, 0, 0, NULL) == AACOK) {
7995 		uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
7996 		uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
7997 		uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
7998 		uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
7999 
8000 		if (mondrv_buf_size) {
8001 			uint32_t offset = mondrv_buf_paddrl - \
8002 			    softs->pci_mem_base_paddr;
8003 
8004 			/*
8005 			 * See if the address is already mapped in, and
8006 			 * if so set it up from the base address
8007 			 */
8008 			if ((mondrv_buf_paddrh == 0) &&
8009 			    (offset + mondrv_buf_size < softs->map_size)) {
8010 				mutex_enter(&aac_prt_mutex);
8011 				softs->debug_buf_offset = offset;
8012 				softs->debug_header_size = mondrv_hdr_size;
8013 				softs->debug_buf_size = mondrv_buf_size;
8014 				softs->debug_fw_flags = 0;
8015 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8016 				mutex_exit(&aac_prt_mutex);
8017 
8018 				return (AACOK);
8019 			}
8020 		}
8021 	}
8022 	return (AACERR);
8023 }
8024 
8025 int
8026 aac_dbflag_on(struct aac_softstate *softs, int flag)
8027 {
8028 	int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
8029 
8030 	return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
8031 	    AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
8032 }
8033 
8034 static void
8035 aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
8036 {
8037 	if (noheader) {
8038 		if (sl) {
8039 			aac_fmt[0] = sl;
8040 			cmn_err(lev, aac_fmt, aac_prt_buf);
8041 		} else {
8042 			cmn_err(lev, &aac_fmt[1], aac_prt_buf);
8043 		}
8044 	} else {
8045 		if (sl) {
8046 			aac_fmt_header[0] = sl;
8047 			cmn_err(lev, aac_fmt_header,
8048 			    softs->vendor_name, softs->instance,
8049 			    aac_prt_buf);
8050 		} else {
8051 			cmn_err(lev, &aac_fmt_header[1],
8052 			    softs->vendor_name, softs->instance,
8053 			    aac_prt_buf);
8054 		}
8055 	}
8056 }
8057 
8058 /*
8059  * The following function comes from Adaptec:
8060  *
8061  * Format and print out the data passed in to UART or console
8062  * as specified by debug flags.
8063  */
8064 void
8065 aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
8066 {
8067 	va_list args;
8068 	char sl; /* system log character */
8069 
8070 	mutex_enter(&aac_prt_mutex);
8071 	/* Set up parameters and call sprintf function to format the data */
8072 	if (strchr("^!?", fmt[0]) == NULL) {
8073 		sl = 0;
8074 	} else {
8075 		sl = fmt[0];
8076 		fmt++;
8077 	}
8078 	va_start(args, fmt);
8079 	(void) vsprintf(aac_prt_buf, fmt, args);
8080 	va_end(args);
8081 
8082 	/* Make sure the softs structure has been passed in for this section */
8083 	if (softs) {
8084 		if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
8085 		    /* If we are set up for a Firmware print */
8086 		    (softs->debug_buf_size)) {
8087 			uint32_t count, i;
8088 
8089 			/* Make sure the string size is within boundaries */
8090 			count = strlen(aac_prt_buf);
8091 			if (count > softs->debug_buf_size)
8092 				count = (uint16_t)softs->debug_buf_size;
8093 
8094 			/*
8095 			 * Wait for no more than AAC_PRINT_TIMEOUT for the
8096 			 * previous message length to clear (the handshake).
8097 			 */
8098 			for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
8099 				if (!PCI_MEM_GET32(softs,
8100 				    softs->debug_buf_offset + \
8101 				    AAC_FW_DBG_STRLEN_OFFSET))
8102 					break;
8103 
8104 				drv_usecwait(1000);
8105 			}
8106 
8107 			/*
8108 			 * If the length is clear, copy over the message, the
8109 			 * flags, and the length. Make sure the length is the
8110 			 * last because that is the signal for the Firmware to
8111 			 * pick it up.
8112 			 */
8113 			if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
8114 			    AAC_FW_DBG_STRLEN_OFFSET)) {
8115 				PCI_MEM_REP_PUT8(softs,
8116 				    softs->debug_buf_offset + \
8117 				    softs->debug_header_size,
8118 				    aac_prt_buf, count);
8119 				PCI_MEM_PUT32(softs,
8120 				    softs->debug_buf_offset + \
8121 				    AAC_FW_DBG_FLAGS_OFFSET,
8122 				    softs->debug_fw_flags);
8123 				PCI_MEM_PUT32(softs,
8124 				    softs->debug_buf_offset + \
8125 				    AAC_FW_DBG_STRLEN_OFFSET, count);
8126 			} else {
8127 				cmn_err(CE_WARN, "UART output fail");
8128 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8129 			}
8130 		}
8131 
8132 		/*
8133 		 * If the Kernel Debug Print flag is set, send it off
8134 		 * to the Kernel Debugger
8135 		 */
8136 		if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8137 			aac_cmn_err(softs, lev, sl,
8138 			    (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
8139 	} else {
8140 		/* Driver not initialized yet, no firmware or header output */
8141 		if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8142 			aac_cmn_err(softs, lev, sl, 1);
8143 	}
8144 	mutex_exit(&aac_prt_mutex);
8145 }
8146 
8147 /*
8148  * Translate command number to description string
8149  */
8150 static char *
8151 aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
8152 {
8153 	int i;
8154 
8155 	for (i = 0; cmdlist[i].key != -1; i++) {
8156 		if (cmd == cmdlist[i].key)
8157 			return (cmdlist[i].message);
8158 	}
8159 	return (NULL);
8160 }
8161 
8162 static void
8163 aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
8164 {
8165 	struct scsi_pkt *pkt = acp->pkt;
8166 	struct scsi_address *ap = &pkt->pkt_address;
8167 	int is_pd = 0;
8168 	int ctl = ddi_get_instance(softs->devinfo_p);
8169 	int tgt = ap->a_target;
8170 	int lun = ap->a_lun;
8171 	union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
8172 	uchar_t cmd = cdbp->scc_cmd;
8173 	char *desc;
8174 
8175 	if (tgt >= AAC_MAX_LD) {
8176 		is_pd = 1;
8177 		ctl = ((struct aac_nondasd *)acp->dvp)->bus;
8178 		tgt = ((struct aac_nondasd *)acp->dvp)->tid;
8179 		lun = 0;
8180 	}
8181 
8182 	if ((desc = aac_cmd_name(cmd,
8183 	    (struct aac_key_strings *)scsi_cmds)) == NULL) {
8184 		aac_printf(softs, CE_NOTE,
8185 		    "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
8186 		    cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
8187 		return;
8188 	}
8189 
8190 	switch (cmd) {
8191 	case SCMD_READ:
8192 	case SCMD_WRITE:
8193 		aac_printf(softs, CE_NOTE,
8194 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8195 		    desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
8196 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8197 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8198 		break;
8199 	case SCMD_READ_G1:
8200 	case SCMD_WRITE_G1:
8201 		aac_printf(softs, CE_NOTE,
8202 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8203 		    desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
8204 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8205 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8206 		break;
8207 	case SCMD_READ_G4:
8208 	case SCMD_WRITE_G4:
8209 		aac_printf(softs, CE_NOTE,
8210 		    "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
8211 		    desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
8212 		    GETG4COUNT(cdbp),
8213 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8214 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8215 		break;
8216 	case SCMD_READ_G5:
8217 	case SCMD_WRITE_G5:
8218 		aac_printf(softs, CE_NOTE,
8219 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8220 		    desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
8221 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
8222 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8223 		break;
8224 	default:
8225 		aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
8226 		    desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
8227 	}
8228 }
8229 
8230 void
8231 aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
8232 {
8233 	struct aac_cmd *acp = slotp->acp;
8234 	struct aac_fib *fibp = slotp->fibp;
8235 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
8236 	uint16_t fib_size;
8237 	uint32_t fib_cmd, sub_cmd;
8238 	char *cmdstr, *subcmdstr;
8239 	char *caller;
8240 	int i;
8241 
8242 	if (acp) {
8243 		if (!(softs->debug_fib_flags & acp->fib_flags))
8244 			return;
8245 		if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
8246 			caller = "SCMD";
8247 		else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
8248 			caller = "IOCTL";
8249 		else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
8250 			caller = "SRB";
8251 		else
8252 			return;
8253 	} else {
8254 		if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
8255 			return;
8256 		caller = "SYNC";
8257 	}
8258 
8259 	fib_cmd = ddi_get16(acc, &fibp->Header.Command);
8260 	cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
8261 	sub_cmd = (uint32_t)-1;
8262 	subcmdstr = NULL;
8263 
8264 	/* Print FIB header */
8265 	if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
8266 		aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
8267 		aac_printf(softs, CE_NOTE, "     XferState  %d",
8268 		    ddi_get32(acc, &fibp->Header.XferState));
8269 		aac_printf(softs, CE_NOTE, "     Command    %d",
8270 		    ddi_get16(acc, &fibp->Header.Command));
8271 		aac_printf(softs, CE_NOTE, "     StructType %d",
8272 		    ddi_get8(acc, &fibp->Header.StructType));
8273 		aac_printf(softs, CE_NOTE, "     Flags      0x%x",
8274 		    ddi_get8(acc, &fibp->Header.Flags));
8275 		aac_printf(softs, CE_NOTE, "     Size       %d",
8276 		    ddi_get16(acc, &fibp->Header.Size));
8277 		aac_printf(softs, CE_NOTE, "     SenderSize %d",
8278 		    ddi_get16(acc, &fibp->Header.SenderSize));
8279 		aac_printf(softs, CE_NOTE, "     SenderAddr 0x%x",
8280 		    ddi_get32(acc, &fibp->Header.SenderFibAddress));
8281 		aac_printf(softs, CE_NOTE, "     RcvrAddr   0x%x",
8282 		    ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
8283 		aac_printf(softs, CE_NOTE, "     SenderData 0x%x",
8284 		    ddi_get32(acc, &fibp->Header.SenderData));
8285 	}
8286 
8287 	/* Print FIB data */
8288 	switch (fib_cmd) {
8289 	case ContainerCommand:
8290 		sub_cmd = ddi_get32(acc,
8291 		    (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
8292 		subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
8293 		if (subcmdstr == NULL)
8294 			break;
8295 
8296 		switch (sub_cmd) {
8297 		case VM_ContainerConfig: {
8298 			struct aac_Container *pContainer =
8299 			    (struct aac_Container *)fibp->data;
8300 
8301 			fib_cmd = sub_cmd;
8302 			cmdstr = subcmdstr;
8303 			sub_cmd = (uint32_t)-1;
8304 			subcmdstr = NULL;
8305 
8306 			sub_cmd = ddi_get32(acc,
8307 			    &pContainer->CTCommand.command);
8308 			subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
8309 			if (subcmdstr == NULL)
8310 				break;
8311 			aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
8312 			    subcmdstr,
8313 			    ddi_get32(acc, &pContainer->CTCommand.param[0]),
8314 			    ddi_get32(acc, &pContainer->CTCommand.param[1]),
8315 			    ddi_get32(acc, &pContainer->CTCommand.param[2]));
8316 			return;
8317 		}
8318 
8319 		case VM_Ioctl:
8320 			fib_cmd = sub_cmd;
8321 			cmdstr = subcmdstr;
8322 			sub_cmd = (uint32_t)-1;
8323 			subcmdstr = NULL;
8324 
8325 			sub_cmd = ddi_get32(acc,
8326 			    (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
8327 			subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
8328 			break;
8329 
8330 		case VM_CtBlockRead:
8331 		case VM_CtBlockWrite: {
8332 			struct aac_blockread *br =
8333 			    (struct aac_blockread *)fibp->data;
8334 			struct aac_sg_table *sg = &br->SgMap;
8335 			uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8336 
8337 			aac_printf(softs, CE_NOTE,
8338 			    "FIB> %s Container %d  0x%x/%d", subcmdstr,
8339 			    ddi_get32(acc, &br->ContainerId),
8340 			    ddi_get32(acc, &br->BlockNumber),
8341 			    ddi_get32(acc, &br->ByteCount));
8342 			for (i = 0; i < sgcount; i++)
8343 				aac_printf(softs, CE_NOTE,
8344 				    "     %d: 0x%08x/%d", i,
8345 				    ddi_get32(acc, &sg->SgEntry[i].SgAddress),
8346 				    ddi_get32(acc, &sg->SgEntry[i]. \
8347 				    SgByteCount));
8348 			return;
8349 		}
8350 		}
8351 		break;
8352 
8353 	case ContainerCommand64: {
8354 		struct aac_blockread64 *br =
8355 		    (struct aac_blockread64 *)fibp->data;
8356 		struct aac_sg_table64 *sg = &br->SgMap64;
8357 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8358 		uint64_t sgaddr;
8359 
8360 		sub_cmd = br->Command;
8361 		subcmdstr = NULL;
8362 		if (sub_cmd == VM_CtHostRead64)
8363 			subcmdstr = "VM_CtHostRead64";
8364 		else if (sub_cmd == VM_CtHostWrite64)
8365 			subcmdstr = "VM_CtHostWrite64";
8366 		else
8367 			break;
8368 
8369 		aac_printf(softs, CE_NOTE,
8370 		    "FIB> %s Container %d  0x%x/%d", subcmdstr,
8371 		    ddi_get16(acc, &br->ContainerId),
8372 		    ddi_get32(acc, &br->BlockNumber),
8373 		    ddi_get16(acc, &br->SectorCount));
8374 		for (i = 0; i < sgcount; i++) {
8375 			sgaddr = ddi_get64(acc,
8376 			    &sg->SgEntry64[i].SgAddress);
8377 			aac_printf(softs, CE_NOTE,
8378 			    "     %d: 0x%08x.%08x/%d", i,
8379 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
8380 			    ddi_get32(acc, &sg->SgEntry64[i]. \
8381 			    SgByteCount));
8382 		}
8383 		return;
8384 	}
8385 
8386 	case RawIo: {
8387 		struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
8388 		struct aac_sg_tableraw *sg = &io->SgMapRaw;
8389 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
8390 		uint64_t sgaddr;
8391 
8392 		aac_printf(softs, CE_NOTE,
8393 		    "FIB> RawIo Container %d  0x%llx/%d 0x%x",
8394 		    ddi_get16(acc, &io->ContainerId),
8395 		    ddi_get64(acc, &io->BlockNumber),
8396 		    ddi_get32(acc, &io->ByteCount),
8397 		    ddi_get16(acc, &io->Flags));
8398 		for (i = 0; i < sgcount; i++) {
8399 			sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
8400 			aac_printf(softs, CE_NOTE, "     %d: 0x%08x.%08x/%d", i,
8401 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
8402 			    ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
8403 		}
8404 		return;
8405 	}
8406 
8407 	case ClusterCommand:
8408 		sub_cmd = ddi_get32(acc,
8409 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8410 		subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
8411 		break;
8412 
8413 	case AifRequest:
8414 		sub_cmd = ddi_get32(acc,
8415 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8416 		subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
8417 		break;
8418 
8419 	default:
8420 		break;
8421 	}
8422 
8423 	fib_size = ddi_get16(acc, &(fibp->Header.Size));
8424 	if (subcmdstr)
8425 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8426 		    subcmdstr, fib_size);
8427 	else if (cmdstr && sub_cmd == (uint32_t)-1)
8428 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8429 		    cmdstr, fib_size);
8430 	else if (cmdstr)
8431 		aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
8432 		    cmdstr, sub_cmd, fib_size);
8433 	else
8434 		aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
8435 		    fib_cmd, fib_size);
8436 }
8437 
8438 static void
8439 aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
8440 {
8441 	int aif_command;
8442 	uint32_t aif_seqnumber;
8443 	int aif_en_type;
8444 	char *str;
8445 
8446 	aif_command = LE_32(aif->command);
8447 	aif_seqnumber = LE_32(aif->seqNumber);
8448 	aif_en_type = LE_32(aif->data.EN.type);
8449 
8450 	switch (aif_command) {
8451 	case AifCmdEventNotify:
8452 		str = aac_cmd_name(aif_en_type, aac_aifens);
8453 		if (str)
8454 			aac_printf(softs, CE_NOTE, "AIF! %s", str);
8455 		else
8456 			aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
8457 			    aif_en_type);
8458 		break;
8459 
8460 	case AifCmdJobProgress:
8461 		switch (LE_32(aif->data.PR[0].status)) {
8462 		case AifJobStsSuccess:
8463 			str = "success"; break;
8464 		case AifJobStsFinished:
8465 			str = "finished"; break;
8466 		case AifJobStsAborted:
8467 			str = "aborted"; break;
8468 		case AifJobStsFailed:
8469 			str = "failed"; break;
8470 		case AifJobStsSuspended:
8471 			str = "suspended"; break;
8472 		case AifJobStsRunning:
8473 			str = "running"; break;
8474 		default:
8475 			str = "unknown"; break;
8476 		}
8477 		aac_printf(softs, CE_NOTE,
8478 		    "AIF! JobProgress (%d) - %s (%d, %d)",
8479 		    aif_seqnumber, str,
8480 		    LE_32(aif->data.PR[0].currentTick),
8481 		    LE_32(aif->data.PR[0].finalTick));
8482 		break;
8483 
8484 	case AifCmdAPIReport:
8485 		aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
8486 		    aif_seqnumber);
8487 		break;
8488 
8489 	case AifCmdDriverNotify:
8490 		aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
8491 		    aif_seqnumber);
8492 		break;
8493 
8494 	default:
8495 		aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
8496 		    aif_command, aif_seqnumber);
8497 		break;
8498 	}
8499 }
8500 
8501 #endif /* DEBUG */
8502