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