xref: /illumos-gate/usr/src/uts/common/io/aac/aac.c (revision 3fe80ca4)
17c478bd9Sstevel@tonic-gate /*
23fced439Szhongyan gu - Sun Microsystems - Beijing China  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
4830d82f7Spl 
57c478bd9Sstevel@tonic-gate /*
6*3fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
715c07adcSJohn Levon  * Copyright (c) 2018, Joyent, Inc.
858bc78c7SXin Chen  * Copyright 2005-08 Adaptec, Inc.
958bc78c7SXin Chen  * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
107c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Michael Smith
117c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 Scott Long
127c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 BSDi
137c478bd9Sstevel@tonic-gate  * All rights reserved.
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
167c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
177c478bd9Sstevel@tonic-gate  * are met:
187c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
197c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
207c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
217c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
227c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
237c478bd9Sstevel@tonic-gate  *
247c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
257c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
267c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
277c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
287c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29830d82f7Spl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30830d82f7Spl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
317c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
327c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
337c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
397c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/devops.h>
417c478bd9Sstevel@tonic-gate #include <sys/pci.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h>
447c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
457c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
487c478bd9Sstevel@tonic-gate #include "aac_regs.h"
497c478bd9Sstevel@tonic-gate #include "aac.h"
507c478bd9Sstevel@tonic-gate 
517675db54Syw /*
527675db54Syw  * FMA header files
537675db54Syw  */
547675db54Syw #include <sys/ddifm.h>
557675db54Syw #include <sys/fm/protocol.h>
567675db54Syw #include <sys/fm/util.h>
577675db54Syw #include <sys/fm/io/ddi.h>
587675db54Syw 
59830d82f7Spl /*
60830d82f7Spl  * For minor nodes created by the SCSA framework, minor numbers are
61830d82f7Spl  * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
62830d82f7Spl  * number less than 64.
63830d82f7Spl  *
64830d82f7Spl  * To support cfgadm, need to confirm the SCSA framework by creating
65830d82f7Spl  * devctl/scsi and driver specific minor nodes under SCSA format,
66830d82f7Spl  * and calling scsi_hba_xxx() functions aacordingly.
67830d82f7Spl  */
687c478bd9Sstevel@tonic-gate 
69830d82f7Spl #define	AAC_MINOR		32
70830d82f7Spl #define	INST2AAC(x)		(((x) << INST_MINOR_SHIFT) | AAC_MINOR)
71830d82f7Spl #define	AAC_SCSA_MINOR(x)	((x) & TRAN_MINOR_MASK)
72830d82f7Spl #define	AAC_IS_SCSA_NODE(x)	((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
737c478bd9Sstevel@tonic-gate 
7458bc78c7SXin Chen #define	SD2TRAN(sd)		((sd)->sd_address.a_hba_tran)
757c478bd9Sstevel@tonic-gate #define	AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
76c9487164Spl #define	AAC_DIP2TRAN(dip)	((scsi_hba_tran_t *)ddi_get_driver_private(dip))
77c9487164Spl #define	AAC_DIP2SOFTS(dip)	(AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
7858bc78c7SXin Chen #define	SD2AAC(sd)		(AAC_TRAN2SOFTS(SD2TRAN(sd)))
7958bc78c7SXin Chen #define	AAC_PD(t)		((t) - AAC_MAX_LD)
8058bc78c7SXin Chen #define	AAC_DEV(softs, t)	(((t) < AAC_MAX_LD) ? \
8158bc78c7SXin Chen 				&(softs)->containers[(t)].dev : \
8258bc78c7SXin Chen 				((t) < AAC_MAX_DEV(softs)) ? \
8358bc78c7SXin Chen 				&(softs)->nondasds[AAC_PD(t)].dev : NULL)
8458bc78c7SXin Chen #define	AAC_DEVCFG_BEGIN(softs, tgt) \
8558bc78c7SXin Chen 				aac_devcfg((softs), (tgt), 1)
8658bc78c7SXin Chen #define	AAC_DEVCFG_END(softs, tgt) \
8758bc78c7SXin Chen 				aac_devcfg((softs), (tgt), 0)
88c9487164Spl #define	PKT2AC(pkt)		((struct aac_cmd *)(pkt)->pkt_ha_private)
89382c8bcaSpl #define	AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
90382c8bcaSpl 		if (!(cond)) { \
91382c8bcaSpl 			int count = (timeout) * 10; \
92382c8bcaSpl 			while (count) { \
93382c8bcaSpl 				drv_usecwait(100); \
94382c8bcaSpl 				if (cond) \
95382c8bcaSpl 					break; \
96382c8bcaSpl 				count--; \
977c478bd9Sstevel@tonic-gate 			} \
98382c8bcaSpl 			(timeout) = (count + 9) / 10; \
997c478bd9Sstevel@tonic-gate 		} \
100382c8bcaSpl 	}
101830d82f7Spl 
102c9487164Spl #define	AAC_SENSE_DATA_DESCR_LEN \
103c9487164Spl 	(sizeof (struct scsi_descr_sense_hdr) + \
104830d82f7Spl 	sizeof (struct scsi_information_sense_descr))
105d7c5bf88Spl #define	AAC_ARQ64_LENGTH \
106d7c5bf88Spl 	(sizeof (struct scsi_arq_status) + \
107d7c5bf88Spl 	AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
108d7c5bf88Spl 
109830d82f7Spl /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
110830d82f7Spl #define	AAC_GETGXADDR(cmdlen, cdbp) \
111830d82f7Spl 	((cmdlen == 6) ? GETG0ADDR(cdbp) : \
112830d82f7Spl 	(cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
113830d82f7Spl 	((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
114830d82f7Spl 
115830d82f7Spl #define	AAC_CDB_INQUIRY_CMDDT	0x02
116830d82f7Spl #define	AAC_CDB_INQUIRY_EVPD	0x01
117830d82f7Spl #define	AAC_VPD_PAGE_CODE	1
118830d82f7Spl #define	AAC_VPD_PAGE_LENGTH	3
119830d82f7Spl #define	AAC_VPD_PAGE_DATA	4
120830d82f7Spl #define	AAC_VPD_ID_CODESET	0
121830d82f7Spl #define	AAC_VPD_ID_TYPE		1
122830d82f7Spl #define	AAC_VPD_ID_LENGTH	3
123830d82f7Spl #define	AAC_VPD_ID_DATA		4
124830d82f7Spl 
12558bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_HEAD_SIZE			0x08
12658bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_SIZE			0x08
12758bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_MASK			0xC0
12858bc78c7SXin Chen /* 00b - peripheral device addressing method */
12958bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL		0x00
13058bc78c7SXin Chen /* 01b - flat space addressing method */
13158bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE		0x40
13258bc78c7SXin Chen /* 10b - logical unit addressing method */
13358bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT		0x80
13458bc78c7SXin Chen 
135942c5e3cSpl /* Return the size of FIB with data part type data_type */
136942c5e3cSpl #define	AAC_FIB_SIZEOF(data_type) \
137942c5e3cSpl 	(sizeof (struct aac_fib_header) + sizeof (data_type))
138942c5e3cSpl /* Return the container size defined in mir */
139942c5e3cSpl #define	AAC_MIR_SIZE(softs, acc, mir) \
140830d82f7Spl 	(((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
141942c5e3cSpl 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
142942c5e3cSpl 	((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
143942c5e3cSpl 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
144830d82f7Spl 
145d937e6ebSpl /* The last entry of aac_cards[] is for unknown cards */
146d937e6ebSpl #define	AAC_UNKNOWN_CARD \
147d937e6ebSpl 	(sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
148d937e6ebSpl #define	CARD_IS_UNKNOWN(i)	(i == AAC_UNKNOWN_CARD)
149d937e6ebSpl #define	BUF_IS_READ(bp)		((bp)->b_flags & B_READ)
150c9487164Spl #define	AAC_IS_Q_EMPTY(q)	((q)->q_head == NULL)
151382c8bcaSpl #define	AAC_CMDQ(acp)		(!((acp)->flags & AAC_CMD_SYNC))
1527c478bd9Sstevel@tonic-gate 
153c9487164Spl #define	PCI_MEM_GET32(softs, off) \
154c9487164Spl 	ddi_get32((softs)->pci_mem_handle, \
155a74f7440Spl 	    (void *)((softs)->pci_mem_base_vaddr + (off)))
156c9487164Spl #define	PCI_MEM_PUT32(softs, off, val) \
157c9487164Spl 	ddi_put32((softs)->pci_mem_handle, \
158a74f7440Spl 	    (void *)((softs)->pci_mem_base_vaddr + (off)), \
1591dd0a2dbSpl 	    (uint32_t)(val))
160942c5e3cSpl #define	PCI_MEM_GET16(softs, off) \
161942c5e3cSpl 	ddi_get16((softs)->pci_mem_handle, \
162a74f7440Spl 	(void *)((softs)->pci_mem_base_vaddr + (off)))
163942c5e3cSpl #define	PCI_MEM_PUT16(softs, off, val) \
164942c5e3cSpl 	ddi_put16((softs)->pci_mem_handle, \
165a74f7440Spl 	(void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
166942c5e3cSpl /* Write host data at valp to device mem[off] repeatedly count times */
1671dd0a2dbSpl #define	PCI_MEM_REP_PUT8(softs, off, valp, count) \
1681dd0a2dbSpl 	ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
1691dd0a2dbSpl 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
1701dd0a2dbSpl 	    count, DDI_DEV_AUTOINCR)
171942c5e3cSpl /* Read device data at mem[off] to host addr valp repeatedly count times */
172942c5e3cSpl #define	PCI_MEM_REP_GET8(softs, off, valp, count) \
173942c5e3cSpl 	ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
174942c5e3cSpl 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
175942c5e3cSpl 	    count, DDI_DEV_AUTOINCR)
176942c5e3cSpl #define	AAC_GET_FIELD8(acc, d, s, field) \
177942c5e3cSpl 	(d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
178942c5e3cSpl #define	AAC_GET_FIELD32(acc, d, s, field) \
179942c5e3cSpl 	(d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
180942c5e3cSpl #define	AAC_GET_FIELD64(acc, d, s, field) \
181942c5e3cSpl 	(d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
182942c5e3cSpl #define	AAC_REP_GET_FIELD8(acc, d, s, field, r) \
183942c5e3cSpl 	ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
184942c5e3cSpl 	    (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
185942c5e3cSpl #define	AAC_REP_GET_FIELD32(acc, d, s, field, r) \
186942c5e3cSpl 	ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
187942c5e3cSpl 	    (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
1887c478bd9Sstevel@tonic-gate 
189382c8bcaSpl #define	AAC_ENABLE_INTR(softs) { \
190830d82f7Spl 		if (softs->flags & AAC_FLAGS_NEW_COMM) \
191830d82f7Spl 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
192830d82f7Spl 		else \
193830d82f7Spl 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
1941ee13a44SXinChen 		softs->state |= AAC_STATE_INTR; \
195382c8bcaSpl 	}
196382c8bcaSpl 
1971ee13a44SXinChen #define	AAC_DISABLE_INTR(softs)	{ \
1981ee13a44SXinChen 		PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
1991ee13a44SXinChen 		softs->state &= ~AAC_STATE_INTR; \
2001ee13a44SXinChen 	}
201c9487164Spl #define	AAC_STATUS_CLR(softs, mask)	PCI_MEM_PUT32(softs, AAC_ODBR, mask)
202c9487164Spl #define	AAC_STATUS_GET(softs)		PCI_MEM_GET32(softs, AAC_ODBR)
203c9487164Spl #define	AAC_NOTIFY(softs, val)		PCI_MEM_PUT32(softs, AAC_IDBR, val)
204c9487164Spl #define	AAC_OUTB_GET(softs)		PCI_MEM_GET32(softs, AAC_OQUE)
205c9487164Spl #define	AAC_OUTB_SET(softs, val)	PCI_MEM_PUT32(softs, AAC_OQUE, val)
206830d82f7Spl #define	AAC_FWSTATUS_GET(softs)	\
207c9487164Spl 	((softs)->aac_if.aif_get_fwstatus(softs))
208830d82f7Spl #define	AAC_MAILBOX_GET(softs, mb) \
209830d82f7Spl 	((softs)->aac_if.aif_get_mailbox((softs), (mb)))
210830d82f7Spl #define	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
211830d82f7Spl 	((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
212c9487164Spl 	    (arg0), (arg1), (arg2), (arg3)))
213830d82f7Spl 
214f42c2f53Szhongyan gu - Sun Microsystems - Beijing China #define	AAC_MGT_SLOT_NUM	2
215382c8bcaSpl #define	AAC_THROTTLE_DRAIN	-1
216382c8bcaSpl 
217382c8bcaSpl #define	AAC_QUIESCE_TICK	1	/* 1 second */
21858bc78c7SXin Chen #define	AAC_QUIESCE_TIMEOUT	180	/* 180 seconds */
219382c8bcaSpl #define	AAC_DEFAULT_TICK	10	/* 10 seconds */
220942c5e3cSpl #define	AAC_SYNC_TICK		(30*60)	/* 30 minutes */
221832e0b5aSpl 
222d7c5bf88Spl /* Poll time for aac_do_poll_io() */
223382c8bcaSpl #define	AAC_POLL_TIME		60	/* 60 seconds */
224d7c5bf88Spl 
22558bc78c7SXin Chen /* IOP reset */
22658bc78c7SXin Chen #define	AAC_IOP_RESET_SUCCEED		0	/* IOP reset succeed */
22758bc78c7SXin Chen #define	AAC_IOP_RESET_FAILED		-1	/* IOP reset failed */
22858bc78c7SXin Chen #define	AAC_IOP_RESET_ABNORMAL		-2	/* Reset operation abnormal */
22958bc78c7SXin Chen 
230d937e6ebSpl /*
231d937e6ebSpl  * Hardware access functions
232d937e6ebSpl  */
233830d82f7Spl static int aac_rx_get_fwstatus(struct aac_softstate *);
234830d82f7Spl static int aac_rx_get_mailbox(struct aac_softstate *, int);
235942c5e3cSpl static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
236942c5e3cSpl     uint32_t, uint32_t, uint32_t);
237830d82f7Spl static int aac_rkt_get_fwstatus(struct aac_softstate *);
238830d82f7Spl static int aac_rkt_get_mailbox(struct aac_softstate *, int);
239830d82f7Spl static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
240c9487164Spl     uint32_t, uint32_t, uint32_t);
241830d82f7Spl 
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate  * SCSA function prototypes
2447c478bd9Sstevel@tonic-gate  */
2457c478bd9Sstevel@tonic-gate static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
2467c478bd9Sstevel@tonic-gate static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
247830d82f7Spl static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
24819397407SSherry Moore static int aac_quiesce(dev_info_t *);
249f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /*
252d7c5bf88Spl  * Interrupt handler functions
2537c478bd9Sstevel@tonic-gate  */
254b6094a86Sjd static int aac_query_intrs(struct aac_softstate *, int);
255b6094a86Sjd static int aac_add_intrs(struct aac_softstate *);
256b6094a86Sjd static void aac_remove_intrs(struct aac_softstate *);
257f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_enable_intrs(struct aac_softstate *);
258f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_disable_intrs(struct aac_softstate *);
259b4a8b33bSToomas Soome static uint_t aac_intr_old(caddr_t, caddr_t);
260b4a8b33bSToomas Soome static uint_t aac_intr_new(caddr_t, caddr_t);
2617c478bd9Sstevel@tonic-gate static uint_t aac_softintr(caddr_t);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /*
264d7c5bf88Spl  * Internal functions in attach
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate static int aac_check_card_type(struct aac_softstate *);
267830d82f7Spl static int aac_check_firmware(struct aac_softstate *);
2687c478bd9Sstevel@tonic-gate static int aac_common_attach(struct aac_softstate *);
269830d82f7Spl static void aac_common_detach(struct aac_softstate *);
270942c5e3cSpl static int aac_probe_containers(struct aac_softstate *);
271830d82f7Spl static int aac_alloc_comm_space(struct aac_softstate *);
2727c478bd9Sstevel@tonic-gate static int aac_setup_comm_space(struct aac_softstate *);
273830d82f7Spl static void aac_free_comm_space(struct aac_softstate *);
2747c478bd9Sstevel@tonic-gate static int aac_hba_setup(struct aac_softstate *);
2757c478bd9Sstevel@tonic-gate 
276d937e6ebSpl /*
277d937e6ebSpl  * Sync FIB operation functions
278d937e6ebSpl  */
279d937e6ebSpl int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
280c9487164Spl     uint32_t, uint32_t, uint32_t, uint32_t *);
281942c5e3cSpl static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
284382c8bcaSpl  * Command queue operation functions
2857c478bd9Sstevel@tonic-gate  */
286382c8bcaSpl static void aac_cmd_initq(struct aac_cmd_queue *);
2877c478bd9Sstevel@tonic-gate static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
2887c478bd9Sstevel@tonic-gate static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
289382c8bcaSpl static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /*
292c9487164Spl  * FIB queue operation functions
2937c478bd9Sstevel@tonic-gate  */
294d7c5bf88Spl static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
295d7c5bf88Spl static int aac_fib_dequeue(struct aac_softstate *, int, int *);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*
298c9487164Spl  * Slot operation functions
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate static int aac_create_slots(struct aac_softstate *);
3017c478bd9Sstevel@tonic-gate static void aac_destroy_slots(struct aac_softstate *);
302942c5e3cSpl static void aac_alloc_fibs(struct aac_softstate *);
303d7c5bf88Spl static void aac_destroy_fibs(struct aac_softstate *);
3047c478bd9Sstevel@tonic-gate static struct aac_slot *aac_get_slot(struct aac_softstate *);
305830d82f7Spl static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
306830d82f7Spl static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
307830d82f7Spl static void aac_free_fib(struct aac_slot *);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
310d7c5bf88Spl  * Internal functions
3117c478bd9Sstevel@tonic-gate  */
312f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
313f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     uint16_t);
314942c5e3cSpl static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
315942c5e3cSpl static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
316942c5e3cSpl static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
317942c5e3cSpl static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
318942c5e3cSpl static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
319942c5e3cSpl static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
320b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
3217c478bd9Sstevel@tonic-gate static void aac_start_waiting_io(struct aac_softstate *);
3227c478bd9Sstevel@tonic-gate static void aac_drain_comp_q(struct aac_softstate *);
323d7c5bf88Spl int aac_do_io(struct aac_softstate *, struct aac_cmd *);
324f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
325f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
326f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
3277c478bd9Sstevel@tonic-gate static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
328382c8bcaSpl static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
329d937e6ebSpl static int aac_send_command(struct aac_softstate *, struct aac_slot *);
33058bc78c7SXin Chen static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
3317675db54Syw static int aac_dma_sync_ac(struct aac_cmd *);
332830d82f7Spl static int aac_shutdown(struct aac_softstate *);
333830d82f7Spl static int aac_reset_adapter(struct aac_softstate *);
334382c8bcaSpl static int aac_do_quiesce(struct aac_softstate *softs);
335382c8bcaSpl static int aac_do_unquiesce(struct aac_softstate *softs);
336382c8bcaSpl static void aac_unhold_bus(struct aac_softstate *, int);
33758bc78c7SXin Chen static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
338382c8bcaSpl     int, int);
339830d82f7Spl 
340830d82f7Spl /*
341d937e6ebSpl  * Adapter Initiated FIB handling function
342830d82f7Spl  */
3430749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
3440749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib *, int);
3450749e8deSXin Chen - Sun Microsystems - Beijing China static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3480749e8deSXin Chen - Sun Microsystems - Beijing China  * Event handling related functions
3497c478bd9Sstevel@tonic-gate  */
3500749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_timer(void *);
3510749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_event_thread(struct aac_softstate *);
3520749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_event_disp(struct aac_softstate *, int);
3537c478bd9Sstevel@tonic-gate 
354830d82f7Spl /*
355d937e6ebSpl  * IOCTL interface related functions
356830d82f7Spl  */
357830d82f7Spl static int aac_open(dev_t *, int, int, cred_t *);
358830d82f7Spl static int aac_close(dev_t, int, int, cred_t *);
359830d82f7Spl static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
360942c5e3cSpl extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
361830d82f7Spl 
3627675db54Syw /*
3637675db54Syw  * FMA Prototypes
3647675db54Syw  */
3657675db54Syw static void aac_fm_init(struct aac_softstate *);
3667675db54Syw static void aac_fm_fini(struct aac_softstate *);
3677675db54Syw static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
3687675db54Syw int aac_check_acc_handle(ddi_acc_handle_t);
3697675db54Syw int aac_check_dma_handle(ddi_dma_handle_t);
3707675db54Syw void aac_fm_ereport(struct aac_softstate *, char *);
3717675db54Syw 
37258bc78c7SXin Chen /*
37358bc78c7SXin Chen  * Auto enumeration functions
37458bc78c7SXin Chen  */
37558bc78c7SXin Chen static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
37658bc78c7SXin Chen static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
37758bc78c7SXin Chen     void *, dev_info_t **);
3780749e8deSXin Chen - Sun Microsystems - Beijing China static int aac_handle_dr(struct aac_softstate *, int, int, int);
3790749e8deSXin Chen - Sun Microsystems - Beijing China 
3800749e8deSXin Chen - Sun Microsystems - Beijing China extern pri_t minclsyspri;
38158bc78c7SXin Chen 
3821dd0a2dbSpl #ifdef DEBUG
3831dd0a2dbSpl /*
3841dd0a2dbSpl  * UART	debug output support
3851dd0a2dbSpl  */
3861dd0a2dbSpl 
3871dd0a2dbSpl #define	AAC_PRINT_BUFFER_SIZE		512
3881dd0a2dbSpl #define	AAC_PRINT_TIMEOUT		250	/* 1/4 sec. = 250 msec. */
3891dd0a2dbSpl 
3901dd0a2dbSpl #define	AAC_FW_DBG_STRLEN_OFFSET	0x00
3911dd0a2dbSpl #define	AAC_FW_DBG_FLAGS_OFFSET		0x04
3921dd0a2dbSpl #define	AAC_FW_DBG_BLED_OFFSET		0x08
3931dd0a2dbSpl 
3941dd0a2dbSpl static int aac_get_fw_debug_buffer(struct aac_softstate *);
3951dd0a2dbSpl static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
3961dd0a2dbSpl static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
3971dd0a2dbSpl 
3981dd0a2dbSpl static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
399942c5e3cSpl static char aac_fmt[] = " %s";
400942c5e3cSpl static char aac_fmt_header[] = " %s.%d: %s";
4011dd0a2dbSpl static kmutex_t aac_prt_mutex;
4021dd0a2dbSpl 
4031dd0a2dbSpl /*
4041dd0a2dbSpl  * Debug flags to be put into the softstate flags field
4051dd0a2dbSpl  * when initialized
4061dd0a2dbSpl  */
4071dd0a2dbSpl uint32_t aac_debug_flags =
4081dd0a2dbSpl /*    AACDB_FLAGS_KERNEL_PRINT | */
4091dd0a2dbSpl /*    AACDB_FLAGS_FW_PRINT |	*/
4101dd0a2dbSpl /*    AACDB_FLAGS_MISC |	*/
4111dd0a2dbSpl /*    AACDB_FLAGS_FUNC1 |	*/
4121dd0a2dbSpl /*    AACDB_FLAGS_FUNC2 |	*/
4131dd0a2dbSpl /*    AACDB_FLAGS_SCMD |	*/
4141dd0a2dbSpl /*    AACDB_FLAGS_AIF |		*/
4151dd0a2dbSpl /*    AACDB_FLAGS_FIB |		*/
4161dd0a2dbSpl /*    AACDB_FLAGS_IOCTL |	*/
4171dd0a2dbSpl 0;
41858bc78c7SXin Chen uint32_t aac_debug_fib_flags =
41958bc78c7SXin Chen /*    AACDB_FLAGS_FIB_RW |	*/
42058bc78c7SXin Chen /*    AACDB_FLAGS_FIB_IOCTL |	*/
42158bc78c7SXin Chen /*    AACDB_FLAGS_FIB_SRB |	*/
42258bc78c7SXin Chen /*    AACDB_FLAGS_FIB_SYNC |	*/
42358bc78c7SXin Chen /*    AACDB_FLAGS_FIB_HEADER |	*/
42458bc78c7SXin Chen /*    AACDB_FLAGS_FIB_TIMEOUT |	*/
42558bc78c7SXin Chen 0;
4261dd0a2dbSpl 
4271dd0a2dbSpl #endif /* DEBUG */
4281dd0a2dbSpl 
429830d82f7Spl static struct cb_ops aac_cb_ops = {
430830d82f7Spl 	aac_open,	/* open */
431830d82f7Spl 	aac_close,	/* close */
432830d82f7Spl 	nodev,		/* strategy */
433830d82f7Spl 	nodev,		/* print */
434830d82f7Spl 	nodev,		/* dump */
435830d82f7Spl 	nodev,		/* read */
436830d82f7Spl 	nodev,		/* write */
437830d82f7Spl 	aac_ioctl,	/* ioctl */
438830d82f7Spl 	nodev,		/* devmap */
439830d82f7Spl 	nodev,		/* mmap */
440830d82f7Spl 	nodev,		/* segmap */
441830d82f7Spl 	nochpoll,	/* poll */
442d7c5bf88Spl 	ddi_prop_op,	/* cb_prop_op */
443830d82f7Spl 	NULL,		/* streamtab */
444830d82f7Spl 	D_64BIT | D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
445830d82f7Spl 	CB_REV,		/* cb_rev */
446830d82f7Spl 	nodev,		/* async I/O read entry point */
447830d82f7Spl 	nodev		/* async I/O write entry point */
448830d82f7Spl };
449830d82f7Spl 
4507c478bd9Sstevel@tonic-gate static struct dev_ops aac_dev_ops = {
4517c478bd9Sstevel@tonic-gate 	DEVO_REV,
4527c478bd9Sstevel@tonic-gate 	0,
453f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_getinfo,
4547c478bd9Sstevel@tonic-gate 	nulldev,
4557c478bd9Sstevel@tonic-gate 	nulldev,
4567c478bd9Sstevel@tonic-gate 	aac_attach,
4577c478bd9Sstevel@tonic-gate 	aac_detach,
458830d82f7Spl 	aac_reset,
459830d82f7Spl 	&aac_cb_ops,
4607c478bd9Sstevel@tonic-gate 	NULL,
46119397407SSherry Moore 	NULL,
46219397407SSherry Moore 	aac_quiesce,
4637c478bd9Sstevel@tonic-gate };
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate static struct modldrv aac_modldrv = {
4667c478bd9Sstevel@tonic-gate 	&mod_driverops,
467832e0b5aSpl 	"AAC Driver " AAC_DRIVER_VERSION,
4687c478bd9Sstevel@tonic-gate 	&aac_dev_ops,
4697c478bd9Sstevel@tonic-gate };
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate static struct modlinkage aac_modlinkage = {
4727c478bd9Sstevel@tonic-gate 	MODREV_1,
4737c478bd9Sstevel@tonic-gate 	&aac_modldrv,
4747c478bd9Sstevel@tonic-gate 	NULL
4757c478bd9Sstevel@tonic-gate };
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate static struct aac_softstate  *aac_softstatep;
4787c478bd9Sstevel@tonic-gate 
479830d82f7Spl /*
480d937e6ebSpl  * Supported card list
481d937e6ebSpl  * ordered in vendor id, subvendor id, subdevice id, and device id
482830d82f7Spl  */
4837c478bd9Sstevel@tonic-gate static struct aac_card_type aac_cards[] = {
484d937e6ebSpl 	{0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
485382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
486382c8bcaSpl 	    "Dell", "PERC 3/Di"},
487d937e6ebSpl 	{0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
488382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
489382c8bcaSpl 	    "Dell", "PERC 3/Di"},
490d937e6ebSpl 	{0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
491382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
492382c8bcaSpl 	    "Dell", "PERC 3/Si"},
493830d82f7Spl 	{0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
494382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
495382c8bcaSpl 	    "Dell", "PERC 3/Di"},
496d937e6ebSpl 	{0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
497382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
498382c8bcaSpl 	    "Dell", "PERC 3/Si"},
499d937e6ebSpl 	{0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
500382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
501382c8bcaSpl 	    "Dell", "PERC 3/Di"},
502830d82f7Spl 	{0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
503382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
504382c8bcaSpl 	    "Dell", "PERC 3/Di"},
505d937e6ebSpl 	{0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
506382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
507382c8bcaSpl 	    "Dell", "PERC 3/Di"},
508d937e6ebSpl 	{0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
509382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
510382c8bcaSpl 	    "Dell", "PERC 3/Di"},
511d937e6ebSpl 	{0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
512382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
513382c8bcaSpl 	    "Dell", "PERC 3/Di"},
514d937e6ebSpl 	{0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
515382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
516c9487164Spl 	    "Dell", "PERC 320/DC"},
517d937e6ebSpl 	{0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
518382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
519d937e6ebSpl 
520d937e6ebSpl 	{0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
521c9487164Spl 	    0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
522d937e6ebSpl 	{0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
523c9487164Spl 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
524d937e6ebSpl 	{0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
525c9487164Spl 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
526830d82f7Spl 
527d937e6ebSpl 	{0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
528382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
529382c8bcaSpl 	{0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
530382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
531d937e6ebSpl 
532d937e6ebSpl 	{0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
533382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
534c9487164Spl 	    "Adaptec", "2200S"},
535d937e6ebSpl 	{0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
536382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
537c9487164Spl 	    "Adaptec", "2120S"},
538830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
539382c8bcaSpl 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
540c9487164Spl 	    "Adaptec", "2200S"},
541830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
542c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
543830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
544c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
545830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
546c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
547830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
548c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
549830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
550c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
551830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
552c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
553830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
554c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
555830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
556c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
557d937e6ebSpl 	{0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
558382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
559830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
560382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
561830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
562382c8bcaSpl 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
563830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
564c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
565830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
566c9487164Spl 	    0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
567830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
568c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
569830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
570c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
571830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
572c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
573830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
574c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
575830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
576c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
577830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
578c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
579830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
580c9487164Spl 	    0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
581830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
582c9487164Spl 	    0, AAC_TYPE_SATA, "ICP", "9024RO"},
583830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
584c9487164Spl 	    0, AAC_TYPE_SATA, "ICP", "9014RO"},
585830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
586c9487164Spl 	    0, AAC_TYPE_SATA, "ICP", "9047MA"},
587830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
588c9487164Spl 	    0, AAC_TYPE_SATA, "ICP", "9087MA"},
589830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
590c9487164Spl 	    0, AAC_TYPE_SAS, "ICP", "9085LI"},
591830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
592c9487164Spl 	    0, AAC_TYPE_SAS, "ICP", "5085BR"},
593830d82f7Spl 	{0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
594c9487164Spl 	    0, AAC_TYPE_SATA, "ICP", "9067MA"},
595830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
596c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
597830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
598c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
599830d82f7Spl 	{0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
600c9487164Spl 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
601832e0b5aSpl 	{0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
602c9487164Spl 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
603832e0b5aSpl 	{0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
604c9487164Spl 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
605832e0b5aSpl 	{0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
606c9487164Spl 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
607830d82f7Spl 
608830d82f7Spl 	{0, 0, 0, 0, AAC_HWIF_UNKNOWN,
609c9487164Spl 	    0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
610c9487164Spl };
611c9487164Spl 
612c9487164Spl /*
613c9487164Spl  * Hardware access functions for i960 based cards
614c9487164Spl  */
615c9487164Spl static struct aac_interface aac_rx_interface = {
616c9487164Spl 	aac_rx_get_fwstatus,
617c9487164Spl 	aac_rx_get_mailbox,
618c9487164Spl 	aac_rx_set_mailbox
619c9487164Spl };
620c9487164Spl 
621c9487164Spl /*
622c9487164Spl  * Hardware access functions for Rocket based cards
623c9487164Spl  */
624c9487164Spl static struct aac_interface aac_rkt_interface = {
625c9487164Spl 	aac_rkt_get_fwstatus,
626c9487164Spl 	aac_rkt_get_mailbox,
627c9487164Spl 	aac_rkt_set_mailbox
6287c478bd9Sstevel@tonic-gate };
6297c478bd9Sstevel@tonic-gate 
630830d82f7Spl ddi_device_acc_attr_t aac_acc_attr = {
631837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
6327c478bd9Sstevel@tonic-gate 	DDI_STRUCTURE_LE_ACC,
633837c1ac4SStephen Hanson 	DDI_STRICTORDER_ACC,
634837c1ac4SStephen Hanson 	DDI_DEFAULT_ACC
6357c478bd9Sstevel@tonic-gate };
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate static struct {
6387c478bd9Sstevel@tonic-gate 	int	size;
6397c478bd9Sstevel@tonic-gate 	int	notify;
6407c478bd9Sstevel@tonic-gate } aac_qinfo[] = {
6417c478bd9Sstevel@tonic-gate 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
6427c478bd9Sstevel@tonic-gate 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
6437c478bd9Sstevel@tonic-gate 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
6447c478bd9Sstevel@tonic-gate 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
6457c478bd9Sstevel@tonic-gate 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
6467c478bd9Sstevel@tonic-gate 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
6477c478bd9Sstevel@tonic-gate 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
6487c478bd9Sstevel@tonic-gate 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
6497c478bd9Sstevel@tonic-gate };
6507c478bd9Sstevel@tonic-gate 
651830d82f7Spl /*
652830d82f7Spl  * Default aac dma attributes
653830d82f7Spl  */
654382c8bcaSpl static ddi_dma_attr_t aac_dma_attr = {
655c9487164Spl 	DMA_ATTR_V0,
656382c8bcaSpl 	0,		/* lowest usable address */
657c9487164Spl 	0xffffffffull,	/* high DMA address range */
658382c8bcaSpl 	0xffffffffull,	/* DMA counter register */
659c9487164Spl 	AAC_DMA_ALIGN,	/* DMA address alignment */
660c9487164Spl 	1,		/* DMA burstsizes */
661c9487164Spl 	1,		/* min effective DMA size */
662c9487164Spl 	0xffffffffull,	/* max DMA xfer size */
663c9487164Spl 	0xffffffffull,	/* segment boundary */
664382c8bcaSpl 	1,		/* s/g list length */
665c9487164Spl 	AAC_BLK_SIZE,	/* granularity of device */
66658bc78c7SXin Chen 	0		/* DMA transfer flags */
66758bc78c7SXin Chen };
66858bc78c7SXin Chen 
669382c8bcaSpl static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
670382c8bcaSpl static uint32_t aac_timebase = 0;	/* internal timer in seconds */
671382c8bcaSpl 
672382c8bcaSpl /*
673382c8bcaSpl  * Warlock directives
674382c8bcaSpl  *
675382c8bcaSpl  * Different variables with the same types have to be protected by the
676382c8bcaSpl  * same mutex; otherwise, warlock will complain with "variables don't
677382c8bcaSpl  * seem to be protected consistently". For example,
678382c8bcaSpl  * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
679382c8bcaSpl  * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
680382c8bcaSpl  * declare them as protected explictly at aac_cmd_dequeue().
681382c8bcaSpl  */
682382c8bcaSpl _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
683382c8bcaSpl     scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
684382c8bcaSpl     mode_format mode_geometry mode_header aac_cmd))
685942c5e3cSpl _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
686942c5e3cSpl     aac_sge))
687382c8bcaSpl _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
688382c8bcaSpl     aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
689382c8bcaSpl     aac_sg_table aac_srb))
690382c8bcaSpl _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
691382c8bcaSpl _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
69258bc78c7SXin Chen _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate int
_init(void)6957c478bd9Sstevel@tonic-gate _init(void)
6967c478bd9Sstevel@tonic-gate {
697c9487164Spl 	int rval = 0;
6987c478bd9Sstevel@tonic-gate 
6991dd0a2dbSpl #ifdef DEBUG
7001dd0a2dbSpl 	mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
7011dd0a2dbSpl #endif
7021dd0a2dbSpl 	DBCALLED(NULL, 1);
703830d82f7Spl 
704c9487164Spl 	if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
705c9487164Spl 	    sizeof (struct aac_softstate), 0)) != 0)
7067c478bd9Sstevel@tonic-gate 		goto error;
7077c478bd9Sstevel@tonic-gate 
708c9487164Spl 	if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
709c9487164Spl 		ddi_soft_state_fini((void *)&aac_softstatep);
7107c478bd9Sstevel@tonic-gate 		goto error;
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
713c9487164Spl 	if ((rval = mod_install(&aac_modlinkage)) != 0) {
714c9487164Spl 		ddi_soft_state_fini((void *)&aac_softstatep);
7157c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&aac_modlinkage);
7167c478bd9Sstevel@tonic-gate 		goto error;
7177c478bd9Sstevel@tonic-gate 	}
718c9487164Spl 	return (rval);
719830d82f7Spl 
7207c478bd9Sstevel@tonic-gate error:
7211dd0a2dbSpl 	AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
7221dd0a2dbSpl #ifdef DEBUG
7231dd0a2dbSpl 	mutex_destroy(&aac_prt_mutex);
7241dd0a2dbSpl #endif
725c9487164Spl 	return (rval);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)7297c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
7307c478bd9Sstevel@tonic-gate {
7311dd0a2dbSpl 	DBCALLED(NULL, 1);
7327c478bd9Sstevel@tonic-gate 	return (mod_info(&aac_modlinkage, modinfop));
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*
736830d82f7Spl  * An HBA driver cannot be unload unless you reboot,
737830d82f7Spl  * so this function will be of no use.
7387c478bd9Sstevel@tonic-gate  */
7397c478bd9Sstevel@tonic-gate int
_fini(void)7407c478bd9Sstevel@tonic-gate _fini(void)
7417c478bd9Sstevel@tonic-gate {
742c9487164Spl 	int rval;
7437c478bd9Sstevel@tonic-gate 
7441dd0a2dbSpl 	DBCALLED(NULL, 1);
745830d82f7Spl 
746c9487164Spl 	if ((rval = mod_remove(&aac_modlinkage)) != 0)
7477c478bd9Sstevel@tonic-gate 		goto error;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	scsi_hba_fini(&aac_modlinkage);
750c9487164Spl 	ddi_soft_state_fini((void *)&aac_softstatep);
7511dd0a2dbSpl #ifdef DEBUG
7521dd0a2dbSpl 	mutex_destroy(&aac_prt_mutex);
7531dd0a2dbSpl #endif
7547c478bd9Sstevel@tonic-gate 	return (0);
755830d82f7Spl 
7567c478bd9Sstevel@tonic-gate error:
7571dd0a2dbSpl 	AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
758c9487164Spl 	return (rval);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate static int
aac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)7627c478bd9Sstevel@tonic-gate aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7637c478bd9Sstevel@tonic-gate {
764382c8bcaSpl 	int instance, i;
7651dd0a2dbSpl 	struct aac_softstate *softs = NULL;
7667c478bd9Sstevel@tonic-gate 	int attach_state = 0;
76758bc78c7SXin Chen 	char *data;
7687c478bd9Sstevel@tonic-gate 
7691dd0a2dbSpl 	DBCALLED(NULL, 1);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	switch (cmd) {
772830d82f7Spl 	case DDI_ATTACH:
773830d82f7Spl 		break;
774830d82f7Spl 	case DDI_RESUME:
775830d82f7Spl 		return (DDI_FAILURE);
776830d82f7Spl 	default:
777830d82f7Spl 		return (DDI_FAILURE);
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7817c478bd9Sstevel@tonic-gate 
782830d82f7Spl 	/* Get soft state */
7837c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
7841dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
7857c478bd9Sstevel@tonic-gate 		goto error;
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 	softs = ddi_get_soft_state(aac_softstatep, instance);
788d937e6ebSpl 	attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
7897c478bd9Sstevel@tonic-gate 
790382c8bcaSpl 	softs->instance = instance;
791d937e6ebSpl 	softs->devinfo_p = dip;
792382c8bcaSpl 	softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
793382c8bcaSpl 	softs->addr_dma_attr.dma_attr_granular = 1;
79458bc78c7SXin Chen 	softs->acc_attr = aac_acc_attr;
795837c1ac4SStephen Hanson 	softs->reg_attr = aac_acc_attr;
796d937e6ebSpl 	softs->card = AAC_UNKNOWN_CARD;
7971dd0a2dbSpl #ifdef DEBUG
7981dd0a2dbSpl 	softs->debug_flags = aac_debug_flags;
79958bc78c7SXin Chen 	softs->debug_fib_flags = aac_debug_fib_flags;
8001dd0a2dbSpl #endif
801830d82f7Spl 
80258bc78c7SXin Chen 	/* Initialize FMA */
80358bc78c7SXin Chen 	aac_fm_init(softs);
80458bc78c7SXin Chen 
805830d82f7Spl 	/* Check the card type */
806d937e6ebSpl 	if (aac_check_card_type(softs) == AACERR) {
8071dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "Card not supported");
8087c478bd9Sstevel@tonic-gate 		goto error;
809830d82f7Spl 	}
810830d82f7Spl 	/* We have found the right card and everything is OK */
811830d82f7Spl 	attach_state |= AAC_ATTACH_CARD_DETECTED;
812830d82f7Spl 
813830d82f7Spl 	/* Map PCI mem space */
814830d82f7Spl 	if (ddi_regs_map_setup(dip, 1,
8151dd0a2dbSpl 	    (caddr_t *)&softs->pci_mem_base_vaddr, 0,
816837c1ac4SStephen Hanson 	    softs->map_size_min, &softs->reg_attr,
817c9487164Spl 	    &softs->pci_mem_handle) != DDI_SUCCESS)
818830d82f7Spl 		goto error;
819830d82f7Spl 
820830d82f7Spl 	softs->map_size = softs->map_size_min;
821830d82f7Spl 	attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	AAC_DISABLE_INTR(softs);
8247c478bd9Sstevel@tonic-gate 
825f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Init mutexes and condvars */
8260749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
8270749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8280749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
8290749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8300749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
8310749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8320749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
8330749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8340749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->aifq_mutex, NULL,
835b6094a86Sjd 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
836830d82f7Spl 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
8371ee13a44SXinChen 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
838382c8bcaSpl 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
8390749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
8400749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
8410749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
842830d82f7Spl 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
843830d82f7Spl 
844f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Init the cmd queues */
845f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	for (i = 0; i < AAC_CMDQ_NUM; i++)
846f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_cmd_initq(&softs->q_wait[i]);
847f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_initq(&softs->q_busy);
848f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_initq(&softs->q_comp);
849f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
85058bc78c7SXin Chen 	/* Check for legacy device naming support */
85158bc78c7SXin Chen 	softs->legacy = 1; /* default to use legacy name */
85258bc78c7SXin Chen 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
85358bc78c7SXin Chen 	    "legacy-name-enable", &data) == DDI_SUCCESS)) {
85458bc78c7SXin Chen 		if (strcmp(data, "no") == 0) {
85558bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
85658bc78c7SXin Chen 			softs->legacy = 0;
85758bc78c7SXin Chen 		}
85858bc78c7SXin Chen 		ddi_prop_free(data);
85958bc78c7SXin Chen 	}
86058bc78c7SXin Chen 
861830d82f7Spl 	/*
862830d82f7Spl 	 * Everything has been set up till now,
863830d82f7Spl 	 * we will do some common attach.
864830d82f7Spl 	 */
865f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
866f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_common_attach(softs) == AACERR) {
867f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		mutex_exit(&softs->io_lock);
868830d82f7Spl 		goto error;
869f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
870f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
871830d82f7Spl 	attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
872830d82f7Spl 
87372888e72Speng liu - Sun Microsystems - Beijing China 	/* Check for buf breakup support */
87472888e72Speng liu - Sun Microsystems - Beijing China 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
87572888e72Speng liu - Sun Microsystems - Beijing China 	    "breakup-enable", &data) == DDI_SUCCESS)) {
87672888e72Speng liu - Sun Microsystems - Beijing China 		if (strcmp(data, "yes") == 0) {
87772888e72Speng liu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
87872888e72Speng liu - Sun Microsystems - Beijing China 			softs->flags |= AAC_FLAGS_BRKUP;
87972888e72Speng liu - Sun Microsystems - Beijing China 		}
88072888e72Speng liu - Sun Microsystems - Beijing China 		ddi_prop_free(data);
88172888e72Speng liu - Sun Microsystems - Beijing China 	}
88272888e72Speng liu - Sun Microsystems - Beijing China 	softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
88372888e72Speng liu - Sun Microsystems - Beijing China 	if (softs->flags & AAC_FLAGS_BRKUP) {
88472888e72Speng liu - Sun Microsystems - Beijing China 		softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
88572888e72Speng liu - Sun Microsystems - Beijing China 		    DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
88672888e72Speng liu - Sun Microsystems - Beijing China 	}
88772888e72Speng liu - Sun Microsystems - Beijing China 
888830d82f7Spl 	if (aac_hba_setup(softs) != AACOK)
889830d82f7Spl 		goto error;
890830d82f7Spl 	attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
8917c478bd9Sstevel@tonic-gate 
892830d82f7Spl 	/* Create devctl/scsi nodes for cfgadm */
893830d82f7Spl 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
894c9487164Spl 	    INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
8951dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
8967c478bd9Sstevel@tonic-gate 		goto error;
897830d82f7Spl 	}
898830d82f7Spl 	attach_state |= AAC_ATTACH_CREATE_DEVCTL;
8997c478bd9Sstevel@tonic-gate 
900c9487164Spl 	if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
901c9487164Spl 	    DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
9021dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
9037c478bd9Sstevel@tonic-gate 		goto error;
904830d82f7Spl 	}
905830d82f7Spl 	attach_state |= AAC_ATTACH_CREATE_SCSI;
906830d82f7Spl 
907c9487164Spl 	/* Create aac node for app. to issue ioctls */
908c9487164Spl 	if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
909c9487164Spl 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
9101dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
911830d82f7Spl 		goto error;
912830d82f7Spl 	}
9137c478bd9Sstevel@tonic-gate 
9140749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Common attach is OK, so we are attached! */
9150749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->state |= AAC_STATE_RUN;
9160749e8deSXin Chen - Sun Microsystems - Beijing China 
9170749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Create event thread */
9180749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->fibctx_p = &softs->aifctx;
9190749e8deSXin Chen - Sun Microsystems - Beijing China 	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
9200749e8deSXin Chen - Sun Microsystems - Beijing China 	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
9210749e8deSXin Chen - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
9220749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->state &= ~AAC_STATE_RUN;
92358bc78c7SXin Chen 		goto error;
92458bc78c7SXin Chen 	}
92558bc78c7SXin Chen 
926382c8bcaSpl 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
927382c8bcaSpl 
928830d82f7Spl 	/* Create a thread for command timeout */
9290749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->timeout_id = timeout(aac_timer, (void *)softs,
9300749e8deSXin Chen - Sun Microsystems - Beijing China 	    (aac_tick * drv_usectohz(1000000)));
931830d82f7Spl 
932830d82f7Spl 	/* Common attach is OK, so we are attached! */
9337c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
9341dd0a2dbSpl 	AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
9357c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate error:
938830d82f7Spl 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
939830d82f7Spl 		ddi_remove_minor_node(dip, "scsi");
940830d82f7Spl 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
941830d82f7Spl 		ddi_remove_minor_node(dip, "devctl");
942830d82f7Spl 	if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
943830d82f7Spl 		aac_common_detach(softs);
944830d82f7Spl 	if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
9457c478bd9Sstevel@tonic-gate 		(void) scsi_hba_detach(dip);
946c9487164Spl 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
9477c478bd9Sstevel@tonic-gate 	}
948830d82f7Spl 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
9490749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->io_lock);
950382c8bcaSpl 		mutex_destroy(&softs->q_comp_mutex);
9510749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->time_mutex);
9520749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->ev_lock);
9530749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->aifq_mutex);
954830d82f7Spl 		cv_destroy(&softs->event);
9551ee13a44SXinChen 		cv_destroy(&softs->sync_fib_cv);
956382c8bcaSpl 		cv_destroy(&softs->drain_cv);
9570749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->event_wait_cv);
9580749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->event_disp_cv);
9590749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->aifq_cv);
9607c478bd9Sstevel@tonic-gate 	}
961830d82f7Spl 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
9627c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&softs->pci_mem_handle);
9637675db54Syw 	aac_fm_fini(softs);
964830d82f7Spl 	if (attach_state & AAC_ATTACH_CARD_DETECTED)
9657c478bd9Sstevel@tonic-gate 		softs->card = AACERR;
966830d82f7Spl 	if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
9677c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(aac_softstatep, instance);
9687c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
9697c478bd9Sstevel@tonic-gate }
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate static int
aac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)9727c478bd9Sstevel@tonic-gate aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9737c478bd9Sstevel@tonic-gate {
974c9487164Spl 	scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
975c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
9767c478bd9Sstevel@tonic-gate 
9771dd0a2dbSpl 	DBCALLED(softs, 1);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	switch (cmd) {
980830d82f7Spl 	case DDI_DETACH:
981830d82f7Spl 		break;
982830d82f7Spl 	case DDI_SUSPEND:
983830d82f7Spl 		return (DDI_FAILURE);
984830d82f7Spl 	default:
985830d82f7Spl 		return (DDI_FAILURE);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
988382c8bcaSpl 	mutex_enter(&softs->io_lock);
989382c8bcaSpl 	AAC_DISABLE_INTR(softs);
990830d82f7Spl 	softs->state = AAC_STATE_STOPPED;
991382c8bcaSpl 
992382c8bcaSpl 	ddi_remove_minor_node(dip, "aac");
993382c8bcaSpl 	ddi_remove_minor_node(dip, "scsi");
994382c8bcaSpl 	ddi_remove_minor_node(dip, "devctl");
995382c8bcaSpl 	mutex_exit(&softs->io_lock);
996830d82f7Spl 
997830d82f7Spl 	aac_common_detach(softs);
998830d82f7Spl 
999f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
10007c478bd9Sstevel@tonic-gate 	(void) scsi_hba_detach(dip);
10017c478bd9Sstevel@tonic-gate 	scsi_hba_tran_free(tran);
1002f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
1003382c8bcaSpl 
10040749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Stop timer */
10050749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
10060749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->timeout_id) {
10070749e8deSXin Chen - Sun Microsystems - Beijing China 		timeout_id_t tid = softs->timeout_id;
10080749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->timeout_id = 0;
10090749e8deSXin Chen - Sun Microsystems - Beijing China 
10100749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->time_mutex);
10110749e8deSXin Chen - Sun Microsystems - Beijing China 		(void) untimeout(tid);
10120749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_enter(&softs->time_mutex);
10130749e8deSXin Chen - Sun Microsystems - Beijing China 	}
10140749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
10150749e8deSXin Chen - Sun Microsystems - Beijing China 
10160749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Destroy event thread */
10170749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
10180749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_signal(&softs->event_disp_cv);
10190749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
10200749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
10210749e8deSXin Chen - Sun Microsystems - Beijing China 
10220749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->aifq_cv);
10230749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event_disp_cv);
10240749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event_wait_cv);
10250749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->drain_cv);
10261ee13a44SXinChen 	cv_destroy(&softs->sync_fib_cv);
10270749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event);
1028830d82f7Spl 	mutex_destroy(&softs->aifq_mutex);
10290749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->ev_lock);
10300749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->time_mutex);
10310749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->q_comp_mutex);
1032382c8bcaSpl 	mutex_destroy(&softs->io_lock);
1033830d82f7Spl 
10347c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&softs->pci_mem_handle);
10357675db54Syw 	aac_fm_fini(softs);
1036d937e6ebSpl 	softs->hwif = AAC_HWIF_UNKNOWN;
1037d937e6ebSpl 	softs->card = AAC_UNKNOWN_CARD;
1038c9487164Spl 	ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate 
1043830d82f7Spl /*ARGSUSED*/
1044830d82f7Spl static int
aac_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)1045830d82f7Spl aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
1046830d82f7Spl {
1047c9487164Spl 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1048830d82f7Spl 
10491dd0a2dbSpl 	DBCALLED(softs, 1);
1050830d82f7Spl 
1051942c5e3cSpl 	mutex_enter(&softs->io_lock);
10521ee13a44SXinChen 	AAC_DISABLE_INTR(softs);
1053830d82f7Spl 	(void) aac_shutdown(softs);
1054942c5e3cSpl 	mutex_exit(&softs->io_lock);
1055830d82f7Spl 
1056830d82f7Spl 	return (DDI_SUCCESS);
1057830d82f7Spl }
1058830d82f7Spl 
105919397407SSherry Moore /*
106019397407SSherry Moore  * quiesce(9E) entry point.
106119397407SSherry Moore  *
106219397407SSherry Moore  * This function is called when the system is single-threaded at high
106319397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
106419397407SSherry Moore  * blocked.
106519397407SSherry Moore  *
106619397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
106719397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
106819397407SSherry Moore  */
106919397407SSherry Moore static int
aac_quiesce(dev_info_t * dip)107019397407SSherry Moore aac_quiesce(dev_info_t *dip)
107119397407SSherry Moore {
107219397407SSherry Moore 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
107319397407SSherry Moore 
107419397407SSherry Moore 	if (softs == NULL)
107519397407SSherry Moore 		return (DDI_FAILURE);
107619397407SSherry Moore 
10770749e8deSXin Chen - Sun Microsystems - Beijing China 	_NOTE(ASSUMING_PROTECTED(softs->state))
107819397407SSherry Moore 	AAC_DISABLE_INTR(softs);
107919397407SSherry Moore 
108019397407SSherry Moore 	return (DDI_SUCCESS);
108119397407SSherry Moore }
108219397407SSherry Moore 
1083f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /* ARGSUSED */
1084f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_getinfo(dev_info_t * self,ddi_info_cmd_t infocmd,void * arg,void ** result)1085f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
1086f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     void **result)
1087f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1088f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int error = DDI_SUCCESS;
1089f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1090f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	switch (infocmd) {
1091f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	case DDI_INFO_DEVT2INSTANCE:
1092f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		*result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
1093f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		break;
1094f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	default:
1095f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		error = DDI_FAILURE;
1096f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1097f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (error);
1098f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1099f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1100830d82f7Spl /*
1101830d82f7Spl  * Bring the controller down to a dormant state and detach all child devices.
1102830d82f7Spl  * This function is called before detach or system shutdown.
1103830d82f7Spl  * Note: we can assume that the q_wait on the controller is empty, as we
1104830d82f7Spl  * won't allow shutdown if any device is open.
1105830d82f7Spl  */
1106830d82f7Spl static int
aac_shutdown(struct aac_softstate * softs)1107830d82f7Spl aac_shutdown(struct aac_softstate *softs)
1108830d82f7Spl {
1109f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
1110f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_close_command *cc;
1111c9487164Spl 	int rval;
1112830d82f7Spl 
1113f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
1114f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
1115f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1116f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
1117f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1118942c5e3cSpl 	ddi_put32(acc, &cc->Command, VM_CloseAll);
1119942c5e3cSpl 	ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
1120830d82f7Spl 
1121c9487164Spl 	/* Flush all caches, set FW to write through mode */
1122942c5e3cSpl 	rval = aac_sync_fib(softs, ContainerCommand,
1123942c5e3cSpl 	    AAC_FIB_SIZEOF(struct aac_close_command));
1124f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
1125830d82f7Spl 
11261dd0a2dbSpl 	AACDB_PRINT(softs, CE_NOTE,
11271dd0a2dbSpl 	    "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
1128c9487164Spl 	return (rval);
1129830d82f7Spl }
1130830d82f7Spl 
11317c478bd9Sstevel@tonic-gate static uint_t
aac_softintr(caddr_t arg)11327c478bd9Sstevel@tonic-gate aac_softintr(caddr_t arg)
11337c478bd9Sstevel@tonic-gate {
1134a74f7440Spl 	struct aac_softstate *softs = (void *)arg;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
11377c478bd9Sstevel@tonic-gate 		aac_drain_comp_q(softs);
1138c9487164Spl 	}
1139f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (DDI_INTR_CLAIMED);
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
1142830d82f7Spl /*
1143830d82f7Spl  * Setup auto sense data for pkt
1144830d82f7Spl  */
1145d937e6ebSpl static void
aac_set_arq_data(struct scsi_pkt * pkt,uchar_t key,uchar_t add_code,uchar_t qual_code,uint64_t info)1146830d82f7Spl aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
1147c9487164Spl     uchar_t add_code, uchar_t qual_code, uint64_t info)
11487c478bd9Sstevel@tonic-gate {
114958bc78c7SXin Chen 	struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
11507c478bd9Sstevel@tonic-gate 
115158bc78c7SXin Chen 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
115258bc78c7SXin Chen 	pkt->pkt_state |= STATE_ARQ_DONE;
1153830d82f7Spl 
115458bc78c7SXin Chen 	*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
11557c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
11567c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_resid = 0;
1157830d82f7Spl 	arqstat->sts_rqpkt_state =
1158c9487164Spl 	    STATE_GOT_BUS |
1159c9487164Spl 	    STATE_GOT_TARGET |
1160c9487164Spl 	    STATE_SENT_CMD |
1161c9487164Spl 	    STATE_XFERRED_DATA;
11627c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_statistics = 0;
1163830d82f7Spl 
1164c9487164Spl 	if (info <= 0xfffffffful) {
1165830d82f7Spl 		arqstat->sts_sensedata.es_valid = 1;
1166830d82f7Spl 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1167830d82f7Spl 		arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
1168830d82f7Spl 		arqstat->sts_sensedata.es_key = key;
1169830d82f7Spl 		arqstat->sts_sensedata.es_add_code = add_code;
1170830d82f7Spl 		arqstat->sts_sensedata.es_qual_code = qual_code;
1171830d82f7Spl 
1172830d82f7Spl 		arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
1173830d82f7Spl 		arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
1174830d82f7Spl 		arqstat->sts_sensedata.es_info_3 = (info >>  8) & 0xFF;
1175830d82f7Spl 		arqstat->sts_sensedata.es_info_4 = info & 0xFF;
1176830d82f7Spl 	} else { /* 64-bit LBA */
1177830d82f7Spl 		struct scsi_descr_sense_hdr *dsp;
1178830d82f7Spl 		struct scsi_information_sense_descr *isd;
1179830d82f7Spl 
1180830d82f7Spl 		dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
1181830d82f7Spl 		dsp->ds_class = CLASS_EXTENDED_SENSE;
1182830d82f7Spl 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
1183830d82f7Spl 		dsp->ds_key = key;
1184830d82f7Spl 		dsp->ds_add_code = add_code;
1185830d82f7Spl 		dsp->ds_qual_code = qual_code;
1186830d82f7Spl 		dsp->ds_addl_sense_length =
1187c9487164Spl 		    sizeof (struct scsi_information_sense_descr);
1188830d82f7Spl 
1189830d82f7Spl 		isd = (struct scsi_information_sense_descr *)(dsp+1);
1190830d82f7Spl 		isd->isd_descr_type = DESCR_INFORMATION;
1191830d82f7Spl 		isd->isd_valid = 1;
1192830d82f7Spl 		isd->isd_information[0] = (info >> 56) & 0xFF;
1193830d82f7Spl 		isd->isd_information[1] = (info >> 48) & 0xFF;
1194830d82f7Spl 		isd->isd_information[2] = (info >> 40) & 0xFF;
1195830d82f7Spl 		isd->isd_information[3] = (info >> 32) & 0xFF;
1196830d82f7Spl 		isd->isd_information[4] = (info >> 24) & 0xFF;
1197830d82f7Spl 		isd->isd_information[5] = (info >> 16) & 0xFF;
1198830d82f7Spl 		isd->isd_information[6] = (info >>  8) & 0xFF;
1199830d82f7Spl 		isd->isd_information[7] = (info) & 0xFF;
1200830d82f7Spl 	}
1201830d82f7Spl }
1202830d82f7Spl 
1203830d82f7Spl /*
1204830d82f7Spl  * Setup auto sense data for HARDWARE ERROR
1205830d82f7Spl  */
1206830d82f7Spl static void
aac_set_arq_data_hwerr(struct aac_cmd * acp)1207830d82f7Spl aac_set_arq_data_hwerr(struct aac_cmd *acp)
1208830d82f7Spl {
1209830d82f7Spl 	union scsi_cdb *cdbp;
1210830d82f7Spl 	uint64_t err_blkno;
1211830d82f7Spl 
1212a74f7440Spl 	cdbp = (void *)acp->pkt->pkt_cdbp;
1213830d82f7Spl 	err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
1214830d82f7Spl 	aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
1215830d82f7Spl }
1216830d82f7Spl 
1217830d82f7Spl /*
1218830d82f7Spl  * Send a command to the adapter in New Comm. interface
1219830d82f7Spl  */
1220830d82f7Spl static int
aac_send_command(struct aac_softstate * softs,struct aac_slot * slotp)1221830d82f7Spl aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
1222830d82f7Spl {
1223830d82f7Spl 	uint32_t index, device;
1224830d82f7Spl 
1225830d82f7Spl 	index = PCI_MEM_GET32(softs, AAC_IQUE);
1226942c5e3cSpl 	if (index == 0xffffffffUL) {
1227830d82f7Spl 		index = PCI_MEM_GET32(softs, AAC_IQUE);
1228942c5e3cSpl 		if (index == 0xffffffffUL)
1229942c5e3cSpl 			return (AACERR);
1230942c5e3cSpl 	}
1231830d82f7Spl 
1232830d82f7Spl 	device = index;
1233830d82f7Spl 	PCI_MEM_PUT32(softs, device,
1234c9487164Spl 	    (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
1235830d82f7Spl 	device += 4;
1236830d82f7Spl 	PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
1237830d82f7Spl 	device += 4;
1238942c5e3cSpl 	PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
1239830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_IQUE, index);
1240830d82f7Spl 	return (AACOK);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate 
1243382c8bcaSpl static void
aac_end_io(struct aac_softstate * softs,struct aac_cmd * acp)1244382c8bcaSpl aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
1245382c8bcaSpl {
124658bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
1247382c8bcaSpl 	int q = AAC_CMDQ(acp);
1248382c8bcaSpl 
1249382c8bcaSpl 	if (acp->slotp) { /* outstanding cmd */
1250f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
1251f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			aac_release_slot(softs, acp->slotp);
1252f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			acp->slotp = NULL;
1253f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1254382c8bcaSpl 		if (dvp) {
1255382c8bcaSpl 			dvp->ncmds[q]--;
1256382c8bcaSpl 			if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
1257382c8bcaSpl 			    dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
1258382c8bcaSpl 				aac_set_throttle(softs, dvp, q,
1259382c8bcaSpl 				    softs->total_slots);
1260f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			/*
1261f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Setup auto sense data for UNIT ATTENTION
1262f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Each lun should generate a unit attention
1263f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * condition when reset.
1264f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Phys. drives are treated as logical ones
1265f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * during error recovery.
1266f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 */
1267f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (dvp->type == AAC_DEV_LD) {
1268f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				struct aac_container *ctp =
1269f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    (struct aac_container *)dvp;
1270f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				if (ctp->reset == 0)
1271f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 					goto noreset;
1272f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1273f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				AACDB_PRINT(softs, CE_NOTE,
1274f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    "Unit attention: reset");
1275f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				ctp->reset = 0;
1276f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
1277f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    0x29, 0x02, 0);
1278f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			}
1279382c8bcaSpl 		}
1280f42c2f53Szhongyan gu - Sun Microsystems - Beijing China noreset:
1281382c8bcaSpl 		softs->bus_ncmds[q]--;
1282f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_cmd_delete(&softs->q_busy, acp);
1283382c8bcaSpl 	} else { /* cmd in waiting queue */
1284382c8bcaSpl 		aac_cmd_delete(&softs->q_wait[q], acp);
1285382c8bcaSpl 	}
1286382c8bcaSpl 
1287382c8bcaSpl 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
1288382c8bcaSpl 		mutex_enter(&softs->q_comp_mutex);
1289382c8bcaSpl 		aac_cmd_enqueue(&softs->q_comp, acp);
1290382c8bcaSpl 		mutex_exit(&softs->q_comp_mutex);
1291382c8bcaSpl 	} else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
1292382c8bcaSpl 		cv_broadcast(&softs->event);
1293382c8bcaSpl 	}
1294382c8bcaSpl }
1295382c8bcaSpl 
1296d7c5bf88Spl static void
aac_handle_io(struct aac_softstate * softs,int index)1297d7c5bf88Spl aac_handle_io(struct aac_softstate *softs, int index)
1298d7c5bf88Spl {
1299d7c5bf88Spl 	struct aac_slot *slotp;
1300d7c5bf88Spl 	struct aac_cmd *acp;
1301d7c5bf88Spl 	uint32_t fast;
1302d7c5bf88Spl 
1303d7c5bf88Spl 	fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
1304d7c5bf88Spl 	index >>= 2;
1305d7c5bf88Spl 
1306d7c5bf88Spl 	/* Make sure firmware reported index is valid */
1307d7c5bf88Spl 	ASSERT(index >= 0 && index < softs->total_slots);
1308d7c5bf88Spl 	slotp = &softs->io_slot[index];
1309d7c5bf88Spl 	ASSERT(slotp->index == index);
1310d7c5bf88Spl 	acp = slotp->acp;
131158bc78c7SXin Chen 
131258bc78c7SXin Chen 	if (acp == NULL || acp->slotp != slotp) {
131358bc78c7SXin Chen 		cmn_err(CE_WARN,
131458bc78c7SXin Chen 		    "Firmware error: invalid slot index received from FW");
131558bc78c7SXin Chen 		return;
131658bc78c7SXin Chen 	}
1317d7c5bf88Spl 
1318382c8bcaSpl 	acp->flags |= AAC_CMD_CMPLT;
1319d7c5bf88Spl 	(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
1320d7c5bf88Spl 
1321382c8bcaSpl 	if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
1322382c8bcaSpl 		/*
1323382c8bcaSpl 		 * For fast response IO, the firmware do not return any FIB
1324382c8bcaSpl 		 * data, so we need to fill in the FIB status and state so that
1325382c8bcaSpl 		 * FIB users can handle it correctly.
1326382c8bcaSpl 		 */
1327382c8bcaSpl 		if (fast) {
1328382c8bcaSpl 			uint32_t state;
13297675db54Syw 
1330942c5e3cSpl 			state = ddi_get32(slotp->fib_acc_handle,
1331942c5e3cSpl 			    &slotp->fibp->Header.XferState);
1332382c8bcaSpl 			/*
1333382c8bcaSpl 			 * Update state for CPU not for device, no DMA sync
1334382c8bcaSpl 			 * needed
1335382c8bcaSpl 			 */
1336942c5e3cSpl 			ddi_put32(slotp->fib_acc_handle,
1337942c5e3cSpl 			    &slotp->fibp->Header.XferState,
1338942c5e3cSpl 			    state | AAC_FIBSTATE_DONEADAP);
1339942c5e3cSpl 			ddi_put32(slotp->fib_acc_handle,
1340a74f7440Spl 			    (void *)&slotp->fibp->data[0], ST_OK);
1341382c8bcaSpl 		}
1342d7c5bf88Spl 
1343382c8bcaSpl 		/* Handle completed ac */
1344382c8bcaSpl 		acp->ac_comp(softs, acp);
1345382c8bcaSpl 	} else {
1346382c8bcaSpl 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1347382c8bcaSpl 		acp->flags |= AAC_CMD_ERR;
1348382c8bcaSpl 		if (acp->pkt) {
1349382c8bcaSpl 			acp->pkt->pkt_reason = CMD_TRAN_ERR;
1350382c8bcaSpl 			acp->pkt->pkt_statistics = 0;
1351382c8bcaSpl 		}
1352d7c5bf88Spl 	}
1353382c8bcaSpl 	aac_end_io(softs, acp);
1354d7c5bf88Spl }
1355d7c5bf88Spl 
1356830d82f7Spl /*
1357830d82f7Spl  * Interrupt handler for New Comm. interface
1358830d82f7Spl  * New Comm. interface use a different mechanism for interrupt. No explict
1359830d82f7Spl  * message queues, and driver need only accesses the mapped PCI mem space to
1360830d82f7Spl  * find the completed FIB or AIF.
1361830d82f7Spl  */
1362382c8bcaSpl static int
aac_process_intr_new(struct aac_softstate * softs)1363382c8bcaSpl aac_process_intr_new(struct aac_softstate *softs)
13647c478bd9Sstevel@tonic-gate {
1365c9487164Spl 	uint32_t index;
1366830d82f7Spl 
1367830d82f7Spl 	index = AAC_OUTB_GET(softs);
1368c9487164Spl 	if (index == 0xfffffffful)
1369830d82f7Spl 		index = AAC_OUTB_GET(softs);
13707675db54Syw 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
13717675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
137258bc78c7SXin Chen 		return (0);
13737675db54Syw 	}
1374382c8bcaSpl 	if (index != 0xfffffffful) {
1375382c8bcaSpl 		do {
1376382c8bcaSpl 			if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
1377382c8bcaSpl 				aac_handle_io(softs, index);
1378382c8bcaSpl 			} else if (index != 0xfffffffeul) {
1379382c8bcaSpl 				struct aac_fib *fibp;	/* FIB in AIF queue */
13800749e8deSXin Chen - Sun Microsystems - Beijing China 				uint16_t fib_size;
1381830d82f7Spl 
1382382c8bcaSpl 				/*
1383382c8bcaSpl 				 * 0xfffffffe means that the controller wants
1384382c8bcaSpl 				 * more work, ignore it for now. Otherwise,
1385382c8bcaSpl 				 * AIF received.
1386382c8bcaSpl 				 */
1387382c8bcaSpl 				index &= ~2;
1388382c8bcaSpl 
13890749e8deSXin Chen - Sun Microsystems - Beijing China 				fibp = (struct aac_fib *)(softs-> \
13900749e8deSXin Chen - Sun Microsystems - Beijing China 				    pci_mem_base_vaddr + index);
13910749e8deSXin Chen - Sun Microsystems - Beijing China 				fib_size = PCI_MEM_GET16(softs, index + \
1392942c5e3cSpl 				    offsetof(struct aac_fib, Header.Size));
13930749e8deSXin Chen - Sun Microsystems - Beijing China 
13940749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_save_aif(softs, softs->pci_mem_handle,
13950749e8deSXin Chen - Sun Microsystems - Beijing China 				    fibp, fib_size);
1396382c8bcaSpl 
1397382c8bcaSpl 				/*
1398382c8bcaSpl 				 * AIF memory is owned by the adapter, so let it
1399382c8bcaSpl 				 * know that we are done with it.
1400382c8bcaSpl 				 */
1401382c8bcaSpl 				AAC_OUTB_SET(softs, index);
1402382c8bcaSpl 				AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1403382c8bcaSpl 			}
1404382c8bcaSpl 
1405382c8bcaSpl 			index = AAC_OUTB_GET(softs);
1406382c8bcaSpl 		} while (index != 0xfffffffful);
1407382c8bcaSpl 
1408382c8bcaSpl 		/*
1409382c8bcaSpl 		 * Process waiting cmds before start new ones to
1410382c8bcaSpl 		 * ensure first IOs are serviced first.
1411382c8bcaSpl 		 */
1412382c8bcaSpl 		aac_start_waiting_io(softs);
1413382c8bcaSpl 		return (AAC_DB_COMMAND_READY);
1414382c8bcaSpl 	} else {
1415382c8bcaSpl 		return (0);
1416382c8bcaSpl 	}
1417382c8bcaSpl }
1418382c8bcaSpl 
1419382c8bcaSpl static uint_t
aac_intr_new(caddr_t arg,caddr_t arg1 __unused)1420b4a8b33bSToomas Soome aac_intr_new(caddr_t arg, caddr_t arg1 __unused)
1421382c8bcaSpl {
1422a74f7440Spl 	struct aac_softstate *softs = (void *)arg;
1423382c8bcaSpl 	uint_t rval;
1424382c8bcaSpl 
1425382c8bcaSpl 	mutex_enter(&softs->io_lock);
1426382c8bcaSpl 	if (aac_process_intr_new(softs))
1427382c8bcaSpl 		rval = DDI_INTR_CLAIMED;
1428382c8bcaSpl 	else
1429382c8bcaSpl 		rval = DDI_INTR_UNCLAIMED;
1430382c8bcaSpl 	mutex_exit(&softs->io_lock);
1431830d82f7Spl 
1432382c8bcaSpl 	aac_drain_comp_q(softs);
1433382c8bcaSpl 	return (rval);
1434830d82f7Spl }
1435830d82f7Spl 
1436830d82f7Spl /*
1437830d82f7Spl  * Interrupt handler for old interface
1438830d82f7Spl  * Explicit message queues are used to send FIB to and get completed FIB from
1439830d82f7Spl  * the adapter. Driver and adapter maitain the queues in the producer/consumer
1440830d82f7Spl  * manner. The driver has to query the queues to find the completed FIB.
1441830d82f7Spl  */
1442382c8bcaSpl static int
aac_process_intr_old(struct aac_softstate * softs)1443382c8bcaSpl aac_process_intr_old(struct aac_softstate *softs)
1444830d82f7Spl {
14457c478bd9Sstevel@tonic-gate 	uint16_t status;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	status = AAC_STATUS_GET(softs);
14487675db54Syw 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
14497675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
14507675db54Syw 		return (DDI_INTR_UNCLAIMED);
14517675db54Syw 	}
1452830d82f7Spl 	if (status & AAC_DB_RESPONSE_READY) {
1453d7c5bf88Spl 		int slot_idx;
1454d7c5bf88Spl 
1455830d82f7Spl 		/* ACK the intr */
14567c478bd9Sstevel@tonic-gate 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
14577c478bd9Sstevel@tonic-gate 		(void) AAC_STATUS_GET(softs);
1458382c8bcaSpl 		while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
1459382c8bcaSpl 		    &slot_idx) == AACOK)
1460382c8bcaSpl 			aac_handle_io(softs, slot_idx);
1461830d82f7Spl 
1462382c8bcaSpl 		/*
1463382c8bcaSpl 		 * Process waiting cmds before start new ones to
1464382c8bcaSpl 		 * ensure first IOs are serviced first.
1465382c8bcaSpl 		 */
14667c478bd9Sstevel@tonic-gate 		aac_start_waiting_io(softs);
1467382c8bcaSpl 		return (AAC_DB_RESPONSE_READY);
14687c478bd9Sstevel@tonic-gate 	} else if (status & AAC_DB_COMMAND_READY) {
1469d7c5bf88Spl 		int aif_idx;
1470d7c5bf88Spl 
14717c478bd9Sstevel@tonic-gate 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
14727c478bd9Sstevel@tonic-gate 		(void) AAC_STATUS_GET(softs);
1473382c8bcaSpl 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
1474382c8bcaSpl 		    AACOK) {
1475942c5e3cSpl 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
14760749e8deSXin Chen - Sun Microsystems - Beijing China 			struct aac_fib *fibp;	/* FIB in communication space */
14770749e8deSXin Chen - Sun Microsystems - Beijing China 			uint16_t fib_size;
1478942c5e3cSpl 			uint32_t fib_xfer_state;
1479d7c5bf88Spl 			uint32_t addr, size;
1480d7c5bf88Spl 
1481d7c5bf88Spl 			ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
1482382c8bcaSpl 
1483942c5e3cSpl #define	AAC_SYNC_AIF(softs, aif_idx, type) \
1484942c5e3cSpl 	{ (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
1485942c5e3cSpl 	    offsetof(struct aac_comm_space, \
1486942c5e3cSpl 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
1487942c5e3cSpl 	    (type)); }
1488942c5e3cSpl 
1489942c5e3cSpl 			/* Copy AIF from adapter to the empty AIF slot */
1490942c5e3cSpl 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
14910749e8deSXin Chen - Sun Microsystems - Beijing China 			fibp = &softs->comm_space->adapter_fibs[aif_idx];
14920749e8deSXin Chen - Sun Microsystems - Beijing China 			fib_size = ddi_get16(acc, &fibp->Header.Size);
1493942c5e3cSpl 
14940749e8deSXin Chen - Sun Microsystems - Beijing China 			aac_save_aif(softs, acc, fibp, fib_size);
1495d7c5bf88Spl 
1496d7c5bf88Spl 			/* Complete AIF back to adapter with good status */
1497942c5e3cSpl 			fib_xfer_state = LE_32(fibp->Header.XferState);
1498942c5e3cSpl 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
14990749e8deSXin Chen - Sun Microsystems - Beijing China 				ddi_put32(acc, &fibp->Header.XferState,
1500942c5e3cSpl 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
15010749e8deSXin Chen - Sun Microsystems - Beijing China 				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
15020749e8deSXin Chen - Sun Microsystems - Beijing China 				if (fib_size > AAC_FIB_SIZE)
15030749e8deSXin Chen - Sun Microsystems - Beijing China 					ddi_put16(acc, &fibp->Header.Size,
1504942c5e3cSpl 					    AAC_FIB_SIZE);
1505942c5e3cSpl 				AAC_SYNC_AIF(softs, aif_idx,
1506942c5e3cSpl 				    DDI_DMA_SYNC_FORDEV);
1507d7c5bf88Spl 			}
1508d7c5bf88Spl 
1509d7c5bf88Spl 			/* Put the AIF response on the response queue */
1510942c5e3cSpl 			addr = ddi_get32(acc,
1511942c5e3cSpl 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1512942c5e3cSpl 			    Header.SenderFibAddress);
1513942c5e3cSpl 			size = (uint32_t)ddi_get16(acc,
1514942c5e3cSpl 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1515942c5e3cSpl 			    Header.Size);
1516942c5e3cSpl 			ddi_put32(acc,
1517942c5e3cSpl 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1518942c5e3cSpl 			    Header.ReceiverFibAddress, addr);
1519d7c5bf88Spl 			if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
1520d7c5bf88Spl 			    addr, size) == AACERR)
1521830d82f7Spl 				cmn_err(CE_NOTE, "!AIF ack failed");
1522830d82f7Spl 		}
1523382c8bcaSpl 		return (AAC_DB_COMMAND_READY);
1524382c8bcaSpl 	} else if (status & AAC_DB_PRINTF_READY) {
1525382c8bcaSpl 		/* ACK the intr */
1526382c8bcaSpl 		AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
1527382c8bcaSpl 		(void) AAC_STATUS_GET(softs);
1528382c8bcaSpl 		(void) ddi_dma_sync(softs->comm_space_dma_handle,
1529942c5e3cSpl 		    offsetof(struct aac_comm_space, adapter_print_buf),
1530382c8bcaSpl 		    AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
1531382c8bcaSpl 		if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
1532382c8bcaSpl 		    DDI_SUCCESS)
1533382c8bcaSpl 			cmn_err(CE_NOTE, "MSG From Adapter: %s",
1534382c8bcaSpl 			    softs->comm_space->adapter_print_buf);
1535382c8bcaSpl 		else
1536382c8bcaSpl 			ddi_fm_service_impact(softs->devinfo_p,
1537382c8bcaSpl 			    DDI_SERVICE_UNAFFECTED);
1538382c8bcaSpl 		AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
1539382c8bcaSpl 		return (AAC_DB_PRINTF_READY);
1540830d82f7Spl 	} else if (status & AAC_DB_COMMAND_NOT_FULL) {
1541830d82f7Spl 		/*
1542830d82f7Spl 		 * Without these two condition statements, the OS could hang
1543830d82f7Spl 		 * after a while, especially if there are a lot of AIF's to
1544830d82f7Spl 		 * handle, for instance if a drive is pulled from an array
1545830d82f7Spl 		 * under heavy load.
1546830d82f7Spl 		 */
1547830d82f7Spl 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1548382c8bcaSpl 		return (AAC_DB_COMMAND_NOT_FULL);
1549830d82f7Spl 	} else if (status & AAC_DB_RESPONSE_NOT_FULL) {
1550830d82f7Spl 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1551830d82f7Spl 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
1552382c8bcaSpl 		return (AAC_DB_RESPONSE_NOT_FULL);
1553c9487164Spl 	} else {
1554382c8bcaSpl 		return (0);
1555c9487164Spl 	}
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate 
1558382c8bcaSpl static uint_t
aac_intr_old(caddr_t arg,caddr_t arg1 __unused)1559b4a8b33bSToomas Soome aac_intr_old(caddr_t arg, caddr_t arg1 __unused)
1560382c8bcaSpl {
1561a74f7440Spl 	struct aac_softstate *softs = (void *)arg;
1562382c8bcaSpl 	int rval;
1563382c8bcaSpl 
1564382c8bcaSpl 	mutex_enter(&softs->io_lock);
1565382c8bcaSpl 	if (aac_process_intr_old(softs))
1566382c8bcaSpl 		rval = DDI_INTR_CLAIMED;
1567382c8bcaSpl 	else
1568382c8bcaSpl 		rval = DDI_INTR_UNCLAIMED;
1569382c8bcaSpl 	mutex_exit(&softs->io_lock);
1570382c8bcaSpl 
1571382c8bcaSpl 	aac_drain_comp_q(softs);
1572382c8bcaSpl 	return (rval);
1573382c8bcaSpl }
1574382c8bcaSpl 
1575b6094a86Sjd /*
1576b6094a86Sjd  * Query FIXED or MSI interrupts
1577b6094a86Sjd  */
1578b6094a86Sjd static int
aac_query_intrs(struct aac_softstate * softs,int intr_type)1579b6094a86Sjd aac_query_intrs(struct aac_softstate *softs, int intr_type)
1580b6094a86Sjd {
1581b6094a86Sjd 	dev_info_t *dip = softs->devinfo_p;
1582f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int avail, actual, count;
1583b6094a86Sjd 	int i, flag, ret;
1584b6094a86Sjd 
1585b6094a86Sjd 	AACDB_PRINT(softs, CE_NOTE,
1586b6094a86Sjd 	    "aac_query_intrs:interrupt type 0x%x", intr_type);
1587b6094a86Sjd 
1588b6094a86Sjd 	/* Get number of interrupts */
1589b6094a86Sjd 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
1590b6094a86Sjd 	if ((ret != DDI_SUCCESS) || (count == 0)) {
1591b6094a86Sjd 		AACDB_PRINT(softs, CE_WARN,
1592b6094a86Sjd 		    "ddi_intr_get_nintrs() failed, ret %d count %d",
1593b6094a86Sjd 		    ret, count);
1594b6094a86Sjd 		return (DDI_FAILURE);
1595b6094a86Sjd 	}
1596b6094a86Sjd 
1597b6094a86Sjd 	/* Get number of available interrupts */
1598b6094a86Sjd 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
1599b6094a86Sjd 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
1600b6094a86Sjd 		AACDB_PRINT(softs, CE_WARN,
1601b6094a86Sjd 		    "ddi_intr_get_navail() failed, ret %d avail %d",
1602b6094a86Sjd 		    ret, avail);
1603b6094a86Sjd 		return (DDI_FAILURE);
1604b6094a86Sjd 	}
1605b6094a86Sjd 
1606b6094a86Sjd 	AACDB_PRINT(softs, CE_NOTE,
1607b6094a86Sjd 	    "ddi_intr_get_nvail returned %d, navail() returned %d",
1608b6094a86Sjd 	    count, avail);
1609b6094a86Sjd 
1610b6094a86Sjd 	/* Allocate an array of interrupt handles */
1611f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	softs->intr_size = count * sizeof (ddi_intr_handle_t);
1612f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
1613b6094a86Sjd 
1614b6094a86Sjd 	if (intr_type == DDI_INTR_TYPE_MSI) {
1615b6094a86Sjd 		count = 1; /* only one vector needed by now */
1616b6094a86Sjd 		flag = DDI_INTR_ALLOC_STRICT;
1617b6094a86Sjd 	} else { /* must be DDI_INTR_TYPE_FIXED */
1618b6094a86Sjd 		flag = DDI_INTR_ALLOC_NORMAL;
1619b6094a86Sjd 	}
1620b6094a86Sjd 
1621b6094a86Sjd 	/* Call ddi_intr_alloc() */
1622b6094a86Sjd 	ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
1623b6094a86Sjd 	    count, &actual, flag);
1624b6094a86Sjd 
1625b6094a86Sjd 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
1626b6094a86Sjd 		AACDB_PRINT(softs, CE_WARN,
1627b6094a86Sjd 		    "ddi_intr_alloc() failed, ret = %d", ret);
1628b6094a86Sjd 		actual = 0;
1629b6094a86Sjd 		goto error;
1630b6094a86Sjd 	}
1631b6094a86Sjd 
1632b6094a86Sjd 	if (actual < count) {
1633b6094a86Sjd 		AACDB_PRINT(softs, CE_NOTE,
1634b6094a86Sjd 		    "Requested: %d, Received: %d", count, actual);
1635b6094a86Sjd 		goto error;
1636b6094a86Sjd 	}
1637b6094a86Sjd 
1638b6094a86Sjd 	softs->intr_cnt = actual;
1639b6094a86Sjd 
1640b6094a86Sjd 	/* Get priority for first msi, assume remaining are all the same */
1641b6094a86Sjd 	if ((ret = ddi_intr_get_pri(softs->htable[0],
1642b6094a86Sjd 	    &softs->intr_pri)) != DDI_SUCCESS) {
1643b6094a86Sjd 		AACDB_PRINT(softs, CE_WARN,
1644b6094a86Sjd 		    "ddi_intr_get_pri() failed, ret = %d", ret);
1645b6094a86Sjd 		goto error;
1646b6094a86Sjd 	}
1647b6094a86Sjd 
1648b6094a86Sjd 	/* Test for high level mutex */
1649b6094a86Sjd 	if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
1650b6094a86Sjd 		AACDB_PRINT(softs, CE_WARN,
1651b6094a86Sjd 		    "aac_query_intrs: Hi level interrupt not supported");
1652b6094a86Sjd 		goto error;
1653b6094a86Sjd 	}
1654b6094a86Sjd 
1655b6094a86Sjd 	return (DDI_SUCCESS);
1656b6094a86Sjd 
1657b6094a86Sjd error:
1658b6094a86Sjd 	/* Free already allocated intr */
1659b6094a86Sjd 	for (i = 0; i < actual; i++)
1660b6094a86Sjd 		(void) ddi_intr_free(softs->htable[i]);
1661b6094a86Sjd 
1662f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	kmem_free(softs->htable, softs->intr_size);
1663b6094a86Sjd 	return (DDI_FAILURE);
1664b6094a86Sjd }
1665b6094a86Sjd 
1666349b53ddSStuart Maybee 
1667b6094a86Sjd /*
1668b6094a86Sjd  * Register FIXED or MSI interrupts, and enable them
1669b6094a86Sjd  */
1670b6094a86Sjd static int
aac_add_intrs(struct aac_softstate * softs)1671b6094a86Sjd aac_add_intrs(struct aac_softstate *softs)
1672b6094a86Sjd {
1673b6094a86Sjd 	int i, ret;
1674f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int actual;
1675b6094a86Sjd 	ddi_intr_handler_t *aac_intr;
1676b6094a86Sjd 
1677b6094a86Sjd 	actual = softs->intr_cnt;
1678b4a8b33bSToomas Soome 	aac_intr = ((softs->flags & AAC_FLAGS_NEW_COMM) ?
1679b6094a86Sjd 	    aac_intr_new : aac_intr_old);
1680b6094a86Sjd 
1681b6094a86Sjd 	/* Call ddi_intr_add_handler() */
1682b6094a86Sjd 	for (i = 0; i < actual; i++) {
1683b6094a86Sjd 		if ((ret = ddi_intr_add_handler(softs->htable[i],
1684b6094a86Sjd 		    aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
1685b6094a86Sjd 			cmn_err(CE_WARN,
1686b6094a86Sjd 			    "ddi_intr_add_handler() failed ret = %d", ret);
1687b6094a86Sjd 
1688b6094a86Sjd 			/* Free already allocated intr */
1689b6094a86Sjd 			for (i = 0; i < actual; i++)
1690b6094a86Sjd 				(void) ddi_intr_free(softs->htable[i]);
1691b6094a86Sjd 
1692f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			kmem_free(softs->htable, softs->intr_size);
1693b6094a86Sjd 			return (DDI_FAILURE);
1694b6094a86Sjd 		}
1695b6094a86Sjd 	}
1696b6094a86Sjd 
1697b6094a86Sjd 	if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
1698b6094a86Sjd 	    != DDI_SUCCESS) {
1699b6094a86Sjd 		cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
1700b6094a86Sjd 
1701b6094a86Sjd 		/* Free already allocated intr */
1702b6094a86Sjd 		for (i = 0; i < actual; i++)
1703b6094a86Sjd 			(void) ddi_intr_free(softs->htable[i]);
1704b6094a86Sjd 
1705f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		kmem_free(softs->htable, softs->intr_size);
1706b6094a86Sjd 		return (DDI_FAILURE);
1707b6094a86Sjd 	}
1708b6094a86Sjd 
1709b6094a86Sjd 	return (DDI_SUCCESS);
1710b6094a86Sjd }
1711b6094a86Sjd 
1712b6094a86Sjd /*
1713b6094a86Sjd  * Unregister FIXED or MSI interrupts
1714b6094a86Sjd  */
1715b6094a86Sjd static void
aac_remove_intrs(struct aac_softstate * softs)1716b6094a86Sjd aac_remove_intrs(struct aac_softstate *softs)
1717b6094a86Sjd {
1718b6094a86Sjd 	int i;
1719b6094a86Sjd 
1720b6094a86Sjd 	/* Disable all interrupts */
1721f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_disable_intrs(softs);
1722b6094a86Sjd 	/* Call ddi_intr_remove_handler() */
1723b6094a86Sjd 	for (i = 0; i < softs->intr_cnt; i++) {
1724b6094a86Sjd 		(void) ddi_intr_remove_handler(softs->htable[i]);
1725b6094a86Sjd 		(void) ddi_intr_free(softs->htable[i]);
1726b6094a86Sjd 	}
1727b6094a86Sjd 
1728f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	kmem_free(softs->htable, softs->intr_size);
1729f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1730f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1731f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_enable_intrs(struct aac_softstate * softs)1732f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_enable_intrs(struct aac_softstate *softs)
1733f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1734f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval = AACOK;
1735f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1736f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1737f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* for MSI block enable */
1738f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
1739f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    DDI_SUCCESS)
1740f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
1741f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
1742f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		int i;
1743f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1744f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* Call ddi_intr_enable() for legacy/MSI non block enable */
1745f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		for (i = 0; i < softs->intr_cnt; i++) {
1746f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
1747f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				rval = AACERR;
1748f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1749f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1750f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
1751f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1752f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1753f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_disable_intrs(struct aac_softstate * softs)1754f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_disable_intrs(struct aac_softstate *softs)
1755f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1756f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval = AACOK;
1757f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1758f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1759f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* Call ddi_intr_block_disable() */
1760f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
1761f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    DDI_SUCCESS)
1762f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
1763f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
1764f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		int i;
1765f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1766f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		for (i = 0; i < softs->intr_cnt; i++) {
1767f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
1768f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				rval = AACERR;
1769f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1770f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1771f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
1772b6094a86Sjd }
1773b6094a86Sjd 
1774d7c5bf88Spl /*
1775d7c5bf88Spl  * Set pkt_reason and OR in pkt_statistics flag
1776d7c5bf88Spl  */
1777d7c5bf88Spl static void
aac_set_pkt_reason(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason,uint_t stat)1778d7c5bf88Spl aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
1779d7c5bf88Spl     uchar_t reason, uint_t stat)
1780d7c5bf88Spl {
1781382c8bcaSpl #ifndef __lock_lint
1782d7c5bf88Spl 	_NOTE(ARGUNUSED(softs))
1783382c8bcaSpl #endif
1784d7c5bf88Spl 	if (acp->pkt->pkt_reason == CMD_CMPLT)
1785d7c5bf88Spl 		acp->pkt->pkt_reason = reason;
1786d7c5bf88Spl 	acp->pkt->pkt_statistics |= stat;
1787d7c5bf88Spl }
1788d7c5bf88Spl 
1789830d82f7Spl /*
1790d7c5bf88Spl  * Handle a finished pkt of soft SCMD
1791830d82f7Spl  */
1792830d82f7Spl static void
aac_soft_callback(struct aac_softstate * softs,struct aac_cmd * acp)1793d7c5bf88Spl aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
1794830d82f7Spl {
1795d7c5bf88Spl 	ASSERT(acp->pkt);
1796830d82f7Spl 
1797d7c5bf88Spl 	acp->flags |= AAC_CMD_CMPLT;
1798830d82f7Spl 
1799d7c5bf88Spl 	acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
180058bc78c7SXin Chen 	    STATE_SENT_CMD | STATE_GOT_STATUS;
1801d7c5bf88Spl 	if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
1802d7c5bf88Spl 		acp->pkt->pkt_resid = 0;
1803830d82f7Spl 
1804d7c5bf88Spl 	/* AAC_CMD_NO_INTR means no complete callback */
1805c9487164Spl 	if (!(acp->flags & AAC_CMD_NO_INTR)) {
1806382c8bcaSpl 		mutex_enter(&softs->q_comp_mutex);
1807c9487164Spl 		aac_cmd_enqueue(&softs->q_comp, acp);
1808382c8bcaSpl 		mutex_exit(&softs->q_comp_mutex);
1809830d82f7Spl 		ddi_trigger_softintr(softs->softint_id);
1810830d82f7Spl 	}
1811830d82f7Spl }
1812830d82f7Spl 
1813830d82f7Spl /*
1814c9487164Spl  * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
1815830d82f7Spl  */
1816d7c5bf88Spl 
1817d7c5bf88Spl /*
1818d7c5bf88Spl  * Handle completed logical device IO command
1819d7c5bf88Spl  */
1820382c8bcaSpl /*ARGSUSED*/
1821830d82f7Spl static void
aac_ld_complete(struct aac_softstate * softs,struct aac_cmd * acp)1822d7c5bf88Spl aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1823830d82f7Spl {
1824d7c5bf88Spl 	struct aac_slot *slotp = acp->slotp;
1825d7c5bf88Spl 	struct aac_blockread_response *resp;
1826942c5e3cSpl 	uint32_t status;
1827830d82f7Spl 
1828382c8bcaSpl 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1829382c8bcaSpl 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1830382c8bcaSpl 
183158bc78c7SXin Chen 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
183258bc78c7SXin Chen 
1833d7c5bf88Spl 	/*
1834d7c5bf88Spl 	 * block_read/write has a similar response header, use blockread
1835d7c5bf88Spl 	 * response for both.
1836d7c5bf88Spl 	 */
1837382c8bcaSpl 	resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
1838942c5e3cSpl 	status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
1839942c5e3cSpl 	if (status == ST_OK) {
1840382c8bcaSpl 		acp->pkt->pkt_resid = 0;
1841382c8bcaSpl 		acp->pkt->pkt_state |= STATE_XFERRED_DATA;
1842d7c5bf88Spl 	} else {
1843382c8bcaSpl 		aac_set_arq_data_hwerr(acp);
1844d7c5bf88Spl 	}
1845d7c5bf88Spl }
1846832e0b5aSpl 
184758bc78c7SXin Chen /*
184858bc78c7SXin Chen  * Handle completed phys. device IO command
184958bc78c7SXin Chen  */
185058bc78c7SXin Chen static void
aac_pd_complete(struct aac_softstate * softs,struct aac_cmd * acp)185158bc78c7SXin Chen aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
185258bc78c7SXin Chen {
185358bc78c7SXin Chen 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
185458bc78c7SXin Chen 	struct aac_fib *fibp = acp->slotp->fibp;
185558bc78c7SXin Chen 	struct scsi_pkt *pkt = acp->pkt;
185658bc78c7SXin Chen 	struct aac_srb_reply *resp;
185758bc78c7SXin Chen 	uint32_t resp_status;
185858bc78c7SXin Chen 
185958bc78c7SXin Chen 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
186058bc78c7SXin Chen 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
186158bc78c7SXin Chen 
186258bc78c7SXin Chen 	resp = (struct aac_srb_reply *)&fibp->data[0];
186358bc78c7SXin Chen 	resp_status = ddi_get32(acc, &resp->status);
186458bc78c7SXin Chen 
186558bc78c7SXin Chen 	/* First check FIB status */
186658bc78c7SXin Chen 	if (resp_status == ST_OK) {
186758bc78c7SXin Chen 		uint32_t scsi_status;
186858bc78c7SXin Chen 		uint32_t srb_status;
186958bc78c7SXin Chen 		uint32_t data_xfer_length;
187058bc78c7SXin Chen 
187158bc78c7SXin Chen 		scsi_status = ddi_get32(acc, &resp->scsi_status);
187258bc78c7SXin Chen 		srb_status = ddi_get32(acc, &resp->srb_status);
187358bc78c7SXin Chen 		data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
187458bc78c7SXin Chen 
187558bc78c7SXin Chen 		*pkt->pkt_scbp = (uint8_t)scsi_status;
187658bc78c7SXin Chen 		pkt->pkt_state |= STATE_GOT_STATUS;
187758bc78c7SXin Chen 		if (scsi_status == STATUS_GOOD) {
187858bc78c7SXin Chen 			uchar_t cmd = ((union scsi_cdb *)(void *)
187958bc78c7SXin Chen 			    (pkt->pkt_cdbp))->scc_cmd;
188058bc78c7SXin Chen 
188158bc78c7SXin Chen 			/* Next check SRB status */
188258bc78c7SXin Chen 			switch (srb_status & 0x3f) {
188358bc78c7SXin Chen 			case SRB_STATUS_DATA_OVERRUN:
188458bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
188558bc78c7SXin Chen 				    "scmd=%d, xfer=%d, buflen=%d",
188658bc78c7SXin Chen 				    (uint32_t)cmd, data_xfer_length,
188758bc78c7SXin Chen 				    acp->bcount);
188858bc78c7SXin Chen 
188958bc78c7SXin Chen 				switch (cmd) {
189058bc78c7SXin Chen 				case SCMD_READ:
189158bc78c7SXin Chen 				case SCMD_WRITE:
189258bc78c7SXin Chen 				case SCMD_READ_G1:
189358bc78c7SXin Chen 				case SCMD_WRITE_G1:
189458bc78c7SXin Chen 				case SCMD_READ_G4:
189558bc78c7SXin Chen 				case SCMD_WRITE_G4:
189658bc78c7SXin Chen 				case SCMD_READ_G5:
189758bc78c7SXin Chen 				case SCMD_WRITE_G5:
189858bc78c7SXin Chen 					aac_set_pkt_reason(softs, acp,
189958bc78c7SXin Chen 					    CMD_DATA_OVR, 0);
190058bc78c7SXin Chen 					break;
190158bc78c7SXin Chen 				}
190258bc78c7SXin Chen 				/*FALLTHRU*/
190358bc78c7SXin Chen 			case SRB_STATUS_ERROR_RECOVERY:
190458bc78c7SXin Chen 			case SRB_STATUS_PENDING:
190558bc78c7SXin Chen 			case SRB_STATUS_SUCCESS:
190658bc78c7SXin Chen 				/*
190758bc78c7SXin Chen 				 * pkt_resid should only be calculated if the
190858bc78c7SXin Chen 				 * status is ERROR_RECOVERY/PENDING/SUCCESS/
190958bc78c7SXin Chen 				 * OVERRUN/UNDERRUN
191058bc78c7SXin Chen 				 */
191158bc78c7SXin Chen 				if (data_xfer_length) {
191258bc78c7SXin Chen 					pkt->pkt_state |= STATE_XFERRED_DATA;
191358bc78c7SXin Chen 					pkt->pkt_resid = acp->bcount - \
191458bc78c7SXin Chen 					    data_xfer_length;
191558bc78c7SXin Chen 					ASSERT(pkt->pkt_resid >= 0);
191658bc78c7SXin Chen 				}
191758bc78c7SXin Chen 				break;
191858bc78c7SXin Chen 			case SRB_STATUS_ABORTED:
191958bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
192058bc78c7SXin Chen 				    "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
192158bc78c7SXin Chen 				    data_xfer_length, pkt->pkt_resid);
192258bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_ABORTED,
192358bc78c7SXin Chen 				    STAT_ABORTED);
192458bc78c7SXin Chen 				break;
192558bc78c7SXin Chen 			case SRB_STATUS_ABORT_FAILED:
192658bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
192758bc78c7SXin Chen 				    "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
192858bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
192958bc78c7SXin Chen 				    pkt->pkt_resid);
193058bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
193158bc78c7SXin Chen 				    0);
193258bc78c7SXin Chen 				break;
193358bc78c7SXin Chen 			case SRB_STATUS_PARITY_ERROR:
193458bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
193558bc78c7SXin Chen 				    "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
193658bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
193758bc78c7SXin Chen 				    pkt->pkt_resid);
193858bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
193958bc78c7SXin Chen 				break;
194058bc78c7SXin Chen 			case SRB_STATUS_NO_DEVICE:
194158bc78c7SXin Chen 			case SRB_STATUS_INVALID_PATH_ID:
194258bc78c7SXin Chen 			case SRB_STATUS_INVALID_TARGET_ID:
194358bc78c7SXin Chen 			case SRB_STATUS_INVALID_LUN:
194458bc78c7SXin Chen 			case SRB_STATUS_SELECTION_TIMEOUT:
194558bc78c7SXin Chen #ifdef DEBUG
194658bc78c7SXin Chen 				if (AAC_DEV_IS_VALID(acp->dvp)) {
194758bc78c7SXin Chen 					AACDB_PRINT(softs, CE_NOTE,
194858bc78c7SXin Chen 					    "SRB_STATUS_NO_DEVICE(%d), " \
194958bc78c7SXin Chen 					    "xfer=%d, resid=%d ",
195058bc78c7SXin Chen 					    srb_status & 0x3f,
195158bc78c7SXin Chen 					    data_xfer_length, pkt->pkt_resid);
195258bc78c7SXin Chen 				}
195358bc78c7SXin Chen #endif
195458bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
195558bc78c7SXin Chen 				break;
195658bc78c7SXin Chen 			case SRB_STATUS_COMMAND_TIMEOUT:
195758bc78c7SXin Chen 			case SRB_STATUS_TIMEOUT:
195858bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
195958bc78c7SXin Chen 				    "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
196058bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
196158bc78c7SXin Chen 				    pkt->pkt_resid);
196258bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
196358bc78c7SXin Chen 				    STAT_TIMEOUT);
196458bc78c7SXin Chen 				break;
196558bc78c7SXin Chen 			case SRB_STATUS_BUS_RESET:
196658bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
196758bc78c7SXin Chen 				    "SRB_STATUS_BUS_RESET, xfer=%d, " \
196858bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
196958bc78c7SXin Chen 				    pkt->pkt_resid);
197058bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_RESET,
197158bc78c7SXin Chen 				    STAT_BUS_RESET);
197258bc78c7SXin Chen 				break;
197358bc78c7SXin Chen 			default:
197458bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
197558bc78c7SXin Chen 				    "xfer=%d, resid=%d", srb_status & 0x3f,
197658bc78c7SXin Chen 				    data_xfer_length, pkt->pkt_resid);
197758bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
197858bc78c7SXin Chen 				break;
197958bc78c7SXin Chen 			}
198058bc78c7SXin Chen 		} else if (scsi_status == STATUS_CHECK) {
198158bc78c7SXin Chen 			/* CHECK CONDITION */
198258bc78c7SXin Chen 			struct scsi_arq_status *arqstat =
198358bc78c7SXin Chen 			    (void *)(pkt->pkt_scbp);
198458bc78c7SXin Chen 			uint32_t sense_data_size;
198558bc78c7SXin Chen 
198658bc78c7SXin Chen 			pkt->pkt_state |= STATE_ARQ_DONE;
198758bc78c7SXin Chen 
198858bc78c7SXin Chen 			*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
198958bc78c7SXin Chen 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
199058bc78c7SXin Chen 			arqstat->sts_rqpkt_resid = 0;
199158bc78c7SXin Chen 			arqstat->sts_rqpkt_state =
199258bc78c7SXin Chen 			    STATE_GOT_BUS |
199358bc78c7SXin Chen 			    STATE_GOT_TARGET |
199458bc78c7SXin Chen 			    STATE_SENT_CMD |
199558bc78c7SXin Chen 			    STATE_XFERRED_DATA;
199658bc78c7SXin Chen 			arqstat->sts_rqpkt_statistics = 0;
199758bc78c7SXin Chen 
199858bc78c7SXin Chen 			sense_data_size = ddi_get32(acc,
199958bc78c7SXin Chen 			    &resp->sense_data_size);
200058bc78c7SXin Chen 			ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
200158bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE,
200258bc78c7SXin Chen 			    "CHECK CONDITION: sense len=%d, xfer len=%d",
200358bc78c7SXin Chen 			    sense_data_size, data_xfer_length);
200458bc78c7SXin Chen 
200558bc78c7SXin Chen 			if (sense_data_size > SENSE_LENGTH)
200658bc78c7SXin Chen 				sense_data_size = SENSE_LENGTH;
200758bc78c7SXin Chen 			ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
200858bc78c7SXin Chen 			    (uint8_t *)resp->sense_data, sense_data_size,
200958bc78c7SXin Chen 			    DDI_DEV_AUTOINCR);
201058bc78c7SXin Chen 		} else {
201158bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
201258bc78c7SXin Chen 			    "scsi_status=%d, srb_status=%d",
201358bc78c7SXin Chen 			    scsi_status, srb_status);
201458bc78c7SXin Chen 			aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
201558bc78c7SXin Chen 		}
201658bc78c7SXin Chen 	} else {
201758bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
201858bc78c7SXin Chen 		    resp_status);
201958bc78c7SXin Chen 		aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
202058bc78c7SXin Chen 	}
202158bc78c7SXin Chen }
202258bc78c7SXin Chen 
2023d7c5bf88Spl /*
2024d7c5bf88Spl  * Handle completed IOCTL command
2025d7c5bf88Spl  */
2026382c8bcaSpl /*ARGSUSED*/
2027d7c5bf88Spl void
aac_ioctl_complete(struct aac_softstate * softs,struct aac_cmd * acp)2028d7c5bf88Spl aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2029d7c5bf88Spl {
2030d7c5bf88Spl 	struct aac_slot *slotp = acp->slotp;
2031830d82f7Spl 
2032382c8bcaSpl 	/*
2033382c8bcaSpl 	 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
2034382c8bcaSpl 	 * may wait on softs->event, so use cv_broadcast() instead
2035382c8bcaSpl 	 * of cv_signal().
2036382c8bcaSpl 	 */
2037382c8bcaSpl 	ASSERT(acp->flags & AAC_CMD_SYNC);
2038382c8bcaSpl 	ASSERT(acp->flags & AAC_CMD_NO_CB);
2039382c8bcaSpl 
2040d7c5bf88Spl 	/* Get the size of the response FIB from its FIB.Header.Size field */
2041942c5e3cSpl 	acp->fib_size = ddi_get16(slotp->fib_acc_handle,
2042942c5e3cSpl 	    &slotp->fibp->Header.Size);
2043830d82f7Spl 
2044d7c5bf88Spl 	ASSERT(acp->fib_size <= softs->aac_max_fib_size);
2045942c5e3cSpl 	ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
2046942c5e3cSpl 	    (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
2047382c8bcaSpl }
2048832e0b5aSpl 
2049f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
2050f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Handle completed sync fib command
2051f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
2052f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*ARGSUSED*/
2053f42c2f53Szhongyan gu - Sun Microsystems - Beijing China void
aac_sync_complete(struct aac_softstate * softs,struct aac_cmd * acp)2054f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2055f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2056f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2057f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2058382c8bcaSpl /*
2059382c8bcaSpl  * Handle completed Flush command
2060382c8bcaSpl  */
2061382c8bcaSpl /*ARGSUSED*/
2062382c8bcaSpl static void
aac_synccache_complete(struct aac_softstate * softs,struct aac_cmd * acp)2063382c8bcaSpl aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2064382c8bcaSpl {
2065382c8bcaSpl 	struct aac_slot *slotp = acp->slotp;
2066382c8bcaSpl 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2067382c8bcaSpl 	struct aac_synchronize_reply *resp;
2068382c8bcaSpl 	uint32_t status;
2069832e0b5aSpl 
2070382c8bcaSpl 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2071382c8bcaSpl 
207258bc78c7SXin Chen 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
207358bc78c7SXin Chen 
2074382c8bcaSpl 	resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
2075382c8bcaSpl 	status = ddi_get32(acc, &resp->Status);
2076382c8bcaSpl 	if (status != CT_OK)
2077382c8bcaSpl 		aac_set_arq_data_hwerr(acp);
2078830d82f7Spl }
2079830d82f7Spl 
20801ee13a44SXinChen /*ARGSUSED*/
2081b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void
aac_startstop_complete(struct aac_softstate * softs,struct aac_cmd * acp)2082b40e8a89Szhongyan gu - Sun Microsystems - Beijing China aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2083b40e8a89Szhongyan gu - Sun Microsystems - Beijing China {
2084b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp = acp->slotp;
2085b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2086b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_Container_resp *resp;
2087b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t status;
2088b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2089b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2090b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2091b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2092b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2093b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
2094b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	status = ddi_get32(acc, &resp->Status);
2095b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	if (status != 0) {
2096b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
2097b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		aac_set_arq_data_hwerr(acp);
2098b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	}
2099b40e8a89Szhongyan gu - Sun Microsystems - Beijing China }
2100b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2101830d82f7Spl /*
2102830d82f7Spl  * Access PCI space to see if the driver can support the card
2103830d82f7Spl  */
21047c478bd9Sstevel@tonic-gate static int
aac_check_card_type(struct aac_softstate * softs)21057c478bd9Sstevel@tonic-gate aac_check_card_type(struct aac_softstate *softs)
21067c478bd9Sstevel@tonic-gate {
2107d937e6ebSpl 	ddi_acc_handle_t pci_config_handle;
2108d937e6ebSpl 	int card_index;
21097c478bd9Sstevel@tonic-gate 	uint32_t pci_cmd;
21107c478bd9Sstevel@tonic-gate 
2111830d82f7Spl 	/* Map pci configuration space */
2112c9487164Spl 	if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
2113c9487164Spl 	    DDI_SUCCESS) {
21141dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
21157c478bd9Sstevel@tonic-gate 		return (AACERR);
21167c478bd9Sstevel@tonic-gate 	}
21177c478bd9Sstevel@tonic-gate 
21181cea6be9Sxc 	softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
21191cea6be9Sxc 	softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
21201cea6be9Sxc 	softs->subvendid = pci_config_get16(pci_config_handle,
21211cea6be9Sxc 	    PCI_CONF_SUBVENID);
21221cea6be9Sxc 	softs->subsysid = pci_config_get16(pci_config_handle,
21231cea6be9Sxc 	    PCI_CONF_SUBSYSID);
21241cea6be9Sxc 
2125d937e6ebSpl 	card_index = 0;
2126d937e6ebSpl 	while (!CARD_IS_UNKNOWN(card_index)) {
21271cea6be9Sxc 		if ((aac_cards[card_index].vendor == softs->vendid) &&
21281cea6be9Sxc 		    (aac_cards[card_index].device == softs->devid) &&
21291cea6be9Sxc 		    (aac_cards[card_index].subvendor == softs->subvendid) &&
21301cea6be9Sxc 		    (aac_cards[card_index].subsys == softs->subsysid)) {
21317c478bd9Sstevel@tonic-gate 			break;
21327c478bd9Sstevel@tonic-gate 		}
2133d937e6ebSpl 		card_index++;
21347c478bd9Sstevel@tonic-gate 	}
21357c478bd9Sstevel@tonic-gate 
2136d937e6ebSpl 	softs->card = card_index;
2137d937e6ebSpl 	softs->hwif = aac_cards[card_index].hwif;
2138d937e6ebSpl 
2139d937e6ebSpl 	/*
2140d937e6ebSpl 	 * Unknown aac card
2141d937e6ebSpl 	 * do a generic match based on the VendorID and DeviceID to
2142d937e6ebSpl 	 * support the new cards in the aac family
2143d937e6ebSpl 	 */
2144d937e6ebSpl 	if (CARD_IS_UNKNOWN(card_index)) {
21451cea6be9Sxc 		if (softs->vendid != 0x9005) {
21461dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
21471cea6be9Sxc 			    "Unknown vendor 0x%x", softs->vendid);
2148d937e6ebSpl 			goto error;
21497c478bd9Sstevel@tonic-gate 		}
21501cea6be9Sxc 		switch (softs->devid) {
2151d937e6ebSpl 		case 0x285:
2152d937e6ebSpl 			softs->hwif = AAC_HWIF_I960RX;
2153d937e6ebSpl 			break;
2154d937e6ebSpl 		case 0x286:
2155d937e6ebSpl 			softs->hwif = AAC_HWIF_RKT;
2156d937e6ebSpl 			break;
2157d937e6ebSpl 		default:
21581dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
21591cea6be9Sxc 			    "Unknown device \"pci9005,%x\"", softs->devid);
21607c478bd9Sstevel@tonic-gate 			goto error;
21617c478bd9Sstevel@tonic-gate 		}
2162d937e6ebSpl 	}
2163d937e6ebSpl 
2164d937e6ebSpl 	/* Set hardware dependent interface */
2165d937e6ebSpl 	switch (softs->hwif) {
2166d937e6ebSpl 	case AAC_HWIF_I960RX:
2167d937e6ebSpl 		softs->aac_if = aac_rx_interface;
2168d937e6ebSpl 		softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
2169d937e6ebSpl 		break;
2170d937e6ebSpl 	case AAC_HWIF_RKT:
2171d937e6ebSpl 		softs->aac_if = aac_rkt_interface;
2172d937e6ebSpl 		softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
2173d937e6ebSpl 		break;
2174d937e6ebSpl 	default:
21751dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
21761dd0a2dbSpl 		    "Unknown hardware interface %d", softs->hwif);
2177d937e6ebSpl 		goto error;
2178d937e6ebSpl 	}
2179d937e6ebSpl 
2180d937e6ebSpl 	/* Set card names */
2181d937e6ebSpl 	(void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
2182c9487164Spl 	    AAC_VENDOR_LEN);
2183d937e6ebSpl 	(void *)strncpy(softs->product_name, aac_cards[card_index].desc,
2184c9487164Spl 	    AAC_PRODUCT_LEN);
2185d937e6ebSpl 
2186d937e6ebSpl 	/* Set up quirks */
2187d937e6ebSpl 	softs->flags = aac_cards[card_index].quirks;
2188d937e6ebSpl 
2189d937e6ebSpl 	/* Force the busmaster enable bit on */
2190d937e6ebSpl 	pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2191d937e6ebSpl 	if ((pci_cmd & PCI_COMM_ME) == 0) {
2192d937e6ebSpl 		pci_cmd |= PCI_COMM_ME;
2193c9487164Spl 		pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
2194c9487164Spl 		pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2195d937e6ebSpl 		if ((pci_cmd & PCI_COMM_ME) == 0) {
2196c9487164Spl 			cmn_err(CE_CONT, "?Cannot enable busmaster bit");
2197d937e6ebSpl 			goto error;
2198d937e6ebSpl 		}
2199d937e6ebSpl 	}
2200d937e6ebSpl 
2201d937e6ebSpl 	/* Set memory base to map */
22021dd0a2dbSpl 	softs->pci_mem_base_paddr = 0xfffffff0UL & \
22031dd0a2dbSpl 	    pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 	pci_config_teardown(&pci_config_handle);
2206d937e6ebSpl 
2207d937e6ebSpl 	return (AACOK); /* card type detected */
22087c478bd9Sstevel@tonic-gate error:
22097c478bd9Sstevel@tonic-gate 	pci_config_teardown(&pci_config_handle);
2210830d82f7Spl 	return (AACERR); /* no matched card found */
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate 
2213f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
2214f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Do the usual interrupt handler setup stuff.
2215f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
2216f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_register_intrs(struct aac_softstate * softs)2217f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_register_intrs(struct aac_softstate *softs)
2218f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2219f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	dev_info_t *dip;
2220f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int intr_types;
2221f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2222f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(softs->devinfo_p);
2223f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	dip = softs->devinfo_p;
2224f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2225f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get the type of device intrrupts */
2226f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
2227f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2228f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "ddi_intr_get_supported_types() failed");
2229f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2230f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2231f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AACDB_PRINT(softs, CE_NOTE,
2232f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
2233f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2234f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Query interrupt, and alloc/init all needed struct */
2235f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (intr_types & DDI_INTR_TYPE_MSI) {
2236f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
2237f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    != DDI_SUCCESS) {
2238f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_WARN,
2239f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			    "MSI interrupt query failed");
2240f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			return (AACERR);
2241f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
2242f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		softs->intr_type = DDI_INTR_TYPE_MSI;
2243f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
2244f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
2245f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    != DDI_SUCCESS) {
2246f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_WARN,
2247f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			    "FIXED interrupt query failed");
2248f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			return (AACERR);
2249f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
2250f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		softs->intr_type = DDI_INTR_TYPE_FIXED;
2251f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
2252f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2253f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Device cannot suppport both FIXED and MSI interrupts");
2254f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2255f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2256f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2257f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Connect interrupt handlers */
2258f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_add_intrs(softs) != DDI_SUCCESS) {
2259f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2260f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Interrupt registration failed, intr type: %s",
2261f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
2262f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2263f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2264f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_enable_intrs(softs);
2265f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2266f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
2267f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
2268f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2269f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Can not setup soft interrupt handler!");
2270f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_remove_intrs(softs);
2271f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2272f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2273f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2274f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (AACOK);
2275f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2276f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2277f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void
aac_unregister_intrs(struct aac_softstate * softs)2278f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_unregister_intrs(struct aac_softstate *softs)
2279f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2280f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_remove_intrs(softs);
2281f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_remove_softintr(softs->softint_id);
2282f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2283f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2284830d82f7Spl /*
2285830d82f7Spl  * Check the firmware to determine the features to support and the FIB
2286830d82f7Spl  * parameters to use.
2287830d82f7Spl  */
22887c478bd9Sstevel@tonic-gate static int
aac_check_firmware(struct aac_softstate * softs)2289830d82f7Spl aac_check_firmware(struct aac_softstate *softs)
22907c478bd9Sstevel@tonic-gate {
2291830d82f7Spl 	uint32_t options;
2292830d82f7Spl 	uint32_t atu_size;
2293830d82f7Spl 	ddi_acc_handle_t pci_handle;
229458bc78c7SXin Chen 	uint8_t *data;
2295830d82f7Spl 	uint32_t max_fibs;
2296830d82f7Spl 	uint32_t max_fib_size;
2297830d82f7Spl 	uint32_t sg_tablesize;
2298830d82f7Spl 	uint32_t max_sectors;
2299830d82f7Spl 	uint32_t status;
2300830d82f7Spl 
2301c9ffe217SToomas Soome 	max_fibs = 0;
2302c9ffe217SToomas Soome 	max_sectors = 0;
2303c9ffe217SToomas Soome 	sg_tablesize = 0;
2304c9ffe217SToomas Soome 
2305830d82f7Spl 	/* Get supported options */
2306c9487164Spl 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
2307c9487164Spl 	    &status)) != AACOK) {
2308c9487164Spl 		if (status != SRB_STATUS_INVALID_REQUEST) {
2309830d82f7Spl 			cmn_err(CE_CONT,
2310c9487164Spl 			    "?Fatal error: request adapter info error");
2311830d82f7Spl 			return (AACERR);
2312830d82f7Spl 		}
2313830d82f7Spl 		options = 0;
2314830d82f7Spl 		atu_size = 0;
2315830d82f7Spl 	} else {
2316830d82f7Spl 		options = AAC_MAILBOX_GET(softs, 1);
2317830d82f7Spl 		atu_size = AAC_MAILBOX_GET(softs, 2);
2318830d82f7Spl 	}
23197c478bd9Sstevel@tonic-gate 
2320382c8bcaSpl 	if (softs->state & AAC_STATE_RESET) {
2321830d82f7Spl 		if ((softs->support_opt == options) &&
2322c9487164Spl 		    (softs->atu_size == atu_size))
2323830d82f7Spl 			return (AACOK);
2324830d82f7Spl 
2325830d82f7Spl 		cmn_err(CE_WARN,
2326c9487164Spl 		    "?Fatal error: firmware changed, system needs reboot");
2327830d82f7Spl 		return (AACERR);
23287c478bd9Sstevel@tonic-gate 	}
23297c478bd9Sstevel@tonic-gate 
2330c9487164Spl 	/*
2331c9487164Spl 	 * The following critical settings are initialized only once during
2332c9487164Spl 	 * driver attachment.
2333c9487164Spl 	 */
2334830d82f7Spl 	softs->support_opt = options;
2335830d82f7Spl 	softs->atu_size = atu_size;
2336830d82f7Spl 
2337830d82f7Spl 	/* Process supported options */
2338830d82f7Spl 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
2339c9487164Spl 	    (softs->flags & AAC_FLAGS_NO4GB) == 0) {
23401cea6be9Sxc 		AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
2341830d82f7Spl 		softs->flags |= AAC_FLAGS_4GB_WINDOW;
2342382c8bcaSpl 	} else {
2343382c8bcaSpl 		/*
2344382c8bcaSpl 		 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
2345382c8bcaSpl 		 * only. IO is handled by the DMA engine which does not suffer
2346382c8bcaSpl 		 * from the ATU window programming workarounds necessary for
2347382c8bcaSpl 		 * CPU copy operations.
2348382c8bcaSpl 		 */
2349382c8bcaSpl 		softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
2350382c8bcaSpl 		softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
23517c478bd9Sstevel@tonic-gate 	}
2352830d82f7Spl 
2353830d82f7Spl 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
23541cea6be9Sxc 		AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
2355830d82f7Spl 		softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
2356830d82f7Spl 		softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
2357830d82f7Spl 		softs->flags |= AAC_FLAGS_SG_64BIT;
2358830d82f7Spl 	}
2359830d82f7Spl 
2360830d82f7Spl 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
2361830d82f7Spl 		softs->flags |= AAC_FLAGS_ARRAY_64BIT;
23621cea6be9Sxc 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
2363830d82f7Spl 	}
2364830d82f7Spl 
236558bc78c7SXin Chen 	if (options & AAC_SUPPORTED_NONDASD) {
236658bc78c7SXin Chen 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
236758bc78c7SXin Chen 		    "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
236858bc78c7SXin Chen 			if (strcmp((char *)data, "yes") == 0) {
236958bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
237058bc78c7SXin Chen 				    "!Enable Non-DASD access");
237158bc78c7SXin Chen 				softs->flags |= AAC_FLAGS_NONDASD;
237258bc78c7SXin Chen 			}
237358bc78c7SXin Chen 			ddi_prop_free(data);
237458bc78c7SXin Chen 		}
237558bc78c7SXin Chen 	}
237658bc78c7SXin Chen 
2377830d82f7Spl 	/* Read preferred settings */
2378830d82f7Spl 	max_fib_size = 0;
2379830d82f7Spl 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
2380c9487164Spl 	    0, 0, 0, 0, NULL)) == AACOK) {
2381830d82f7Spl 		options = AAC_MAILBOX_GET(softs, 1);
2382830d82f7Spl 		max_fib_size = (options & 0xffff);
2383830d82f7Spl 		max_sectors = (options >> 16) << 1;
2384830d82f7Spl 		options = AAC_MAILBOX_GET(softs, 2);
2385830d82f7Spl 		sg_tablesize = (options >> 16);
2386830d82f7Spl 		options = AAC_MAILBOX_GET(softs, 3);
2387830d82f7Spl 		max_fibs = (options & 0xffff);
2388830d82f7Spl 	}
2389830d82f7Spl 
2390830d82f7Spl 	/* Enable new comm. and rawio at the same time */
2391830d82f7Spl 	if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
2392c9487164Spl 	    (max_fib_size != 0)) {
239358bc78c7SXin Chen 		/* read out and save PCI MBR */
2394830d82f7Spl 		if ((atu_size > softs->map_size) &&
2395c9487164Spl 		    (ddi_regs_map_setup(softs->devinfo_p, 1,
2396837c1ac4SStephen Hanson 		    (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
2397c9487164Spl 		    &pci_handle) == DDI_SUCCESS)) {
2398830d82f7Spl 			ddi_regs_map_free(&softs->pci_mem_handle);
2399830d82f7Spl 			softs->pci_mem_handle = pci_handle;
240058bc78c7SXin Chen 			softs->pci_mem_base_vaddr = data;
2401830d82f7Spl 			softs->map_size = atu_size;
2402830d82f7Spl 		}
2403830d82f7Spl 		if (atu_size == softs->map_size) {
2404830d82f7Spl 			softs->flags |= AAC_FLAGS_NEW_COMM;
24051cea6be9Sxc 			AACDB_PRINT(softs, CE_NOTE,
24061cea6be9Sxc 			    "!Enable New Comm. interface");
2407830d82f7Spl 		}
2408830d82f7Spl 	}
2409830d82f7Spl 
2410830d82f7Spl 	/* Set FIB parameters */
2411830d82f7Spl 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
2412830d82f7Spl 		softs->aac_max_fibs = max_fibs;
2413830d82f7Spl 		softs->aac_max_fib_size = max_fib_size;
2414830d82f7Spl 		softs->aac_max_sectors = max_sectors;
2415830d82f7Spl 		softs->aac_sg_tablesize = sg_tablesize;
2416830d82f7Spl 
2417830d82f7Spl 		softs->flags |= AAC_FLAGS_RAW_IO;
24181cea6be9Sxc 		AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
2419830d82f7Spl 	} else {
2420830d82f7Spl 		softs->aac_max_fibs =
2421c9487164Spl 		    (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
2422942c5e3cSpl 		softs->aac_max_fib_size = AAC_FIB_SIZE;
2423382c8bcaSpl 		softs->aac_max_sectors = 128;	/* 64K */
2424382c8bcaSpl 		if (softs->flags & AAC_FLAGS_17SG)
2425382c8bcaSpl 			softs->aac_sg_tablesize = 17;
2426382c8bcaSpl 		else if (softs->flags & AAC_FLAGS_34SG)
2427382c8bcaSpl 			softs->aac_sg_tablesize = 34;
2428830d82f7Spl 		else if (softs->flags & AAC_FLAGS_SG_64BIT)
2429830d82f7Spl 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2430c9487164Spl 			    sizeof (struct aac_blockwrite64) +
2431c9487164Spl 			    sizeof (struct aac_sg_entry64)) /
2432c9487164Spl 			    sizeof (struct aac_sg_entry64);
2433830d82f7Spl 		else
2434830d82f7Spl 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2435c9487164Spl 			    sizeof (struct aac_blockwrite) +
2436c9487164Spl 			    sizeof (struct aac_sg_entry)) /
2437c9487164Spl 			    sizeof (struct aac_sg_entry);
2438830d82f7Spl 	}
2439830d82f7Spl 
2440830d82f7Spl 	if ((softs->flags & AAC_FLAGS_RAW_IO) &&
2441c9487164Spl 	    (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
2442830d82f7Spl 		softs->flags |= AAC_FLAGS_LBA_64BIT;
24431cea6be9Sxc 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
2444830d82f7Spl 	}
2445830d82f7Spl 	softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
2446830d82f7Spl 	softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
2447382c8bcaSpl 	/*
2448382c8bcaSpl 	 * 64K maximum segment size in scatter gather list is controlled by
2449382c8bcaSpl 	 * the NEW_COMM bit in the adapter information. If not set, the card
2450382c8bcaSpl 	 * can only accept a maximum of 64K. It is not recommended to permit
2451382c8bcaSpl 	 * more than 128KB of total transfer size to the adapters because
2452382c8bcaSpl 	 * performance is negatively impacted.
2453382c8bcaSpl 	 *
2454382c8bcaSpl 	 * For new comm, segment size equals max xfer size. For old comm,
2455382c8bcaSpl 	 * we use 64K for both.
2456382c8bcaSpl 	 */
2457382c8bcaSpl 	softs->buf_dma_attr.dma_attr_count_max =
2458382c8bcaSpl 	    softs->buf_dma_attr.dma_attr_maxxfer - 1;
2459830d82f7Spl 
246058bc78c7SXin Chen 	/* Setup FIB operations */
2461d7c5bf88Spl 	if (softs->flags & AAC_FLAGS_RAW_IO)
2462d7c5bf88Spl 		softs->aac_cmd_fib = aac_cmd_fib_rawio;
2463d7c5bf88Spl 	else if (softs->flags & AAC_FLAGS_SG_64BIT)
2464d7c5bf88Spl 		softs->aac_cmd_fib = aac_cmd_fib_brw64;
2465d7c5bf88Spl 	else
2466d7c5bf88Spl 		softs->aac_cmd_fib = aac_cmd_fib_brw;
2467942c5e3cSpl 	softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
2468942c5e3cSpl 	    aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
2469d7c5bf88Spl 
2470d7c5bf88Spl 	/* 64-bit LBA needs descriptor format sense data */
2471d7c5bf88Spl 	softs->slen = sizeof (struct scsi_arq_status);
2472d7c5bf88Spl 	if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
2473d7c5bf88Spl 	    softs->slen < AAC_ARQ64_LENGTH)
2474d7c5bf88Spl 		softs->slen = AAC_ARQ64_LENGTH;
2475d7c5bf88Spl 
24761cea6be9Sxc 	AACDB_PRINT(softs, CE_NOTE,
2477c9487164Spl 	    "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
2478c9487164Spl 	    softs->aac_max_fibs, softs->aac_max_fib_size,
2479c9487164Spl 	    softs->aac_max_sectors, softs->aac_sg_tablesize);
2480830d82f7Spl 
2481830d82f7Spl 	return (AACOK);
2482830d82f7Spl }
2483830d82f7Spl 
2484942c5e3cSpl static void
aac_fsa_rev(struct aac_softstate * softs,struct FsaRev * fsarev0,struct FsaRev * fsarev1)2485942c5e3cSpl aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
2486942c5e3cSpl     struct FsaRev *fsarev1)
2487942c5e3cSpl {
2488f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
2489942c5e3cSpl 
2490942c5e3cSpl 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
2491942c5e3cSpl 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
2492942c5e3cSpl 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
2493942c5e3cSpl 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
2494942c5e3cSpl 	AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
2495942c5e3cSpl }
2496942c5e3cSpl 
2497d937e6ebSpl /*
2498d937e6ebSpl  * The following function comes from Adaptec:
2499d937e6ebSpl  *
2500d937e6ebSpl  * Query adapter information and supplement adapter information
2501d937e6ebSpl  */
2502d937e6ebSpl static int
aac_get_adapter_info(struct aac_softstate * softs,struct aac_adapter_info * ainfr,struct aac_supplement_adapter_info * sinfr)2503d937e6ebSpl aac_get_adapter_info(struct aac_softstate *softs,
2504942c5e3cSpl     struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
2505d937e6ebSpl {
2506f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2507f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2508f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
2509d937e6ebSpl 	struct aac_adapter_info *ainfp;
2510d937e6ebSpl 	struct aac_supplement_adapter_info *sinfp;
2511f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
2512f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2513f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2514f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2515f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2516d937e6ebSpl 
2517942c5e3cSpl 	ddi_put8(acc, &fibp->data[0], 0);
2518942c5e3cSpl 	if (aac_sync_fib(softs, RequestAdapterInfo,
25193fced439Szhongyan gu - Sun Microsystems - Beijing China 	    AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
25201dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
2521f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2522f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
2523d937e6ebSpl 	}
2524c9487164Spl 	ainfp = (struct aac_adapter_info *)fibp->data;
2525d937e6ebSpl 	if (ainfr) {
2526942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2527942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
2528942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
2529942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
2530942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
2531942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
2532942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
2533942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
2534942c5e3cSpl 		aac_fsa_rev(softs, &ainfp->KernelRevision,
2535942c5e3cSpl 		    &ainfr->KernelRevision);
2536942c5e3cSpl 		aac_fsa_rev(softs, &ainfp->MonitorRevision,
2537942c5e3cSpl 		    &ainfr->MonitorRevision);
2538942c5e3cSpl 		aac_fsa_rev(softs, &ainfp->HardwareRevision,
2539942c5e3cSpl 		    &ainfr->HardwareRevision);
2540942c5e3cSpl 		aac_fsa_rev(softs, &ainfp->BIOSRevision,
2541942c5e3cSpl 		    &ainfr->BIOSRevision);
2542942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
2543942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
2544942c5e3cSpl 		AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
2545942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
2546942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2547942c5e3cSpl 		AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
2548d937e6ebSpl 	}
2549d937e6ebSpl 	if (sinfr) {
2550d937e6ebSpl 		if (!(softs->support_opt &
2551c9487164Spl 		    AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
25521dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
25531dd0a2dbSpl 			    "SupplementAdapterInfo not supported");
2554f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
2555f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			goto finish;
2556d937e6ebSpl 		}
2557942c5e3cSpl 		ddi_put8(acc, &fibp->data[0], 0);
2558942c5e3cSpl 		if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
25593fced439Szhongyan gu - Sun Microsystems - Beijing China 		    AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
25603fced439Szhongyan gu - Sun Microsystems - Beijing China 		    != AACOK) {
25611dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
25621dd0a2dbSpl 			    "RequestSupplementAdapterInfo failed");
2563f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
2564f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			goto finish;
2565d937e6ebSpl 		}
2566c9487164Spl 		sinfp = (struct aac_supplement_adapter_info *)fibp->data;
2567942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
2568942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
2569942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
2570942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
2571942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
2572942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
2573942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
2574942c5e3cSpl 		AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
2575942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
2576942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
2577942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
2578942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
2579942c5e3cSpl 		    sizeof (struct vpd_info));
2580942c5e3cSpl 		aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
2581942c5e3cSpl 		    &sinfr->FlashFirmwareRevision);
2582942c5e3cSpl 		AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
2583942c5e3cSpl 		aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
2584942c5e3cSpl 		    &sinfr->FlashFirmwareBootRevision);
2585942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
2586942c5e3cSpl 		    MFG_PCBA_SERIAL_NUMBER_WIDTH);
2587942c5e3cSpl 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
2588942c5e3cSpl 		    MFG_WWN_WIDTH);
2589b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
2590b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
2591b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (sinfr->ExpansionFlag == 1) {
2592b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
2593b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_GET_FIELD32(acc, sinfr, sinfp,
2594b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			    SupportedPerformanceMode);
2595b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
2596b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			    ReservedGrowth[0], 80);
2597b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		}
2598d937e6ebSpl 	}
2599f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = AACOK;
2600f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
2601f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
2602f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
2603d937e6ebSpl }
2604d937e6ebSpl 
260558bc78c7SXin Chen static int
aac_get_bus_info(struct aac_softstate * softs,uint32_t * bus_max,uint32_t * tgt_max)260658bc78c7SXin Chen aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
260758bc78c7SXin Chen     uint32_t *tgt_max)
260858bc78c7SXin Chen {
2609f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2610f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2611f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
261258bc78c7SXin Chen 	struct aac_ctcfg *c_cmd;
261358bc78c7SXin Chen 	struct aac_ctcfg_resp *c_resp;
261458bc78c7SXin Chen 	uint32_t scsi_method_id;
261558bc78c7SXin Chen 	struct aac_bus_info *cmd;
261658bc78c7SXin Chen 	struct aac_bus_info_response *resp;
261758bc78c7SXin Chen 	int rval;
261858bc78c7SXin Chen 
2619f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2620f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2621f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2622f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
262358bc78c7SXin Chen 	/* Detect MethodId */
262458bc78c7SXin Chen 	c_cmd = (struct aac_ctcfg *)&fibp->data[0];
262558bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
262658bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
262758bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->param, 0);
262858bc78c7SXin Chen 	rval = aac_sync_fib(softs, ContainerCommand,
262958bc78c7SXin Chen 	    AAC_FIB_SIZEOF(struct aac_ctcfg));
263058bc78c7SXin Chen 	c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
263158bc78c7SXin Chen 	if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
263258bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN,
263358bc78c7SXin Chen 		    "VM_ContainerConfig command fail");
2634f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2635f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
263658bc78c7SXin Chen 	}
263758bc78c7SXin Chen 	scsi_method_id = ddi_get32(acc, &c_resp->param);
263858bc78c7SXin Chen 
263958bc78c7SXin Chen 	/* Detect phys. bus count and max. target id first */
264058bc78c7SXin Chen 	cmd = (struct aac_bus_info *)&fibp->data[0];
264158bc78c7SXin Chen 	ddi_put32(acc, &cmd->Command, VM_Ioctl);
264258bc78c7SXin Chen 	ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
264358bc78c7SXin Chen 	ddi_put32(acc, &cmd->MethodId, scsi_method_id);
264458bc78c7SXin Chen 	ddi_put32(acc, &cmd->ObjectId, 0);
264558bc78c7SXin Chen 	ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
264658bc78c7SXin Chen 	/*
264758bc78c7SXin Chen 	 * For VM_Ioctl, the firmware uses the Header.Size filled from the
264858bc78c7SXin Chen 	 * driver as the size to be returned. Therefore the driver has to use
264958bc78c7SXin Chen 	 * sizeof (struct aac_bus_info_response) because it is greater than
265058bc78c7SXin Chen 	 * sizeof (struct aac_bus_info).
265158bc78c7SXin Chen 	 */
265258bc78c7SXin Chen 	rval = aac_sync_fib(softs, ContainerCommand,
265358bc78c7SXin Chen 	    AAC_FIB_SIZEOF(struct aac_bus_info_response));
265458bc78c7SXin Chen 	resp = (struct aac_bus_info_response *)cmd;
265558bc78c7SXin Chen 
265658bc78c7SXin Chen 	/* Scan all coordinates with INQUIRY */
265758bc78c7SXin Chen 	if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
265858bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
2659f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2660f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
266158bc78c7SXin Chen 	}
266258bc78c7SXin Chen 	*bus_max = ddi_get32(acc, &resp->BusCount);
266358bc78c7SXin Chen 	*tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
2664f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2665f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
2666f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
266758bc78c7SXin Chen 	return (AACOK);
266858bc78c7SXin Chen }
266958bc78c7SXin Chen 
2670830d82f7Spl /*
2671830d82f7Spl  * The following function comes from Adaptec:
2672830d82f7Spl  *
2673830d82f7Spl  * Routine to be called during initialization of communications with
2674830d82f7Spl  * the adapter to handle possible adapter configuration issues. When
2675830d82f7Spl  * the adapter first boots up, it examines attached drives, etc, and
2676830d82f7Spl  * potentially comes up with a new or revised configuration (relative to
2677830d82f7Spl  * what's stored in it's NVRAM). Additionally it may discover problems
2678830d82f7Spl  * that make the current physical configuration unworkable (currently
2679830d82f7Spl  * applicable only to cluster configuration issues).
2680830d82f7Spl  *
2681830d82f7Spl  * If there are no configuration issues or the issues are considered
2682830d82f7Spl  * trival by the adapter, it will set it's configuration status to
2683830d82f7Spl  * "FSACT_CONTINUE" and execute the "commit confiuguration" action
2684830d82f7Spl  * automatically on it's own.
2685830d82f7Spl  *
2686830d82f7Spl  * However, if there are non-trivial issues, the adapter will set it's
2687830d82f7Spl  * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
2688830d82f7Spl  * and wait for some agent on the host to issue the "\ContainerCommand
2689830d82f7Spl  * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
2690830d82f7Spl  * adapter to commit the new/updated configuration and enable
2691830d82f7Spl  * un-inhibited operation.  The host agent should first issue the
2692830d82f7Spl  * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
2693830d82f7Spl  * command to obtain information about config issues detected by
2694830d82f7Spl  * the adapter.
2695830d82f7Spl  *
2696830d82f7Spl  * Normally the adapter's PC BIOS will execute on the host following
2697830d82f7Spl  * adapter poweron and reset and will be responsible for querring the
2698830d82f7Spl  * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
2699830d82f7Spl  * command if appropriate.
2700830d82f7Spl  *
2701830d82f7Spl  * However, with the introduction of IOP reset support, the adapter may
2702830d82f7Spl  * boot up without the benefit of the adapter's PC BIOS host agent.
2703830d82f7Spl  * This routine is intended to take care of these issues in situations
2704830d82f7Spl  * where BIOS doesn't execute following adapter poweron or reset.  The
2705830d82f7Spl  * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
2706830d82f7Spl  * there is no harm in doing this when it's already been done.
2707830d82f7Spl  */
2708830d82f7Spl static int
aac_handle_adapter_config_issues(struct aac_softstate * softs)2709830d82f7Spl aac_handle_adapter_config_issues(struct aac_softstate *softs)
2710830d82f7Spl {
2711f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2712f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2713f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
2714830d82f7Spl 	struct aac_Container *cmd;
2715c9487164Spl 	struct aac_Container_resp *resp;
2716830d82f7Spl 	struct aac_cf_status_header *cfg_sts_hdr;
2717942c5e3cSpl 	uint32_t resp_status;
2718942c5e3cSpl 	uint32_t ct_status;
2719830d82f7Spl 	uint32_t cfg_stat_action;
2720c9487164Spl 	int rval;
2721830d82f7Spl 
2722f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2723f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2724f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2725f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2726c9487164Spl 	/* Get adapter config status */
2727c9487164Spl 	cmd = (struct aac_Container *)&fibp->data[0];
2728830d82f7Spl 
2729382c8bcaSpl 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2730942c5e3cSpl 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2731942c5e3cSpl 	ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
2732942c5e3cSpl 	ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
2733942c5e3cSpl 	    sizeof (struct aac_cf_status_header));
2734942c5e3cSpl 	rval = aac_sync_fib(softs, ContainerCommand,
2735942c5e3cSpl 	    AAC_FIB_SIZEOF(struct aac_Container));
2736c9487164Spl 	resp = (struct aac_Container_resp *)cmd;
2737c9487164Spl 	cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
2738c9487164Spl 
2739942c5e3cSpl 	resp_status = ddi_get32(acc, &resp->Status);
2740942c5e3cSpl 	ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2741942c5e3cSpl 	if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
2742942c5e3cSpl 		cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
2743830d82f7Spl 
2744c9487164Spl 		/* Commit configuration if it's reasonable to do so. */
2745830d82f7Spl 		if (cfg_stat_action <= CFACT_PAUSE) {
2746942c5e3cSpl 			bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2747942c5e3cSpl 			ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2748942c5e3cSpl 			ddi_put32(acc, &cmd->CTCommand.command,
2749942c5e3cSpl 			    CT_COMMIT_CONFIG);
2750942c5e3cSpl 			rval = aac_sync_fib(softs, ContainerCommand,
2751942c5e3cSpl 			    AAC_FIB_SIZEOF(struct aac_Container));
2752942c5e3cSpl 
2753942c5e3cSpl 			resp_status = ddi_get32(acc, &resp->Status);
2754942c5e3cSpl 			ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2755942c5e3cSpl 			if ((rval == AACOK) && (resp_status == 0) &&
2756942c5e3cSpl 			    (ct_status == CT_OK))
2757c9487164Spl 				/* Successful completion */
2758c9487164Spl 				rval = AACMPE_OK;
2759c9487164Spl 			else
2760c9487164Spl 				/* Auto-commit aborted due to error(s). */
2761c9487164Spl 				rval = AACMPE_COMMIT_CONFIG;
2762830d82f7Spl 		} else {
2763830d82f7Spl 			/*
2764830d82f7Spl 			 * Auto-commit aborted due to adapter indicating
2765830d82f7Spl 			 * configuration issue(s) too dangerous to auto-commit.
2766830d82f7Spl 			 */
2767c9487164Spl 			rval = AACMPE_CONFIG_STATUS;
2768830d82f7Spl 		}
2769830d82f7Spl 	} else {
2770830d82f7Spl 		cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
2771c9487164Spl 		rval = AACMPE_CONFIG_STATUS;
2772830d82f7Spl 	}
2773f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2774f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
2775c9487164Spl 	return (rval);
2776830d82f7Spl }
2777830d82f7Spl 
2778830d82f7Spl /*
2779830d82f7Spl  * Hardware initialization and resource allocation
2780830d82f7Spl  */
2781830d82f7Spl static int
aac_common_attach(struct aac_softstate * softs)2782830d82f7Spl aac_common_attach(struct aac_softstate *softs)
2783830d82f7Spl {
2784382c8bcaSpl 	uint32_t status;
2785830d82f7Spl 	int i;
27860749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_supplement_adapter_info sinf;
2787830d82f7Spl 
27881dd0a2dbSpl 	DBCALLED(softs, 1);
2789830d82f7Spl 
2790d7c5bf88Spl 	/*
2791d7c5bf88Spl 	 * Do a little check here to make sure there aren't any outstanding
2792d7c5bf88Spl 	 * FIBs in the message queue. At this point there should not be and
2793d7c5bf88Spl 	 * if there are they are probably left over from another instance of
2794d7c5bf88Spl 	 * the driver like when the system crashes and the crash dump driver
2795d7c5bf88Spl 	 * gets loaded.
2796d7c5bf88Spl 	 */
2797d7c5bf88Spl 	while (AAC_OUTB_GET(softs) != 0xfffffffful)
2798d7c5bf88Spl 		;
2799d7c5bf88Spl 
2800830d82f7Spl 	/*
2801830d82f7Spl 	 * Wait the card to complete booting up before do anything that
2802830d82f7Spl 	 * attempts to communicate with it.
2803830d82f7Spl 	 */
2804382c8bcaSpl 	status = AAC_FWSTATUS_GET(softs);
2805382c8bcaSpl 	if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
2806382c8bcaSpl 		goto error;
2807382c8bcaSpl 	i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
2808382c8bcaSpl 	AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
2809382c8bcaSpl 	if (i == 0) {
2810830d82f7Spl 		cmn_err(CE_CONT, "?Fatal error: controller not ready");
28117675db54Syw 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28127675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2813830d82f7Spl 		goto error;
2814830d82f7Spl 	}
2815830d82f7Spl 
2816830d82f7Spl 	/* Read and set card supported options and settings */
28177675db54Syw 	if (aac_check_firmware(softs) == AACERR) {
28187675db54Syw 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28197675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2820830d82f7Spl 		goto error;
28217675db54Syw 	}
2822830d82f7Spl 
2823f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Add interrupt handlers */
2824f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_register_intrs(softs) == AACERR) {
2825f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		cmn_err(CE_CONT,
2826f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "?Fatal error: interrupts register failed");
2827f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto error;
2828f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
28297c478bd9Sstevel@tonic-gate 
28307c478bd9Sstevel@tonic-gate 	/* Setup communication space with the card */
2831830d82f7Spl 	if (softs->comm_space_dma_handle == NULL) {
2832830d82f7Spl 		if (aac_alloc_comm_space(softs) != AACOK)
2833830d82f7Spl 			goto error;
2834830d82f7Spl 	}
28357c478bd9Sstevel@tonic-gate 	if (aac_setup_comm_space(softs) != AACOK) {
28367c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?Setup communication space failed");
28377675db54Syw 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28387675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28397c478bd9Sstevel@tonic-gate 		goto error;
28407c478bd9Sstevel@tonic-gate 	}
28417c478bd9Sstevel@tonic-gate 
28421dd0a2dbSpl #ifdef DEBUG
2843942c5e3cSpl 	if (aac_get_fw_debug_buffer(softs) != AACOK)
28441dd0a2dbSpl 		cmn_err(CE_CONT, "?firmware UART trace not supported");
28451dd0a2dbSpl #endif
28461dd0a2dbSpl 
2847830d82f7Spl 	/* Allocate slots */
2848c9487164Spl 	if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
2849830d82f7Spl 		cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
2850830d82f7Spl 		goto error;
2851830d82f7Spl 	}
28521dd0a2dbSpl 	AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
2853830d82f7Spl 
2854830d82f7Spl 	/* Allocate FIBs */
2855942c5e3cSpl 	if (softs->total_fibs < softs->total_slots) {
2856942c5e3cSpl 		aac_alloc_fibs(softs);
2857942c5e3cSpl 		if (softs->total_fibs == 0)
2858942c5e3cSpl 			goto error;
2859942c5e3cSpl 		AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
2860942c5e3cSpl 		    softs->total_fibs);
2861830d82f7Spl 	}
2862830d82f7Spl 
2863f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
2864f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
2865f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
28660749e8deSXin Chen - Sun Microsystems - Beijing China 	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
28673fced439Szhongyan gu - Sun Microsystems - Beijing China 		softs->feature_bits = sinf.FeatureBits;
28683fced439Szhongyan gu - Sun Microsystems - Beijing China 		softs->support_opt2 = sinf.SupportedOptions2;
28693fced439Szhongyan gu - Sun Microsystems - Beijing China 
28700749e8deSXin Chen - Sun Microsystems - Beijing China 		/* Get adapter names */
28710749e8deSXin Chen - Sun Microsystems - Beijing China 		if (CARD_IS_UNKNOWN(softs->card)) {
2872d937e6ebSpl 			char *p, *p0, *p1;
2873d937e6ebSpl 
2874d937e6ebSpl 			/*
2875d937e6ebSpl 			 * Now find the controller name in supp_adapter_info->
2876d937e6ebSpl 			 * AdapterTypeText. Use the first word as the vendor
2877d937e6ebSpl 			 * and the other words as the product name.
2878d937e6ebSpl 			 */
28791dd0a2dbSpl 			AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
28801dd0a2dbSpl 			    "\"%s\"", sinf.AdapterTypeText);
2881d937e6ebSpl 			p = sinf.AdapterTypeText;
2882d937e6ebSpl 			p0 = p1 = NULL;
2883d937e6ebSpl 			/* Skip heading spaces */
2884d937e6ebSpl 			while (*p && (*p == ' ' || *p == '\t'))
2885d937e6ebSpl 				p++;
2886d937e6ebSpl 			p0 = p;
2887d937e6ebSpl 			while (*p && (*p != ' ' && *p != '\t'))
2888d937e6ebSpl 				p++;
2889d937e6ebSpl 			/* Remove middle spaces */
2890d937e6ebSpl 			while (*p && (*p == ' ' || *p == '\t'))
2891d937e6ebSpl 				*p++ = 0;
2892d937e6ebSpl 			p1 = p;
2893d937e6ebSpl 			/* Remove trailing spaces */
2894d937e6ebSpl 			p = p1 + strlen(p1) - 1;
2895d937e6ebSpl 			while (p > p1 && (*p == ' ' || *p == '\t'))
2896d937e6ebSpl 				*p-- = 0;
2897d937e6ebSpl 			if (*p0 && *p1) {
2898d937e6ebSpl 				(void *)strncpy(softs->vendor_name, p0,
2899c9487164Spl 				    AAC_VENDOR_LEN);
2900d937e6ebSpl 				(void *)strncpy(softs->product_name, p1,
2901c9487164Spl 				    AAC_PRODUCT_LEN);
2902d937e6ebSpl 			} else {
2903d937e6ebSpl 				cmn_err(CE_WARN,
2904c9487164Spl 				    "?adapter name mis-formatted\n");
2905d937e6ebSpl 				if (*p0)
2906d937e6ebSpl 					(void *)strncpy(softs->product_name,
2907c9487164Spl 					    p0, AAC_PRODUCT_LEN);
2908d937e6ebSpl 			}
2909d937e6ebSpl 		}
29100749e8deSXin Chen - Sun Microsystems - Beijing China 	} else {
29110749e8deSXin Chen - Sun Microsystems - Beijing China 		cmn_err(CE_CONT, "?Query adapter information failed");
2912d937e6ebSpl 	}
2913d937e6ebSpl 
29140749e8deSXin Chen - Sun Microsystems - Beijing China 
29151cea6be9Sxc 	cmn_err(CE_NOTE,
29161cea6be9Sxc 	    "!aac driver %d.%02d.%02d-%d, found card: " \
29171cea6be9Sxc 	    "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
29181cea6be9Sxc 	    AAC_DRIVER_MAJOR_VERSION,
29191cea6be9Sxc 	    AAC_DRIVER_MINOR_VERSION,
29201cea6be9Sxc 	    AAC_DRIVER_BUGFIX_LEVEL,
29211cea6be9Sxc 	    AAC_DRIVER_BUILD,
29221cea6be9Sxc 	    softs->vendor_name, softs->product_name,
29231cea6be9Sxc 	    softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
29241cea6be9Sxc 	    softs->pci_mem_base_paddr);
29251cea6be9Sxc 
2926830d82f7Spl 	/* Perform acceptance of adapter-detected config changes if possible */
2927830d82f7Spl 	if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
2928830d82f7Spl 		cmn_err(CE_CONT, "?Handle adapter config issues failed");
29297675db54Syw 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
29307675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2931830d82f7Spl 		goto error;
2932830d82f7Spl 	}
2933830d82f7Spl 
293458bc78c7SXin Chen 	/* Setup containers (logical devices) */
2935942c5e3cSpl 	if (aac_probe_containers(softs) != AACOK) {
29367c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?Fatal error: get container info error");
29377c478bd9Sstevel@tonic-gate 		goto error;
29387c478bd9Sstevel@tonic-gate 	}
29397c478bd9Sstevel@tonic-gate 
29403fced439Szhongyan gu - Sun Microsystems - Beijing China 	/* Check for JBOD support. Default disable */
29413fced439Szhongyan gu - Sun Microsystems - Beijing China 	char *data;
29423fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
29433fced439Szhongyan gu - Sun Microsystems - Beijing China 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
29443fced439Szhongyan gu - Sun Microsystems - Beijing China 		    0, "jbod-enable", &data) == DDI_SUCCESS)) {
29453fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (strcmp(data, "yes") == 0) {
29463fced439Szhongyan gu - Sun Microsystems - Beijing China 				AACDB_PRINT(softs, CE_NOTE,
29473fced439Szhongyan gu - Sun Microsystems - Beijing China 				    "Enable JBOD access");
29483fced439Szhongyan gu - Sun Microsystems - Beijing China 				softs->flags |= AAC_FLAGS_JBOD;
29493fced439Szhongyan gu - Sun Microsystems - Beijing China 			}
29503fced439Szhongyan gu - Sun Microsystems - Beijing China 			ddi_prop_free(data);
29513fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
29523fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
29533fced439Szhongyan gu - Sun Microsystems - Beijing China 
295458bc78c7SXin Chen 	/* Setup phys. devices */
29553fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
295658bc78c7SXin Chen 		uint32_t bus_max, tgt_max;
295758bc78c7SXin Chen 		uint32_t bus, tgt;
295858bc78c7SXin Chen 		int index;
295958bc78c7SXin Chen 
296058bc78c7SXin Chen 		if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
296158bc78c7SXin Chen 			cmn_err(CE_CONT, "?Fatal error: get bus info error");
296258bc78c7SXin Chen 			goto error;
296358bc78c7SXin Chen 		}
296458bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
296558bc78c7SXin Chen 		    bus_max, tgt_max);
296658bc78c7SXin Chen 		if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
296758bc78c7SXin Chen 			if (softs->state & AAC_STATE_RESET) {
296858bc78c7SXin Chen 				cmn_err(CE_WARN,
296958bc78c7SXin Chen 				    "?Fatal error: bus map changed");
297058bc78c7SXin Chen 				goto error;
297158bc78c7SXin Chen 			}
297258bc78c7SXin Chen 			softs->bus_max = bus_max;
297358bc78c7SXin Chen 			softs->tgt_max = tgt_max;
297458bc78c7SXin Chen 			if (softs->nondasds) {
297558bc78c7SXin Chen 				kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
297658bc78c7SXin Chen 				    sizeof (struct aac_nondasd));
297758bc78c7SXin Chen 			}
297858bc78c7SXin Chen 			softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
297958bc78c7SXin Chen 			    sizeof (struct aac_nondasd), KM_SLEEP);
298058bc78c7SXin Chen 
298158bc78c7SXin Chen 			index = 0;
298258bc78c7SXin Chen 			for (bus = 0; bus < softs->bus_max; bus++) {
298358bc78c7SXin Chen 				for (tgt = 0; tgt < softs->tgt_max; tgt++) {
298458bc78c7SXin Chen 					struct aac_nondasd *dvp =
298558bc78c7SXin Chen 					    &softs->nondasds[index++];
298658bc78c7SXin Chen 					dvp->dev.type = AAC_DEV_PD;
298758bc78c7SXin Chen 					dvp->bus = bus;
298858bc78c7SXin Chen 					dvp->tid = tgt;
298958bc78c7SXin Chen 				}
299058bc78c7SXin Chen 			}
299158bc78c7SXin Chen 		}
299258bc78c7SXin Chen 	}
299358bc78c7SXin Chen 
29947675db54Syw 	/* Check dma & acc handles allocated in attach */
29957675db54Syw 	if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
29967675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29977675db54Syw 		goto error;
29987675db54Syw 	}
29997675db54Syw 
30007675db54Syw 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
30017675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
30027675db54Syw 		goto error;
30037675db54Syw 	}
30047675db54Syw 
30057675db54Syw 	for (i = 0; i < softs->total_slots; i++) {
30067675db54Syw 		if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
30077675db54Syw 		    DDI_SUCCESS) {
30087675db54Syw 			ddi_fm_service_impact(softs->devinfo_p,
30097675db54Syw 			    DDI_SERVICE_LOST);
30107675db54Syw 			goto error;
30117675db54Syw 		}
30127675db54Syw 	}
30137675db54Syw 
30147c478bd9Sstevel@tonic-gate 	return (AACOK);
30157c478bd9Sstevel@tonic-gate error:
3016382c8bcaSpl 	if (softs->state & AAC_STATE_RESET)
3017830d82f7Spl 		return (AACERR);
301858bc78c7SXin Chen 	if (softs->nondasds) {
301958bc78c7SXin Chen 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
302058bc78c7SXin Chen 		    sizeof (struct aac_nondasd));
302158bc78c7SXin Chen 		softs->nondasds = NULL;
302258bc78c7SXin Chen 	}
3023d7c5bf88Spl 	if (softs->total_fibs > 0)
3024d7c5bf88Spl 		aac_destroy_fibs(softs);
3025830d82f7Spl 	if (softs->total_slots > 0)
3026830d82f7Spl 		aac_destroy_slots(softs);
3027830d82f7Spl 	if (softs->comm_space_dma_handle)
3028830d82f7Spl 		aac_free_comm_space(softs);
30297c478bd9Sstevel@tonic-gate 	return (AACERR);
30307c478bd9Sstevel@tonic-gate }
30317c478bd9Sstevel@tonic-gate 
3032830d82f7Spl /*
3033830d82f7Spl  * Hardware shutdown and resource release
3034830d82f7Spl  */
3035830d82f7Spl static void
aac_common_detach(struct aac_softstate * softs)3036830d82f7Spl aac_common_detach(struct aac_softstate *softs)
3037830d82f7Spl {
30381dd0a2dbSpl 	DBCALLED(softs, 1);
3039830d82f7Spl 
3040f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_unregister_intrs(softs);
3041f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3042f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
3043830d82f7Spl 	(void) aac_shutdown(softs);
3044830d82f7Spl 
304558bc78c7SXin Chen 	if (softs->nondasds) {
304658bc78c7SXin Chen 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
304758bc78c7SXin Chen 		    sizeof (struct aac_nondasd));
304858bc78c7SXin Chen 		softs->nondasds = NULL;
304958bc78c7SXin Chen 	}
3050d7c5bf88Spl 	aac_destroy_fibs(softs);
3051830d82f7Spl 	aac_destroy_slots(softs);
3052830d82f7Spl 	aac_free_comm_space(softs);
3053f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
3054830d82f7Spl }
3055830d82f7Spl 
3056830d82f7Spl /*
3057830d82f7Spl  * Send a synchronous command to the controller and wait for a result.
3058830d82f7Spl  * Indicate if the controller completed the command with an error status.
3059830d82f7Spl  */
3060830d82f7Spl int
aac_sync_mbcommand(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,uint32_t * statusp)30617c478bd9Sstevel@tonic-gate aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
3062c9487164Spl     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
3063c9487164Spl     uint32_t *statusp)
30647c478bd9Sstevel@tonic-gate {
3065382c8bcaSpl 	int timeout;
30667c478bd9Sstevel@tonic-gate 	uint32_t status;
30677c478bd9Sstevel@tonic-gate 
3068830d82f7Spl 	if (statusp != NULL)
3069c9487164Spl 		*statusp = SRB_STATUS_SUCCESS;
3070830d82f7Spl 
3071830d82f7Spl 	/* Fill in mailbox */
30727c478bd9Sstevel@tonic-gate 	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
30737c478bd9Sstevel@tonic-gate 
3074830d82f7Spl 	/* Ensure the sync command doorbell flag is cleared */
30757c478bd9Sstevel@tonic-gate 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30767c478bd9Sstevel@tonic-gate 
3077830d82f7Spl 	/* Then set it to signal the adapter */
30787c478bd9Sstevel@tonic-gate 	AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
30797c478bd9Sstevel@tonic-gate 
3080830d82f7Spl 	/* Spin waiting for the command to complete */
3081382c8bcaSpl 	timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
3082382c8bcaSpl 	AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
3083382c8bcaSpl 	if (!timeout) {
30841dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
3085c9487164Spl 		    "Sync command timed out after %d seconds (0x%x)!",
30861dd0a2dbSpl 		    AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
3087830d82f7Spl 		return (AACERR);
30887c478bd9Sstevel@tonic-gate 	}
30897c478bd9Sstevel@tonic-gate 
3090830d82f7Spl 	/* Clear the completion flag */
30917c478bd9Sstevel@tonic-gate 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30927c478bd9Sstevel@tonic-gate 
3093830d82f7Spl 	/* Get the command status */
30947c478bd9Sstevel@tonic-gate 	status = AAC_MAILBOX_GET(softs, 0);
30957c478bd9Sstevel@tonic-gate 	if (statusp != NULL)
30967c478bd9Sstevel@tonic-gate 		*statusp = status;
3097c9487164Spl 	if (status != SRB_STATUS_SUCCESS) {
30981dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
30991dd0a2dbSpl 		    "Sync command fail: status = 0x%x", status);
3100830d82f7Spl 		return (AACERR);
3101830d82f7Spl 	}
3102830d82f7Spl 
31037c478bd9Sstevel@tonic-gate 	return (AACOK);
31047c478bd9Sstevel@tonic-gate }
31057c478bd9Sstevel@tonic-gate 
3106830d82f7Spl /*
3107830d82f7Spl  * Send a synchronous FIB to the adapter and wait for its completion
3108830d82f7Spl  */
31097c478bd9Sstevel@tonic-gate static int
aac_sync_fib(struct aac_softstate * softs,uint16_t cmd,uint16_t fibsize)3110942c5e3cSpl aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
31117c478bd9Sstevel@tonic-gate {
3112f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
31137c478bd9Sstevel@tonic-gate 
31141ee13a44SXinChen 	acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
31151ee13a44SXinChen 	if (softs->state & AAC_STATE_INTR)
31161ee13a44SXinChen 		acp->flags |= AAC_CMD_NO_CB;
31171ee13a44SXinChen 	else
31181ee13a44SXinChen 		acp->flags |= AAC_CMD_NO_INTR;
31191ee13a44SXinChen 
3120f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->ac_comp = aac_sync_complete;
3121f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->timeout = AAC_SYNC_TIMEOUT;
3122f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = fibsize;
31231ee13a44SXinChen 
3124942c5e3cSpl 	/*
3125f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	 * Only need to setup sync fib header, caller should have init
3126f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	 * fib data
3127942c5e3cSpl 	 */
3128f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, cmd);
312958bc78c7SXin Chen 
31301ee13a44SXinChen 	(void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
31311ee13a44SXinChen 	    DDI_DMA_SYNC_FORDEV);
3132830d82f7Spl 
31331ee13a44SXinChen 	aac_start_io(softs, acp);
31347675db54Syw 
31351ee13a44SXinChen 	if (softs->state & AAC_STATE_INTR)
31361ee13a44SXinChen 		return (aac_do_sync_io(softs, acp));
31371ee13a44SXinChen 	else
31381ee13a44SXinChen 		return (aac_do_poll_io(softs, acp));
31397c478bd9Sstevel@tonic-gate }
31407c478bd9Sstevel@tonic-gate 
3141382c8bcaSpl static void
aac_cmd_initq(struct aac_cmd_queue * q)3142382c8bcaSpl aac_cmd_initq(struct aac_cmd_queue *q)
3143382c8bcaSpl {
3144382c8bcaSpl 	q->q_head = NULL;
3145382c8bcaSpl 	q->q_tail = (struct aac_cmd *)&q->q_head;
3146382c8bcaSpl }
3147382c8bcaSpl 
3148830d82f7Spl /*
3149c9487164Spl  * Remove a cmd from the head of q
3150830d82f7Spl  */
31517c478bd9Sstevel@tonic-gate static struct aac_cmd *
aac_cmd_dequeue(struct aac_cmd_queue * q)31527c478bd9Sstevel@tonic-gate aac_cmd_dequeue(struct aac_cmd_queue *q)
31537c478bd9Sstevel@tonic-gate {
3154382c8bcaSpl 	struct aac_cmd *acp;
3155382c8bcaSpl 
3156382c8bcaSpl 	_NOTE(ASSUMING_PROTECTED(*q))
3157c9487164Spl 
3158382c8bcaSpl 	if ((acp = q->q_head) != NULL) {
3159382c8bcaSpl 		if ((q->q_head = acp->next) != NULL)
3160382c8bcaSpl 			acp->next = NULL;
3161382c8bcaSpl 		else
3162382c8bcaSpl 			q->q_tail = (struct aac_cmd *)&q->q_head;
3163382c8bcaSpl 		acp->prev = NULL;
31647c478bd9Sstevel@tonic-gate 	}
3165382c8bcaSpl 	return (acp);
31667c478bd9Sstevel@tonic-gate }
31677c478bd9Sstevel@tonic-gate 
3168830d82f7Spl /*
3169830d82f7Spl  * Add a cmd to the tail of q
3170830d82f7Spl  */
31717c478bd9Sstevel@tonic-gate static void
aac_cmd_enqueue(struct aac_cmd_queue * q,struct aac_cmd * acp)3172c9487164Spl aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
31737c478bd9Sstevel@tonic-gate {
3174382c8bcaSpl 	ASSERT(acp->next == NULL);
3175382c8bcaSpl 	acp->prev = q->q_tail;
3176382c8bcaSpl 	q->q_tail->next = acp;
3177c9487164Spl 	q->q_tail = acp;
3178382c8bcaSpl }
3179382c8bcaSpl 
3180382c8bcaSpl /*
3181382c8bcaSpl  * Remove the cmd ac from q
3182382c8bcaSpl  */
3183382c8bcaSpl static void
aac_cmd_delete(struct aac_cmd_queue * q,struct aac_cmd * acp)3184382c8bcaSpl aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
3185382c8bcaSpl {
3186382c8bcaSpl 	if (acp->prev) {
3187382c8bcaSpl 		if ((acp->prev->next = acp->next) != NULL) {
3188382c8bcaSpl 			acp->next->prev = acp->prev;
3189382c8bcaSpl 			acp->next = NULL;
3190382c8bcaSpl 		} else {
3191382c8bcaSpl 			q->q_tail = acp->prev;
3192382c8bcaSpl 		}
3193382c8bcaSpl 		acp->prev = NULL;
3194382c8bcaSpl 	}
3195382c8bcaSpl 	/* ac is not in the queue */
31967c478bd9Sstevel@tonic-gate }
31977c478bd9Sstevel@tonic-gate 
3198830d82f7Spl /*
3199830d82f7Spl  * Atomically insert an entry into the nominated queue, returns 0 on success or
3200830d82f7Spl  * AACERR if the queue is full.
3201830d82f7Spl  *
3202830d82f7Spl  * Note: it would be more efficient to defer notifying the controller in
3203830d82f7Spl  *	 the case where we may be inserting several entries in rapid succession,
3204830d82f7Spl  *	 but implementing this usefully may be difficult (it would involve a
3205830d82f7Spl  *	 separate queue/notify interface).
3206830d82f7Spl  */
32077c478bd9Sstevel@tonic-gate static int
aac_fib_enqueue(struct aac_softstate * softs,int queue,uint32_t fib_addr,uint32_t fib_size)3208d7c5bf88Spl aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
3209d7c5bf88Spl     uint32_t fib_size)
32107c478bd9Sstevel@tonic-gate {
3211942c5e3cSpl 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3212942c5e3cSpl 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
32137c478bd9Sstevel@tonic-gate 	uint32_t pi, ci;
32147c478bd9Sstevel@tonic-gate 
32151dd0a2dbSpl 	DBCALLED(softs, 2);
32167c478bd9Sstevel@tonic-gate 
3217d7c5bf88Spl 	ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
32187c478bd9Sstevel@tonic-gate 
3219830d82f7Spl 	/* Get the producer/consumer indices */
3220a74f7440Spl 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3221a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32227675db54Syw 	    DDI_DMA_SYNC_FORCPU);
3223942c5e3cSpl 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
32247675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
32257675db54Syw 		return (AACERR);
32267675db54Syw 	}
32277675db54Syw 
3228942c5e3cSpl 	pi = ddi_get32(acc,
3229942c5e3cSpl 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3230942c5e3cSpl 	ci = ddi_get32(acc,
3231942c5e3cSpl 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3232830d82f7Spl 
3233830d82f7Spl 	/*
3234830d82f7Spl 	 * Wrap the queue first before we check the queue to see
3235830d82f7Spl 	 * if it is full
3236830d82f7Spl 	 */
3237830d82f7Spl 	if (pi >= aac_qinfo[queue].size)
3238830d82f7Spl 		pi = 0;
3239830d82f7Spl 
3240830d82f7Spl 	/* XXX queue full */
3241382c8bcaSpl 	if ((pi + 1) == ci)
3242830d82f7Spl 		return (AACERR);
3243830d82f7Spl 
3244830d82f7Spl 	/* Fill in queue entry */
3245942c5e3cSpl 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
3246942c5e3cSpl 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
3247a74f7440Spl 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3248a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3249942c5e3cSpl 	    DDI_DMA_SYNC_FORDEV);
3250830d82f7Spl 
3251830d82f7Spl 	/* Update producer index */
3252942c5e3cSpl 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
3253942c5e3cSpl 	    pi + 1);
3254942c5e3cSpl 	(void) ddi_dma_sync(dma,
3255a74f7440Spl 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
3256a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
32577675db54Syw 	    DDI_DMA_SYNC_FORDEV);
3258830d82f7Spl 
3259830d82f7Spl 	if (aac_qinfo[queue].notify != 0)
3260830d82f7Spl 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3261830d82f7Spl 	return (AACOK);
3262830d82f7Spl }
3263830d82f7Spl 
3264830d82f7Spl /*
3265830d82f7Spl  * Atomically remove one entry from the nominated queue, returns 0 on
3266830d82f7Spl  * success or AACERR if the queue is empty.
3267830d82f7Spl  */
3268830d82f7Spl static int
aac_fib_dequeue(struct aac_softstate * softs,int queue,int * idxp)3269d7c5bf88Spl aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
3270830d82f7Spl {
3271942c5e3cSpl 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3272942c5e3cSpl 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3273d7c5bf88Spl 	uint32_t pi, ci;
3274d7c5bf88Spl 	int unfull = 0;
3275830d82f7Spl 
32761dd0a2dbSpl 	DBCALLED(softs, 2);
32777c478bd9Sstevel@tonic-gate 
3278d7c5bf88Spl 	ASSERT(idxp);
3279d7c5bf88Spl 
3280830d82f7Spl 	/* Get the producer/consumer indices */
3281a74f7440Spl 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3282a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32837675db54Syw 	    DDI_DMA_SYNC_FORCPU);
3284942c5e3cSpl 	pi = ddi_get32(acc,
3285942c5e3cSpl 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3286942c5e3cSpl 	ci = ddi_get32(acc,
3287942c5e3cSpl 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
32887c478bd9Sstevel@tonic-gate 
3289830d82f7Spl 	/* Check for queue empty */
3290382c8bcaSpl 	if (ci == pi)
3291382c8bcaSpl 		return (AACERR);
32927c478bd9Sstevel@tonic-gate 
3293830d82f7Spl 	if (pi >= aac_qinfo[queue].size)
3294830d82f7Spl 		pi = 0;
3295382c8bcaSpl 
3296830d82f7Spl 	/* Check for queue full */
32977c478bd9Sstevel@tonic-gate 	if (ci == pi + 1)
32987c478bd9Sstevel@tonic-gate 		unfull = 1;
32997c478bd9Sstevel@tonic-gate 
33007c478bd9Sstevel@tonic-gate 	/*
3301830d82f7Spl 	 * The controller does not wrap the queue,
33027c478bd9Sstevel@tonic-gate 	 * so we have to do it by ourselves
33037c478bd9Sstevel@tonic-gate 	 */
33047c478bd9Sstevel@tonic-gate 	if (ci >= aac_qinfo[queue].size)
33057c478bd9Sstevel@tonic-gate 		ci = 0;
33067c478bd9Sstevel@tonic-gate 
3307830d82f7Spl 	/* Fetch the entry */
3308a74f7440Spl 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3309a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
33107675db54Syw 	    DDI_DMA_SYNC_FORCPU);
3311942c5e3cSpl 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
33127675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3313382c8bcaSpl 		return (AACERR);
33147675db54Syw 	}
33157675db54Syw 
3316830d82f7Spl 	switch (queue) {
3317d7c5bf88Spl 	case AAC_HOST_NORM_RESP_Q:
3318d7c5bf88Spl 	case AAC_HOST_HIGH_RESP_Q:
3319942c5e3cSpl 		*idxp = ddi_get32(acc,
3320942c5e3cSpl 		    &(softs->qentries[queue] + ci)->aq_fib_addr);
3321d7c5bf88Spl 		break;
3322d7c5bf88Spl 
3323830d82f7Spl 	case AAC_HOST_NORM_CMD_Q:
3324830d82f7Spl 	case AAC_HOST_HIGH_CMD_Q:
3325942c5e3cSpl 		*idxp = ddi_get32(acc,
3326942c5e3cSpl 		    &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
3327830d82f7Spl 		break;
3328830d82f7Spl 
3329830d82f7Spl 	default:
3330830d82f7Spl 		cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
3331382c8bcaSpl 		return (AACERR);
3332830d82f7Spl 	}
33337c478bd9Sstevel@tonic-gate 
3334830d82f7Spl 	/* Update consumer index */
3335942c5e3cSpl 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
3336942c5e3cSpl 	    ci + 1);
3337942c5e3cSpl 	(void) ddi_dma_sync(dma,
3338a74f7440Spl 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
3339a74f7440Spl 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
33407675db54Syw 	    DDI_DMA_SYNC_FORDEV);
3341382c8bcaSpl 
3342830d82f7Spl 	if (unfull && aac_qinfo[queue].notify != 0)
3343830d82f7Spl 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3344382c8bcaSpl 	return (AACOK);
3345830d82f7Spl }
3346830d82f7Spl 
3347830d82f7Spl static struct aac_mntinforesp *
aac_get_mntinfo(struct aac_softstate * softs,int cid)3348f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_get_mntinfo(struct aac_softstate *softs, int cid)
3349830d82f7Spl {
3350f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3351f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
3352942c5e3cSpl 	struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
33537675db54Syw 	struct aac_mntinforesp *mir;
3354830d82f7Spl 
3355942c5e3cSpl 	ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
3356c9487164Spl 	    (softs->flags & AAC_FLAGS_LBA_64BIT) ?
3357942c5e3cSpl 	    VM_NameServe64 : VM_NameServe);
3358942c5e3cSpl 	ddi_put32(acc, &mi->MntType, FT_FILESYS);
3359942c5e3cSpl 	ddi_put32(acc, &mi->MntCount, cid);
3360830d82f7Spl 
3361942c5e3cSpl 	if (aac_sync_fib(softs, ContainerCommand,
3362942c5e3cSpl 	    AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
33631dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
3364830d82f7Spl 		return (NULL);
3365830d82f7Spl 	}
3366830d82f7Spl 
33677675db54Syw 	mir = (struct aac_mntinforesp *)&fibp->data[0];
3368942c5e3cSpl 	if (ddi_get32(acc, &mir->Status) == ST_OK)
33697675db54Syw 		return (mir);
33707675db54Syw 	return (NULL);
3371830d82f7Spl }
33727c478bd9Sstevel@tonic-gate 
3373382c8bcaSpl static int
aac_get_container_count(struct aac_softstate * softs,int * count)3374942c5e3cSpl aac_get_container_count(struct aac_softstate *softs, int *count)
3375830d82f7Spl {
3376f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
3377942c5e3cSpl 	struct aac_mntinforesp *mir;
3378f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
3379830d82f7Spl 
3380f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3381f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
3382f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3383f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
3384f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
3385f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3386f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3387942c5e3cSpl 	*count = ddi_get32(acc, &mir->MntRespCount);
3388942c5e3cSpl 	if (*count > AAC_MAX_LD) {
3389942c5e3cSpl 		AACDB_PRINT(softs, CE_CONT,
3390942c5e3cSpl 		    "container count(%d) > AAC_MAX_LD", *count);
3391f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
3392f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3393942c5e3cSpl 	}
3394f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = AACOK;
3395f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3396f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
3397f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3398f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
3399830d82f7Spl }
3400830d82f7Spl 
3401942c5e3cSpl static int
aac_get_container_uid(struct aac_softstate * softs,uint32_t cid,uint32_t * uid)3402942c5e3cSpl aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
3403830d82f7Spl {
3404f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3405942c5e3cSpl 	struct aac_Container *ct = (struct aac_Container *) \
3406f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    &softs->sync_ac.slotp->fibp->data[0];
3407382c8bcaSpl 
3408942c5e3cSpl 	bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
3409942c5e3cSpl 	ddi_put32(acc, &ct->Command, VM_ContainerConfig);
3410942c5e3cSpl 	ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
3411942c5e3cSpl 	ddi_put32(acc, &ct->CTCommand.param[0], cid);
3412942c5e3cSpl 
3413942c5e3cSpl 	if (aac_sync_fib(softs, ContainerCommand,
3414942c5e3cSpl 	    AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
3415942c5e3cSpl 		return (AACERR);
3416942c5e3cSpl 	if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
3417942c5e3cSpl 		return (AACERR);
3418942c5e3cSpl 
3419942c5e3cSpl 	*uid = ddi_get32(acc, &ct->CTCommand.param[1]);
3420942c5e3cSpl 	return (AACOK);
34217c478bd9Sstevel@tonic-gate }
34227c478bd9Sstevel@tonic-gate 
3423f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
3424f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Request information of the container cid
3425f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
3426f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static struct aac_mntinforesp *
aac_get_container_info(struct aac_softstate * softs,int cid)3427f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_get_container_info(struct aac_softstate *softs, int cid)
3428f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
3429f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3430f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_mntinforesp *mir;
3431f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval_uid;
3432f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t uid;
3433f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3434f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get container UID first so that it will not overwrite mntinfo */
3435f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval_uid = aac_get_container_uid(softs, cid, &uid);
3436f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3437f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get container basic info */
3438f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
3439f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_CONT,
3440f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "query container %d info failed", cid);
3441f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (NULL);
3442f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3443f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
3444f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (mir);
3445f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (rval_uid != AACOK) {
3446f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_CONT,
3447f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "query container %d uid failed", cid);
3448f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (NULL);
3449f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3450f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3451f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &mir->Status, uid);
3452f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (mir);
3453f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
3454f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
34550749e8deSXin Chen - Sun Microsystems - Beijing China static enum aac_cfg_event
aac_probe_container(struct aac_softstate * softs,uint32_t cid)3456942c5e3cSpl aac_probe_container(struct aac_softstate *softs, uint32_t cid)
34577c478bd9Sstevel@tonic-gate {
34580749e8deSXin Chen - Sun Microsystems - Beijing China 	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
3459942c5e3cSpl 	struct aac_container *dvp = &softs->containers[cid];
3460830d82f7Spl 	struct aac_mntinforesp *mir;
34610749e8deSXin Chen - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
3462f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3463f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3464f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
34657c478bd9Sstevel@tonic-gate 
3466942c5e3cSpl 	/* Get container basic info */
3467f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
34680749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AAC_CFG_NULL_NOEXIST */
3469f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3470f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3471830d82f7Spl 
3472942c5e3cSpl 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
347358bc78c7SXin Chen 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3474942c5e3cSpl 			AACDB_PRINT(softs, CE_NOTE,
3475942c5e3cSpl 			    ">>> Container %d deleted", cid);
347658bc78c7SXin Chen 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
34770749e8deSXin Chen - Sun Microsystems - Beijing China 			event = AAC_CFG_DELETE;
3478942c5e3cSpl 		}
34790749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AAC_CFG_NULL_NOEXIST */
3480942c5e3cSpl 	} else {
34810749e8deSXin Chen - Sun Microsystems - Beijing China 		uint64_t size;
34820749e8deSXin Chen - Sun Microsystems - Beijing China 		uint32_t uid;
34830749e8deSXin Chen - Sun Microsystems - Beijing China 
34840749e8deSXin Chen - Sun Microsystems - Beijing China 		event = AAC_CFG_NULL_EXIST;
34850749e8deSXin Chen - Sun Microsystems - Beijing China 
3486942c5e3cSpl 		size = AAC_MIR_SIZE(softs, acc, mir);
3487f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		uid = ddi_get32(acc, &mir->Status);
348858bc78c7SXin Chen 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3489942c5e3cSpl 			if (dvp->uid != uid) {
3490942c5e3cSpl 				AACDB_PRINT(softs, CE_WARN,
3491942c5e3cSpl 				    ">>> Container %u uid changed to %d",
3492942c5e3cSpl 				    cid, uid);
3493942c5e3cSpl 				dvp->uid = uid;
34940749e8deSXin Chen - Sun Microsystems - Beijing China 				event = AAC_CFG_CHANGE;
3495942c5e3cSpl 			}
3496942c5e3cSpl 			if (dvp->size != size) {
3497942c5e3cSpl 				AACDB_PRINT(softs, CE_NOTE,
3498942c5e3cSpl 				    ">>> Container %u size changed to %"PRIu64,
3499942c5e3cSpl 				    cid, size);
3500942c5e3cSpl 				dvp->size = size;
35010749e8deSXin Chen - Sun Microsystems - Beijing China 				event = AAC_CFG_CHANGE;
3502942c5e3cSpl 			}
3503942c5e3cSpl 		} else { /* Init new container */
3504942c5e3cSpl 			AACDB_PRINT(softs, CE_NOTE,
350558bc78c7SXin Chen 			    ">>> Container %d added: " \
350658bc78c7SXin Chen 			    "size=0x%x.%08x, type=%d, name=%s",
350758bc78c7SXin Chen 			    cid,
350858bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.CapacityHigh),
350958bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.Capacity),
351058bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.VolType),
351158bc78c7SXin Chen 			    mir->MntObj.FileSystemName);
351258bc78c7SXin Chen 			dvp->dev.flags |= AAC_DFLAG_VALID;
351358bc78c7SXin Chen 			dvp->dev.type = AAC_DEV_LD;
35147c478bd9Sstevel@tonic-gate 
3515942c5e3cSpl 			dvp->cid = cid;
3516942c5e3cSpl 			dvp->uid = uid;
3517942c5e3cSpl 			dvp->size = size;
3518942c5e3cSpl 			dvp->locked = 0;
3519942c5e3cSpl 			dvp->deleted = 0;
35200749e8deSXin Chen - Sun Microsystems - Beijing China 
35210749e8deSXin Chen - Sun Microsystems - Beijing China 			event = AAC_CFG_ADD;
3522942c5e3cSpl 		}
3523942c5e3cSpl 	}
3524f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3525f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
3526f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
35270749e8deSXin Chen - Sun Microsystems - Beijing China 	return (event);
35287c478bd9Sstevel@tonic-gate }
35297c478bd9Sstevel@tonic-gate 
3530830d82f7Spl /*
3531830d82f7Spl  * Do a rescan of all the possible containers and update the container list
353258bc78c7SXin Chen  * with newly online/offline containers, and prepare for autoconfiguration.
3533830d82f7Spl  */
3534942c5e3cSpl static int
aac_probe_containers(struct aac_softstate * softs)3535942c5e3cSpl aac_probe_containers(struct aac_softstate *softs)
3536830d82f7Spl {
3537942c5e3cSpl 	int i, count, total;
3538830d82f7Spl 
3539942c5e3cSpl 	/* Loop over possible containers */
3540942c5e3cSpl 	count = softs->container_count;
3541942c5e3cSpl 	if (aac_get_container_count(softs, &count) == AACERR)
3542942c5e3cSpl 		return (AACERR);
35430749e8deSXin Chen - Sun Microsystems - Beijing China 
3544942c5e3cSpl 	for (i = total = 0; i < count; i++) {
35450749e8deSXin Chen - Sun Microsystems - Beijing China 		enum aac_cfg_event event = aac_probe_container(softs, i);
35460749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((event != AAC_CFG_NULL_NOEXIST) &&
35470749e8deSXin Chen - Sun Microsystems - Beijing China 		    (event != AAC_CFG_NULL_EXIST)) {
35480749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_dr(softs, i, -1, event);
3549942c5e3cSpl 			total++;
35500749e8deSXin Chen - Sun Microsystems - Beijing China 		}
3551942c5e3cSpl 	}
35520749e8deSXin Chen - Sun Microsystems - Beijing China 
3553830d82f7Spl 	if (count < softs->container_count) {
3554942c5e3cSpl 		struct aac_container *dvp;
3555942c5e3cSpl 
3556942c5e3cSpl 		for (dvp = &softs->containers[count];
3557942c5e3cSpl 		    dvp < &softs->containers[softs->container_count]; dvp++) {
355858bc78c7SXin Chen 			if (!AAC_DEV_IS_VALID(&dvp->dev))
3559830d82f7Spl 				continue;
35601dd0a2dbSpl 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
3561382c8bcaSpl 			    dvp->cid);
356258bc78c7SXin Chen 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
35630749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_dr(softs, dvp->cid, -1,
35640749e8deSXin Chen - Sun Microsystems - Beijing China 			    AAC_CFG_DELETE);
3565830d82f7Spl 		}
3566830d82f7Spl 	}
35670749e8deSXin Chen - Sun Microsystems - Beijing China 
3568942c5e3cSpl 	softs->container_count = count;
3569942c5e3cSpl 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
3570942c5e3cSpl 	return (AACOK);
3571830d82f7Spl }
3572830d82f7Spl 
35733fced439Szhongyan gu - Sun Microsystems - Beijing China static int
aac_probe_jbod(struct aac_softstate * softs,int tgt,int event)35743fced439Szhongyan gu - Sun Microsystems - Beijing China aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
35753fced439Szhongyan gu - Sun Microsystems - Beijing China {
35763ce33fb0SHengqing Hu 	ASSERT(AAC_MAX_LD <= tgt);
35773ce33fb0SHengqing Hu 	ASSERT(tgt < AAC_MAX_DEV(softs));
35783fced439Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_device *dvp;
35793fced439Szhongyan gu - Sun Microsystems - Beijing China 	dvp = AAC_DEV(softs, tgt);
35803fced439Szhongyan gu - Sun Microsystems - Beijing China 
35813fced439Szhongyan gu - Sun Microsystems - Beijing China 	switch (event) {
35823fced439Szhongyan gu - Sun Microsystems - Beijing China 	case AAC_CFG_ADD:
35833fced439Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE,
35843fced439Szhongyan gu - Sun Microsystems - Beijing China 		    ">>> Jbod %d added", tgt - AAC_MAX_LD);
35853fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->flags |= AAC_DFLAG_VALID;
35863fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->type = AAC_DEV_PD;
35873fced439Szhongyan gu - Sun Microsystems - Beijing China 		break;
35883fced439Szhongyan gu - Sun Microsystems - Beijing China 	case AAC_CFG_DELETE:
35893fced439Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE,
35903fced439Szhongyan gu - Sun Microsystems - Beijing China 		    ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
35913fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->flags &= ~AAC_DFLAG_VALID;
35923fced439Szhongyan gu - Sun Microsystems - Beijing China 		break;
35933fced439Szhongyan gu - Sun Microsystems - Beijing China 	default:
35943fced439Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
35953fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
35963fced439Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_handle_dr(softs, tgt, 0, event);
35973fced439Szhongyan gu - Sun Microsystems - Beijing China 	return (AACOK);
35983fced439Szhongyan gu - Sun Microsystems - Beijing China }
35993fced439Szhongyan gu - Sun Microsystems - Beijing China 
36007c478bd9Sstevel@tonic-gate static int
aac_alloc_comm_space(struct aac_softstate * softs)3601830d82f7Spl aac_alloc_comm_space(struct aac_softstate *softs)
36027c478bd9Sstevel@tonic-gate {
36037c478bd9Sstevel@tonic-gate 	size_t rlen;
36047c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t cookie;
36057c478bd9Sstevel@tonic-gate 	uint_t cookien;
36067c478bd9Sstevel@tonic-gate 
3607830d82f7Spl 	/* Allocate DMA for comm. space */
36087c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(
3609c9487164Spl 	    softs->devinfo_p,
3610c9487164Spl 	    &softs->addr_dma_attr,
3611c9487164Spl 	    DDI_DMA_SLEEP,
3612c9487164Spl 	    NULL,
3613c9487164Spl 	    &softs->comm_space_dma_handle) != DDI_SUCCESS) {
36141dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
36151dd0a2dbSpl 		    "Cannot alloc dma handle for communication area");
36167c478bd9Sstevel@tonic-gate 		goto error;
36177c478bd9Sstevel@tonic-gate 	}
36187c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(
3619c9487164Spl 	    softs->comm_space_dma_handle,
3620c9487164Spl 	    sizeof (struct aac_comm_space),
362158bc78c7SXin Chen 	    &softs->acc_attr,
3622c9487164Spl 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3623c9487164Spl 	    DDI_DMA_SLEEP,
3624c9487164Spl 	    NULL,
3625c9487164Spl 	    (caddr_t *)&softs->comm_space,
3626c9487164Spl 	    &rlen,
3627c9487164Spl 	    &softs->comm_space_acc_handle) != DDI_SUCCESS) {
36281dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
36291dd0a2dbSpl 		    "Cannot alloc mem for communication area");
36307c478bd9Sstevel@tonic-gate 		goto error;
36317c478bd9Sstevel@tonic-gate 	}
36327c478bd9Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(
3633c9487164Spl 	    softs->comm_space_dma_handle,
3634c9487164Spl 	    NULL,
3635c9487164Spl 	    (caddr_t)softs->comm_space,
3636c9487164Spl 	    sizeof (struct aac_comm_space),
3637c9487164Spl 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3638c9487164Spl 	    DDI_DMA_SLEEP,
3639c9487164Spl 	    NULL,
3640c9487164Spl 	    &cookie,
3641c9487164Spl 	    &cookien) != DDI_DMA_MAPPED) {
36421dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
36431dd0a2dbSpl 		    "DMA bind failed for communication area");
36447c478bd9Sstevel@tonic-gate 		goto error;
36457c478bd9Sstevel@tonic-gate 	}
3646830d82f7Spl 	softs->comm_space_phyaddr = cookie.dmac_address;
3647830d82f7Spl 
3648830d82f7Spl 	return (AACOK);
36497c478bd9Sstevel@tonic-gate error:
36507c478bd9Sstevel@tonic-gate 	if (softs->comm_space_acc_handle) {
36517c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&softs->comm_space_acc_handle);
36527c478bd9Sstevel@tonic-gate 		softs->comm_space_acc_handle = NULL;
36537c478bd9Sstevel@tonic-gate 	}
36547c478bd9Sstevel@tonic-gate 	if (softs->comm_space_dma_handle) {
36557c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&softs->comm_space_dma_handle);
36567c478bd9Sstevel@tonic-gate 		softs->comm_space_dma_handle = NULL;
36577c478bd9Sstevel@tonic-gate 	}
36587c478bd9Sstevel@tonic-gate 	return (AACERR);
36597c478bd9Sstevel@tonic-gate }
36607c478bd9Sstevel@tonic-gate 
36617c478bd9Sstevel@tonic-gate static void
aac_free_comm_space(struct aac_softstate * softs)3662830d82f7Spl aac_free_comm_space(struct aac_softstate *softs)
3663830d82f7Spl {
3664942c5e3cSpl 
3665830d82f7Spl 	(void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
3666830d82f7Spl 	ddi_dma_mem_free(&softs->comm_space_acc_handle);
3667830d82f7Spl 	softs->comm_space_acc_handle = NULL;
3668830d82f7Spl 	ddi_dma_free_handle(&softs->comm_space_dma_handle);
3669830d82f7Spl 	softs->comm_space_dma_handle = NULL;
367048e2f283SToomas Soome 	softs->comm_space_phyaddr = 0;
3671830d82f7Spl }
3672830d82f7Spl 
3673830d82f7Spl /*
3674830d82f7Spl  * Initialize the data structures that are required for the communication
3675830d82f7Spl  * interface to operate
3676830d82f7Spl  */
3677830d82f7Spl static int
aac_setup_comm_space(struct aac_softstate * softs)3678830d82f7Spl aac_setup_comm_space(struct aac_softstate *softs)
3679830d82f7Spl {
3680942c5e3cSpl 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3681942c5e3cSpl 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3682830d82f7Spl 	uint32_t comm_space_phyaddr;
3683830d82f7Spl 	struct aac_adapter_init *initp;
3684830d82f7Spl 	int qoffset;
3685830d82f7Spl 
3686830d82f7Spl 	comm_space_phyaddr = softs->comm_space_phyaddr;
3687830d82f7Spl 
3688830d82f7Spl 	/* Setup adapter init struct */
3689830d82f7Spl 	initp = &softs->comm_space->init_data;
3690830d82f7Spl 	bzero(initp, sizeof (struct aac_adapter_init));
3691942c5e3cSpl 
3692942c5e3cSpl 	ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
3693942c5e3cSpl 	ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
3694830d82f7Spl 
3695830d82f7Spl 	/* Setup new/old comm. specific data */
3696830d82f7Spl 	if (softs->flags & AAC_FLAGS_RAW_IO) {
3697b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		uint32_t init_flags = 0;
3698b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
3699b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->flags & AAC_FLAGS_NEW_COMM)
3700b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
3701b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		/* AAC_SUPPORTED_POWER_MANAGEMENT */
3702b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
3703b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
3704b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
3705942c5e3cSpl 		ddi_put32(acc, &initp->InitStructRevision,
3706942c5e3cSpl 		    AAC_INIT_STRUCT_REVISION_4);
3707b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		ddi_put32(acc, &initp->InitFlags, init_flags);
3708830d82f7Spl 		/* Setup the preferred settings */
3709942c5e3cSpl 		ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
3710942c5e3cSpl 		ddi_put32(acc, &initp->MaxIoSize,
3711942c5e3cSpl 		    (softs->aac_max_sectors << 9));
3712942c5e3cSpl 		ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
3713830d82f7Spl 	} else {
3714830d82f7Spl 		/*
3715830d82f7Spl 		 * Tells the adapter about the physical location of various
3716830d82f7Spl 		 * important shared data structures
3717830d82f7Spl 		 */
3718942c5e3cSpl 		ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
3719942c5e3cSpl 		    comm_space_phyaddr + \
3720942c5e3cSpl 		    offsetof(struct aac_comm_space, adapter_fibs));
3721942c5e3cSpl 		ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
3722942c5e3cSpl 		ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
3723942c5e3cSpl 		ddi_put32(acc, &initp->AdapterFibsSize,
3724942c5e3cSpl 		    AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
3725942c5e3cSpl 		ddi_put32(acc, &initp->PrintfBufferAddress,
3726942c5e3cSpl 		    comm_space_phyaddr + \
3727942c5e3cSpl 		    offsetof(struct aac_comm_space, adapter_print_buf));
3728942c5e3cSpl 		ddi_put32(acc, &initp->PrintfBufferSize,
3729942c5e3cSpl 		    AAC_ADAPTER_PRINT_BUFSIZE);
3730942c5e3cSpl 		ddi_put32(acc, &initp->MiniPortRevision,
3731942c5e3cSpl 		    AAC_INIT_STRUCT_MINIPORT_REVISION);
3732942c5e3cSpl 		ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
3733830d82f7Spl 
3734830d82f7Spl 		qoffset = (comm_space_phyaddr + \
3735942c5e3cSpl 		    offsetof(struct aac_comm_space, qtable)) % \
3736c9487164Spl 		    AAC_QUEUE_ALIGN;
3737830d82f7Spl 		if (qoffset)
3738830d82f7Spl 			qoffset = AAC_QUEUE_ALIGN - qoffset;
3739830d82f7Spl 		softs->qtablep = (struct aac_queue_table *) \
3740c9487164Spl 		    ((char *)&softs->comm_space->qtable + qoffset);
3741942c5e3cSpl 		ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
3742942c5e3cSpl 		    offsetof(struct aac_comm_space, qtable) + qoffset);
3743830d82f7Spl 
3744830d82f7Spl 		/* Init queue table */
3745942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3746942c5e3cSpl 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3747942c5e3cSpl 		    AAC_HOST_NORM_CMD_ENTRIES);
3748942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3749942c5e3cSpl 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3750942c5e3cSpl 		    AAC_HOST_NORM_CMD_ENTRIES);
3751942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3752942c5e3cSpl 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3753942c5e3cSpl 		    AAC_HOST_HIGH_CMD_ENTRIES);
3754942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3755942c5e3cSpl 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3756942c5e3cSpl 		    AAC_HOST_HIGH_CMD_ENTRIES);
3757942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3758942c5e3cSpl 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3759942c5e3cSpl 		    AAC_ADAP_NORM_CMD_ENTRIES);
3760942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3761942c5e3cSpl 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3762942c5e3cSpl 		    AAC_ADAP_NORM_CMD_ENTRIES);
3763942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3764942c5e3cSpl 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3765942c5e3cSpl 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3766942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3767942c5e3cSpl 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3768942c5e3cSpl 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3769942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3770942c5e3cSpl 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3771942c5e3cSpl 		    AAC_HOST_NORM_RESP_ENTRIES);
3772942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3773942c5e3cSpl 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3774942c5e3cSpl 		    AAC_HOST_NORM_RESP_ENTRIES);
3775942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3776942c5e3cSpl 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3777942c5e3cSpl 		    AAC_HOST_HIGH_RESP_ENTRIES);
3778942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3779942c5e3cSpl 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3780942c5e3cSpl 		    AAC_HOST_HIGH_RESP_ENTRIES);
3781942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3782942c5e3cSpl 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3783942c5e3cSpl 		    AAC_ADAP_NORM_RESP_ENTRIES);
3784942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3785942c5e3cSpl 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3786942c5e3cSpl 		    AAC_ADAP_NORM_RESP_ENTRIES);
3787942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3788942c5e3cSpl 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3789942c5e3cSpl 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3790942c5e3cSpl 		ddi_put32(acc, &softs->qtablep-> \
3791942c5e3cSpl 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3792942c5e3cSpl 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3793830d82f7Spl 
3794830d82f7Spl 		/* Init queue entries */
3795830d82f7Spl 		softs->qentries[AAC_HOST_NORM_CMD_Q] =
3796c9487164Spl 		    &softs->qtablep->qt_HostNormCmdQueue[0];
3797830d82f7Spl 		softs->qentries[AAC_HOST_HIGH_CMD_Q] =
3798c9487164Spl 		    &softs->qtablep->qt_HostHighCmdQueue[0];
3799830d82f7Spl 		softs->qentries[AAC_ADAP_NORM_CMD_Q] =
3800c9487164Spl 		    &softs->qtablep->qt_AdapNormCmdQueue[0];
3801830d82f7Spl 		softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
3802c9487164Spl 		    &softs->qtablep->qt_AdapHighCmdQueue[0];
3803830d82f7Spl 		softs->qentries[AAC_HOST_NORM_RESP_Q] =
3804c9487164Spl 		    &softs->qtablep->qt_HostNormRespQueue[0];
3805830d82f7Spl 		softs->qentries[AAC_HOST_HIGH_RESP_Q] =
3806c9487164Spl 		    &softs->qtablep->qt_HostHighRespQueue[0];
3807830d82f7Spl 		softs->qentries[AAC_ADAP_NORM_RESP_Q] =
3808c9487164Spl 		    &softs->qtablep->qt_AdapNormRespQueue[0];
3809830d82f7Spl 		softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
3810c9487164Spl 		    &softs->qtablep->qt_AdapHighRespQueue[0];
3811830d82f7Spl 	}
3812942c5e3cSpl 	(void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
3813830d82f7Spl 
3814830d82f7Spl 	/* Send init structure to the card */
3815c9487164Spl 	if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
3816c9487164Spl 	    comm_space_phyaddr + \
3817942c5e3cSpl 	    offsetof(struct aac_comm_space, init_data),
3818c9487164Spl 	    0, 0, 0, NULL) == AACERR) {
38191dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
38201dd0a2dbSpl 		    "Cannot send init structure to adapter");
3821830d82f7Spl 		return (AACERR);
3822830d82f7Spl 	}
3823830d82f7Spl 
3824830d82f7Spl 	return (AACOK);
3825830d82f7Spl }
3826830d82f7Spl 
3827830d82f7Spl static uchar_t *
aac_vendor_id(struct aac_softstate * softs,uchar_t * buf)3828830d82f7Spl aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
3829830d82f7Spl {
3830d937e6ebSpl 	(void) memset(buf, ' ', AAC_VENDOR_LEN);
3831d937e6ebSpl 	bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
3832d937e6ebSpl 	return (buf + AAC_VENDOR_LEN);
3833830d82f7Spl }
3834830d82f7Spl 
3835830d82f7Spl static uchar_t *
aac_product_id(struct aac_softstate * softs,uchar_t * buf)3836830d82f7Spl aac_product_id(struct aac_softstate *softs, uchar_t *buf)
3837830d82f7Spl {
3838d937e6ebSpl 	(void) memset(buf, ' ', AAC_PRODUCT_LEN);
3839d937e6ebSpl 	bcopy(softs->product_name, buf, strlen(softs->product_name));
3840d937e6ebSpl 	return (buf + AAC_PRODUCT_LEN);
3841830d82f7Spl }
3842830d82f7Spl 
3843830d82f7Spl /*
3844830d82f7Spl  * Construct unit serial number from container uid
3845830d82f7Spl  */
3846830d82f7Spl static uchar_t *
aac_lun_serialno(struct aac_softstate * softs,int tgt,uchar_t * buf)3847830d82f7Spl aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
3848830d82f7Spl {
3849830d82f7Spl 	int i, d;
385058bc78c7SXin Chen 	uint32_t uid;
385158bc78c7SXin Chen 
385258bc78c7SXin Chen 	ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
3853830d82f7Spl 
385458bc78c7SXin Chen 	uid = softs->containers[tgt].uid;
3855830d82f7Spl 	for (i = 7; i >= 0; i--) {
3856830d82f7Spl 		d = uid & 0xf;
3857830d82f7Spl 		buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
3858830d82f7Spl 		uid >>= 4;
3859830d82f7Spl 	}
3860830d82f7Spl 	return (buf + 8);
3861830d82f7Spl }
3862830d82f7Spl 
3863830d82f7Spl /*
3864830d82f7Spl  * SPC-3 7.5 INQUIRY command implementation
3865830d82f7Spl  */
3866830d82f7Spl static void
aac_inquiry(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp)3867830d82f7Spl aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
3868c9487164Spl     union scsi_cdb *cdbp, struct buf *bp)
3869830d82f7Spl {
3870830d82f7Spl 	int tgt = pkt->pkt_address.a_target;
3871830d82f7Spl 	char *b_addr = NULL;
3872830d82f7Spl 	uchar_t page = cdbp->cdb_opaque[2];
3873830d82f7Spl 
3874830d82f7Spl 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
3875830d82f7Spl 		/* Command Support Data is not supported */
3876830d82f7Spl 		aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
3877830d82f7Spl 		return;
3878830d82f7Spl 	}
3879830d82f7Spl 
3880830d82f7Spl 	if (bp && bp->b_un.b_addr && bp->b_bcount) {
3881830d82f7Spl 		if (bp->b_flags & (B_PHYS | B_PAGEIO))
3882830d82f7Spl 			bp_mapin(bp);
3883830d82f7Spl 		b_addr = bp->b_un.b_addr;
3884830d82f7Spl 	}
3885830d82f7Spl 
3886830d82f7Spl 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
3887830d82f7Spl 		uchar_t *vpdp = (uchar_t *)b_addr;
3888830d82f7Spl 		uchar_t *idp, *sp;
3889830d82f7Spl 
3890830d82f7Spl 		/* SPC-3 8.4 Vital product data parameters */
3891830d82f7Spl 		switch (page) {
3892830d82f7Spl 		case 0x00:
3893830d82f7Spl 			/* Supported VPD pages */
389451ccf66eSjd 			if (vpdp == NULL ||
389551ccf66eSjd 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
3896830d82f7Spl 				return;
3897830d82f7Spl 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3898830d82f7Spl 			vpdp[AAC_VPD_PAGE_CODE] = 0x00;
3899830d82f7Spl 			vpdp[AAC_VPD_PAGE_LENGTH] = 3;
3900830d82f7Spl 
3901830d82f7Spl 			vpdp[AAC_VPD_PAGE_DATA] = 0x00;
3902830d82f7Spl 			vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
3903830d82f7Spl 			vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
3904830d82f7Spl 
3905830d82f7Spl 			pkt->pkt_state |= STATE_XFERRED_DATA;
3906830d82f7Spl 			break;
3907830d82f7Spl 
3908830d82f7Spl 		case 0x80:
3909830d82f7Spl 			/* Unit serial number page */
391051ccf66eSjd 			if (vpdp == NULL ||
391151ccf66eSjd 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
3912830d82f7Spl 				return;
3913830d82f7Spl 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3914830d82f7Spl 			vpdp[AAC_VPD_PAGE_CODE] = 0x80;
3915830d82f7Spl 			vpdp[AAC_VPD_PAGE_LENGTH] = 8;
3916830d82f7Spl 
3917830d82f7Spl 			sp = &vpdp[AAC_VPD_PAGE_DATA];
3918830d82f7Spl 			(void) aac_lun_serialno(softs, tgt, sp);
3919830d82f7Spl 
3920830d82f7Spl 			pkt->pkt_state |= STATE_XFERRED_DATA;
3921830d82f7Spl 			break;
3922830d82f7Spl 
3923830d82f7Spl 		case 0x83:
3924830d82f7Spl 			/* Device identification page */
392551ccf66eSjd 			if (vpdp == NULL ||
392651ccf66eSjd 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
3927830d82f7Spl 				return;
3928830d82f7Spl 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3929830d82f7Spl 			vpdp[AAC_VPD_PAGE_CODE] = 0x83;
3930830d82f7Spl 
3931830d82f7Spl 			idp = &vpdp[AAC_VPD_PAGE_DATA];
3932830d82f7Spl 			bzero(idp, AAC_VPD_ID_LENGTH);
3933830d82f7Spl 			idp[AAC_VPD_ID_CODESET] = 0x02;
3934830d82f7Spl 			idp[AAC_VPD_ID_TYPE] = 0x01;
3935830d82f7Spl 
3936830d82f7Spl 			/*
3937830d82f7Spl 			 * SPC-3 Table 111 - Identifier type
3938830d82f7Spl 			 * One recommanded method of constructing the remainder
3939830d82f7Spl 			 * of identifier field is to concatenate the product
3940830d82f7Spl 			 * identification field from the standard INQUIRY data
3941830d82f7Spl 			 * field and the product serial number field from the
3942830d82f7Spl 			 * unit serial number page.
3943830d82f7Spl 			 */
3944830d82f7Spl 			sp = &idp[AAC_VPD_ID_DATA];
3945830d82f7Spl 			sp = aac_vendor_id(softs, sp);
3946830d82f7Spl 			sp = aac_product_id(softs, sp);
3947830d82f7Spl 			sp = aac_lun_serialno(softs, tgt, sp);
3948a74f7440Spl 			idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
3949a74f7440Spl 			    (uintptr_t)&idp[AAC_VPD_ID_DATA];
3950830d82f7Spl 
3951a74f7440Spl 			vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
3952a74f7440Spl 			    (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
3953830d82f7Spl 			pkt->pkt_state |= STATE_XFERRED_DATA;
3954830d82f7Spl 			break;
3955830d82f7Spl 
3956830d82f7Spl 		default:
3957830d82f7Spl 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3958c9487164Spl 			    0x24, 0x00, 0);
3959830d82f7Spl 			break;
3960830d82f7Spl 		}
3961830d82f7Spl 	} else {
3962c9487164Spl 		struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
3963830d82f7Spl 		size_t len = sizeof (struct scsi_inquiry);
3964830d82f7Spl 
3965830d82f7Spl 		if (page != 0) {
3966830d82f7Spl 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3967c9487164Spl 			    0x24, 0x00, 0);
3968830d82f7Spl 			return;
3969830d82f7Spl 		}
397051ccf66eSjd 		if (inqp == NULL || bp->b_bcount < len)
3971830d82f7Spl 			return;
3972830d82f7Spl 
3973830d82f7Spl 		bzero(inqp, len);
3974830d82f7Spl 		inqp->inq_len = AAC_ADDITIONAL_LEN;
3975830d82f7Spl 		inqp->inq_ansi = AAC_ANSI_VER;
3976830d82f7Spl 		inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
3977830d82f7Spl 		(void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
3978830d82f7Spl 		(void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
3979830d82f7Spl 		bcopy("V1.0", inqp->inq_revision, 4);
3980830d82f7Spl 		inqp->inq_cmdque = 1; /* enable tagged-queuing */
3981830d82f7Spl 		/*
3982830d82f7Spl 		 * For "sd-max-xfer-size" property which may impact performance
3983830d82f7Spl 		 * when IO threads increase.
3984830d82f7Spl 		 */
3985830d82f7Spl 		inqp->inq_wbus32 = 1;
3986830d82f7Spl 
3987830d82f7Spl 		pkt->pkt_state |= STATE_XFERRED_DATA;
3988830d82f7Spl 	}
3989830d82f7Spl }
3990830d82f7Spl 
3991830d82f7Spl /*
3992830d82f7Spl  * SPC-3 7.10 MODE SENSE command implementation
3993830d82f7Spl  */
3994830d82f7Spl static void
aac_mode_sense(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp,int capacity)3995830d82f7Spl aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
3996c9487164Spl     union scsi_cdb *cdbp, struct buf *bp, int capacity)
39977c478bd9Sstevel@tonic-gate {
39987c478bd9Sstevel@tonic-gate 	uchar_t pagecode;
39997c478bd9Sstevel@tonic-gate 	struct mode_header *headerp;
400051ccf66eSjd 	struct mode_header_g1 *g1_headerp;
40017c478bd9Sstevel@tonic-gate 	unsigned int ncyl;
400251ccf66eSjd 	caddr_t sense_data;
400351ccf66eSjd 	caddr_t next_page;
400451ccf66eSjd 	size_t sdata_size;
400551ccf66eSjd 	size_t pages_size;
400651ccf66eSjd 	int unsupport_page = 0;
400751ccf66eSjd 
400851ccf66eSjd 	ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
400951ccf66eSjd 	    cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
40127c478bd9Sstevel@tonic-gate 		return;
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
40157c478bd9Sstevel@tonic-gate 		bp_mapin(bp);
4016830d82f7Spl 	pkt->pkt_state |= STATE_XFERRED_DATA;
401751ccf66eSjd 	pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
401851ccf66eSjd 
401951ccf66eSjd 	/* calculate the size of needed buffer */
402051ccf66eSjd 	if (cdbp->scc_cmd == SCMD_MODE_SENSE)
402151ccf66eSjd 		sdata_size = MODE_HEADER_LENGTH;
402251ccf66eSjd 	else /* must be SCMD_MODE_SENSE_G1 */
402351ccf66eSjd 		sdata_size = MODE_HEADER_LENGTH_G1;
40247c478bd9Sstevel@tonic-gate 
402551ccf66eSjd 	pages_size = 0;
40267c478bd9Sstevel@tonic-gate 	switch (pagecode) {
40277c478bd9Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE3_CODE:
402851ccf66eSjd 		pages_size += sizeof (struct mode_format);
402951ccf66eSjd 		break;
403051ccf66eSjd 
403151ccf66eSjd 	case SD_MODE_SENSE_PAGE4_CODE:
403251ccf66eSjd 		pages_size += sizeof (struct mode_geometry);
403351ccf66eSjd 		break;
403451ccf66eSjd 
403551ccf66eSjd 	case MODEPAGE_CTRL_MODE:
403651ccf66eSjd 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
403751ccf66eSjd 			pages_size += sizeof (struct mode_control_scsi3);
403851ccf66eSjd 		} else {
403951ccf66eSjd 			unsupport_page = 1;
404051ccf66eSjd 		}
404151ccf66eSjd 		break;
404251ccf66eSjd 
404351ccf66eSjd 	case MODEPAGE_ALLPAGES:
404451ccf66eSjd 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
404551ccf66eSjd 			pages_size += sizeof (struct mode_format) +
404651ccf66eSjd 			    sizeof (struct mode_geometry) +
404751ccf66eSjd 			    sizeof (struct mode_control_scsi3);
404851ccf66eSjd 		} else {
404951ccf66eSjd 			pages_size += sizeof (struct mode_format) +
405051ccf66eSjd 			    sizeof (struct mode_geometry);
405151ccf66eSjd 		}
405251ccf66eSjd 		break;
405351ccf66eSjd 
405451ccf66eSjd 	default:
405551ccf66eSjd 		/* unsupported pages */
405651ccf66eSjd 		unsupport_page = 1;
405751ccf66eSjd 	}
405851ccf66eSjd 
405951ccf66eSjd 	/* allocate buffer to fill the send data */
406051ccf66eSjd 	sdata_size += pages_size;
406151ccf66eSjd 	sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
406251ccf66eSjd 
406351ccf66eSjd 	if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
406451ccf66eSjd 		headerp = (struct mode_header *)sense_data;
406551ccf66eSjd 		headerp->length = MODE_HEADER_LENGTH + pages_size -
406651ccf66eSjd 		    sizeof (headerp->length);
406751ccf66eSjd 		headerp->bdesc_length = 0;
406851ccf66eSjd 		next_page = sense_data + sizeof (struct mode_header);
406951ccf66eSjd 	} else {
4070a74f7440Spl 		g1_headerp = (void *)sense_data;
4071b6094a86Sjd 		g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
4072b6094a86Sjd 		    sizeof (g1_headerp->length));
407351ccf66eSjd 		g1_headerp->bdesc_length = 0;
407451ccf66eSjd 		next_page = sense_data + sizeof (struct mode_header_g1);
407551ccf66eSjd 	}
407651ccf66eSjd 
407751ccf66eSjd 	if (unsupport_page)
407851ccf66eSjd 		goto finish;
407951ccf66eSjd 
408051ccf66eSjd 	if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
408151ccf66eSjd 	    pagecode == MODEPAGE_ALLPAGES) {
408251ccf66eSjd 		/* SBC-3 7.1.3.3 Format device page */
408351ccf66eSjd 		struct mode_format *page3p;
408451ccf66eSjd 
4085a74f7440Spl 		page3p = (void *)next_page;
40867c478bd9Sstevel@tonic-gate 		page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
40877c478bd9Sstevel@tonic-gate 		page3p->mode_page.length = sizeof (struct mode_format);
40887c478bd9Sstevel@tonic-gate 		page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
40897c478bd9Sstevel@tonic-gate 		page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
40907c478bd9Sstevel@tonic-gate 
409151ccf66eSjd 		next_page += sizeof (struct mode_format);
409251ccf66eSjd 	}
409351ccf66eSjd 
409451ccf66eSjd 	if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
409551ccf66eSjd 	    pagecode == MODEPAGE_ALLPAGES) {
409651ccf66eSjd 		/* SBC-3 7.1.3.8 Rigid disk device geometry page */
409751ccf66eSjd 		struct mode_geometry *page4p;
409851ccf66eSjd 
4099a74f7440Spl 		page4p = (void *)next_page;
41007c478bd9Sstevel@tonic-gate 		page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
41017c478bd9Sstevel@tonic-gate 		page4p->mode_page.length = sizeof (struct mode_geometry);
41027c478bd9Sstevel@tonic-gate 		page4p->heads = AAC_NUMBER_OF_HEADS;
41037c478bd9Sstevel@tonic-gate 		page4p->rpm = BE_16(AAC_ROTATION_SPEED);
41047c478bd9Sstevel@tonic-gate 		ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
41057c478bd9Sstevel@tonic-gate 		page4p->cyl_lb = ncyl & 0xff;
41067c478bd9Sstevel@tonic-gate 		page4p->cyl_mb = (ncyl >> 8) & 0xff;
41077c478bd9Sstevel@tonic-gate 		page4p->cyl_ub = (ncyl >> 16) & 0xff;
41087c478bd9Sstevel@tonic-gate 
410951ccf66eSjd 		next_page += sizeof (struct mode_geometry);
411051ccf66eSjd 	}
4111830d82f7Spl 
411251ccf66eSjd 	if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
411351ccf66eSjd 	    softs->flags & AAC_FLAGS_LBA_64BIT) {
411451ccf66eSjd 		/* 64-bit LBA need large sense data */
411551ccf66eSjd 		struct mode_control_scsi3 *mctl;
411651ccf66eSjd 
4117a74f7440Spl 		mctl = (void *)next_page;
411851ccf66eSjd 		mctl->mode_page.code = MODEPAGE_CTRL_MODE;
411951ccf66eSjd 		mctl->mode_page.length =
412051ccf66eSjd 		    sizeof (struct mode_control_scsi3) -
412151ccf66eSjd 		    sizeof (struct mode_page);
412251ccf66eSjd 		mctl->d_sense = 1;
41237c478bd9Sstevel@tonic-gate 	}
412451ccf66eSjd 
412551ccf66eSjd finish:
412651ccf66eSjd 	/* copyout the valid data. */
412751ccf66eSjd 	bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
412851ccf66eSjd 	kmem_free(sense_data, sdata_size);
41297c478bd9Sstevel@tonic-gate }
41307c478bd9Sstevel@tonic-gate 
413158bc78c7SXin Chen static int
aac_name_node(dev_info_t * dip,char * name,int len)413258bc78c7SXin Chen aac_name_node(dev_info_t *dip, char *name, int len)
413358bc78c7SXin Chen {
413458bc78c7SXin Chen 	int tgt, lun;
413558bc78c7SXin Chen 
413658bc78c7SXin Chen 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
413758bc78c7SXin Chen 	    DDI_PROP_DONTPASS, "target", -1);
413858bc78c7SXin Chen 	if (tgt == -1)
413958bc78c7SXin Chen 		return (DDI_FAILURE);
414058bc78c7SXin Chen 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
414158bc78c7SXin Chen 	    DDI_PROP_DONTPASS, "lun", -1);
414258bc78c7SXin Chen 	if (lun == -1)
414358bc78c7SXin Chen 		return (DDI_FAILURE);
414458bc78c7SXin Chen 
414558bc78c7SXin Chen 	(void) snprintf(name, len, "%x,%x", tgt, lun);
414658bc78c7SXin Chen 	return (DDI_SUCCESS);
414758bc78c7SXin Chen }
414858bc78c7SXin Chen 
41497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
41507c478bd9Sstevel@tonic-gate static int
aac_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * tran,struct scsi_device * sd)41517c478bd9Sstevel@tonic-gate aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4152c9487164Spl     scsi_hba_tran_t *tran, struct scsi_device *sd)
41537c478bd9Sstevel@tonic-gate {
4154c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
4155942c5e3cSpl #if defined(DEBUG) || defined(__lock_lint)
4156942c5e3cSpl 	int ctl = ddi_get_instance(softs->devinfo_p);
4157942c5e3cSpl #endif
415858bc78c7SXin Chen 	uint16_t tgt = sd->sd_address.a_target;
415958bc78c7SXin Chen 	uint8_t lun = sd->sd_address.a_lun;
416058bc78c7SXin Chen 	struct aac_device *dvp;
41617c478bd9Sstevel@tonic-gate 
41621dd0a2dbSpl 	DBCALLED(softs, 2);
41637c478bd9Sstevel@tonic-gate 
416458bc78c7SXin Chen 	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
416558bc78c7SXin Chen 		/*
416658bc78c7SXin Chen 		 * If no persistent node exist, we don't allow .conf node
416758bc78c7SXin Chen 		 * to be created.
416858bc78c7SXin Chen 		 */
416958bc78c7SXin Chen 		if (aac_find_child(softs, tgt, lun) != NULL) {
417058bc78c7SXin Chen 			if (ndi_merge_node(tgt_dip, aac_name_node) !=
417158bc78c7SXin Chen 			    DDI_SUCCESS)
417258bc78c7SXin Chen 				/* Create this .conf node */
417358bc78c7SXin Chen 				return (DDI_SUCCESS);
417458bc78c7SXin Chen 		}
4175fd4ae32fSyf 		return (DDI_FAILURE);
4176830d82f7Spl 	}
4177c9487164Spl 
4178c9487164Spl 	/*
417958bc78c7SXin Chen 	 * Only support container/phys. device that has been
418058bc78c7SXin Chen 	 * detected and valid
4181c9487164Spl 	 */
4182382c8bcaSpl 	mutex_enter(&softs->io_lock);
418358bc78c7SXin Chen 	if (tgt >= AAC_MAX_DEV(softs)) {
418458bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs,
418558bc78c7SXin Chen 		    "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
4186382c8bcaSpl 		mutex_exit(&softs->io_lock);
41877c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4188830d82f7Spl 	}
418958bc78c7SXin Chen 
419058bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
419158bc78c7SXin Chen 		dvp = (struct aac_device *)&softs->containers[tgt];
419258bc78c7SXin Chen 		if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
419358bc78c7SXin Chen 			AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
419458bc78c7SXin Chen 			    ctl, tgt, lun);
419558bc78c7SXin Chen 			mutex_exit(&softs->io_lock);
419658bc78c7SXin Chen 			return (DDI_FAILURE);
419758bc78c7SXin Chen 		}
419858bc78c7SXin Chen 		/*
419958bc78c7SXin Chen 		 * Save the tgt_dip for the given target if one doesn't exist
420058bc78c7SXin Chen 		 * already. Dip's for non-existance tgt's will be cleared in
420158bc78c7SXin Chen 		 * tgt_free.
420258bc78c7SXin Chen 		 */
420358bc78c7SXin Chen 		if (softs->containers[tgt].dev.dip == NULL &&
420458bc78c7SXin Chen 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
420558bc78c7SXin Chen 			softs->containers[tgt].dev.dip = tgt_dip;
420658bc78c7SXin Chen 	} else {
420758bc78c7SXin Chen 		dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
42083fced439Szhongyan gu - Sun Microsystems - Beijing China 		/*
42093fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * Save the tgt_dip for the given target if one doesn't exist
42103fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * already. Dip's for non-existance tgt's will be cleared in
42113fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * tgt_free.
42123fced439Szhongyan gu - Sun Microsystems - Beijing China 		 */
42133fced439Szhongyan gu - Sun Microsystems - Beijing China 
42143fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->nondasds[AAC_PD(tgt)].dev.dip  == NULL &&
42153fced439Szhongyan gu - Sun Microsystems - Beijing China 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
42163fced439Szhongyan gu - Sun Microsystems - Beijing China 			softs->nondasds[AAC_PD(tgt)].dev.dip  = tgt_dip;
421758bc78c7SXin Chen 	}
421858bc78c7SXin Chen 
421972888e72Speng liu - Sun Microsystems - Beijing China 	if (softs->flags & AAC_FLAGS_BRKUP) {
422072888e72Speng liu - Sun Microsystems - Beijing China 		if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
422172888e72Speng liu - Sun Microsystems - Beijing China 		    "buf_break", 1) != DDI_PROP_SUCCESS) {
422272888e72Speng liu - Sun Microsystems - Beijing China 			cmn_err(CE_CONT, "unable to create "
422372888e72Speng liu - Sun Microsystems - Beijing China 			    "property for t%dL%d (buf_break)", tgt, lun);
422472888e72Speng liu - Sun Microsystems - Beijing China 		}
42259c57abc8Ssrivijitha dugganapalli 	}
422672888e72Speng liu - Sun Microsystems - Beijing China 
422758bc78c7SXin Chen 	AACDB_PRINT(softs, CE_NOTE,
422858bc78c7SXin Chen 	    "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
422958bc78c7SXin Chen 	    (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
423058bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
423158bc78c7SXin Chen 	return (DDI_SUCCESS);
423258bc78c7SXin Chen }
423358bc78c7SXin Chen 
423458bc78c7SXin Chen static void
aac_tran_tgt_free(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * hba_tran,struct scsi_device * sd)423558bc78c7SXin Chen aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
423658bc78c7SXin Chen     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
423758bc78c7SXin Chen {
423858bc78c7SXin Chen #ifndef __lock_lint
423958bc78c7SXin Chen 	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
424058bc78c7SXin Chen #endif
424158bc78c7SXin Chen 
424258bc78c7SXin Chen 	struct aac_softstate *softs = SD2AAC(sd);
424358bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
424458bc78c7SXin Chen 
424558bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
424658bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
424758bc78c7SXin Chen 		if (softs->containers[tgt].dev.dip == tgt_dip)
424858bc78c7SXin Chen 			softs->containers[tgt].dev.dip = NULL;
424958bc78c7SXin Chen 	} else {
42503fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
42513fced439Szhongyan gu - Sun Microsystems - Beijing China 			softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
425258bc78c7SXin Chen 		softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
425358bc78c7SXin Chen 	}
425458bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
42557c478bd9Sstevel@tonic-gate }
42567c478bd9Sstevel@tonic-gate 
42577c478bd9Sstevel@tonic-gate /*
4258830d82f7Spl  * Check if the firmware is Up And Running. If it is in the Kernel Panic
4259830d82f7Spl  * state, (BlinkLED code + 1) is returned.
4260830d82f7Spl  *    0 -- firmware up and running
4261830d82f7Spl  *   -1 -- firmware dead
4262830d82f7Spl  *   >0 -- firmware kernel panic
4263830d82f7Spl  */
4264830d82f7Spl static int
aac_check_adapter_health(struct aac_softstate * softs)4265830d82f7Spl aac_check_adapter_health(struct aac_softstate *softs)
4266830d82f7Spl {
4267c9487164Spl 	int rval;
4268830d82f7Spl 
4269c9487164Spl 	rval = PCI_MEM_GET32(softs, AAC_OMR0);
4270830d82f7Spl 
4271942c5e3cSpl 	if (rval & AAC_KERNEL_UP_AND_RUNNING) {
4272c9487164Spl 		rval = 0;
4273942c5e3cSpl 	} else if (rval & AAC_KERNEL_PANIC) {
4274942c5e3cSpl 		cmn_err(CE_WARN, "firmware panic");
4275c9487164Spl 		rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
4276942c5e3cSpl 	} else {
4277942c5e3cSpl 		cmn_err(CE_WARN, "firmware dead");
4278c9487164Spl 		rval = -1;
4279942c5e3cSpl 	}
4280c9487164Spl 	return (rval);
4281830d82f7Spl }
4282830d82f7Spl 
4283382c8bcaSpl static void
aac_abort_iocmd(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason)4284382c8bcaSpl aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
4285382c8bcaSpl     uchar_t reason)
4286830d82f7Spl {
4287382c8bcaSpl 	acp->flags |= AAC_CMD_ABORT;
4288830d82f7Spl 
4289382c8bcaSpl 	if (acp->pkt) {
429058bc78c7SXin Chen 		if (acp->slotp) { /* outstanding cmd */
429158bc78c7SXin Chen 			acp->pkt->pkt_state |= STATE_GOT_STATUS;
429258bc78c7SXin Chen 		}
4293382c8bcaSpl 
4294382c8bcaSpl 		switch (reason) {
4295382c8bcaSpl 		case CMD_TIMEOUT:
429658bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
429758bc78c7SXin Chen 			    acp);
4298382c8bcaSpl 			aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
4299382c8bcaSpl 			    STAT_TIMEOUT | STAT_BUS_RESET);
4300382c8bcaSpl 			break;
4301382c8bcaSpl 		case CMD_RESET:
4302382c8bcaSpl 			/* aac support only RESET_ALL */
430358bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
4304382c8bcaSpl 			aac_set_pkt_reason(softs, acp, CMD_RESET,
4305382c8bcaSpl 			    STAT_BUS_RESET);
4306382c8bcaSpl 			break;
4307382c8bcaSpl 		case CMD_ABORTED:
430858bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
430958bc78c7SXin Chen 			    acp);
4310382c8bcaSpl 			aac_set_pkt_reason(softs, acp, CMD_ABORTED,
4311382c8bcaSpl 			    STAT_ABORTED);
4312830d82f7Spl 			break;
4313382c8bcaSpl 		}
4314830d82f7Spl 	}
4315382c8bcaSpl 	aac_end_io(softs, acp);
4316830d82f7Spl }
4317830d82f7Spl 
4318832e0b5aSpl /*
4319382c8bcaSpl  * Abort all the pending commands of type iocmd or just the command pkt
4320382c8bcaSpl  * corresponding to pkt
4321832e0b5aSpl  */
4322830d82f7Spl static void
aac_abort_iocmds(struct aac_softstate * softs,int iocmd,struct scsi_pkt * pkt,int reason)4323382c8bcaSpl aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
4324382c8bcaSpl     int reason)
4325830d82f7Spl {
4326382c8bcaSpl 	struct aac_cmd *ac_arg, *acp;
4327830d82f7Spl 	int i;
4328830d82f7Spl 
4329382c8bcaSpl 	if (pkt == NULL) {
4330382c8bcaSpl 		ac_arg = NULL;
4331382c8bcaSpl 	} else {
4332382c8bcaSpl 		ac_arg = PKT2AC(pkt);
4333382c8bcaSpl 		iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
4334382c8bcaSpl 		    AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
4335382c8bcaSpl 	}
4336830d82f7Spl 
4337382c8bcaSpl 	/*
4338382c8bcaSpl 	 * a) outstanding commands on the controller
4339382c8bcaSpl 	 * Note: should abort outstanding commands only after one
4340382c8bcaSpl 	 * IOP reset has been done.
4341382c8bcaSpl 	 */
4342832e0b5aSpl 	if (iocmd & AAC_IOCMD_OUTSTANDING) {
4343382c8bcaSpl 		struct aac_cmd *acp;
4344382c8bcaSpl 
4345c9487164Spl 		for (i = 0; i < AAC_MAX_LD; i++) {
434658bc78c7SXin Chen 			if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
4347942c5e3cSpl 				softs->containers[i].reset = 1;
4348c9487164Spl 		}
4349382c8bcaSpl 		while ((acp = softs->q_busy.q_head) != NULL)
4350382c8bcaSpl 			aac_abort_iocmd(softs, acp, reason);
4351382c8bcaSpl 	}
4352382c8bcaSpl 
4353382c8bcaSpl 	/* b) commands in the waiting queues */
4354382c8bcaSpl 	for (i = 0; i < AAC_CMDQ_NUM; i++) {
4355382c8bcaSpl 		if (iocmd & (1 << i)) {
4356382c8bcaSpl 			if (ac_arg) {
4357382c8bcaSpl 				aac_abort_iocmd(softs, ac_arg, reason);
4358832e0b5aSpl 			} else {
4359382c8bcaSpl 				while ((acp = softs->q_wait[i].q_head) != NULL)
4360382c8bcaSpl 					aac_abort_iocmd(softs, acp, reason);
4361832e0b5aSpl 			}
4362832e0b5aSpl 		}
4363832e0b5aSpl 	}
4364382c8bcaSpl }
4365830d82f7Spl 
4366382c8bcaSpl /*
4367382c8bcaSpl  * The draining thread is shared among quiesce threads. It terminates
4368382c8bcaSpl  * when the adapter is quiesced or stopped by aac_stop_drain().
4369382c8bcaSpl  */
4370382c8bcaSpl static void
aac_check_drain(void * arg)4371382c8bcaSpl aac_check_drain(void *arg)
4372382c8bcaSpl {
4373382c8bcaSpl 	struct aac_softstate *softs = arg;
4374832e0b5aSpl 
4375382c8bcaSpl 	mutex_enter(&softs->io_lock);
4376382c8bcaSpl 	if (softs->ndrains) {
437758bc78c7SXin Chen 		softs->drain_timeid = 0;
4378382c8bcaSpl 		/*
4379382c8bcaSpl 		 * If both ASYNC and SYNC bus throttle are held,
4380382c8bcaSpl 		 * wake up threads only when both are drained out.
4381382c8bcaSpl 		 */
4382382c8bcaSpl 		if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
4383382c8bcaSpl 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
4384382c8bcaSpl 		    (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
4385382c8bcaSpl 		    softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
4386382c8bcaSpl 			cv_broadcast(&softs->drain_cv);
4387382c8bcaSpl 		else
4388382c8bcaSpl 			softs->drain_timeid = timeout(aac_check_drain, softs,
4389382c8bcaSpl 			    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4390832e0b5aSpl 	}
4391382c8bcaSpl 	mutex_exit(&softs->io_lock);
4392382c8bcaSpl }
4393832e0b5aSpl 
4394382c8bcaSpl /*
4395382c8bcaSpl  * If not draining the outstanding cmds, drain them. Otherwise,
4396382c8bcaSpl  * only update ndrains.
4397382c8bcaSpl  */
4398382c8bcaSpl static void
aac_start_drain(struct aac_softstate * softs)4399382c8bcaSpl aac_start_drain(struct aac_softstate *softs)
4400382c8bcaSpl {
4401382c8bcaSpl 	if (softs->ndrains == 0) {
440258bc78c7SXin Chen 		ASSERT(softs->drain_timeid == 0);
4403382c8bcaSpl 		softs->drain_timeid = timeout(aac_check_drain, softs,
4404382c8bcaSpl 		    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4405382c8bcaSpl 	}
4406382c8bcaSpl 	softs->ndrains++;
4407382c8bcaSpl }
4408832e0b5aSpl 
4409382c8bcaSpl /*
4410382c8bcaSpl  * Stop the draining thread when no other threads use it any longer.
4411382c8bcaSpl  * Side effect: io_lock may be released in the middle.
4412382c8bcaSpl  */
4413382c8bcaSpl static void
aac_stop_drain(struct aac_softstate * softs)4414382c8bcaSpl aac_stop_drain(struct aac_softstate *softs)
4415382c8bcaSpl {
4416382c8bcaSpl 	softs->ndrains--;
4417382c8bcaSpl 	if (softs->ndrains == 0) {
4418382c8bcaSpl 		if (softs->drain_timeid != 0) {
4419382c8bcaSpl 			timeout_id_t tid = softs->drain_timeid;
4420382c8bcaSpl 
4421382c8bcaSpl 			softs->drain_timeid = 0;
4422382c8bcaSpl 			mutex_exit(&softs->io_lock);
4423382c8bcaSpl 			(void) untimeout(tid);
4424382c8bcaSpl 			mutex_enter(&softs->io_lock);
4425830d82f7Spl 		}
4426830d82f7Spl 	}
4427830d82f7Spl }
4428830d82f7Spl 
4429830d82f7Spl /*
4430830d82f7Spl  * The following function comes from Adaptec:
44317c478bd9Sstevel@tonic-gate  *
4432830d82f7Spl  * Once do an IOP reset, basically the driver have to re-initialize the card
4433830d82f7Spl  * as if up from a cold boot, and the driver is responsible for any IO that
4434830d82f7Spl  * is outstanding to the adapter at the time of the IOP RESET. And prepare
4435830d82f7Spl  * for IOP RESET by making the init code modular with the ability to call it
4436830d82f7Spl  * from multiple places.
44377c478bd9Sstevel@tonic-gate  */
4438830d82f7Spl static int
aac_reset_adapter(struct aac_softstate * softs)4439830d82f7Spl aac_reset_adapter(struct aac_softstate *softs)
4440830d82f7Spl {
4441830d82f7Spl 	int health;
4442830d82f7Spl 	uint32_t status;
444358bc78c7SXin Chen 	int rval = AAC_IOP_RESET_FAILED;
4444830d82f7Spl 
44451dd0a2dbSpl 	DBCALLED(softs, 1);
4446830d82f7Spl 
4447382c8bcaSpl 	ASSERT(softs->state & AAC_STATE_RESET);
4448830d82f7Spl 
44497675db54Syw 	ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
4450830d82f7Spl 	/* Disable interrupt */
4451830d82f7Spl 	AAC_DISABLE_INTR(softs);
4452830d82f7Spl 
4453830d82f7Spl 	health = aac_check_adapter_health(softs);
44547675db54Syw 	if (health == -1) {
44557675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
4456830d82f7Spl 		goto finish;
44577675db54Syw 	}
4458830d82f7Spl 	if (health == 0) /* flush drives if possible */
4459830d82f7Spl 		(void) aac_shutdown(softs);
4460830d82f7Spl 
4461830d82f7Spl 	/* Execute IOP reset */
4462c9487164Spl 	if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
4463c9487164Spl 	    &status)) != AACOK) {
4464f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		ddi_acc_handle_t acc;
4465c9487164Spl 		struct aac_fib *fibp;
4466830d82f7Spl 		struct aac_pause_command *pc;
4467830d82f7Spl 
4468382c8bcaSpl 		if ((status & 0xf) == 0xf) {
4469382c8bcaSpl 			uint32_t wait_count;
4470830d82f7Spl 
4471382c8bcaSpl 			/*
4472382c8bcaSpl 			 * Sunrise Lake has dual cores and we must drag the
4473382c8bcaSpl 			 * other core with us to reset simultaneously. There
4474382c8bcaSpl 			 * are 2 bits in the Inbound Reset Control and Status
4475382c8bcaSpl 			 * Register (offset 0x38) of the Sunrise Lake to reset
4476382c8bcaSpl 			 * the chip without clearing out the PCI configuration
4477382c8bcaSpl 			 * info (COMMAND & BARS).
4478382c8bcaSpl 			 */
4479382c8bcaSpl 			PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
4480382c8bcaSpl 
4481382c8bcaSpl 			/*
4482382c8bcaSpl 			 * We need to wait for 5 seconds before accessing the MU
4483382c8bcaSpl 			 * again 10000 * 100us = 1000,000us = 1000ms = 1s
4484382c8bcaSpl 			 */
4485382c8bcaSpl 			wait_count = 5 * 10000;
4486382c8bcaSpl 			while (wait_count) {
4487382c8bcaSpl 				drv_usecwait(100); /* delay 100 microseconds */
4488382c8bcaSpl 				wait_count--;
4489382c8bcaSpl 			}
4490382c8bcaSpl 		} else {
4491382c8bcaSpl 			if (status == SRB_STATUS_INVALID_REQUEST)
4492382c8bcaSpl 				cmn_err(CE_WARN, "!IOP_RESET not supported");
4493382c8bcaSpl 			else /* probably timeout */
4494382c8bcaSpl 				cmn_err(CE_WARN, "!IOP_RESET failed");
4495382c8bcaSpl 
4496382c8bcaSpl 			/* Unwind aac_shutdown() */
4497f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
4498f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			acc = softs->sync_ac.slotp->fib_acc_handle;
4499f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
4500f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			fibp = softs->sync_ac.slotp->fibp;
4501382c8bcaSpl 			pc = (struct aac_pause_command *)&fibp->data[0];
4502382c8bcaSpl 
4503382c8bcaSpl 			bzero(pc, sizeof (*pc));
4504942c5e3cSpl 			ddi_put32(acc, &pc->Command, VM_ContainerConfig);
4505942c5e3cSpl 			ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
4506942c5e3cSpl 			ddi_put32(acc, &pc->Timeout, 1);
4507942c5e3cSpl 			ddi_put32(acc, &pc->Min, 1);
4508942c5e3cSpl 			ddi_put32(acc, &pc->NoRescan, 1);
4509382c8bcaSpl 
4510942c5e3cSpl 			(void) aac_sync_fib(softs, ContainerCommand,
4511942c5e3cSpl 			    AAC_FIB_SIZEOF(struct aac_pause_command));
4512f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			aac_sync_fib_slot_release(softs, &softs->sync_ac);
4513382c8bcaSpl 
451458bc78c7SXin Chen 			if (aac_check_adapter_health(softs) != 0)
451558bc78c7SXin Chen 				ddi_fm_service_impact(softs->devinfo_p,
451658bc78c7SXin Chen 				    DDI_SERVICE_LOST);
451758bc78c7SXin Chen 			else
451858bc78c7SXin Chen 				/*
451958bc78c7SXin Chen 				 * IOP reset not supported or IOP not reseted
452058bc78c7SXin Chen 				 */
452158bc78c7SXin Chen 				rval = AAC_IOP_RESET_ABNORMAL;
4522382c8bcaSpl 			goto finish;
4523382c8bcaSpl 		}
4524830d82f7Spl 	}
4525830d82f7Spl 
4526830d82f7Spl 	/*
4527830d82f7Spl 	 * Re-read and renegotiate the FIB parameters, as one of the actions
4528830d82f7Spl 	 * that can result from an IOP reset is the running of a new firmware
4529830d82f7Spl 	 * image.
4530830d82f7Spl 	 */
4531830d82f7Spl 	if (aac_common_attach(softs) != AACOK)
4532830d82f7Spl 		goto finish;
4533830d82f7Spl 
453458bc78c7SXin Chen 	rval = AAC_IOP_RESET_SUCCEED;
4535830d82f7Spl 
4536830d82f7Spl finish:
4537830d82f7Spl 	AAC_ENABLE_INTR(softs);
4538830d82f7Spl 	return (rval);
4539830d82f7Spl }
4540830d82f7Spl 
4541382c8bcaSpl static void
aac_set_throttle(struct aac_softstate * softs,struct aac_device * dvp,int q,int throttle)454258bc78c7SXin Chen aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
4543382c8bcaSpl     int throttle)
4544382c8bcaSpl {
4545382c8bcaSpl 	/*
4546382c8bcaSpl 	 * If the bus is draining/quiesced, no changes to the throttles
4547382c8bcaSpl 	 * are allowed. All throttles should have been set to 0.
4548382c8bcaSpl 	 */
4549382c8bcaSpl 	if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
4550382c8bcaSpl 		return;
4551382c8bcaSpl 	dvp->throttle[q] = throttle;
4552382c8bcaSpl }
4553382c8bcaSpl 
4554382c8bcaSpl static void
aac_hold_bus(struct aac_softstate * softs,int iocmds)4555382c8bcaSpl aac_hold_bus(struct aac_softstate *softs, int iocmds)
4556382c8bcaSpl {
4557382c8bcaSpl 	int i, q;
4558382c8bcaSpl 
4559382c8bcaSpl 	/* Hold bus by holding every device on the bus */
4560382c8bcaSpl 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4561382c8bcaSpl 		if (iocmds & (1 << q)) {
4562382c8bcaSpl 			softs->bus_throttle[q] = 0;
4563382c8bcaSpl 			for (i = 0; i < AAC_MAX_LD; i++)
456458bc78c7SXin Chen 				aac_set_throttle(softs,
456558bc78c7SXin Chen 				    &softs->containers[i].dev, q, 0);
456658bc78c7SXin Chen 			for (i = 0; i < AAC_MAX_PD(softs); i++)
456758bc78c7SXin Chen 				aac_set_throttle(softs,
456858bc78c7SXin Chen 				    &softs->nondasds[i].dev, q, 0);
4569382c8bcaSpl 		}
4570382c8bcaSpl 	}
4571382c8bcaSpl }
4572382c8bcaSpl 
4573382c8bcaSpl static void
aac_unhold_bus(struct aac_softstate * softs,int iocmds)4574382c8bcaSpl aac_unhold_bus(struct aac_softstate *softs, int iocmds)
4575382c8bcaSpl {
4576f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int i, q, max_throttle;
4577382c8bcaSpl 
4578382c8bcaSpl 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4579382c8bcaSpl 		if (iocmds & (1 << q)) {
4580382c8bcaSpl 			/*
4581382c8bcaSpl 			 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
4582382c8bcaSpl 			 * quiesced or being drained by possibly some quiesce
4583382c8bcaSpl 			 * threads.
4584382c8bcaSpl 			 */
4585382c8bcaSpl 			if (q == AAC_CMDQ_ASYNC && ((softs->state &
4586382c8bcaSpl 			    AAC_STATE_QUIESCED) || softs->ndrains))
4587382c8bcaSpl 				continue;
4588f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (q == AAC_CMDQ_ASYNC)
4589f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				max_throttle = softs->total_slots -
4590f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    AAC_MGT_SLOT_NUM;
4591f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			else
4592f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				max_throttle = softs->total_slots - 1;
4593f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			softs->bus_throttle[q] = max_throttle;
4594382c8bcaSpl 			for (i = 0; i < AAC_MAX_LD; i++)
459558bc78c7SXin Chen 				aac_set_throttle(softs,
459658bc78c7SXin Chen 				    &softs->containers[i].dev,
4597f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    q, max_throttle);
459858bc78c7SXin Chen 			for (i = 0; i < AAC_MAX_PD(softs); i++)
459958bc78c7SXin Chen 				aac_set_throttle(softs, &softs->nondasds[i].dev,
4600f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    q, max_throttle);
4601382c8bcaSpl 		}
4602382c8bcaSpl 	}
4603382c8bcaSpl }
4604382c8bcaSpl 
4605830d82f7Spl static int
aac_do_reset(struct aac_softstate * softs)4606830d82f7Spl aac_do_reset(struct aac_softstate *softs)
4607830d82f7Spl {
4608382c8bcaSpl 	int health;
4609382c8bcaSpl 	int rval;
4610830d82f7Spl 
4611382c8bcaSpl 	softs->state |= AAC_STATE_RESET;
4612382c8bcaSpl 	health = aac_check_adapter_health(softs);
4613830d82f7Spl 
4614830d82f7Spl 	/*
4615382c8bcaSpl 	 * Hold off new io commands and wait all outstanding io
4616382c8bcaSpl 	 * commands to complete.
4617830d82f7Spl 	 */
461858bc78c7SXin Chen 	if (health == 0) {
461958bc78c7SXin Chen 		int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
462058bc78c7SXin Chen 		int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
462158bc78c7SXin Chen 
462258bc78c7SXin Chen 		if (sync_cmds == 0 && async_cmds == 0) {
462358bc78c7SXin Chen 			rval = AAC_IOP_RESET_SUCCEED;
462458bc78c7SXin Chen 			goto finish;
462558bc78c7SXin Chen 		}
4626382c8bcaSpl 		/*
4627382c8bcaSpl 		 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
4628382c8bcaSpl 		 * to complete the outstanding io commands
4629382c8bcaSpl 		 */
4630382c8bcaSpl 		int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
4631382c8bcaSpl 		int (*intr_handler)(struct aac_softstate *);
4632382c8bcaSpl 
4633382c8bcaSpl 		aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4634382c8bcaSpl 		/*
4635382c8bcaSpl 		 * Poll the adapter by ourselves in case interrupt is disabled
4636382c8bcaSpl 		 * and to avoid releasing the io_lock.
4637382c8bcaSpl 		 */
4638382c8bcaSpl 		intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
4639382c8bcaSpl 		    aac_process_intr_new : aac_process_intr_old;
4640382c8bcaSpl 		while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
4641382c8bcaSpl 		    softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
4642382c8bcaSpl 			drv_usecwait(100);
4643382c8bcaSpl 			(void) intr_handler(softs);
4644382c8bcaSpl 			timeout--;
4645382c8bcaSpl 		}
4646382c8bcaSpl 		aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
464758bc78c7SXin Chen 
464858bc78c7SXin Chen 		if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
464958bc78c7SXin Chen 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
465058bc78c7SXin Chen 			/* Cmds drained out */
465158bc78c7SXin Chen 			rval = AAC_IOP_RESET_SUCCEED;
465258bc78c7SXin Chen 			goto finish;
465358bc78c7SXin Chen 		} else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
465458bc78c7SXin Chen 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
465558bc78c7SXin Chen 			/* Cmds not drained out, adapter overloaded */
465658bc78c7SXin Chen 			rval = AAC_IOP_RESET_ABNORMAL;
465758bc78c7SXin Chen 			goto finish;
465858bc78c7SXin Chen 		}
4659832e0b5aSpl 	}
4660830d82f7Spl 
4661382c8bcaSpl 	/*
466258bc78c7SXin Chen 	 * If a longer waiting time still can't drain any outstanding io
4663382c8bcaSpl 	 * commands, do IOP reset.
4664382c8bcaSpl 	 */
466558bc78c7SXin Chen 	if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
466658bc78c7SXin Chen 		softs->state |= AAC_STATE_DEAD;
4667830d82f7Spl 
466858bc78c7SXin Chen finish:
4669382c8bcaSpl 	softs->state &= ~AAC_STATE_RESET;
4670c9487164Spl 	return (rval);
4671830d82f7Spl }
4672830d82f7Spl 
46737c478bd9Sstevel@tonic-gate static int
aac_tran_reset(struct scsi_address * ap,int level)46747c478bd9Sstevel@tonic-gate aac_tran_reset(struct scsi_address *ap, int level)
46757c478bd9Sstevel@tonic-gate {
4676c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4677382c8bcaSpl 	int rval;
46787c478bd9Sstevel@tonic-gate 
46791dd0a2dbSpl 	DBCALLED(softs, 1);
4680830d82f7Spl 
4681830d82f7Spl 	if (level != RESET_ALL) {
4682830d82f7Spl 		cmn_err(CE_NOTE, "!reset target/lun not supported");
4683830d82f7Spl 		return (0);
4684830d82f7Spl 	}
4685830d82f7Spl 
4686382c8bcaSpl 	mutex_enter(&softs->io_lock);
468758bc78c7SXin Chen 	switch (rval = aac_do_reset(softs)) {
468858bc78c7SXin Chen 	case AAC_IOP_RESET_SUCCEED:
4689382c8bcaSpl 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
4690382c8bcaSpl 		    NULL, CMD_RESET);
4691382c8bcaSpl 		aac_start_waiting_io(softs);
469258bc78c7SXin Chen 		break;
469358bc78c7SXin Chen 	case AAC_IOP_RESET_FAILED:
469458bc78c7SXin Chen 		/* Abort IOCTL cmds when adapter is dead */
4695382c8bcaSpl 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
469658bc78c7SXin Chen 		break;
469758bc78c7SXin Chen 	case AAC_IOP_RESET_ABNORMAL:
469858bc78c7SXin Chen 		aac_start_waiting_io(softs);
4699382c8bcaSpl 	}
4700382c8bcaSpl 	mutex_exit(&softs->io_lock);
4701830d82f7Spl 
4702382c8bcaSpl 	aac_drain_comp_q(softs);
470358bc78c7SXin Chen 	return (rval == 0);
47047c478bd9Sstevel@tonic-gate }
47057c478bd9Sstevel@tonic-gate 
4706830d82f7Spl static int
aac_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)4707830d82f7Spl aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
47087c478bd9Sstevel@tonic-gate {
4709c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
47107c478bd9Sstevel@tonic-gate 
47111dd0a2dbSpl 	DBCALLED(softs, 1);
4712830d82f7Spl 
4713382c8bcaSpl 	mutex_enter(&softs->io_lock);
4714382c8bcaSpl 	aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
4715382c8bcaSpl 	mutex_exit(&softs->io_lock);
4716830d82f7Spl 
4717382c8bcaSpl 	aac_drain_comp_q(softs);
4718830d82f7Spl 	return (1);
47197c478bd9Sstevel@tonic-gate }
47207c478bd9Sstevel@tonic-gate 
4721d7c5bf88Spl void
aac_free_dmamap(struct aac_cmd * acp)4722c9487164Spl aac_free_dmamap(struct aac_cmd *acp)
47237c478bd9Sstevel@tonic-gate {
4724830d82f7Spl 	/* Free dma mapping */
4725c9487164Spl 	if (acp->flags & AAC_CMD_DMA_VALID) {
4726c9487164Spl 		ASSERT(acp->buf_dma_handle);
4727c9487164Spl 		(void) ddi_dma_unbind_handle(acp->buf_dma_handle);
4728c9487164Spl 		acp->flags &= ~AAC_CMD_DMA_VALID;
4729832e0b5aSpl 	}
4730832e0b5aSpl 
4731c9487164Spl 	if (acp->abp != NULL) { /* free non-aligned buf DMA */
4732c9487164Spl 		ASSERT(acp->buf_dma_handle);
4733d7c5bf88Spl 		if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
4734d7c5bf88Spl 			ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
4735d7c5bf88Spl 			    (uint8_t *)acp->abp, acp->bp->b_bcount,
4736d7c5bf88Spl 			    DDI_DEV_AUTOINCR);
4737c9487164Spl 		ddi_dma_mem_free(&acp->abh);
4738c9487164Spl 		acp->abp = NULL;
4739832e0b5aSpl 	}
4740832e0b5aSpl 
4741c9487164Spl 	if (acp->buf_dma_handle) {
4742c9487164Spl 		ddi_dma_free_handle(&acp->buf_dma_handle);
4743c9487164Spl 		acp->buf_dma_handle = NULL;
47447c478bd9Sstevel@tonic-gate 	}
47457c478bd9Sstevel@tonic-gate }
47467c478bd9Sstevel@tonic-gate 
4747382c8bcaSpl static void
aac_unknown_scmd(struct aac_softstate * softs,struct aac_cmd * acp)4748382c8bcaSpl aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
4749382c8bcaSpl {
4750382c8bcaSpl 	AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
4751a74f7440Spl 	    ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
4752382c8bcaSpl 	aac_free_dmamap(acp);
4753382c8bcaSpl 	aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
4754382c8bcaSpl 	aac_soft_callback(softs, acp);
4755382c8bcaSpl }
4756382c8bcaSpl 
4757382c8bcaSpl /*
4758382c8bcaSpl  * Handle command to logical device
4759382c8bcaSpl  */
47607c478bd9Sstevel@tonic-gate static int
aac_tran_start_ld(struct aac_softstate * softs,struct aac_cmd * acp)4761382c8bcaSpl aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
47627c478bd9Sstevel@tonic-gate {
4763382c8bcaSpl 	struct aac_container *dvp;
4764382c8bcaSpl 	struct scsi_pkt *pkt;
47657c478bd9Sstevel@tonic-gate 	union scsi_cdb *cdbp;
4766c9487164Spl 	struct buf *bp;
4767c9487164Spl 	int rval;
4768830d82f7Spl 
476958bc78c7SXin Chen 	dvp = (struct aac_container *)acp->dvp;
4770382c8bcaSpl 	pkt = acp->pkt;
4771a74f7440Spl 	cdbp = (void *)pkt->pkt_cdbp;
4772d7c5bf88Spl 	bp = acp->bp;
4773d7c5bf88Spl 
4774382c8bcaSpl 	switch (cdbp->scc_cmd) {
4775830d82f7Spl 	case SCMD_INQUIRY: /* inquiry */
4776c9487164Spl 		aac_free_dmamap(acp);
4777830d82f7Spl 		aac_inquiry(softs, pkt, cdbp, bp);
4778d7c5bf88Spl 		aac_soft_callback(softs, acp);
4779c9487164Spl 		rval = TRAN_ACCEPT;
4780830d82f7Spl 		break;
47817c478bd9Sstevel@tonic-gate 
4782830d82f7Spl 	case SCMD_READ_CAPACITY: /* read capacity */
4783830d82f7Spl 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4784830d82f7Spl 			struct scsi_capacity cap;
4785832e0b5aSpl 			uint64_t last_lba;
47867c478bd9Sstevel@tonic-gate 
4787830d82f7Spl 			/* check 64-bit LBA */
4788382c8bcaSpl 			last_lba = dvp->size - 1;
4789832e0b5aSpl 			if (last_lba > 0xffffffffull) {
4790c9487164Spl 				cap.capacity = 0xfffffffful;
4791832e0b5aSpl 			} else {
4792832e0b5aSpl 				cap.capacity = BE_32(last_lba);
4793832e0b5aSpl 			}
4794830d82f7Spl 			cap.lbasize = BE_32(AAC_SECTOR_SIZE);
4795830d82f7Spl 
4796c9487164Spl 			aac_free_dmamap(acp);
4797d937e6ebSpl 			if (bp->b_flags & (B_PHYS|B_PAGEIO))
4798830d82f7Spl 				bp_mapin(bp);
479951ccf66eSjd 			bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
4800830d82f7Spl 			pkt->pkt_state |= STATE_XFERRED_DATA;
4801830d82f7Spl 		}
4802d7c5bf88Spl 		aac_soft_callback(softs, acp);
4803c9487164Spl 		rval = TRAN_ACCEPT;
4804830d82f7Spl 		break;
4805830d82f7Spl 
4806830d82f7Spl 	case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
4807830d82f7Spl 		/* Check if containers need 64-bit LBA support */
4808382c8bcaSpl 		if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
4809382c8bcaSpl 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
4810382c8bcaSpl 				struct scsi_capacity_16 cap16;
4811382c8bcaSpl 				int cap_len = sizeof (struct scsi_capacity_16);
4812382c8bcaSpl 
4813382c8bcaSpl 				bzero(&cap16, cap_len);
4814b6094a86Sjd 				cap16.sc_capacity = BE_64(dvp->size - 1);
4815382c8bcaSpl 				cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
4816382c8bcaSpl 
4817382c8bcaSpl 				aac_free_dmamap(acp);
4818382c8bcaSpl 				if (bp->b_flags & (B_PHYS | B_PAGEIO))
4819382c8bcaSpl 					bp_mapin(bp);
482051ccf66eSjd 				bcopy(&cap16, bp->b_un.b_addr,
482151ccf66eSjd 				    min(bp->b_bcount, cap_len));
4822382c8bcaSpl 				pkt->pkt_state |= STATE_XFERRED_DATA;
4823382c8bcaSpl 			}
4824382c8bcaSpl 			aac_soft_callback(softs, acp);
4825382c8bcaSpl 		} else {
4826382c8bcaSpl 			aac_unknown_scmd(softs, acp);
4827830d82f7Spl 		}
4828c9487164Spl 		rval = TRAN_ACCEPT;
4829830d82f7Spl 		break;
4830830d82f7Spl 
4831830d82f7Spl 	case SCMD_READ_G4: /* read_16 */
4832830d82f7Spl 	case SCMD_WRITE_G4: /* write_16 */
4833d7c5bf88Spl 		if (softs->flags & AAC_FLAGS_RAW_IO) {
4834d7c5bf88Spl 			/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
4835d7c5bf88Spl 			acp->blkno = ((uint64_t) \
4836d7c5bf88Spl 			    GETG4ADDR(cdbp) << 32) | \
4837d7c5bf88Spl 			    (uint32_t)GETG4ADDRTL(cdbp);
4838d7c5bf88Spl 			goto do_io;
4839830d82f7Spl 		}
4840d7c5bf88Spl 		AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
4841382c8bcaSpl 		aac_unknown_scmd(softs, acp);
4842382c8bcaSpl 		rval = TRAN_ACCEPT;
4843382c8bcaSpl 		break;
4844830d82f7Spl 
4845830d82f7Spl 	case SCMD_READ: /* read_6 */
4846830d82f7Spl 	case SCMD_WRITE: /* write_6 */
4847d7c5bf88Spl 		acp->blkno = GETG0ADDR(cdbp);
4848d7c5bf88Spl 		goto do_io;
4849c9487164Spl 
485058bc78c7SXin Chen 	case SCMD_READ_G5: /* read_12 */
485158bc78c7SXin Chen 	case SCMD_WRITE_G5: /* write_12 */
485258bc78c7SXin Chen 		acp->blkno = GETG5ADDR(cdbp);
485358bc78c7SXin Chen 		goto do_io;
485458bc78c7SXin Chen 
4855d7c5bf88Spl 	case SCMD_READ_G1: /* read_10 */
4856d7c5bf88Spl 	case SCMD_WRITE_G1: /* write_10 */
4857d7c5bf88Spl 		acp->blkno = (uint32_t)GETG1ADDR(cdbp);
4858d7c5bf88Spl do_io:
4859d7c5bf88Spl 		if (acp->flags & AAC_CMD_DMA_VALID) {
4860942c5e3cSpl 			uint64_t cnt_size = dvp->size;
4861c9487164Spl 
4862d7c5bf88Spl 			/*
4863d7c5bf88Spl 			 * If LBA > array size AND rawio, the
4864d7c5bf88Spl 			 * adapter may hang. So check it before
4865d7c5bf88Spl 			 * sending.
4866d7c5bf88Spl 			 * NOTE: (blkno + blkcnt) may overflow
4867d7c5bf88Spl 			 */
4868d7c5bf88Spl 			if ((acp->blkno < cnt_size) &&
4869d7c5bf88Spl 			    ((acp->blkno + acp->bcount /
4870d7c5bf88Spl 			    AAC_BLK_SIZE) <= cnt_size)) {
4871d7c5bf88Spl 				rval = aac_do_io(softs, acp);
4872830d82f7Spl 			} else {
4873830d82f7Spl 			/*
4874d7c5bf88Spl 			 * Request exceeds the capacity of disk,
4875d7c5bf88Spl 			 * set error block number to last LBA
4876d7c5bf88Spl 			 * + 1.
4877830d82f7Spl 			 */
4878d7c5bf88Spl 				aac_set_arq_data(pkt,
4879d7c5bf88Spl 				    KEY_ILLEGAL_REQUEST, 0x21,
4880d7c5bf88Spl 				    0x00, cnt_size);
4881d7c5bf88Spl 				aac_soft_callback(softs, acp);
4882c9487164Spl 				rval = TRAN_ACCEPT;
4883c9487164Spl 			}
4884d7c5bf88Spl 		} else if (acp->bcount == 0) {
4885d7c5bf88Spl 			/* For 0 length IO, just return ok */
4886d7c5bf88Spl 			aac_soft_callback(softs, acp);
4887d7c5bf88Spl 			rval = TRAN_ACCEPT;
4888830d82f7Spl 		} else {
4889d7c5bf88Spl 			rval = TRAN_BADPKT;
4890830d82f7Spl 		}
4891830d82f7Spl 		break;
4892830d82f7Spl 
4893830d82f7Spl 	case SCMD_MODE_SENSE: /* mode_sense_6 */
4894d7c5bf88Spl 	case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
4895d7c5bf88Spl 		int capacity;
4896d7c5bf88Spl 
4897c9487164Spl 		aac_free_dmamap(acp);
4898382c8bcaSpl 		if (dvp->size > 0xffffffffull)
4899c9487164Spl 			capacity = 0xfffffffful; /* 64-bit LBA */
4900830d82f7Spl 		else
4901382c8bcaSpl 			capacity = dvp->size;
4902830d82f7Spl 		aac_mode_sense(softs, pkt, cdbp, bp, capacity);
4903d7c5bf88Spl 		aac_soft_callback(softs, acp);
4904c9487164Spl 		rval = TRAN_ACCEPT;
4905830d82f7Spl 		break;
4906d7c5bf88Spl 	}
4907830d82f7Spl 
4908b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	case SCMD_START_STOP:
4909b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
4910b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			acp->aac_cmd_fib = aac_cmd_fib_startstop;
4911b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			acp->ac_comp = aac_startstop_complete;
4912b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			rval = aac_do_io(softs, acp);
4913b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			break;
4914b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		}
4915b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	/* FALLTHRU */
4916830d82f7Spl 	case SCMD_TEST_UNIT_READY:
4917830d82f7Spl 	case SCMD_REQUEST_SENSE:
4918830d82f7Spl 	case SCMD_FORMAT:
4919c9487164Spl 		aac_free_dmamap(acp);
4920830d82f7Spl 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4921c9487164Spl 			if (acp->flags & AAC_CMD_BUF_READ) {
4922830d82f7Spl 				if (bp->b_flags & (B_PHYS|B_PAGEIO))
4923830d82f7Spl 					bp_mapin(bp);
4924830d82f7Spl 				bzero(bp->b_un.b_addr, bp->b_bcount);
4925830d82f7Spl 			}
4926830d82f7Spl 			pkt->pkt_state |= STATE_XFERRED_DATA;
4927830d82f7Spl 		}
4928d7c5bf88Spl 		aac_soft_callback(softs, acp);
4929c9487164Spl 		rval = TRAN_ACCEPT;
4930830d82f7Spl 		break;
4931830d82f7Spl 
4932942c5e3cSpl 	case SCMD_SYNCHRONIZE_CACHE:
4933382c8bcaSpl 		acp->flags |= AAC_CMD_NTAG;
4934942c5e3cSpl 		acp->aac_cmd_fib = aac_cmd_fib_sync;
4935382c8bcaSpl 		acp->ac_comp = aac_synccache_complete;
4936382c8bcaSpl 		rval = aac_do_io(softs, acp);
4937382c8bcaSpl 		break;
4938382c8bcaSpl 
4939830d82f7Spl 	case SCMD_DOORLOCK:
4940c9487164Spl 		aac_free_dmamap(acp);
4941942c5e3cSpl 		dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
4942d7c5bf88Spl 		aac_soft_callback(softs, acp);
4943c9487164Spl 		rval = TRAN_ACCEPT;
4944830d82f7Spl 		break;
4945830d82f7Spl 
4946830d82f7Spl 	default: /* unknown command */
4947382c8bcaSpl 		aac_unknown_scmd(softs, acp);
4948c9487164Spl 		rval = TRAN_ACCEPT;
4949830d82f7Spl 		break;
49507c478bd9Sstevel@tonic-gate 	}
49517c478bd9Sstevel@tonic-gate 
4952382c8bcaSpl 	return (rval);
4953382c8bcaSpl }
4954382c8bcaSpl 
4955382c8bcaSpl static int
aac_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)4956382c8bcaSpl aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
4957382c8bcaSpl {
4958382c8bcaSpl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4959382c8bcaSpl 	struct aac_cmd *acp = PKT2AC(pkt);
496058bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
4961382c8bcaSpl 	int rval;
4962382c8bcaSpl 
4963382c8bcaSpl 	DBCALLED(softs, 2);
4964382c8bcaSpl 
4965382c8bcaSpl 	/*
4966382c8bcaSpl 	 * Reinitialize some fields of ac and pkt; the packet may
4967382c8bcaSpl 	 * have been resubmitted
4968382c8bcaSpl 	 */
4969382c8bcaSpl 	acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
4970382c8bcaSpl 	    AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
4971382c8bcaSpl 	acp->timeout = acp->pkt->pkt_time;
4972382c8bcaSpl 	if (pkt->pkt_flags & FLAG_NOINTR)
4973382c8bcaSpl 		acp->flags |= AAC_CMD_NO_INTR;
497458bc78c7SXin Chen #ifdef DEBUG
497558bc78c7SXin Chen 	acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
497658bc78c7SXin Chen #endif
4977382c8bcaSpl 	pkt->pkt_reason = CMD_CMPLT;
4978382c8bcaSpl 	pkt->pkt_state = 0;
4979382c8bcaSpl 	pkt->pkt_statistics = 0;
498058bc78c7SXin Chen 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
4981382c8bcaSpl 
4982382c8bcaSpl 	if (acp->flags & AAC_CMD_DMA_VALID) {
4983382c8bcaSpl 		pkt->pkt_resid = acp->bcount;
4984382c8bcaSpl 		/* Consistent packets need to be sync'ed first */
4985382c8bcaSpl 		if ((acp->flags & AAC_CMD_CONSISTENT) &&
4986382c8bcaSpl 		    (acp->flags & AAC_CMD_BUF_WRITE))
4987382c8bcaSpl 			if (aac_dma_sync_ac(acp) != AACOK) {
4988382c8bcaSpl 				ddi_fm_service_impact(softs->devinfo_p,
4989382c8bcaSpl 				    DDI_SERVICE_UNAFFECTED);
4990382c8bcaSpl 				return (TRAN_BADPKT);
4991382c8bcaSpl 			}
4992382c8bcaSpl 	} else {
4993382c8bcaSpl 		pkt->pkt_resid = 0;
4994382c8bcaSpl 	}
4995382c8bcaSpl 
4996382c8bcaSpl 	mutex_enter(&softs->io_lock);
4997382c8bcaSpl 	AACDB_PRINT_SCMD(softs, acp);
499858bc78c7SXin Chen 	if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
499958bc78c7SXin Chen 	    !(softs->state & AAC_STATE_DEAD)) {
500058bc78c7SXin Chen 		if (dvp->type == AAC_DEV_LD) {
500158bc78c7SXin Chen 			if (ap->a_lun == 0)
500258bc78c7SXin Chen 				rval = aac_tran_start_ld(softs, acp);
500358bc78c7SXin Chen 			else
500458bc78c7SXin Chen 				goto error;
500558bc78c7SXin Chen 		} else {
500658bc78c7SXin Chen 			rval = aac_do_io(softs, acp);
500758bc78c7SXin Chen 		}
5008382c8bcaSpl 	} else {
500958bc78c7SXin Chen error:
501058bc78c7SXin Chen #ifdef DEBUG
501158bc78c7SXin Chen 		if (!(softs->state & AAC_STATE_DEAD)) {
501258bc78c7SXin Chen 			AACDB_PRINT_TRAN(softs,
501358bc78c7SXin Chen 			    "Cannot send cmd to target t%dL%d: %s",
501458bc78c7SXin Chen 			    ap->a_target, ap->a_lun,
501558bc78c7SXin Chen 			    "target invalid");
501658bc78c7SXin Chen 		} else {
501758bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN,
501858bc78c7SXin Chen 			    "Cannot send cmd to target t%dL%d: %s",
501958bc78c7SXin Chen 			    ap->a_target, ap->a_lun,
502058bc78c7SXin Chen 			    "adapter dead");
502158bc78c7SXin Chen 		}
502258bc78c7SXin Chen #endif
5023382c8bcaSpl 		rval = TRAN_FATAL_ERROR;
5024382c8bcaSpl 	}
5025382c8bcaSpl 	mutex_exit(&softs->io_lock);
5026c9487164Spl 	return (rval);
50277c478bd9Sstevel@tonic-gate }
50287c478bd9Sstevel@tonic-gate 
50297c478bd9Sstevel@tonic-gate static int
aac_tran_getcap(struct scsi_address * ap,char * cap,int whom)50307c478bd9Sstevel@tonic-gate aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
50317c478bd9Sstevel@tonic-gate {
5032c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
503358bc78c7SXin Chen 	struct aac_device *dvp;
5034c9487164Spl 	int rval;
50357c478bd9Sstevel@tonic-gate 
50361dd0a2dbSpl 	DBCALLED(softs, 2);
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate 	/* We don't allow inquiring about capabilities for other targets */
50397c478bd9Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
50401dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
50411dd0a2dbSpl 		    "GetCap> %s not supported: whom=%d", cap, whom);
50427c478bd9Sstevel@tonic-gate 		return (-1);
50437c478bd9Sstevel@tonic-gate 	}
50447c478bd9Sstevel@tonic-gate 
5045382c8bcaSpl 	mutex_enter(&softs->io_lock);
504658bc78c7SXin Chen 	dvp = AAC_DEV(softs, ap->a_target);
504758bc78c7SXin Chen 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5048382c8bcaSpl 		mutex_exit(&softs->io_lock);
504958bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
5050942c5e3cSpl 		    ap->a_target, ap->a_lun);
50517c478bd9Sstevel@tonic-gate 		return (-1);
50527c478bd9Sstevel@tonic-gate 	}
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
5055830d82f7Spl 	case SCSI_CAP_ARQ: /* auto request sense */
50567c478bd9Sstevel@tonic-gate 		rval = 1;
50577c478bd9Sstevel@tonic-gate 		break;
5058830d82f7Spl 	case SCSI_CAP_UNTAGGED_QING:
5059830d82f7Spl 	case SCSI_CAP_TAGGED_QING:
5060830d82f7Spl 		rval = 1;
50617c478bd9Sstevel@tonic-gate 		break;
5062942c5e3cSpl 	case SCSI_CAP_DMA_MAX:
506372888e72Speng liu - Sun Microsystems - Beijing China 		rval = softs->dma_max;
5064942c5e3cSpl 		break;
50657c478bd9Sstevel@tonic-gate 	default:
50667c478bd9Sstevel@tonic-gate 		rval = -1;
50677c478bd9Sstevel@tonic-gate 		break;
50687c478bd9Sstevel@tonic-gate 	}
5069382c8bcaSpl 	mutex_exit(&softs->io_lock);
5070382c8bcaSpl 
50711dd0a2dbSpl 	AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
50721dd0a2dbSpl 	    cap, ap->a_target, ap->a_lun, rval);
50737c478bd9Sstevel@tonic-gate 	return (rval);
50747c478bd9Sstevel@tonic-gate }
50757c478bd9Sstevel@tonic-gate 
50767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
50777c478bd9Sstevel@tonic-gate static int
aac_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)5078c9487164Spl aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
50797c478bd9Sstevel@tonic-gate {
5080c9487164Spl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
508158bc78c7SXin Chen 	struct aac_device *dvp;
5082c9487164Spl 	int rval;
50837c478bd9Sstevel@tonic-gate 
50841dd0a2dbSpl 	DBCALLED(softs, 2);
50857c478bd9Sstevel@tonic-gate 
50867c478bd9Sstevel@tonic-gate 	/* We don't allow inquiring about capabilities for other targets */
50877c478bd9Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
50881dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
50891dd0a2dbSpl 		    "SetCap> %s not supported: whom=%d", cap, whom);
5090830d82f7Spl 		return (-1);
5091830d82f7Spl 	}
5092830d82f7Spl 
5093382c8bcaSpl 	mutex_enter(&softs->io_lock);
509458bc78c7SXin Chen 	dvp = AAC_DEV(softs, ap->a_target);
509558bc78c7SXin Chen 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5096382c8bcaSpl 		mutex_exit(&softs->io_lock);
509758bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
5098942c5e3cSpl 		    ap->a_target, ap->a_lun);
50997c478bd9Sstevel@tonic-gate 		return (-1);
51007c478bd9Sstevel@tonic-gate 	}
51017c478bd9Sstevel@tonic-gate 
51027c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
51037c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
5104942c5e3cSpl 		/* Force auto request sense */
5105830d82f7Spl 		rval = (value == 1) ? 1 : 0;
51067c478bd9Sstevel@tonic-gate 		break;
5107830d82f7Spl 	case SCSI_CAP_UNTAGGED_QING:
5108830d82f7Spl 	case SCSI_CAP_TAGGED_QING:
5109830d82f7Spl 		rval = (value == 1) ? 1 : 0;
5110830d82f7Spl 		break;
51117c478bd9Sstevel@tonic-gate 	default:
51127c478bd9Sstevel@tonic-gate 		rval = -1;
51137c478bd9Sstevel@tonic-gate 		break;
51147c478bd9Sstevel@tonic-gate 	}
5115382c8bcaSpl 	mutex_exit(&softs->io_lock);
51167c478bd9Sstevel@tonic-gate 
51171dd0a2dbSpl 	AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
51181dd0a2dbSpl 	    cap, ap->a_target, ap->a_lun, value, rval);
51197c478bd9Sstevel@tonic-gate 	return (rval);
51207c478bd9Sstevel@tonic-gate }
51217c478bd9Sstevel@tonic-gate 
51227c478bd9Sstevel@tonic-gate static void
aac_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)5123c9487164Spl aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
51247c478bd9Sstevel@tonic-gate {
5125c9487164Spl 	struct aac_cmd *acp = PKT2AC(pkt);
51267c478bd9Sstevel@tonic-gate 
51271dd0a2dbSpl 	DBCALLED(NULL, 2);
51287c478bd9Sstevel@tonic-gate 
5129942c5e3cSpl 	if (acp->sgt) {
5130942c5e3cSpl 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5131942c5e3cSpl 		    acp->left_cookien);
5132d7c5bf88Spl 	}
5133c9487164Spl 	aac_free_dmamap(acp);
5134c9487164Spl 	ASSERT(acp->slotp == NULL);
51357c478bd9Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
51367c478bd9Sstevel@tonic-gate }
51377c478bd9Sstevel@tonic-gate 
5138942c5e3cSpl int
aac_cmd_dma_alloc(struct aac_softstate * softs,struct aac_cmd * acp,struct buf * bp,int flags,int (* cb)(),caddr_t arg)5139942c5e3cSpl aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
5140942c5e3cSpl     struct buf *bp, int flags, int (*cb)(), caddr_t arg)
51417c478bd9Sstevel@tonic-gate {
5142942c5e3cSpl 	int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
5143942c5e3cSpl 	uint_t oldcookiec;
5144c9ffe217SToomas Soome 	int bioerr = 0;
5145c9487164Spl 	int rval;
51467c478bd9Sstevel@tonic-gate 
5147942c5e3cSpl 	oldcookiec = acp->left_cookien;
51487c478bd9Sstevel@tonic-gate 
5149942c5e3cSpl 	/* Move window to build s/g map */
5150942c5e3cSpl 	if (acp->total_nwin > 0) {
5151942c5e3cSpl 		if (++acp->cur_win < acp->total_nwin) {
5152942c5e3cSpl 			off_t off;
5153942c5e3cSpl 			size_t len;
5154c9487164Spl 
5155942c5e3cSpl 			rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
5156942c5e3cSpl 			    &off, &len, &acp->cookie, &acp->left_cookien);
5157942c5e3cSpl 			if (rval == DDI_SUCCESS)
5158942c5e3cSpl 				goto get_dma_cookies;
5159942c5e3cSpl 			AACDB_PRINT(softs, CE_WARN,
5160942c5e3cSpl 			    "ddi_dma_getwin() fail %d", rval);
516158bc78c7SXin Chen 			return (AACERR);
51627c478bd9Sstevel@tonic-gate 		}
5163942c5e3cSpl 		AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
516458bc78c7SXin Chen 		return (AACERR);
5165942c5e3cSpl 	}
5166942c5e3cSpl 
5167942c5e3cSpl 	/* We need to transfer data, so we alloc DMA resources for this pkt */
5168942c5e3cSpl 	if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
5169942c5e3cSpl 		uint_t dma_flags = 0;
5170942c5e3cSpl 		struct aac_sge *sge;
5171830d82f7Spl 
51727c478bd9Sstevel@tonic-gate 		/*
5173830d82f7Spl 		 * We will still use this point to fake some
5174830d82f7Spl 		 * infomation in tran_start
51757c478bd9Sstevel@tonic-gate 		 */
5176c9487164Spl 		acp->bp = bp;
51777c478bd9Sstevel@tonic-gate 
5178830d82f7Spl 		/* Set dma flags */
51797c478bd9Sstevel@tonic-gate 		if (BUF_IS_READ(bp)) {
51807c478bd9Sstevel@tonic-gate 			dma_flags |= DDI_DMA_READ;
5181c9487164Spl 			acp->flags |= AAC_CMD_BUF_READ;
51827c478bd9Sstevel@tonic-gate 		} else {
51837c478bd9Sstevel@tonic-gate 			dma_flags |= DDI_DMA_WRITE;
5184c9487164Spl 			acp->flags |= AAC_CMD_BUF_WRITE;
51857c478bd9Sstevel@tonic-gate 		}
51867c478bd9Sstevel@tonic-gate 		if (flags & PKT_CONSISTENT)
51877c478bd9Sstevel@tonic-gate 			dma_flags |= DDI_DMA_CONSISTENT;
51887c478bd9Sstevel@tonic-gate 		if (flags & PKT_DMA_PARTIAL)
51897c478bd9Sstevel@tonic-gate 			dma_flags |= DDI_DMA_PARTIAL;
51907c478bd9Sstevel@tonic-gate 
5191830d82f7Spl 		/* Alloc buf dma handle */
5192942c5e3cSpl 		if (!acp->buf_dma_handle) {
5193c9487164Spl 			rval = ddi_dma_alloc_handle(softs->devinfo_p,
5194d7c5bf88Spl 			    &softs->buf_dma_attr, cb, arg,
5195c9487164Spl 			    &acp->buf_dma_handle);
5196942c5e3cSpl 			if (rval != DDI_SUCCESS) {
5197942c5e3cSpl 				AACDB_PRINT(softs, CE_WARN,
5198942c5e3cSpl 				    "Can't allocate DMA handle, errno=%d",
5199942c5e3cSpl 				    rval);
5200942c5e3cSpl 				goto error_out;
5201942c5e3cSpl 			}
52027c478bd9Sstevel@tonic-gate 		}
52037c478bd9Sstevel@tonic-gate 
5204830d82f7Spl 		/* Bind buf */
5205942c5e3cSpl 		if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
5206c9487164Spl 			rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
5207942c5e3cSpl 			    bp, dma_flags, cb, arg, &acp->cookie,
5208942c5e3cSpl 			    &acp->left_cookien);
5209830d82f7Spl 		} else {
5210830d82f7Spl 			size_t bufsz;
5211830d82f7Spl 
52121dd0a2dbSpl 			AACDB_PRINT_TRAN(softs,
5213c9487164Spl 			    "non-aligned buffer: addr=0x%p, cnt=%lu",
52141dd0a2dbSpl 			    (void *)bp->b_un.b_addr, bp->b_bcount);
5215830d82f7Spl 			if (bp->b_flags & (B_PAGEIO|B_PHYS))
5216830d82f7Spl 				bp_mapin(bp);
5217830d82f7Spl 
5218c9487164Spl 			rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
5219c9487164Spl 			    AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
522058bc78c7SXin Chen 			    &softs->acc_attr, DDI_DMA_STREAMING,
5221d7c5bf88Spl 			    cb, arg, &acp->abp, &bufsz, &acp->abh);
5222830d82f7Spl 
5223c9487164Spl 			if (rval != DDI_SUCCESS) {
52241dd0a2dbSpl 				AACDB_PRINT(softs, CE_NOTE,
52251dd0a2dbSpl 				    "Cannot alloc DMA to non-aligned buf");
5226942c5e3cSpl 				bioerr = 0;
5227830d82f7Spl 				goto error_out;
5228830d82f7Spl 			}
5229830d82f7Spl 
5230c9487164Spl 			if (acp->flags & AAC_CMD_BUF_WRITE)
5231942c5e3cSpl 				ddi_rep_put8(acp->abh,
5232942c5e3cSpl 				    (uint8_t *)bp->b_un.b_addr,
5233942c5e3cSpl 				    (uint8_t *)acp->abp, bp->b_bcount,
5234942c5e3cSpl 				    DDI_DEV_AUTOINCR);
5235830d82f7Spl 
5236c9487164Spl 			rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
5237d7c5bf88Spl 			    NULL, acp->abp, bufsz, dma_flags, cb, arg,
5238d7c5bf88Spl 			    &acp->cookie, &acp->left_cookien);
5239830d82f7Spl 		}
5240830d82f7Spl 
5241c9487164Spl 		switch (rval) {
52427c478bd9Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
5243c9487164Spl 			if (ddi_dma_numwin(acp->buf_dma_handle,
5244c9487164Spl 			    &acp->total_nwin) == DDI_FAILURE) {
52451dd0a2dbSpl 				AACDB_PRINT(softs, CE_WARN,
52461dd0a2dbSpl 				    "Cannot get number of DMA windows");
5247942c5e3cSpl 				bioerr = 0;
52487c478bd9Sstevel@tonic-gate 				goto error_out;
52497c478bd9Sstevel@tonic-gate 			}
5250942c5e3cSpl 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52511dd0a2dbSpl 			    acp->left_cookien);
5252c9487164Spl 			acp->cur_win = 0;
52537c478bd9Sstevel@tonic-gate 			break;
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
5256942c5e3cSpl 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52571dd0a2dbSpl 			    acp->left_cookien);
5258c9487164Spl 			acp->cur_win = 0;
5259c9487164Spl 			acp->total_nwin = 1;
52607c478bd9Sstevel@tonic-gate 			break;
52617c478bd9Sstevel@tonic-gate 
5262832e0b5aSpl 		case DDI_DMA_NORESOURCES:
5263942c5e3cSpl 			bioerr = 0;
52641dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
52651dd0a2dbSpl 			    "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
5266832e0b5aSpl 			goto error_out;
5267832e0b5aSpl 		case DDI_DMA_BADATTR:
5268832e0b5aSpl 		case DDI_DMA_NOMAPPING:
5269942c5e3cSpl 			bioerr = EFAULT;
52701dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
52711dd0a2dbSpl 			    "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
5272832e0b5aSpl 			goto error_out;
5273832e0b5aSpl 		case DDI_DMA_TOOBIG:
5274942c5e3cSpl 			bioerr = EINVAL;
5275942c5e3cSpl 			AACDB_PRINT(softs, CE_WARN,
5276942c5e3cSpl 			    "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
5277942c5e3cSpl 			    bp->b_bcount);
5278942c5e3cSpl 			goto error_out;
52797c478bd9Sstevel@tonic-gate 		default:
5280942c5e3cSpl 			bioerr = EINVAL;
52811dd0a2dbSpl 			AACDB_PRINT(softs, CE_WARN,
52821dd0a2dbSpl 			    "Cannot bind buf for DMA: %d", rval);
5283832e0b5aSpl 			goto error_out;
52847c478bd9Sstevel@tonic-gate 		}
5285942c5e3cSpl 		acp->flags |= AAC_CMD_DMA_VALID;
5286d7c5bf88Spl 
5287942c5e3cSpl get_dma_cookies:
5288942c5e3cSpl 		ASSERT(acp->left_cookien > 0);
5289942c5e3cSpl 		if (acp->left_cookien > softs->aac_sg_tablesize) {
5290942c5e3cSpl 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
5291942c5e3cSpl 			    acp->left_cookien);
5292942c5e3cSpl 			bioerr = EINVAL;
5293942c5e3cSpl 			goto error_out;
5294942c5e3cSpl 		}
5295942c5e3cSpl 		if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
5296942c5e3cSpl 			kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5297942c5e3cSpl 			    oldcookiec);
5298942c5e3cSpl 			acp->sgt = NULL;
5299942c5e3cSpl 		}
5300942c5e3cSpl 		if (acp->sgt == NULL) {
5301942c5e3cSpl 			acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
5302942c5e3cSpl 			    acp->left_cookien, kf);
5303942c5e3cSpl 			if (acp->sgt == NULL) {
5304d7c5bf88Spl 				AACDB_PRINT(softs, CE_WARN,
5305942c5e3cSpl 				    "sgt kmem_alloc fail");
5306942c5e3cSpl 				bioerr = ENOMEM;
5307942c5e3cSpl 				goto error_out;
5308d7c5bf88Spl 			}
5309d7c5bf88Spl 		}
5310d7c5bf88Spl 
5311942c5e3cSpl 		sge = &acp->sgt[0];
5312942c5e3cSpl 		sge->bcount = acp->cookie.dmac_size;
5313942c5e3cSpl 		sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5314942c5e3cSpl 		sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5315942c5e3cSpl 		acp->bcount = acp->cookie.dmac_size;
5316942c5e3cSpl 		for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
5317942c5e3cSpl 			ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
5318942c5e3cSpl 			sge->bcount = acp->cookie.dmac_size;
5319942c5e3cSpl 			sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5320942c5e3cSpl 			sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5321942c5e3cSpl 			acp->bcount += acp->cookie.dmac_size;
5322942c5e3cSpl 		}
5323d7c5bf88Spl 
5324942c5e3cSpl 		/*
5325942c5e3cSpl 		 * Note: The old DMA engine do not correctly handle
5326942c5e3cSpl 		 * dma_attr_maxxfer attribute. So we have to ensure
5327942c5e3cSpl 		 * it by ourself.
5328942c5e3cSpl 		 */
5329942c5e3cSpl 		if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
5330942c5e3cSpl 			AACDB_PRINT(softs, CE_NOTE,
5331942c5e3cSpl 			    "large xfer size received %d\n", acp->bcount);
5332942c5e3cSpl 			bioerr = EINVAL;
5333d7c5bf88Spl 			goto error_out;
5334d7c5bf88Spl 		}
5335942c5e3cSpl 
5336942c5e3cSpl 		acp->total_xfer += acp->bcount;
5337942c5e3cSpl 
5338942c5e3cSpl 		if (acp->pkt) {
5339942c5e3cSpl 			/* Return remaining byte count */
534058bc78c7SXin Chen 			if (acp->total_xfer <= bp->b_bcount) {
534158bc78c7SXin Chen 				acp->pkt->pkt_resid = bp->b_bcount - \
534258bc78c7SXin Chen 				    acp->total_xfer;
534358bc78c7SXin Chen 			} else {
534458bc78c7SXin Chen 				/*
534558bc78c7SXin Chen 				 * Allocated DMA size is greater than the buf
534658bc78c7SXin Chen 				 * size of bp. This is caused by devices like
534758bc78c7SXin Chen 				 * tape. we have extra bytes allocated, but
534858bc78c7SXin Chen 				 * the packet residual has to stay correct.
534958bc78c7SXin Chen 				 */
535058bc78c7SXin Chen 				acp->pkt->pkt_resid = 0;
535158bc78c7SXin Chen 			}
5352942c5e3cSpl 			AACDB_PRINT_TRAN(softs,
5353942c5e3cSpl 			    "bp=0x%p, xfered=%d/%d, resid=%d",
5354942c5e3cSpl 			    (void *)bp->b_un.b_addr, (int)acp->total_xfer,
5355942c5e3cSpl 			    (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
5356942c5e3cSpl 		}
5357d7c5bf88Spl 	}
5358942c5e3cSpl 	return (AACOK);
5359d7c5bf88Spl 
5360942c5e3cSpl error_out:
5361942c5e3cSpl 	bioerror(bp, bioerr);
5362942c5e3cSpl 	return (AACERR);
5363942c5e3cSpl }
5364d7c5bf88Spl 
5365942c5e3cSpl static struct scsi_pkt *
aac_tran_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)5366942c5e3cSpl aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
5367942c5e3cSpl     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
5368942c5e3cSpl     int (*callback)(), caddr_t arg)
5369942c5e3cSpl {
5370942c5e3cSpl 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5371942c5e3cSpl 	struct aac_cmd *acp, *new_acp;
5372830d82f7Spl 
5373942c5e3cSpl 	DBCALLED(softs, 2);
5374830d82f7Spl 
5375942c5e3cSpl 	/* Allocate pkt */
5376942c5e3cSpl 	if (pkt == NULL) {
5377942c5e3cSpl 		int slen;
5378830d82f7Spl 
5379942c5e3cSpl 		/* Force auto request sense */
5380942c5e3cSpl 		slen = (statuslen > softs->slen) ? statuslen : softs->slen;
5381942c5e3cSpl 		pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
5382942c5e3cSpl 		    slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
5383942c5e3cSpl 		if (pkt == NULL) {
5384942c5e3cSpl 			AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
5385942c5e3cSpl 			return (NULL);
5386942c5e3cSpl 		}
5387942c5e3cSpl 		acp = new_acp = PKT2AC(pkt);
5388942c5e3cSpl 		acp->pkt = pkt;
5389942c5e3cSpl 		acp->cmdlen = cmdlen;
5390942c5e3cSpl 
539158bc78c7SXin Chen 		if (ap->a_target < AAC_MAX_LD) {
539258bc78c7SXin Chen 			acp->dvp = &softs->containers[ap->a_target].dev;
539358bc78c7SXin Chen 			acp->aac_cmd_fib = softs->aac_cmd_fib;
539458bc78c7SXin Chen 			acp->ac_comp = aac_ld_complete;
539558bc78c7SXin Chen 		} else {
539658bc78c7SXin Chen 			_NOTE(ASSUMING_PROTECTED(softs->nondasds))
539758bc78c7SXin Chen 
539858bc78c7SXin Chen 			acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
539958bc78c7SXin Chen 			acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
540058bc78c7SXin Chen 			acp->ac_comp = aac_pd_complete;
540158bc78c7SXin Chen 		}
5402942c5e3cSpl 	} else {
5403942c5e3cSpl 		acp = PKT2AC(pkt);
5404942c5e3cSpl 		new_acp = NULL;
5405942c5e3cSpl 	}
5406942c5e3cSpl 
5407942c5e3cSpl 	if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
5408942c5e3cSpl 		return (pkt);
5409832e0b5aSpl 
5410c9487164Spl 	if (new_acp)
5411d7c5bf88Spl 		aac_tran_destroy_pkt(ap, pkt);
5412832e0b5aSpl 	return (NULL);
54137c478bd9Sstevel@tonic-gate }
54147c478bd9Sstevel@tonic-gate 
54157c478bd9Sstevel@tonic-gate /*
54167c478bd9Sstevel@tonic-gate  * tran_sync_pkt(9E) - explicit DMA synchronization
54177c478bd9Sstevel@tonic-gate  */
54187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
54197c478bd9Sstevel@tonic-gate static void
aac_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)54207c478bd9Sstevel@tonic-gate aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
54217c478bd9Sstevel@tonic-gate {
5422c9487164Spl 	struct aac_cmd *acp = PKT2AC(pkt);
54237c478bd9Sstevel@tonic-gate 
54241dd0a2dbSpl 	DBCALLED(NULL, 2);
54257c478bd9Sstevel@tonic-gate 
54267675db54Syw 	if (aac_dma_sync_ac(acp) != AACOK)
54277675db54Syw 		ddi_fm_service_impact(
54287675db54Syw 		    (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
54297675db54Syw 		    DDI_SERVICE_UNAFFECTED);
54307c478bd9Sstevel@tonic-gate }
54317c478bd9Sstevel@tonic-gate 
54327c478bd9Sstevel@tonic-gate /*
54337c478bd9Sstevel@tonic-gate  * tran_dmafree(9E) - deallocate DMA resources allocated for command
54347c478bd9Sstevel@tonic-gate  */
54357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
54367c478bd9Sstevel@tonic-gate static void
aac_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)54377c478bd9Sstevel@tonic-gate aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
54387c478bd9Sstevel@tonic-gate {
5439c9487164Spl 	struct aac_cmd *acp = PKT2AC(pkt);
54407c478bd9Sstevel@tonic-gate 
54411dd0a2dbSpl 	DBCALLED(NULL, 2);
54427c478bd9Sstevel@tonic-gate 
5443c9487164Spl 	aac_free_dmamap(acp);
54447c478bd9Sstevel@tonic-gate }
54457c478bd9Sstevel@tonic-gate 
5446382c8bcaSpl static int
aac_do_quiesce(struct aac_softstate * softs)5447382c8bcaSpl aac_do_quiesce(struct aac_softstate *softs)
5448382c8bcaSpl {
5449382c8bcaSpl 	aac_hold_bus(softs, AAC_IOCMD_ASYNC);
5450382c8bcaSpl 	if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
5451382c8bcaSpl 		aac_start_drain(softs);
5452382c8bcaSpl 		do {
5453382c8bcaSpl 			if (cv_wait_sig(&softs->drain_cv,
5454382c8bcaSpl 			    &softs->io_lock) == 0) {
5455382c8bcaSpl 				/* Quiesce has been interrupted */
5456382c8bcaSpl 				aac_stop_drain(softs);
5457382c8bcaSpl 				aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5458382c8bcaSpl 				aac_start_waiting_io(softs);
5459382c8bcaSpl 				return (AACERR);
5460382c8bcaSpl 			}
5461382c8bcaSpl 		} while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
5462382c8bcaSpl 		aac_stop_drain(softs);
5463382c8bcaSpl 	}
5464382c8bcaSpl 
5465382c8bcaSpl 	softs->state |= AAC_STATE_QUIESCED;
5466382c8bcaSpl 	return (AACOK);
5467382c8bcaSpl }
5468382c8bcaSpl 
54697c478bd9Sstevel@tonic-gate static int
aac_tran_quiesce(dev_info_t * dip)54707c478bd9Sstevel@tonic-gate aac_tran_quiesce(dev_info_t *dip)
54717c478bd9Sstevel@tonic-gate {
5472c9487164Spl 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5473382c8bcaSpl 	int rval;
5474830d82f7Spl 
54751dd0a2dbSpl 	DBCALLED(softs, 1);
5476830d82f7Spl 
5477382c8bcaSpl 	mutex_enter(&softs->io_lock);
5478382c8bcaSpl 	if (aac_do_quiesce(softs) == AACOK)
5479c9487164Spl 		rval = 0;
5480382c8bcaSpl 	else
5481382c8bcaSpl 		rval = 1;
5482382c8bcaSpl 	mutex_exit(&softs->io_lock);
5483c9487164Spl 	return (rval);
54847c478bd9Sstevel@tonic-gate }
54857c478bd9Sstevel@tonic-gate 
5486382c8bcaSpl static int
aac_do_unquiesce(struct aac_softstate * softs)5487382c8bcaSpl aac_do_unquiesce(struct aac_softstate *softs)
5488382c8bcaSpl {
5489382c8bcaSpl 	softs->state &= ~AAC_STATE_QUIESCED;
5490382c8bcaSpl 	aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5491382c8bcaSpl 
5492382c8bcaSpl 	aac_start_waiting_io(softs);
5493382c8bcaSpl 	return (AACOK);
5494382c8bcaSpl }
5495382c8bcaSpl 
54967c478bd9Sstevel@tonic-gate static int
aac_tran_unquiesce(dev_info_t * dip)54977c478bd9Sstevel@tonic-gate aac_tran_unquiesce(dev_info_t *dip)
54987c478bd9Sstevel@tonic-gate {
5499c9487164Spl 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5500382c8bcaSpl 	int rval;
5501830d82f7Spl 
55021dd0a2dbSpl 	DBCALLED(softs, 1);
5503830d82f7Spl 
5504382c8bcaSpl 	mutex_enter(&softs->io_lock);
5505382c8bcaSpl 	if (aac_do_unquiesce(softs) == AACOK)
5506382c8bcaSpl 		rval = 0;
5507382c8bcaSpl 	else
5508382c8bcaSpl 		rval = 1;
5509382c8bcaSpl 	mutex_exit(&softs->io_lock);
5510382c8bcaSpl 	return (rval);
55117c478bd9Sstevel@tonic-gate }
55127c478bd9Sstevel@tonic-gate 
55137c478bd9Sstevel@tonic-gate static int
aac_hba_setup(struct aac_softstate * softs)55147c478bd9Sstevel@tonic-gate aac_hba_setup(struct aac_softstate *softs)
55157c478bd9Sstevel@tonic-gate {
5516c9487164Spl 	scsi_hba_tran_t *hba_tran;
5517c9487164Spl 	int rval;
55187c478bd9Sstevel@tonic-gate 
55197c478bd9Sstevel@tonic-gate 	hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
55207c478bd9Sstevel@tonic-gate 	if (hba_tran == NULL)
55217c478bd9Sstevel@tonic-gate 		return (AACERR);
55227c478bd9Sstevel@tonic-gate 	hba_tran->tran_hba_private = softs;
55237c478bd9Sstevel@tonic-gate 	hba_tran->tran_tgt_init = aac_tran_tgt_init;
552458bc78c7SXin Chen 	hba_tran->tran_tgt_free = aac_tran_tgt_free;
55257c478bd9Sstevel@tonic-gate 	hba_tran->tran_tgt_probe = scsi_hba_probe;
55267c478bd9Sstevel@tonic-gate 	hba_tran->tran_start = aac_tran_start;
55277c478bd9Sstevel@tonic-gate 	hba_tran->tran_getcap = aac_tran_getcap;
55287c478bd9Sstevel@tonic-gate 	hba_tran->tran_setcap = aac_tran_setcap;
55297c478bd9Sstevel@tonic-gate 	hba_tran->tran_init_pkt = aac_tran_init_pkt;
55307c478bd9Sstevel@tonic-gate 	hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
55317c478bd9Sstevel@tonic-gate 	hba_tran->tran_reset = aac_tran_reset;
5532830d82f7Spl 	hba_tran->tran_abort = aac_tran_abort;
55337c478bd9Sstevel@tonic-gate 	hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
55347c478bd9Sstevel@tonic-gate 	hba_tran->tran_dmafree = aac_tran_dmafree;
55357c478bd9Sstevel@tonic-gate 	hba_tran->tran_quiesce = aac_tran_quiesce;
55367c478bd9Sstevel@tonic-gate 	hba_tran->tran_unquiesce = aac_tran_unquiesce;
553758bc78c7SXin Chen 	hba_tran->tran_bus_config = aac_tran_bus_config;
5538c9487164Spl 	rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
5539d7c5bf88Spl 	    hba_tran, 0);
5540c9487164Spl 	if (rval != DDI_SUCCESS) {
55417c478bd9Sstevel@tonic-gate 		scsi_hba_tran_free(hba_tran);
55421dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
55437c478bd9Sstevel@tonic-gate 		return (AACERR);
55447c478bd9Sstevel@tonic-gate 	}
55457c478bd9Sstevel@tonic-gate 
554658bc78c7SXin Chen 	softs->hba_tran = hba_tran;
55477c478bd9Sstevel@tonic-gate 	return (AACOK);
55487c478bd9Sstevel@tonic-gate }
55497c478bd9Sstevel@tonic-gate 
5550d7c5bf88Spl /*
5551d7c5bf88Spl  * FIB setup operations
5552d7c5bf88Spl  */
5553d7c5bf88Spl 
5554d7c5bf88Spl /*
5555d7c5bf88Spl  * Init FIB header
5556d7c5bf88Spl  */
5557d7c5bf88Spl static void
aac_cmd_fib_header(struct aac_softstate * softs,struct aac_cmd * acp,uint16_t cmd)5558f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
5559f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     uint16_t cmd)
55607c478bd9Sstevel@tonic-gate {
5561f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp = acp->slotp;
5562942c5e3cSpl 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5563942c5e3cSpl 	struct aac_fib *fibp = slotp->fibp;
5564942c5e3cSpl 	uint32_t xfer_state;
5565d7c5bf88Spl 
5566942c5e3cSpl 	xfer_state =
5567c9487164Spl 	    AAC_FIBSTATE_HOSTOWNED |
5568c9487164Spl 	    AAC_FIBSTATE_INITIALISED |
5569c9487164Spl 	    AAC_FIBSTATE_EMPTY |
55700749e8deSXin Chen - Sun Microsystems - Beijing China 	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
5571c9487164Spl 	    AAC_FIBSTATE_FROMHOST |
5572c9487164Spl 	    AAC_FIBSTATE_REXPECTED |
5573942c5e3cSpl 	    AAC_FIBSTATE_NORM;
5574f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
55750749e8deSXin Chen - Sun Microsystems - Beijing China 	if (!(acp->flags & AAC_CMD_SYNC))
55760749e8deSXin Chen - Sun Microsystems - Beijing China 		xfer_state |= AAC_FIBSTATE_ASYNC;
5577942c5e3cSpl 
5578942c5e3cSpl 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
5579942c5e3cSpl 	ddi_put16(acc, &fibp->Header.Command, cmd);
5580942c5e3cSpl 	ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
5581942c5e3cSpl 	ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
5582f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
5583f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
5584942c5e3cSpl 	ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
5585942c5e3cSpl 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5586942c5e3cSpl 	ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
5587d7c5bf88Spl }
55887c478bd9Sstevel@tonic-gate 
5589d7c5bf88Spl /*
5590d7c5bf88Spl  * Init FIB for raw IO command
5591d7c5bf88Spl  */
5592d7c5bf88Spl static void
aac_cmd_fib_rawio(struct aac_softstate * softs,struct aac_cmd * acp)5593942c5e3cSpl aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
5594d7c5bf88Spl {
5595942c5e3cSpl 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5596942c5e3cSpl 	struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
5597942c5e3cSpl 	struct aac_sg_entryraw *sgp;
5598942c5e3cSpl 	struct aac_sge *sge;
5599942c5e3cSpl 
5600942c5e3cSpl 	/* Calculate FIB size */
5601942c5e3cSpl 	acp->fib_size = sizeof (struct aac_fib_header) + \
5602942c5e3cSpl 	    sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
5603942c5e3cSpl 	    sizeof (struct aac_sg_entryraw);
5604942c5e3cSpl 
5605f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, RawIo);
5606942c5e3cSpl 
5607942c5e3cSpl 	ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
5608942c5e3cSpl 	ddi_put16(acc, &io->BpTotal, 0);
5609942c5e3cSpl 	ddi_put16(acc, &io->BpComplete, 0);
5610942c5e3cSpl 
5611942c5e3cSpl 	ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
5612942c5e3cSpl 	ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
5613942c5e3cSpl 	ddi_put16(acc, &io->ContainerId,
5614942c5e3cSpl 	    ((struct aac_container *)acp->dvp)->cid);
5615942c5e3cSpl 
5616942c5e3cSpl 	/* Fill SG table */
5617942c5e3cSpl 	ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
5618942c5e3cSpl 	ddi_put32(acc, &io->ByteCount, acp->bcount);
5619942c5e3cSpl 
5620942c5e3cSpl 	for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
5621942c5e3cSpl 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5622942c5e3cSpl 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5623942c5e3cSpl 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5624942c5e3cSpl 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5625942c5e3cSpl 		sgp->Next = 0;
5626942c5e3cSpl 		sgp->Prev = 0;
5627942c5e3cSpl 		sgp->Flags = 0;
5628942c5e3cSpl 	}
5629942c5e3cSpl }
5630d7c5bf88Spl 
5631942c5e3cSpl /* Init FIB for 64-bit block IO command */
5632942c5e3cSpl static void
aac_cmd_fib_brw64(struct aac_softstate * softs,struct aac_cmd * acp)5633942c5e3cSpl aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
5634942c5e3cSpl {
5635942c5e3cSpl 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5636942c5e3cSpl 	struct aac_blockread64 *br = (struct aac_blockread64 *) \
5637942c5e3cSpl 	    &acp->slotp->fibp->data[0];
5638942c5e3cSpl 	struct aac_sg_entry64 *sgp;
5639942c5e3cSpl 	struct aac_sge *sge;
5640d7c5bf88Spl 
5641942c5e3cSpl 	acp->fib_size = sizeof (struct aac_fib_header) + \
5642942c5e3cSpl 	    sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
5643942c5e3cSpl 	    sizeof (struct aac_sg_entry64);
5644d7c5bf88Spl 
5645f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand64);
5646d7c5bf88Spl 
5647942c5e3cSpl 	/*
5648942c5e3cSpl 	 * The definitions for aac_blockread64 and aac_blockwrite64
5649942c5e3cSpl 	 * are the same.
5650942c5e3cSpl 	 */
5651942c5e3cSpl 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5652942c5e3cSpl 	ddi_put16(acc, &br->ContainerId,
5653942c5e3cSpl 	    ((struct aac_container *)acp->dvp)->cid);
5654942c5e3cSpl 	ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
5655942c5e3cSpl 	    VM_CtHostRead64 : VM_CtHostWrite64);
5656942c5e3cSpl 	ddi_put16(acc, &br->Pad, 0);
5657942c5e3cSpl 	ddi_put16(acc, &br->Flags, 0);
5658942c5e3cSpl 
5659942c5e3cSpl 	/* Fill SG table */
5660942c5e3cSpl 	ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
5661942c5e3cSpl 	ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
5662942c5e3cSpl 
5663942c5e3cSpl 	for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
5664942c5e3cSpl 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5665942c5e3cSpl 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5666942c5e3cSpl 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5667942c5e3cSpl 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5668d7c5bf88Spl 	}
5669d7c5bf88Spl }
5670d7c5bf88Spl 
5671942c5e3cSpl /* Init FIB for block IO command */
5672d7c5bf88Spl static void
aac_cmd_fib_brw(struct aac_softstate * softs,struct aac_cmd * acp)5673942c5e3cSpl aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
5674d7c5bf88Spl {
5675942c5e3cSpl 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5676942c5e3cSpl 	struct aac_blockread *br = (struct aac_blockread *) \
5677942c5e3cSpl 	    &acp->slotp->fibp->data[0];
5678942c5e3cSpl 	struct aac_sg_entry *sgp;
5679942c5e3cSpl 	struct aac_sge *sge = &acp->sgt[0];
5680d7c5bf88Spl 
5681942c5e3cSpl 	if (acp->flags & AAC_CMD_BUF_READ) {
5682d7c5bf88Spl 		acp->fib_size = sizeof (struct aac_fib_header) + \
5683942c5e3cSpl 		    sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
5684942c5e3cSpl 		    sizeof (struct aac_sg_entry);
5685382c8bcaSpl 
5686942c5e3cSpl 		ddi_put32(acc, &br->Command, VM_CtBlockRead);
5687942c5e3cSpl 		ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
5688942c5e3cSpl 		sgp = &br->SgMap.SgEntry[0];
5689942c5e3cSpl 	} else {
5690942c5e3cSpl 		struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
5691d7c5bf88Spl 
5692942c5e3cSpl 		acp->fib_size = sizeof (struct aac_fib_header) + \
5693942c5e3cSpl 		    sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
5694942c5e3cSpl 		    sizeof (struct aac_sg_entry);
5695d7c5bf88Spl 
5696942c5e3cSpl 		ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
5697942c5e3cSpl 		ddi_put32(acc, &bw->Stable, CUNSTABLE);
5698942c5e3cSpl 		ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
5699942c5e3cSpl 		sgp = &bw->SgMap.SgEntry[0];
5700942c5e3cSpl 	}
5701f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5702d7c5bf88Spl 
5703942c5e3cSpl 	/*
5704942c5e3cSpl 	 * aac_blockread and aac_blockwrite have the similar
5705942c5e3cSpl 	 * structure head, so use br for bw here
5706942c5e3cSpl 	 */
5707942c5e3cSpl 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5708942c5e3cSpl 	ddi_put32(acc, &br->ContainerId,
5709942c5e3cSpl 	    ((struct aac_container *)acp->dvp)->cid);
5710942c5e3cSpl 	ddi_put32(acc, &br->ByteCount, acp->bcount);
5711d7c5bf88Spl 
5712942c5e3cSpl 	/* Fill SG table */
5713942c5e3cSpl 	for (sge = &acp->sgt[0];
5714942c5e3cSpl 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5715942c5e3cSpl 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5716942c5e3cSpl 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5717942c5e3cSpl 	}
5718942c5e3cSpl }
5719d7c5bf88Spl 
5720942c5e3cSpl /*ARGSUSED*/
5721942c5e3cSpl void
aac_cmd_fib_copy(struct aac_softstate * softs,struct aac_cmd * acp)5722942c5e3cSpl aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
5723942c5e3cSpl {
5724942c5e3cSpl 	struct aac_slot *slotp = acp->slotp;
5725942c5e3cSpl 	struct aac_fib *fibp = slotp->fibp;
5726942c5e3cSpl 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5727d7c5bf88Spl 
5728942c5e3cSpl 	ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
5729942c5e3cSpl 	    acp->fib_size,   /* only copy data of needed length */
5730942c5e3cSpl 	    DDI_DEV_AUTOINCR);
5731942c5e3cSpl 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5732942c5e3cSpl 	ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
5733d7c5bf88Spl }
5734d7c5bf88Spl 
5735d7c5bf88Spl static void
aac_cmd_fib_sync(struct aac_softstate * softs,struct aac_cmd * acp)5736942c5e3cSpl aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
5737d7c5bf88Spl {
5738f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5739942c5e3cSpl 	struct aac_synchronize_command *sync =
5740f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
5741942c5e3cSpl 
5742f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
5743942c5e3cSpl 
5744f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5745942c5e3cSpl 	ddi_put32(acc, &sync->Command, VM_ContainerConfig);
5746942c5e3cSpl 	ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
5747942c5e3cSpl 	ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
5748942c5e3cSpl 	ddi_put32(acc, &sync->Count,
5749942c5e3cSpl 	    sizeof (((struct aac_synchronize_reply *)0)->Data));
5750942c5e3cSpl }
5751d7c5bf88Spl 
5752b40e8a89Szhongyan gu - Sun Microsystems - Beijing China /*
5753b40e8a89Szhongyan gu - Sun Microsystems - Beijing China  * Start/Stop unit (Power Management)
5754b40e8a89Szhongyan gu - Sun Microsystems - Beijing China  */
5755b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void
aac_cmd_fib_startstop(struct aac_softstate * softs,struct aac_cmd * acp)5756b40e8a89Szhongyan gu - Sun Microsystems - Beijing China aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
5757b40e8a89Szhongyan gu - Sun Microsystems - Beijing China {
5758f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5759b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_Container *cmd =
5760f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    (struct aac_Container *)&acp->slotp->fibp->data[0];
5761b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
5762b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5763b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
5764b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5765f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5766b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
5767b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
5768b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
5769b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
5770b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	    AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
5771b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[1],
5772b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	    ((struct aac_container *)acp->dvp)->cid);
5773b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
5774b40e8a89Szhongyan gu - Sun Microsystems - Beijing China }
5775b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5776942c5e3cSpl /*
5777942c5e3cSpl  * Init FIB for pass-through SCMD
5778942c5e3cSpl  */
5779942c5e3cSpl static void
aac_cmd_fib_srb(struct aac_cmd * acp)5780942c5e3cSpl aac_cmd_fib_srb(struct aac_cmd *acp)
5781942c5e3cSpl {
5782f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5783f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
578458bc78c7SXin Chen 	uint8_t *cdb;
5785942c5e3cSpl 
5786942c5e3cSpl 	ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
5787942c5e3cSpl 	ddi_put32(acc, &srb->retry_limit, 0);
5788942c5e3cSpl 	ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
5789942c5e3cSpl 	ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
579058bc78c7SXin Chen 	if (acp->fibp == NULL) {
579158bc78c7SXin Chen 		if (acp->flags & AAC_CMD_BUF_READ)
579258bc78c7SXin Chen 			ddi_put32(acc, &srb->flags, SRB_DataIn);
579358bc78c7SXin Chen 		else if (acp->flags & AAC_CMD_BUF_WRITE)
579458bc78c7SXin Chen 			ddi_put32(acc, &srb->flags, SRB_DataOut);
579558bc78c7SXin Chen 		ddi_put32(acc, &srb->channel,
579658bc78c7SXin Chen 		    ((struct aac_nondasd *)acp->dvp)->bus);
579758bc78c7SXin Chen 		ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
579858bc78c7SXin Chen 		ddi_put32(acc, &srb->lun, 0);
579958bc78c7SXin Chen 		cdb = acp->pkt->pkt_cdbp;
580058bc78c7SXin Chen 	} else {
580158bc78c7SXin Chen 		struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
5802942c5e3cSpl 
580358bc78c7SXin Chen 		ddi_put32(acc, &srb->flags, srb0->flags);
580458bc78c7SXin Chen 		ddi_put32(acc, &srb->channel, srb0->channel);
580558bc78c7SXin Chen 		ddi_put32(acc, &srb->id, srb0->id);
580658bc78c7SXin Chen 		ddi_put32(acc, &srb->lun, srb0->lun);
580758bc78c7SXin Chen 		cdb = srb0->cdb;
580858bc78c7SXin Chen 	}
580958bc78c7SXin Chen 	ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
5810942c5e3cSpl }
5811382c8bcaSpl 
5812942c5e3cSpl static void
aac_cmd_fib_scsi32(struct aac_softstate * softs,struct aac_cmd * acp)5813942c5e3cSpl aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
5814942c5e3cSpl {
5815942c5e3cSpl 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5816942c5e3cSpl 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5817942c5e3cSpl 	struct aac_sg_entry *sgp;
5818942c5e3cSpl 	struct aac_sge *sge;
5819830d82f7Spl 
5820942c5e3cSpl 	acp->fib_size = sizeof (struct aac_fib_header) + \
5821942c5e3cSpl 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5822942c5e3cSpl 	    acp->left_cookien * sizeof (struct aac_sg_entry);
58237c478bd9Sstevel@tonic-gate 
5824942c5e3cSpl 	/* Fill FIB and SRB headers, and copy cdb */
5825f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ScsiPortCommand);
5826942c5e3cSpl 	aac_cmd_fib_srb(acp);
5827c9487164Spl 
5828942c5e3cSpl 	/* Fill SG table */
5829942c5e3cSpl 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5830942c5e3cSpl 	ddi_put32(acc, &srb->count, acp->bcount);
5831d7c5bf88Spl 
5832942c5e3cSpl 	for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
5833942c5e3cSpl 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5834942c5e3cSpl 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5835942c5e3cSpl 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5836942c5e3cSpl 	}
5837942c5e3cSpl }
5838830d82f7Spl 
5839942c5e3cSpl static void
aac_cmd_fib_scsi64(struct aac_softstate * softs,struct aac_cmd * acp)5840942c5e3cSpl aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
5841942c5e3cSpl {
5842942c5e3cSpl 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5843942c5e3cSpl 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5844942c5e3cSpl 	struct aac_sg_entry64 *sgp;
5845942c5e3cSpl 	struct aac_sge *sge;
5846942c5e3cSpl 
5847942c5e3cSpl 	acp->fib_size = sizeof (struct aac_fib_header) + \
5848942c5e3cSpl 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5849942c5e3cSpl 	    acp->left_cookien * sizeof (struct aac_sg_entry64);
5850942c5e3cSpl 
5851942c5e3cSpl 	/* Fill FIB and SRB headers, and copy cdb */
5852f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
5853942c5e3cSpl 	aac_cmd_fib_srb(acp);
5854942c5e3cSpl 
5855942c5e3cSpl 	/* Fill SG table */
5856942c5e3cSpl 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5857942c5e3cSpl 	ddi_put32(acc, &srb->count, acp->bcount);
5858942c5e3cSpl 
5859942c5e3cSpl 	for (sge = &acp->sgt[0],
5860942c5e3cSpl 	    sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
5861942c5e3cSpl 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5862942c5e3cSpl 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5863942c5e3cSpl 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5864942c5e3cSpl 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
58657c478bd9Sstevel@tonic-gate 	}
58667c478bd9Sstevel@tonic-gate }
58677c478bd9Sstevel@tonic-gate 
5868382c8bcaSpl static int
aac_cmd_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5869382c8bcaSpl aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5870382c8bcaSpl {
5871382c8bcaSpl 	struct aac_slot *slotp;
5872382c8bcaSpl 
5873382c8bcaSpl 	if (slotp = aac_get_slot(softs)) {
5874382c8bcaSpl 		acp->slotp = slotp;
5875382c8bcaSpl 		slotp->acp = acp;
5876942c5e3cSpl 		acp->aac_cmd_fib(softs, acp);
5877382c8bcaSpl 		(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
5878382c8bcaSpl 		    DDI_DMA_SYNC_FORDEV);
5879382c8bcaSpl 		return (AACOK);
5880382c8bcaSpl 	}
5881382c8bcaSpl 	return (AACERR);
5882382c8bcaSpl }
5883382c8bcaSpl 
5884382c8bcaSpl static int
aac_bind_io(struct aac_softstate * softs,struct aac_cmd * acp)5885382c8bcaSpl aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
5886382c8bcaSpl {
588758bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
5888382c8bcaSpl 	int q = AAC_CMDQ(acp);
5889382c8bcaSpl 
58901ee13a44SXinChen 	if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
58911ee13a44SXinChen 		if (dvp) {
58921ee13a44SXinChen 			if (dvp->ncmds[q] < dvp->throttle[q]) {
58931ee13a44SXinChen 				if (!(acp->flags & AAC_CMD_NTAG) ||
58941ee13a44SXinChen 				    dvp->ncmds[q] == 0) {
58951ee13a44SXinChen 					return (aac_cmd_slot_bind(softs, acp));
58961ee13a44SXinChen 				}
58971ee13a44SXinChen 				ASSERT(q == AAC_CMDQ_ASYNC);
58981ee13a44SXinChen 				aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
58991ee13a44SXinChen 				    AAC_THROTTLE_DRAIN);
5900382c8bcaSpl 			}
59011ee13a44SXinChen 		} else {
59021ee13a44SXinChen 			return (aac_cmd_slot_bind(softs, acp));
5903382c8bcaSpl 		}
5904382c8bcaSpl 	}
5905382c8bcaSpl 	return (AACERR);
5906382c8bcaSpl }
5907382c8bcaSpl 
5908f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_sync_fib_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5909f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5910f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
5911f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp;
5912f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
59131ee13a44SXinChen 	while (softs->sync_ac.slotp)
59141ee13a44SXinChen 		cv_wait(&softs->sync_fib_cv, &softs->io_lock);
59151ee13a44SXinChen 
5916f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (slotp = aac_get_slot(softs)) {
5917f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		ASSERT(acp->slotp == NULL);
5918f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5919f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		acp->slotp = slotp;
5920f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		slotp->acp = acp;
5921f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACOK);
5922f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
5923f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (AACERR);
5924f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
5925f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5926f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void
aac_sync_fib_slot_release(struct aac_softstate * softs,struct aac_cmd * acp)5927f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
5928f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
5929f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(acp->slotp);
5930f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5931f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_release_slot(softs, acp->slotp);
5932f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->slotp->acp = NULL;
5933f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->slotp = NULL;
59341ee13a44SXinChen 
59351ee13a44SXinChen 	cv_signal(&softs->sync_fib_cv);
5936f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
5937f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5938830d82f7Spl static void
aac_start_io(struct aac_softstate * softs,struct aac_cmd * acp)5939382c8bcaSpl aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
5940830d82f7Spl {
5941382c8bcaSpl 	struct aac_slot *slotp = acp->slotp;
5942382c8bcaSpl 	int q = AAC_CMDQ(acp);
5943c9487164Spl 	int rval;
5944830d82f7Spl 
5945830d82f7Spl 	/* Set ac and pkt */
5946c9487164Spl 	if (acp->pkt) { /* ac from ioctl has no pkt */
5947382c8bcaSpl 		acp->pkt->pkt_state |=
5948d7c5bf88Spl 		    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
5949c9487164Spl 	}
5950382c8bcaSpl 	if (acp->timeout) /* 0 indicates no timeout */
5951382c8bcaSpl 		acp->timeout += aac_timebase + aac_tick;
5952830d82f7Spl 
5953382c8bcaSpl 	if (acp->dvp)
5954382c8bcaSpl 		acp->dvp->ncmds[q]++;
5955382c8bcaSpl 	softs->bus_ncmds[q]++;
5956382c8bcaSpl 	aac_cmd_enqueue(&softs->q_busy, acp);
5957830d82f7Spl 
595858bc78c7SXin Chen 	AACDB_PRINT_FIB(softs, slotp);
595958bc78c7SXin Chen 
5960830d82f7Spl 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
5961c9487164Spl 		rval = aac_send_command(softs, slotp);
5962830d82f7Spl 	} else {
5963830d82f7Spl 		/*
5964830d82f7Spl 		 * If fib can not be enqueued, the adapter is in an abnormal
5965830d82f7Spl 		 * state, there will be no interrupt to us.
5966830d82f7Spl 		 */
5967c9487164Spl 		rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
5968942c5e3cSpl 		    slotp->fib_phyaddr, acp->fib_size);
5969830d82f7Spl 	}
5970830d82f7Spl 
59717675db54Syw 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
59727675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
59737675db54Syw 
5974830d82f7Spl 	/*
5975830d82f7Spl 	 * NOTE: We send command only when slots availabe, so should never
5976830d82f7Spl 	 * reach here.
5977830d82f7Spl 	 */
5978c9487164Spl 	if (rval != AACOK) {
59791dd0a2dbSpl 		AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
5980d7c5bf88Spl 		if (acp->pkt) {
5981d7c5bf88Spl 			acp->pkt->pkt_state &= ~STATE_SENT_CMD;
5982d7c5bf88Spl 			aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
5983d7c5bf88Spl 		}
5984382c8bcaSpl 		aac_end_io(softs, acp);
5985382c8bcaSpl 		if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
5986d7c5bf88Spl 			ddi_trigger_softintr(softs->softint_id);
5987830d82f7Spl 	}
5988830d82f7Spl }
5989830d82f7Spl 
59907c478bd9Sstevel@tonic-gate static void
aac_start_waitq(struct aac_softstate * softs,struct aac_cmd_queue * q)5991382c8bcaSpl aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
59927c478bd9Sstevel@tonic-gate {
5993382c8bcaSpl 	struct aac_cmd *acp, *next_acp;
59947c478bd9Sstevel@tonic-gate 
5995830d82f7Spl 	/* Serve as many waiting io's as possible */
5996382c8bcaSpl 	for (acp = q->q_head; acp; acp = next_acp) {
5997382c8bcaSpl 		next_acp = acp->next;
5998382c8bcaSpl 		if (aac_bind_io(softs, acp) == AACOK) {
5999382c8bcaSpl 			aac_cmd_delete(q, acp);
6000382c8bcaSpl 			aac_start_io(softs, acp);
6001830d82f7Spl 		}
6002382c8bcaSpl 		if (softs->free_io_slot_head == NULL)
6003382c8bcaSpl 			break;
60047c478bd9Sstevel@tonic-gate 	}
60057c478bd9Sstevel@tonic-gate }
60067c478bd9Sstevel@tonic-gate 
6007382c8bcaSpl static void
aac_start_waiting_io(struct aac_softstate * softs)6008382c8bcaSpl aac_start_waiting_io(struct aac_softstate *softs)
6009382c8bcaSpl {
6010382c8bcaSpl 	/*
6011382c8bcaSpl 	 * Sync FIB io is served before async FIB io so that io requests
6012382c8bcaSpl 	 * sent by interactive userland commands get responded asap.
6013382c8bcaSpl 	 */
6014382c8bcaSpl 	if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
6015382c8bcaSpl 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
6016382c8bcaSpl 	if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
6017382c8bcaSpl 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
6018382c8bcaSpl }
6019382c8bcaSpl 
60207c478bd9Sstevel@tonic-gate static void
aac_drain_comp_q(struct aac_softstate * softs)60217c478bd9Sstevel@tonic-gate aac_drain_comp_q(struct aac_softstate *softs)
60227c478bd9Sstevel@tonic-gate {
6023c9487164Spl 	struct aac_cmd *acp;
6024830d82f7Spl 	struct scsi_pkt *pkt;
60257c478bd9Sstevel@tonic-gate 
6026382c8bcaSpl 	/*CONSTCOND*/
6027382c8bcaSpl 	while (1) {
6028382c8bcaSpl 		mutex_enter(&softs->q_comp_mutex);
6029382c8bcaSpl 		acp = aac_cmd_dequeue(&softs->q_comp);
6030382c8bcaSpl 		mutex_exit(&softs->q_comp_mutex);
6031382c8bcaSpl 		if (acp != NULL) {
6032382c8bcaSpl 			ASSERT(acp->pkt != NULL);
6033382c8bcaSpl 			pkt = acp->pkt;
6034830d82f7Spl 
6035382c8bcaSpl 			if (pkt->pkt_reason == CMD_CMPLT) {
6036382c8bcaSpl 				/*
6037382c8bcaSpl 				 * Consistent packets need to be sync'ed first
6038382c8bcaSpl 				 */
6039382c8bcaSpl 				if ((acp->flags & AAC_CMD_CONSISTENT) &&
6040382c8bcaSpl 				    (acp->flags & AAC_CMD_BUF_READ)) {
6041382c8bcaSpl 					if (aac_dma_sync_ac(acp) != AACOK) {
6042382c8bcaSpl 						ddi_fm_service_impact(
6043382c8bcaSpl 						    softs->devinfo_p,
6044382c8bcaSpl 						    DDI_SERVICE_UNAFFECTED);
6045382c8bcaSpl 						pkt->pkt_reason = CMD_TRAN_ERR;
6046382c8bcaSpl 						pkt->pkt_statistics = 0;
6047382c8bcaSpl 					}
6048382c8bcaSpl 				}
6049382c8bcaSpl 				if ((aac_check_acc_handle(softs-> \
6050382c8bcaSpl 				    comm_space_acc_handle) != DDI_SUCCESS) ||
6051382c8bcaSpl 				    (aac_check_acc_handle(softs-> \
6052382c8bcaSpl 				    pci_mem_handle) != DDI_SUCCESS)) {
6053382c8bcaSpl 					ddi_fm_service_impact(softs->devinfo_p,
6054382c8bcaSpl 					    DDI_SERVICE_UNAFFECTED);
6055382c8bcaSpl 					ddi_fm_acc_err_clear(softs-> \
6056382c8bcaSpl 					    pci_mem_handle, DDI_FME_VER0);
6057382c8bcaSpl 					pkt->pkt_reason = CMD_TRAN_ERR;
6058382c8bcaSpl 					pkt->pkt_statistics = 0;
6059382c8bcaSpl 				}
6060382c8bcaSpl 				if (aac_check_dma_handle(softs-> \
6061382c8bcaSpl 				    comm_space_dma_handle) != DDI_SUCCESS) {
60627675db54Syw 					ddi_fm_service_impact(softs->devinfo_p,
60637675db54Syw 					    DDI_SERVICE_UNAFFECTED);
60647675db54Syw 					pkt->pkt_reason = CMD_TRAN_ERR;
60657675db54Syw 					pkt->pkt_statistics = 0;
60667675db54Syw 				}
60677675db54Syw 			}
60689c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
6069382c8bcaSpl 		} else {
6070382c8bcaSpl 			break;
6071d7c5bf88Spl 		}
6072830d82f7Spl 	}
60737c478bd9Sstevel@tonic-gate }
60747c478bd9Sstevel@tonic-gate 
60757c478bd9Sstevel@tonic-gate static int
aac_alloc_fib(struct aac_softstate * softs,struct aac_slot * slotp)6076830d82f7Spl aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
60777c478bd9Sstevel@tonic-gate {
60787c478bd9Sstevel@tonic-gate 	size_t rlen;
60797c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t cookie;
60807c478bd9Sstevel@tonic-gate 	uint_t cookien;
60817c478bd9Sstevel@tonic-gate 
6082830d82f7Spl 	/* Allocate FIB dma resource */
6083830d82f7Spl 	if (ddi_dma_alloc_handle(
6084c9487164Spl 	    softs->devinfo_p,
6085c9487164Spl 	    &softs->addr_dma_attr,
6086c9487164Spl 	    DDI_DMA_SLEEP,
6087c9487164Spl 	    NULL,
6088c9487164Spl 	    &slotp->fib_dma_handle) != DDI_SUCCESS) {
60891dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
60901dd0a2dbSpl 		    "Cannot alloc dma handle for slot fib area");
6091830d82f7Spl 		goto error;
6092830d82f7Spl 	}
6093830d82f7Spl 	if (ddi_dma_mem_alloc(
6094c9487164Spl 	    slotp->fib_dma_handle,
6095c9487164Spl 	    softs->aac_max_fib_size,
609658bc78c7SXin Chen 	    &softs->acc_attr,
6097c9487164Spl 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6098c9487164Spl 	    DDI_DMA_SLEEP,
6099c9487164Spl 	    NULL,
6100c9487164Spl 	    (caddr_t *)&slotp->fibp,
6101c9487164Spl 	    &rlen,
6102c9487164Spl 	    &slotp->fib_acc_handle) != DDI_SUCCESS) {
61031dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
61041dd0a2dbSpl 		    "Cannot alloc mem for slot fib area");
6105830d82f7Spl 		goto error;
6106830d82f7Spl 	}
6107830d82f7Spl 	if (ddi_dma_addr_bind_handle(
6108c9487164Spl 	    slotp->fib_dma_handle,
6109c9487164Spl 	    NULL,
6110c9487164Spl 	    (caddr_t)slotp->fibp,
6111c9487164Spl 	    softs->aac_max_fib_size,
6112c9487164Spl 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6113c9487164Spl 	    DDI_DMA_SLEEP,
6114c9487164Spl 	    NULL,
6115c9487164Spl 	    &cookie,
6116c9487164Spl 	    &cookien) != DDI_DMA_MAPPED) {
61171dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN,
61181dd0a2dbSpl 		    "dma bind failed for slot fib area");
6119830d82f7Spl 		goto error;
6120830d82f7Spl 	}
61217675db54Syw 
61227675db54Syw 	/* Check dma handles allocated in fib attach */
61237675db54Syw 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
61247675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61257675db54Syw 		goto error;
61267675db54Syw 	}
61277675db54Syw 
61287675db54Syw 	/* Check acc handles allocated in fib attach */
61297675db54Syw 	if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
61307675db54Syw 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61317675db54Syw 		goto error;
61327675db54Syw 	}
61337675db54Syw 
6134830d82f7Spl 	slotp->fib_phyaddr = cookie.dmac_laddress;
6135830d82f7Spl 	return (AACOK);
6136830d82f7Spl 
6137830d82f7Spl error:
6138830d82f7Spl 	if (slotp->fib_acc_handle) {
6139830d82f7Spl 		ddi_dma_mem_free(&slotp->fib_acc_handle);
6140830d82f7Spl 		slotp->fib_acc_handle = NULL;
6141830d82f7Spl 	}
6142830d82f7Spl 	if (slotp->fib_dma_handle) {
6143830d82f7Spl 		ddi_dma_free_handle(&slotp->fib_dma_handle);
6144830d82f7Spl 		slotp->fib_dma_handle = NULL;
61457c478bd9Sstevel@tonic-gate 	}
6146830d82f7Spl 	return (AACERR);
61477c478bd9Sstevel@tonic-gate }
61487c478bd9Sstevel@tonic-gate 
61497c478bd9Sstevel@tonic-gate static void
aac_free_fib(struct aac_slot * slotp)6150830d82f7Spl aac_free_fib(struct aac_slot *slotp)
6151830d82f7Spl {
6152830d82f7Spl 	(void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
6153830d82f7Spl 	ddi_dma_mem_free(&slotp->fib_acc_handle);
6154830d82f7Spl 	slotp->fib_acc_handle = NULL;
6155830d82f7Spl 	ddi_dma_free_handle(&slotp->fib_dma_handle);
6156830d82f7Spl 	slotp->fib_dma_handle = NULL;
6157830d82f7Spl 	slotp->fib_phyaddr = 0;
6158830d82f7Spl }
6159830d82f7Spl 
6160942c5e3cSpl static void
aac_alloc_fibs(struct aac_softstate * softs)6161942c5e3cSpl aac_alloc_fibs(struct aac_softstate *softs)
6162942c5e3cSpl {
6163942c5e3cSpl 	int i;
6164942c5e3cSpl 	struct aac_slot *slotp;
6165942c5e3cSpl 
6166942c5e3cSpl 	for (i = 0; i < softs->total_slots &&
6167942c5e3cSpl 	    softs->total_fibs < softs->total_slots; i++) {
6168942c5e3cSpl 		slotp = &(softs->io_slot[i]);
6169942c5e3cSpl 		if (slotp->fib_phyaddr)
6170942c5e3cSpl 			continue;
6171942c5e3cSpl 		if (aac_alloc_fib(softs, slotp) != AACOK)
6172942c5e3cSpl 			break;
6173942c5e3cSpl 
6174942c5e3cSpl 		/* Insert the slot to the free slot list */
6175942c5e3cSpl 		aac_release_slot(softs, slotp);
6176942c5e3cSpl 		softs->total_fibs++;
6177942c5e3cSpl 	}
6178942c5e3cSpl }
6179942c5e3cSpl 
6180d7c5bf88Spl static void
aac_destroy_fibs(struct aac_softstate * softs)6181d7c5bf88Spl aac_destroy_fibs(struct aac_softstate *softs)
6182d7c5bf88Spl {
6183382c8bcaSpl 	struct aac_slot *slotp;
6184d7c5bf88Spl 
6185382c8bcaSpl 	while ((slotp = softs->free_io_slot_head) != NULL) {
6186382c8bcaSpl 		ASSERT(slotp->fib_phyaddr);
6187382c8bcaSpl 		softs->free_io_slot_head = slotp->next;
6188d7c5bf88Spl 		aac_free_fib(slotp);
6189382c8bcaSpl 		ASSERT(slotp->index == (slotp - softs->io_slot));
6190d7c5bf88Spl 		softs->total_fibs--;
6191d7c5bf88Spl 	}
6192d7c5bf88Spl 	ASSERT(softs->total_fibs == 0);
6193d7c5bf88Spl }
6194d7c5bf88Spl 
6195830d82f7Spl static int
aac_create_slots(struct aac_softstate * softs)6196830d82f7Spl aac_create_slots(struct aac_softstate *softs)
61977c478bd9Sstevel@tonic-gate {
61987c478bd9Sstevel@tonic-gate 	int i;
61997c478bd9Sstevel@tonic-gate 
6200942c5e3cSpl 	softs->total_slots = softs->aac_max_fibs;
6201830d82f7Spl 	softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
6202942c5e3cSpl 	    softs->total_slots, KM_SLEEP);
6203830d82f7Spl 	if (softs->io_slot == NULL) {
62041dd0a2dbSpl 		AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
6205830d82f7Spl 		return (AACERR);
62067c478bd9Sstevel@tonic-gate 	}
6207382c8bcaSpl 	for (i = 0; i < softs->total_slots; i++)
6208382c8bcaSpl 		softs->io_slot[i].index = i;
6209382c8bcaSpl 	softs->free_io_slot_head = NULL;
6210830d82f7Spl 	softs->total_fibs = 0;
6211830d82f7Spl 	return (AACOK);
6212830d82f7Spl }
6213830d82f7Spl 
6214830d82f7Spl static void
aac_destroy_slots(struct aac_softstate * softs)6215830d82f7Spl aac_destroy_slots(struct aac_softstate *softs)
6216830d82f7Spl {
6217382c8bcaSpl 	ASSERT(softs->free_io_slot_head == NULL);
6218830d82f7Spl 
6219830d82f7Spl 	kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
6220c9487164Spl 	    softs->total_slots);
6221830d82f7Spl 	softs->io_slot = NULL;
6222830d82f7Spl 	softs->total_slots = 0;
62237c478bd9Sstevel@tonic-gate }
62247c478bd9Sstevel@tonic-gate 
6225830d82f7Spl struct aac_slot *
aac_get_slot(struct aac_softstate * softs)62267c478bd9Sstevel@tonic-gate aac_get_slot(struct aac_softstate *softs)
62277c478bd9Sstevel@tonic-gate {
6228382c8bcaSpl 	struct aac_slot *slotp;
62297c478bd9Sstevel@tonic-gate 
6230382c8bcaSpl 	if ((slotp = softs->free_io_slot_head) != NULL) {
6231830d82f7Spl 		softs->free_io_slot_head = slotp->next;
6232382c8bcaSpl 		slotp->next = NULL;
62337c478bd9Sstevel@tonic-gate 	}
6234830d82f7Spl 	return (slotp);
6235830d82f7Spl }
62367c478bd9Sstevel@tonic-gate 
6237382c8bcaSpl static void
aac_release_slot(struct aac_softstate * softs,struct aac_slot * slotp)6238830d82f7Spl aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
62397c478bd9Sstevel@tonic-gate {
6240382c8bcaSpl 	ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
6241382c8bcaSpl 	ASSERT(slotp == &softs->io_slot[slotp->index]);
62427c478bd9Sstevel@tonic-gate 
6243830d82f7Spl 	slotp->acp = NULL;
6244382c8bcaSpl 	slotp->next = softs->free_io_slot_head;
6245382c8bcaSpl 	softs->free_io_slot_head = slotp;
62467c478bd9Sstevel@tonic-gate }
62477c478bd9Sstevel@tonic-gate 
6248d7c5bf88Spl int
aac_do_io(struct aac_softstate * softs,struct aac_cmd * acp)6249d7c5bf88Spl aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
6250d7c5bf88Spl {
6251382c8bcaSpl 	if (aac_bind_io(softs, acp) == AACOK)
6252382c8bcaSpl 		aac_start_io(softs, acp);
6253382c8bcaSpl 	else
6254382c8bcaSpl 		aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
6255382c8bcaSpl 
6256382c8bcaSpl 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
6257d7c5bf88Spl 		return (TRAN_ACCEPT);
6258382c8bcaSpl 	/*
6259382c8bcaSpl 	 * Because sync FIB is always 512 bytes and used for critical
6260382c8bcaSpl 	 * functions, async FIB is used for poll IO.
6261382c8bcaSpl 	 */
6262382c8bcaSpl 	if (acp->flags & AAC_CMD_NO_INTR) {
6263382c8bcaSpl 		if (aac_do_poll_io(softs, acp) == AACOK)
6264382c8bcaSpl 			return (TRAN_ACCEPT);
6265382c8bcaSpl 	} else {
6266382c8bcaSpl 		if (aac_do_sync_io(softs, acp) == AACOK)
6267382c8bcaSpl 			return (TRAN_ACCEPT);
6268d7c5bf88Spl 	}
6269382c8bcaSpl 	return (TRAN_BADPKT);
6270d7c5bf88Spl }
6271d7c5bf88Spl 
62727c478bd9Sstevel@tonic-gate static int
aac_do_poll_io(struct aac_softstate * softs,struct aac_cmd * acp)6273830d82f7Spl aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
62747c478bd9Sstevel@tonic-gate {
6275382c8bcaSpl 	int (*intr_handler)(struct aac_softstate *);
6276830d82f7Spl 
6277830d82f7Spl 	/*
6278382c8bcaSpl 	 * Interrupt is disabled, we have to poll the adapter by ourselves.
6279830d82f7Spl 	 */
6280382c8bcaSpl 	intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
6281382c8bcaSpl 	    aac_process_intr_new : aac_process_intr_old;
6282382c8bcaSpl 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
6283382c8bcaSpl 		int i = AAC_POLL_TIME * 1000;
6284d7c5bf88Spl 
6285382c8bcaSpl 		AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
6286382c8bcaSpl 		if (i == 0)
628758bc78c7SXin Chen 			aac_cmd_timeout(softs, acp);
62887c478bd9Sstevel@tonic-gate 	}
62897c478bd9Sstevel@tonic-gate 
6290382c8bcaSpl 	ddi_trigger_softintr(softs->softint_id);
6291382c8bcaSpl 
62927675db54Syw 	if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
6293d7c5bf88Spl 		return (AACOK);
6294d7c5bf88Spl 	return (AACERR);
62957c478bd9Sstevel@tonic-gate }
62967c478bd9Sstevel@tonic-gate 
6297d7c5bf88Spl static int
aac_do_sync_io(struct aac_softstate * softs,struct aac_cmd * acp)6298382c8bcaSpl aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
62997c478bd9Sstevel@tonic-gate {
6300382c8bcaSpl 	ASSERT(softs && acp);
6301830d82f7Spl 
6302382c8bcaSpl 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
6303382c8bcaSpl 		cv_wait(&softs->event, &softs->io_lock);
6304830d82f7Spl 
6305382c8bcaSpl 	if (acp->flags & AAC_CMD_CMPLT)
6306382c8bcaSpl 		return (AACOK);
6307382c8bcaSpl 	return (AACERR);
63087c478bd9Sstevel@tonic-gate }
63097c478bd9Sstevel@tonic-gate 
63107675db54Syw static int
aac_dma_sync_ac(struct aac_cmd * acp)6311d7c5bf88Spl aac_dma_sync_ac(struct aac_cmd *acp)
63127c478bd9Sstevel@tonic-gate {
6313d7c5bf88Spl 	if (acp->buf_dma_handle) {
6314d7c5bf88Spl 		if (acp->flags & AAC_CMD_BUF_WRITE) {
6315d7c5bf88Spl 			if (acp->abp != NULL)
6316d7c5bf88Spl 				ddi_rep_put8(acp->abh,
6317d7c5bf88Spl 				    (uint8_t *)acp->bp->b_un.b_addr,
6318d7c5bf88Spl 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6319d7c5bf88Spl 				    DDI_DEV_AUTOINCR);
6320d7c5bf88Spl 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6321d7c5bf88Spl 			    DDI_DMA_SYNC_FORDEV);
6322d7c5bf88Spl 		} else {
6323d7c5bf88Spl 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6324d7c5bf88Spl 			    DDI_DMA_SYNC_FORCPU);
63257675db54Syw 			if (aac_check_dma_handle(acp->buf_dma_handle) !=
63267675db54Syw 			    DDI_SUCCESS)
63277675db54Syw 				return (AACERR);
6328d7c5bf88Spl 			if (acp->abp != NULL)
6329d7c5bf88Spl 				ddi_rep_get8(acp->abh,
6330d7c5bf88Spl 				    (uint8_t *)acp->bp->b_un.b_addr,
6331d7c5bf88Spl 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6332d7c5bf88Spl 				    DDI_DEV_AUTOINCR);
6333d7c5bf88Spl 		}
6334d7c5bf88Spl 	}
63357675db54Syw 	return (AACOK);
63367c478bd9Sstevel@tonic-gate }
63377c478bd9Sstevel@tonic-gate 
63380749e8deSXin Chen - Sun Microsystems - Beijing China /*
63390749e8deSXin Chen - Sun Microsystems - Beijing China  * Copy AIF from adapter to the empty AIF slot and inform AIF threads
63400749e8deSXin Chen - Sun Microsystems - Beijing China  */
63410749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_save_aif(struct aac_softstate * softs,ddi_acc_handle_t acc,struct aac_fib * fibp0,int fib_size0)63420749e8deSXin Chen - Sun Microsystems - Beijing China aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
63430749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib *fibp0, int fib_size0)
63440749e8deSXin Chen - Sun Microsystems - Beijing China {
63450749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib *fibp;	/* FIB in AIF queue */
63460749e8deSXin Chen - Sun Microsystems - Beijing China 	int fib_size;
63470749e8deSXin Chen - Sun Microsystems - Beijing China 	uint16_t fib_command;
63480749e8deSXin Chen - Sun Microsystems - Beijing China 	int current, next;
63490749e8deSXin Chen - Sun Microsystems - Beijing China 
63500749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Ignore non AIF messages */
63510749e8deSXin Chen - Sun Microsystems - Beijing China 	fib_command = ddi_get16(acc, &fibp0->Header.Command);
63520749e8deSXin Chen - Sun Microsystems - Beijing China 	if (fib_command != AifRequest) {
63530749e8deSXin Chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "!Unknown command from controller");
63540749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
63550749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63560749e8deSXin Chen - Sun Microsystems - Beijing China 
63570749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
63580749e8deSXin Chen - Sun Microsystems - Beijing China 
63590749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Save AIF */
63600749e8deSXin Chen - Sun Microsystems - Beijing China 	fibp = &softs->aifq[softs->aifq_idx].d;
63610749e8deSXin Chen - Sun Microsystems - Beijing China 	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
63620749e8deSXin Chen - Sun Microsystems - Beijing China 	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
63630749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_DEV_AUTOINCR);
63640749e8deSXin Chen - Sun Microsystems - Beijing China 
63650749e8deSXin Chen - Sun Microsystems - Beijing China 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
63660749e8deSXin Chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(softs->devinfo_p,
63670749e8deSXin Chen - Sun Microsystems - Beijing China 		    DDI_SERVICE_UNAFFECTED);
63680749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->aifq_mutex);
63690749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
63700749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63710749e8deSXin Chen - Sun Microsystems - Beijing China 
63720749e8deSXin Chen - Sun Microsystems - Beijing China 	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
63730749e8deSXin Chen - Sun Microsystems - Beijing China 
63740749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Modify AIF contexts */
63750749e8deSXin Chen - Sun Microsystems - Beijing China 	current = softs->aifq_idx;
63760749e8deSXin Chen - Sun Microsystems - Beijing China 	next = (current + 1) % AAC_AIFQ_LENGTH;
63770749e8deSXin Chen - Sun Microsystems - Beijing China 	if (next == 0) {
63780749e8deSXin Chen - Sun Microsystems - Beijing China 		struct aac_fib_context *ctx_p;
63790749e8deSXin Chen - Sun Microsystems - Beijing China 
63800749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->aifq_wrap = 1;
63810749e8deSXin Chen - Sun Microsystems - Beijing China 		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
63820749e8deSXin Chen - Sun Microsystems - Beijing China 			if (next == ctx_p->ctx_idx) {
63830749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
63840749e8deSXin Chen - Sun Microsystems - Beijing China 			} else if (current == ctx_p->ctx_idx &&
63850749e8deSXin Chen - Sun Microsystems - Beijing China 			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
63860749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_idx = next;
63870749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_overrun++;
63880749e8deSXin Chen - Sun Microsystems - Beijing China 			}
63890749e8deSXin Chen - Sun Microsystems - Beijing China 		}
63900749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63910749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->aifq_idx = next;
63920749e8deSXin Chen - Sun Microsystems - Beijing China 
63930749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Wakeup AIF threads */
63940749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_broadcast(&softs->aifq_cv);
63950749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
63960749e8deSXin Chen - Sun Microsystems - Beijing China 
63970749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Wakeup event thread to handle aif */
63980749e8deSXin Chen - Sun Microsystems - Beijing China 	aac_event_disp(softs, AAC_EVENT_AIF);
63990749e8deSXin Chen - Sun Microsystems - Beijing China }
64000749e8deSXin Chen - Sun Microsystems - Beijing China 
64010749e8deSXin Chen - Sun Microsystems - Beijing China static int
aac_return_aif_common(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)64020749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
64030749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
64040749e8deSXin Chen - Sun Microsystems - Beijing China {
64050749e8deSXin Chen - Sun Microsystems - Beijing China 	int current;
64060749e8deSXin Chen - Sun Microsystems - Beijing China 
64070749e8deSXin Chen - Sun Microsystems - Beijing China 	current = ctx->ctx_idx;
64080749e8deSXin Chen - Sun Microsystems - Beijing China 	if (current == softs->aifq_idx &&
64090749e8deSXin Chen - Sun Microsystems - Beijing China 	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
64100749e8deSXin Chen - Sun Microsystems - Beijing China 		return (EAGAIN); /* Empty */
64110749e8deSXin Chen - Sun Microsystems - Beijing China 
64120749e8deSXin Chen - Sun Microsystems - Beijing China 	*fibpp = &softs->aifq[current].d;
64130749e8deSXin Chen - Sun Microsystems - Beijing China 
64140749e8deSXin Chen - Sun Microsystems - Beijing China 	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
64150749e8deSXin Chen - Sun Microsystems - Beijing China 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
64160749e8deSXin Chen - Sun Microsystems - Beijing China 	return (0);
64170749e8deSXin Chen - Sun Microsystems - Beijing China }
64180749e8deSXin Chen - Sun Microsystems - Beijing China 
64190749e8deSXin Chen - Sun Microsystems - Beijing China int
aac_return_aif(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)64200749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
64210749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
64220749e8deSXin Chen - Sun Microsystems - Beijing China {
64230749e8deSXin Chen - Sun Microsystems - Beijing China 	int rval;
64240749e8deSXin Chen - Sun Microsystems - Beijing China 
64250749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
64260749e8deSXin Chen - Sun Microsystems - Beijing China 	rval = aac_return_aif_common(softs, ctx, fibpp);
64270749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
64280749e8deSXin Chen - Sun Microsystems - Beijing China 	return (rval);
64290749e8deSXin Chen - Sun Microsystems - Beijing China }
64300749e8deSXin Chen - Sun Microsystems - Beijing China 
64310749e8deSXin Chen - Sun Microsystems - Beijing China int
aac_return_aif_wait(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)64320749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
64330749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
64340749e8deSXin Chen - Sun Microsystems - Beijing China {
64350749e8deSXin Chen - Sun Microsystems - Beijing China 	int rval;
64360749e8deSXin Chen - Sun Microsystems - Beijing China 
64370749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
64380749e8deSXin Chen - Sun Microsystems - Beijing China 	rval = aac_return_aif_common(softs, ctx, fibpp);
64390749e8deSXin Chen - Sun Microsystems - Beijing China 	if (rval == EAGAIN) {
64400749e8deSXin Chen - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
64410749e8deSXin Chen - Sun Microsystems - Beijing China 		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
64420749e8deSXin Chen - Sun Microsystems - Beijing China 	}
64430749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
64440749e8deSXin Chen - Sun Microsystems - Beijing China 	return ((rval > 0) ? 0 : EINTR);
64450749e8deSXin Chen - Sun Microsystems - Beijing China }
64460749e8deSXin Chen - Sun Microsystems - Beijing China 
6447830d82f7Spl /*
6448830d82f7Spl  * The following function comes from Adaptec:
6449830d82f7Spl  *
6450830d82f7Spl  * When driver sees a particular event that means containers are changed, it
6451830d82f7Spl  * will rescan containers. However a change may not be complete until some
6452830d82f7Spl  * other event is received. For example, creating or deleting an array will
6453830d82f7Spl  * incur as many as six AifEnConfigChange events which would generate six
6454830d82f7Spl  * container rescans. To diminish rescans, driver set a flag to wait for
6455830d82f7Spl  * another particular event. When sees that events come in, it will do rescan.
6456830d82f7Spl  */
6457830d82f7Spl static int
aac_handle_aif(struct aac_softstate * softs,struct aac_aif_command * aif)64580749e8deSXin Chen - Sun Microsystems - Beijing China aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
6459830d82f7Spl {
6460942c5e3cSpl 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
6461942c5e3cSpl 	int en_type;
6462830d82f7Spl 	int devcfg_needed;
64633fced439Szhongyan gu - Sun Microsystems - Beijing China 	int cid;
64643fced439Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t bus_id, tgt_id;
64653fced439Szhongyan gu - Sun Microsystems - Beijing China 	enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
6466830d82f7Spl 
6467830d82f7Spl 	devcfg_needed = 0;
6468942c5e3cSpl 	en_type = LE_32((uint32_t)aif->data.EN.type);
6469830d82f7Spl 
6470942c5e3cSpl 	switch (LE_32((uint32_t)aif->command)) {
6471d7c5bf88Spl 	case AifCmdDriverNotify: {
64723fced439Szhongyan gu - Sun Microsystems - Beijing China 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6473d7c5bf88Spl 
6474942c5e3cSpl 		switch (en_type) {
6475830d82f7Spl 		case AifDenMorphComplete:
6476830d82f7Spl 		case AifDenVolumeExtendComplete:
647758bc78c7SXin Chen 			if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
6478830d82f7Spl 				softs->devcfg_wait_on = AifEnConfigChange;
6479830d82f7Spl 			break;
6480830d82f7Spl 		}
6481942c5e3cSpl 		if (softs->devcfg_wait_on == en_type)
6482830d82f7Spl 			devcfg_needed = 1;
6483830d82f7Spl 		break;
6484d7c5bf88Spl 	}
6485830d82f7Spl 
6486830d82f7Spl 	case AifCmdEventNotify:
64873fced439Szhongyan gu - Sun Microsystems - Beijing China 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6488942c5e3cSpl 		switch (en_type) {
6489830d82f7Spl 		case AifEnAddContainer:
6490830d82f7Spl 		case AifEnDeleteContainer:
6491830d82f7Spl 			softs->devcfg_wait_on = AifEnConfigChange;
6492830d82f7Spl 			break;
6493830d82f7Spl 		case AifEnContainerChange:
6494830d82f7Spl 			if (!softs->devcfg_wait_on)
6495830d82f7Spl 				softs->devcfg_wait_on = AifEnConfigChange;
6496830d82f7Spl 			break;
6497830d82f7Spl 		case AifEnContainerEvent:
6498942c5e3cSpl 			if (ddi_get32(acc, &aif-> \
6499942c5e3cSpl 			    data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
6500830d82f7Spl 				devcfg_needed = 1;
6501830d82f7Spl 			break;
65023fced439Szhongyan gu - Sun Microsystems - Beijing China 		case AifEnAddJBOD:
65033fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD))
65043fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (AACERR);
65053fced439Szhongyan gu - Sun Microsystems - Beijing China 			event = AAC_CFG_ADD;
65063fced439Szhongyan gu - Sun Microsystems - Beijing China 			bus_id = (cid >> 24) & 0xf;
65073fced439Szhongyan gu - Sun Microsystems - Beijing China 			tgt_id = cid & 0xffff;
65083fced439Szhongyan gu - Sun Microsystems - Beijing China 			break;
65093fced439Szhongyan gu - Sun Microsystems - Beijing China 		case AifEnDeleteJBOD:
65103fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD))
65113fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (AACERR);
65123fced439Szhongyan gu - Sun Microsystems - Beijing China 			event = AAC_CFG_DELETE;
65133fced439Szhongyan gu - Sun Microsystems - Beijing China 			bus_id = (cid >> 24) & 0xf;
65143fced439Szhongyan gu - Sun Microsystems - Beijing China 			tgt_id = cid & 0xffff;
65153fced439Szhongyan gu - Sun Microsystems - Beijing China 			break;
6516830d82f7Spl 		}
6517942c5e3cSpl 		if (softs->devcfg_wait_on == en_type)
6518830d82f7Spl 			devcfg_needed = 1;
6519830d82f7Spl 		break;
6520830d82f7Spl 
6521830d82f7Spl 	case AifCmdJobProgress:
6522942c5e3cSpl 		if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
6523942c5e3cSpl 			int pr_status;
6524942c5e3cSpl 			uint32_t pr_ftick, pr_ctick;
6525942c5e3cSpl 
6526942c5e3cSpl 			pr_status = LE_32((uint32_t)aif->data.PR[0].status);
6527942c5e3cSpl 			pr_ctick = LE_32(aif->data.PR[0].currentTick);
6528942c5e3cSpl 			pr_ftick = LE_32(aif->data.PR[0].finalTick);
6529942c5e3cSpl 
6530942c5e3cSpl 			if ((pr_ctick == pr_ftick) ||
6531942c5e3cSpl 			    (pr_status == AifJobStsSuccess))
6532830d82f7Spl 				softs->devcfg_wait_on = AifEnContainerChange;
6533942c5e3cSpl 			else if ((pr_ctick == 0) &&
6534942c5e3cSpl 			    (pr_status == AifJobStsRunning))
6535830d82f7Spl 				softs->devcfg_wait_on = AifEnContainerChange;
6536830d82f7Spl 		}
6537830d82f7Spl 		break;
6538830d82f7Spl 	}
6539830d82f7Spl 
654058bc78c7SXin Chen 	if (devcfg_needed) {
654158bc78c7SXin Chen 		softs->devcfg_wait_on = 0;
6542942c5e3cSpl 		(void) aac_probe_containers(softs);
654358bc78c7SXin Chen 	}
6544830d82f7Spl 
65453fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (event != AAC_CFG_NULL_EXIST) {
65463fced439Szhongyan gu - Sun Microsystems - Beijing China 		ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
65473fced439Szhongyan gu - Sun Microsystems - Beijing China 		(void) aac_probe_jbod(softs,
65483fced439Szhongyan gu - Sun Microsystems - Beijing China 		    AAC_P2VTGT(softs, bus_id, tgt_id), event);
65493fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
65500749e8deSXin Chen - Sun Microsystems - Beijing China 	return (AACOK);
65510749e8deSXin Chen - Sun Microsystems - Beijing China }
6552d7c5bf88Spl 
65530749e8deSXin Chen - Sun Microsystems - Beijing China 
65540749e8deSXin Chen - Sun Microsystems - Beijing China /*
65550749e8deSXin Chen - Sun Microsystems - Beijing China  * Check and handle AIF events
65560749e8deSXin Chen - Sun Microsystems - Beijing China  */
65570749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_aif_event(struct aac_softstate * softs)65580749e8deSXin Chen - Sun Microsystems - Beijing China aac_aif_event(struct aac_softstate *softs)
65590749e8deSXin Chen - Sun Microsystems - Beijing China {
65600749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
65610749e8deSXin Chen - Sun Microsystems - Beijing China 
65620749e8deSXin Chen - Sun Microsystems - Beijing China 	/*CONSTCOND*/
65630749e8deSXin Chen - Sun Microsystems - Beijing China 	while (1) {
65640749e8deSXin Chen - Sun Microsystems - Beijing China 		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
65650749e8deSXin Chen - Sun Microsystems - Beijing China 			break; /* No more AIFs to handle, end loop */
65660749e8deSXin Chen - Sun Microsystems - Beijing China 
65670749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AIF overrun, array create/delete may missed. */
65680749e8deSXin Chen - Sun Microsystems - Beijing China 		if (softs->aifctx.ctx_overrun) {
65690749e8deSXin Chen - Sun Microsystems - Beijing China 			softs->aifctx.ctx_overrun = 0;
6570830d82f7Spl 		}
6571830d82f7Spl 
65720749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AIF received, handle it */
65730749e8deSXin Chen - Sun Microsystems - Beijing China 		struct aac_aif_command *aifp =
65740749e8deSXin Chen - Sun Microsystems - Beijing China 		    (struct aac_aif_command *)&fibp->data[0];
65750749e8deSXin Chen - Sun Microsystems - Beijing China 		uint32_t aif_command = LE_32((uint32_t)aifp->command);
65760749e8deSXin Chen - Sun Microsystems - Beijing China 
65770749e8deSXin Chen - Sun Microsystems - Beijing China 		if (aif_command == AifCmdDriverNotify ||
65780749e8deSXin Chen - Sun Microsystems - Beijing China 		    aif_command == AifCmdEventNotify ||
65790749e8deSXin Chen - Sun Microsystems - Beijing China 		    aif_command == AifCmdJobProgress)
65800749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_aif(softs, aifp);
65810749e8deSXin Chen - Sun Microsystems - Beijing China 	}
6582830d82f7Spl }
6583830d82f7Spl 
6584382c8bcaSpl /*
6585382c8bcaSpl  * Timeout recovery
6586382c8bcaSpl  */
658758bc78c7SXin Chen /*ARGSUSED*/
6588382c8bcaSpl static void
aac_cmd_timeout(struct aac_softstate * softs,struct aac_cmd * acp)658958bc78c7SXin Chen aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
6590382c8bcaSpl {
659158bc78c7SXin Chen #ifdef DEBUG
659258bc78c7SXin Chen 	acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
659358bc78c7SXin Chen 	AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
659458bc78c7SXin Chen 	AACDB_PRINT_FIB(softs, acp->slotp);
659558bc78c7SXin Chen #endif
659658bc78c7SXin Chen 
6597382c8bcaSpl 	/*
6598382c8bcaSpl 	 * Besides the firmware in unhealthy state, an overloaded
6599382c8bcaSpl 	 * adapter may also incur pkt timeout.
6600382c8bcaSpl 	 * There is a chance for an adapter with a slower IOP to take
6601382c8bcaSpl 	 * longer than 60 seconds to process the commands, such as when
6602382c8bcaSpl 	 * to perform IOs. So the adapter is doing a build on a RAID-5
6603382c8bcaSpl 	 * while being required longer completion times should be
6604382c8bcaSpl 	 * tolerated.
6605382c8bcaSpl 	 */
660658bc78c7SXin Chen 	switch (aac_do_reset(softs)) {
660758bc78c7SXin Chen 	case AAC_IOP_RESET_SUCCEED:
660858bc78c7SXin Chen 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
6609382c8bcaSpl 		aac_start_waiting_io(softs);
661058bc78c7SXin Chen 		break;
661158bc78c7SXin Chen 	case AAC_IOP_RESET_FAILED:
6612382c8bcaSpl 		/* Abort all waiting cmds when adapter is dead */
661358bc78c7SXin Chen 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
661458bc78c7SXin Chen 		break;
661558bc78c7SXin Chen 	case AAC_IOP_RESET_ABNORMAL:
661658bc78c7SXin Chen 		aac_start_waiting_io(softs);
6617382c8bcaSpl 	}
6618382c8bcaSpl }
6619382c8bcaSpl 
6620942c5e3cSpl /*
6621942c5e3cSpl  * The following function comes from Adaptec:
6622942c5e3cSpl  *
6623942c5e3cSpl  * Time sync. command added to synchronize time with firmware every 30
6624942c5e3cSpl  * minutes (required for correct AIF timestamps etc.)
6625942c5e3cSpl  */
66260749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_sync_tick(struct aac_softstate * softs)6627942c5e3cSpl aac_sync_tick(struct aac_softstate *softs)
6628942c5e3cSpl {
6629f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
6630f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
6631f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
66320749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66330749e8deSXin Chen - Sun Microsystems - Beijing China 	ASSERT(softs->time_sync <= softs->timebase);
66340749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_sync = 0;
66350749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
66360749e8deSXin Chen - Sun Microsystems - Beijing China 
6637f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Time sync. with firmware every AAC_SYNC_TICK */
6638f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
6639f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
6640942c5e3cSpl 
6641f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
6642f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    ddi_get_time());
6643f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
6644f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
66450749e8deSXin Chen - Sun Microsystems - Beijing China 
66460749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66470749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_sync = softs->timebase;
66480749e8deSXin Chen - Sun Microsystems - Beijing China 	if (rval != AACOK)
66490749e8deSXin Chen - Sun Microsystems - Beijing China 		/* retry shortly */
66500749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->time_sync += aac_tick << 1;
66510749e8deSXin Chen - Sun Microsystems - Beijing China 	else
66520749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->time_sync += AAC_SYNC_TICK;
66530749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
6654942c5e3cSpl }
6655942c5e3cSpl 
66560749e8deSXin Chen - Sun Microsystems - Beijing China /*
66570749e8deSXin Chen - Sun Microsystems - Beijing China  * Timeout checking and handling
66580749e8deSXin Chen - Sun Microsystems - Beijing China  */
66597c478bd9Sstevel@tonic-gate static void
aac_daemon(struct aac_softstate * softs)66600749e8deSXin Chen - Sun Microsystems - Beijing China aac_daemon(struct aac_softstate *softs)
66617c478bd9Sstevel@tonic-gate {
66620749e8deSXin Chen - Sun Microsystems - Beijing China 	int time_out; /* set if timeout happened */
66630749e8deSXin Chen - Sun Microsystems - Beijing China 	int time_adjust;
66640749e8deSXin Chen - Sun Microsystems - Beijing China 	uint32_t softs_timebase;
6665830d82f7Spl 
66660749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66670749e8deSXin Chen - Sun Microsystems - Beijing China 	ASSERT(softs->time_out <= softs->timebase);
66680749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_out = 0;
66690749e8deSXin Chen - Sun Microsystems - Beijing China 	softs_timebase = softs->timebase;
66700749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
6671830d82f7Spl 
66720749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Check slots for timeout pkts */
66730749e8deSXin Chen - Sun Microsystems - Beijing China 	time_adjust = 0;
66740749e8deSXin Chen - Sun Microsystems - Beijing China 	do {
66750749e8deSXin Chen - Sun Microsystems - Beijing China 		struct aac_cmd *acp;
66760749e8deSXin Chen - Sun Microsystems - Beijing China 
66770749e8deSXin Chen - Sun Microsystems - Beijing China 		time_out = 0;
66780749e8deSXin Chen - Sun Microsystems - Beijing China 		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
66790749e8deSXin Chen - Sun Microsystems - Beijing China 			if (acp->timeout == 0)
66800749e8deSXin Chen - Sun Microsystems - Beijing China 				continue;
66810749e8deSXin Chen - Sun Microsystems - Beijing China 
66820749e8deSXin Chen - Sun Microsystems - Beijing China 			/*
66830749e8deSXin Chen - Sun Microsystems - Beijing China 			 * If timeout happened, update outstanding cmds
66840749e8deSXin Chen - Sun Microsystems - Beijing China 			 * to be checked later again.
66850749e8deSXin Chen - Sun Microsystems - Beijing China 			 */
66860749e8deSXin Chen - Sun Microsystems - Beijing China 			if (time_adjust) {
66870749e8deSXin Chen - Sun Microsystems - Beijing China 				acp->timeout += time_adjust;
66880749e8deSXin Chen - Sun Microsystems - Beijing China 				continue;
66890749e8deSXin Chen - Sun Microsystems - Beijing China 			}
66900749e8deSXin Chen - Sun Microsystems - Beijing China 
66910749e8deSXin Chen - Sun Microsystems - Beijing China 			if (acp->timeout <= softs_timebase) {
669258bc78c7SXin Chen 				aac_cmd_timeout(softs, acp);
66930749e8deSXin Chen - Sun Microsystems - Beijing China 				time_out = 1;
66940749e8deSXin Chen - Sun Microsystems - Beijing China 				time_adjust = aac_tick * drv_usectohz(1000000);
66950749e8deSXin Chen - Sun Microsystems - Beijing China 				break; /* timeout happened */
66960749e8deSXin Chen - Sun Microsystems - Beijing China 			} else {
66970749e8deSXin Chen - Sun Microsystems - Beijing China 				break; /* no timeout */
6698382c8bcaSpl 			}
6699830d82f7Spl 		}
67000749e8deSXin Chen - Sun Microsystems - Beijing China 	} while (time_out);
67017c478bd9Sstevel@tonic-gate 
67020749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
67030749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_out = softs->timebase + aac_tick;
67040749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
67050749e8deSXin Chen - Sun Microsystems - Beijing China }
67060749e8deSXin Chen - Sun Microsystems - Beijing China 
67070749e8deSXin Chen - Sun Microsystems - Beijing China /*
67080749e8deSXin Chen - Sun Microsystems - Beijing China  * The event thread handles various tasks serially for the other parts of
67090749e8deSXin Chen - Sun Microsystems - Beijing China  * the driver, so that they can run fast.
67100749e8deSXin Chen - Sun Microsystems - Beijing China  */
67110749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_event_thread(struct aac_softstate * softs)67120749e8deSXin Chen - Sun Microsystems - Beijing China aac_event_thread(struct aac_softstate *softs)
67130749e8deSXin Chen - Sun Microsystems - Beijing China {
67140749e8deSXin Chen - Sun Microsystems - Beijing China 	int run = 1;
67150749e8deSXin Chen - Sun Microsystems - Beijing China 
67160749e8deSXin Chen - Sun Microsystems - Beijing China 	DBCALLED(softs, 1);
67170749e8deSXin Chen - Sun Microsystems - Beijing China 
67180749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
67190749e8deSXin Chen - Sun Microsystems - Beijing China 	while (run) {
67200749e8deSXin Chen - Sun Microsystems - Beijing China 		int events;
67210749e8deSXin Chen - Sun Microsystems - Beijing China 
67220749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((events = softs->events) == 0) {
67230749e8deSXin Chen - Sun Microsystems - Beijing China 			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
67240749e8deSXin Chen - Sun Microsystems - Beijing China 			events = softs->events;
67250749e8deSXin Chen - Sun Microsystems - Beijing China 		}
67260749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->events = 0;
67270749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->ev_lock);
67280749e8deSXin Chen - Sun Microsystems - Beijing China 
67290749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_enter(&softs->io_lock);
67300749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((softs->state & AAC_STATE_RUN) &&
67310749e8deSXin Chen - Sun Microsystems - Beijing China 		    (softs->state & AAC_STATE_DEAD) == 0) {
67320749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_TIMEOUT)
67330749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_daemon(softs);
67340749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_SYNCTICK)
67350749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_sync_tick(softs);
67360749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_AIF)
67370749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_aif_event(softs);
67380749e8deSXin Chen - Sun Microsystems - Beijing China 		} else {
67390749e8deSXin Chen - Sun Microsystems - Beijing China 			run = 0;
67400749e8deSXin Chen - Sun Microsystems - Beijing China 		}
67410749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->io_lock);
67420749e8deSXin Chen - Sun Microsystems - Beijing China 
67430749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_enter(&softs->ev_lock);
6744942c5e3cSpl 	}
6745942c5e3cSpl 
67460749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_signal(&softs->event_wait_cv);
67470749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
67480749e8deSXin Chen - Sun Microsystems - Beijing China }
67490749e8deSXin Chen - Sun Microsystems - Beijing China 
67500749e8deSXin Chen - Sun Microsystems - Beijing China /*
67510749e8deSXin Chen - Sun Microsystems - Beijing China  * Internal timer. It is only responsbile for time counting and report time
67520749e8deSXin Chen - Sun Microsystems - Beijing China  * related events. Events handling is done by aac_event_thread(), so that
67530749e8deSXin Chen - Sun Microsystems - Beijing China  * the timer itself could be as precise as possible.
67540749e8deSXin Chen - Sun Microsystems - Beijing China  */
67550749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_timer(void * arg)67560749e8deSXin Chen - Sun Microsystems - Beijing China aac_timer(void *arg)
67570749e8deSXin Chen - Sun Microsystems - Beijing China {
67580749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_softstate *softs = arg;
67590749e8deSXin Chen - Sun Microsystems - Beijing China 	int events = 0;
67600749e8deSXin Chen - Sun Microsystems - Beijing China 
67610749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
67620749e8deSXin Chen - Sun Microsystems - Beijing China 
67630749e8deSXin Chen - Sun Microsystems - Beijing China 	/* If timer is being stopped, exit */
67640749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->timeout_id) {
67650749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->timeout_id = timeout(aac_timer, (void *)softs,
6766382c8bcaSpl 		    (aac_tick * drv_usectohz(1000000)));
67670749e8deSXin Chen - Sun Microsystems - Beijing China 	} else {
67680749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->time_mutex);
67690749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
67700749e8deSXin Chen - Sun Microsystems - Beijing China 	}
67710749e8deSXin Chen - Sun Microsystems - Beijing China 
67720749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Time counting */
67730749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->timebase += aac_tick;
67740749e8deSXin Chen - Sun Microsystems - Beijing China 
67750749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Check time related events */
67760749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->time_out && softs->time_out <= softs->timebase)
67770749e8deSXin Chen - Sun Microsystems - Beijing China 		events |= AAC_EVENT_TIMEOUT;
67780749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->time_sync && softs->time_sync <= softs->timebase)
67790749e8deSXin Chen - Sun Microsystems - Beijing China 		events |= AAC_EVENT_SYNCTICK;
67800749e8deSXin Chen - Sun Microsystems - Beijing China 
67810749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
67820749e8deSXin Chen - Sun Microsystems - Beijing China 
67830749e8deSXin Chen - Sun Microsystems - Beijing China 	if (events)
67840749e8deSXin Chen - Sun Microsystems - Beijing China 		aac_event_disp(softs, events);
67850749e8deSXin Chen - Sun Microsystems - Beijing China }
67860749e8deSXin Chen - Sun Microsystems - Beijing China 
67870749e8deSXin Chen - Sun Microsystems - Beijing China /*
67880749e8deSXin Chen - Sun Microsystems - Beijing China  * Dispatch events to daemon thread for handling
67890749e8deSXin Chen - Sun Microsystems - Beijing China  */
67900749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_event_disp(struct aac_softstate * softs,int events)67910749e8deSXin Chen - Sun Microsystems - Beijing China aac_event_disp(struct aac_softstate *softs, int events)
67920749e8deSXin Chen - Sun Microsystems - Beijing China {
67930749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
67940749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->events |= events;
67950749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_broadcast(&softs->event_disp_cv);
67960749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
6797830d82f7Spl }
6798830d82f7Spl 
6799830d82f7Spl /*
6800830d82f7Spl  * Architecture dependent functions
6801830d82f7Spl  */
6802830d82f7Spl static int
aac_rx_get_fwstatus(struct aac_softstate * softs)6803830d82f7Spl aac_rx_get_fwstatus(struct aac_softstate *softs)
6804830d82f7Spl {
6805942c5e3cSpl 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6806830d82f7Spl }
6807830d82f7Spl 
6808830d82f7Spl static int
aac_rx_get_mailbox(struct aac_softstate * softs,int mb)6809830d82f7Spl aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
6810830d82f7Spl {
6811830d82f7Spl 	return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
6812830d82f7Spl }
6813830d82f7Spl 
6814830d82f7Spl static void
aac_rx_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)6815830d82f7Spl aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6816c9487164Spl     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6817830d82f7Spl {
6818830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
6819830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
6820830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
6821830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
6822830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
6823830d82f7Spl }
6824830d82f7Spl 
6825830d82f7Spl static int
aac_rkt_get_fwstatus(struct aac_softstate * softs)6826830d82f7Spl aac_rkt_get_fwstatus(struct aac_softstate *softs)
6827830d82f7Spl {
6828942c5e3cSpl 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6829830d82f7Spl }
6830830d82f7Spl 
6831830d82f7Spl static int
aac_rkt_get_mailbox(struct aac_softstate * softs,int mb)6832830d82f7Spl aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
6833830d82f7Spl {
6834830d82f7Spl 	return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
6835830d82f7Spl }
6836830d82f7Spl 
6837830d82f7Spl static void
aac_rkt_set_mailbox(struct aac_softstate * softs,uint32_t cmd,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3)6838830d82f7Spl aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6839c9487164Spl     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6840830d82f7Spl {
6841830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
6842830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
6843830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
6844830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
6845830d82f7Spl 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
6846830d82f7Spl }
6847830d82f7Spl 
6848830d82f7Spl /*
6849830d82f7Spl  * cb_ops functions
6850830d82f7Spl  */
6851830d82f7Spl static int
aac_open(dev_t * devp,int flag,int otyp,cred_t * cred)6852830d82f7Spl aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
6853830d82f7Spl {
6854830d82f7Spl 	struct aac_softstate *softs;
6855830d82f7Spl 	int minor0, minor;
6856830d82f7Spl 	int instance;
6857830d82f7Spl 
68581dd0a2dbSpl 	DBCALLED(NULL, 2);
6859830d82f7Spl 
6860830d82f7Spl 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6861830d82f7Spl 		return (EINVAL);
6862830d82f7Spl 
6863830d82f7Spl 	minor0 = getminor(*devp);
6864830d82f7Spl 	minor = AAC_SCSA_MINOR(minor0);
6865830d82f7Spl 
6866830d82f7Spl 	if (AAC_IS_SCSA_NODE(minor))
6867830d82f7Spl 		return (scsi_hba_open(devp, flag, otyp, cred));
6868830d82f7Spl 
6869830d82f7Spl 	instance = MINOR2INST(minor0);
6870830d82f7Spl 	if (instance >= AAC_MAX_ADAPTERS)
6871830d82f7Spl 		return (ENXIO);
6872830d82f7Spl 
6873830d82f7Spl 	softs = ddi_get_soft_state(aac_softstatep, instance);
6874830d82f7Spl 	if (softs == NULL)
6875830d82f7Spl 		return (ENXIO);
6876830d82f7Spl 
6877830d82f7Spl 	return (0);
6878830d82f7Spl }
6879830d82f7Spl 
6880830d82f7Spl /*ARGSUSED*/
6881830d82f7Spl static int
aac_close(dev_t dev,int flag,int otyp,cred_t * cred)6882830d82f7Spl aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
6883830d82f7Spl {
6884830d82f7Spl 	int minor0, minor;
6885830d82f7Spl 	int instance;
6886830d82f7Spl 
68871dd0a2dbSpl 	DBCALLED(NULL, 2);
6888830d82f7Spl 
6889830d82f7Spl 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6890830d82f7Spl 		return (EINVAL);
6891830d82f7Spl 
6892830d82f7Spl 	minor0 = getminor(dev);
6893830d82f7Spl 	minor = AAC_SCSA_MINOR(minor0);
6894830d82f7Spl 
6895830d82f7Spl 	if (AAC_IS_SCSA_NODE(minor))
6896830d82f7Spl 		return (scsi_hba_close(dev, flag, otyp, cred));
6897830d82f7Spl 
6898830d82f7Spl 	instance = MINOR2INST(minor0);
6899830d82f7Spl 	if (instance >= AAC_MAX_ADAPTERS)
6900830d82f7Spl 		return (ENXIO);
69017c478bd9Sstevel@tonic-gate 
6902830d82f7Spl 	return (0);
6903830d82f7Spl }
6904830d82f7Spl 
6905830d82f7Spl static int
aac_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)6906c9487164Spl aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
6907c9487164Spl     int *rval_p)
6908830d82f7Spl {
6909830d82f7Spl 	struct aac_softstate *softs;
6910830d82f7Spl 	int minor0, minor;
6911830d82f7Spl 	int instance;
6912830d82f7Spl 
69131dd0a2dbSpl 	DBCALLED(NULL, 2);
6914830d82f7Spl 
6915830d82f7Spl 	if (drv_priv(cred_p) != 0)
6916830d82f7Spl 		return (EPERM);
6917830d82f7Spl 
6918830d82f7Spl 	minor0 = getminor(dev);
6919830d82f7Spl 	minor = AAC_SCSA_MINOR(minor0);
6920830d82f7Spl 
6921830d82f7Spl 	if (AAC_IS_SCSA_NODE(minor))
6922830d82f7Spl 		return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
6923830d82f7Spl 
6924830d82f7Spl 	instance = MINOR2INST(minor0);
6925830d82f7Spl 	if (instance < AAC_MAX_ADAPTERS) {
6926830d82f7Spl 		softs = ddi_get_soft_state(aac_softstatep, instance);
6927942c5e3cSpl 		return (aac_do_ioctl(softs, dev, cmd, arg, flag));
6928830d82f7Spl 	}
6929830d82f7Spl 	return (ENXIO);
69307c478bd9Sstevel@tonic-gate }
69317c478bd9Sstevel@tonic-gate 
69327675db54Syw /*
69337675db54Syw  * The IO fault service error handling callback function
69347675db54Syw  */
69357675db54Syw /*ARGSUSED*/
69367675db54Syw static int
aac_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)69377675db54Syw aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
69387675db54Syw {
69397675db54Syw 	/*
69407675db54Syw 	 * as the driver can always deal with an error in any dma or
69417675db54Syw 	 * access handle, we can just return the fme_status value.
69427675db54Syw 	 */
69437675db54Syw 	pci_ereport_post(dip, err, NULL);
69447675db54Syw 	return (err->fme_status);
69457675db54Syw }
69467675db54Syw 
69477675db54Syw /*
69487675db54Syw  * aac_fm_init - initialize fma capabilities and register with IO
69497675db54Syw  *               fault services.
69507675db54Syw  */
69517675db54Syw static void
aac_fm_init(struct aac_softstate * softs)69527675db54Syw aac_fm_init(struct aac_softstate *softs)
69537675db54Syw {
69547675db54Syw 	/*
69557675db54Syw 	 * Need to change iblock to priority for new MSI intr
69567675db54Syw 	 */
69577675db54Syw 	ddi_iblock_cookie_t fm_ibc;
69587675db54Syw 
695958bc78c7SXin Chen 	softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
696058bc78c7SXin Chen 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
696158bc78c7SXin Chen 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
696258bc78c7SXin Chen 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
696358bc78c7SXin Chen 
69647675db54Syw 	/* Only register with IO Fault Services if we have some capability */
69657675db54Syw 	if (softs->fm_capabilities) {
69667675db54Syw 		/* Adjust access and dma attributes for FMA */
6967837c1ac4SStephen Hanson 		softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
696858bc78c7SXin Chen 		softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
696958bc78c7SXin Chen 		softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
69707675db54Syw 
69717675db54Syw 		/*
69727675db54Syw 		 * Register capabilities with IO Fault Services.
69737675db54Syw 		 * fm_capabilities will be updated to indicate
69747675db54Syw 		 * capabilities actually supported (not requested.)
69757675db54Syw 		 */
69767675db54Syw 		ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
69777675db54Syw 
69787675db54Syw 		/*
69797675db54Syw 		 * Initialize pci ereport capabilities if ereport
69807675db54Syw 		 * capable (should always be.)
69817675db54Syw 		 */
69827675db54Syw 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
69837675db54Syw 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69847675db54Syw 			pci_ereport_setup(softs->devinfo_p);
69857675db54Syw 		}
69867675db54Syw 
69877675db54Syw 		/*
69887675db54Syw 		 * Register error callback if error callback capable.
69897675db54Syw 		 */
69907675db54Syw 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69917675db54Syw 			ddi_fm_handler_register(softs->devinfo_p,
69927675db54Syw 			    aac_fm_error_cb, (void *) softs);
69937675db54Syw 		}
69947675db54Syw 	}
69957675db54Syw }
69967675db54Syw 
69977675db54Syw /*
69987675db54Syw  * aac_fm_fini - Releases fma capabilities and un-registers with IO
69997675db54Syw  *               fault services.
70007675db54Syw  */
70017675db54Syw static void
aac_fm_fini(struct aac_softstate * softs)70027675db54Syw aac_fm_fini(struct aac_softstate *softs)
70037675db54Syw {
70047675db54Syw 	/* Only unregister FMA capabilities if registered */
70057675db54Syw 	if (softs->fm_capabilities) {
70067675db54Syw 		/*
70077675db54Syw 		 * Un-register error callback if error callback capable.
70087675db54Syw 		 */
70097675db54Syw 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70107675db54Syw 			ddi_fm_handler_unregister(softs->devinfo_p);
70117675db54Syw 		}
70127675db54Syw 
70137675db54Syw 		/*
70147675db54Syw 		 * Release any resources allocated by pci_ereport_setup()
70157675db54Syw 		 */
70167675db54Syw 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
70177675db54Syw 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70187675db54Syw 			pci_ereport_teardown(softs->devinfo_p);
70197675db54Syw 		}
70207675db54Syw 
70217675db54Syw 		/* Unregister from IO Fault Services */
70227675db54Syw 		ddi_fm_fini(softs->devinfo_p);
702358bc78c7SXin Chen 
702458bc78c7SXin Chen 		/* Adjust access and dma attributes for FMA */
7025837c1ac4SStephen Hanson 		softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
702658bc78c7SXin Chen 		softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
702758bc78c7SXin Chen 		softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
70287675db54Syw 	}
70297675db54Syw }
70307675db54Syw 
70317675db54Syw int
aac_check_acc_handle(ddi_acc_handle_t handle)70327675db54Syw aac_check_acc_handle(ddi_acc_handle_t handle)
70337675db54Syw {
70347675db54Syw 	ddi_fm_error_t de;
70357675db54Syw 
70367675db54Syw 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
70377675db54Syw 	return (de.fme_status);
70387675db54Syw }
70397675db54Syw 
70407675db54Syw int
aac_check_dma_handle(ddi_dma_handle_t handle)70417675db54Syw aac_check_dma_handle(ddi_dma_handle_t handle)
70427675db54Syw {
70437675db54Syw 	ddi_fm_error_t de;
70447675db54Syw 
70457675db54Syw 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
70467675db54Syw 	return (de.fme_status);
70477675db54Syw }
70487675db54Syw 
70497675db54Syw void
aac_fm_ereport(struct aac_softstate * softs,char * detail)70507675db54Syw aac_fm_ereport(struct aac_softstate *softs, char *detail)
70517675db54Syw {
70527675db54Syw 	uint64_t ena;
70537675db54Syw 	char buf[FM_MAX_CLASS];
70547675db54Syw 
70557675db54Syw 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
70567675db54Syw 	ena = fm_ena_generate(0, FM_ENA_FMT1);
70577675db54Syw 	if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
70587675db54Syw 		ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
70597675db54Syw 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
70607675db54Syw 	}
70617675db54Syw }
70627675db54Syw 
706358bc78c7SXin Chen /*
706458bc78c7SXin Chen  * Autoconfiguration support
706558bc78c7SXin Chen  */
706658bc78c7SXin Chen static int
aac_parse_devname(char * devnm,int * tgt,int * lun)706758bc78c7SXin Chen aac_parse_devname(char *devnm, int *tgt, int *lun)
706858bc78c7SXin Chen {
706958bc78c7SXin Chen 	char devbuf[SCSI_MAXNAMELEN];
707058bc78c7SXin Chen 	char *addr;
707158bc78c7SXin Chen 	char *p,  *tp, *lp;
707258bc78c7SXin Chen 	long num;
707358bc78c7SXin Chen 
707458bc78c7SXin Chen 	/* Parse dev name and address */
707558bc78c7SXin Chen 	(void) strcpy(devbuf, devnm);
707658bc78c7SXin Chen 	addr = "";
707758bc78c7SXin Chen 	for (p = devbuf; *p != '\0'; p++) {
707858bc78c7SXin Chen 		if (*p == '@') {
707958bc78c7SXin Chen 			addr = p + 1;
708058bc78c7SXin Chen 			*p = '\0';
708158bc78c7SXin Chen 		} else if (*p == ':') {
708258bc78c7SXin Chen 			*p = '\0';
708358bc78c7SXin Chen 			break;
708458bc78c7SXin Chen 		}
708558bc78c7SXin Chen 	}
708658bc78c7SXin Chen 
708758bc78c7SXin Chen 	/* Parse taget and lun */
708858bc78c7SXin Chen 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
708958bc78c7SXin Chen 		if (*p == ',') {
709058bc78c7SXin Chen 			lp = p + 1;
709158bc78c7SXin Chen 			*p = '\0';
709258bc78c7SXin Chen 			break;
709358bc78c7SXin Chen 		}
709458bc78c7SXin Chen 	}
709558bc78c7SXin Chen 	if (tgt && tp) {
709658bc78c7SXin Chen 		if (ddi_strtol(tp, NULL, 0x10, &num))
709758bc78c7SXin Chen 			return (AACERR);
709858bc78c7SXin Chen 		*tgt = (int)num;
709958bc78c7SXin Chen 	}
710058bc78c7SXin Chen 	if (lun && lp) {
710158bc78c7SXin Chen 		if (ddi_strtol(lp, NULL, 0x10, &num))
710258bc78c7SXin Chen 			return (AACERR);
710358bc78c7SXin Chen 		*lun = (int)num;
710458bc78c7SXin Chen 	}
710558bc78c7SXin Chen 	return (AACOK);
710658bc78c7SXin Chen }
710758bc78c7SXin Chen 
710858bc78c7SXin Chen static dev_info_t *
aac_find_child(struct aac_softstate * softs,uint16_t tgt,uint8_t lun)710958bc78c7SXin Chen aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
711058bc78c7SXin Chen {
711158bc78c7SXin Chen 	dev_info_t *child = NULL;
711258bc78c7SXin Chen 	char addr[SCSI_MAXNAMELEN];
711358bc78c7SXin Chen 	char tmp[MAXNAMELEN];
711458bc78c7SXin Chen 
711558bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
711658bc78c7SXin Chen 		if (lun == 0) {
711758bc78c7SXin Chen 			struct aac_device *dvp = &softs->containers[tgt].dev;
711858bc78c7SXin Chen 
711958bc78c7SXin Chen 			child = dvp->dip;
712058bc78c7SXin Chen 		}
712158bc78c7SXin Chen 	} else {
712258bc78c7SXin Chen 		(void) sprintf(addr, "%x,%x", tgt, lun);
712358bc78c7SXin Chen 		for (child = ddi_get_child(softs->devinfo_p);
712458bc78c7SXin Chen 		    child; child = ddi_get_next_sibling(child)) {
712558bc78c7SXin Chen 			/* We don't care about non-persistent node */
712658bc78c7SXin Chen 			if (ndi_dev_is_persistent_node(child) == 0)
712758bc78c7SXin Chen 				continue;
712858bc78c7SXin Chen 
712958bc78c7SXin Chen 			if (aac_name_node(child, tmp, MAXNAMELEN) !=
713058bc78c7SXin Chen 			    DDI_SUCCESS)
713158bc78c7SXin Chen 				continue;
713258bc78c7SXin Chen 			if (strcmp(addr, tmp) == 0)
713358bc78c7SXin Chen 				break;
713458bc78c7SXin Chen 		}
713558bc78c7SXin Chen 	}
713658bc78c7SXin Chen 	return (child);
713758bc78c7SXin Chen }
713858bc78c7SXin Chen 
713958bc78c7SXin Chen static int
aac_config_child(struct aac_softstate * softs,struct scsi_device * sd,dev_info_t ** dipp)714058bc78c7SXin Chen aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
714158bc78c7SXin Chen     dev_info_t **dipp)
714258bc78c7SXin Chen {
714358bc78c7SXin Chen 	char *nodename = NULL;
714458bc78c7SXin Chen 	char **compatible = NULL;
714558bc78c7SXin Chen 	int ncompatible = 0;
714658bc78c7SXin Chen 	char *childname;
714758bc78c7SXin Chen 	dev_info_t *ldip = NULL;
714858bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
714958bc78c7SXin Chen 	int lun = sd->sd_address.a_lun;
715058bc78c7SXin Chen 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
715158bc78c7SXin Chen 	int rval;
715258bc78c7SXin Chen 
715358bc78c7SXin Chen 	DBCALLED(softs, 2);
715458bc78c7SXin Chen 
715558bc78c7SXin Chen 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
715658bc78c7SXin Chen 	    NULL, &nodename, &compatible, &ncompatible);
715758bc78c7SXin Chen 	if (nodename == NULL) {
715858bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN,
715958bc78c7SXin Chen 		    "found no comptible driver for t%dL%d", tgt, lun);
716058bc78c7SXin Chen 		rval = NDI_FAILURE;
716158bc78c7SXin Chen 		goto finish;
716258bc78c7SXin Chen 	}
716358bc78c7SXin Chen 	childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
716458bc78c7SXin Chen 
716558bc78c7SXin Chen 	/* Create dev node */
716658bc78c7SXin Chen 	rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
716758bc78c7SXin Chen 	    &ldip);
716858bc78c7SXin Chen 	if (rval == NDI_SUCCESS) {
716958bc78c7SXin Chen 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
717058bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
717158bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
717258bc78c7SXin Chen 			    "property for t%dL%d (target)", tgt, lun);
717358bc78c7SXin Chen 			rval = NDI_FAILURE;
717458bc78c7SXin Chen 			goto finish;
717558bc78c7SXin Chen 		}
717658bc78c7SXin Chen 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
717758bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
717858bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
717958bc78c7SXin Chen 			    "property for t%dL%d (lun)", tgt, lun);
718058bc78c7SXin Chen 			rval = NDI_FAILURE;
718158bc78c7SXin Chen 			goto finish;
718258bc78c7SXin Chen 		}
718358bc78c7SXin Chen 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
718458bc78c7SXin Chen 		    "compatible", compatible, ncompatible)
718558bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
718658bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
718758bc78c7SXin Chen 			    "property for t%dL%d (compatible)", tgt, lun);
718858bc78c7SXin Chen 			rval = NDI_FAILURE;
718958bc78c7SXin Chen 			goto finish;
719058bc78c7SXin Chen 		}
719158bc78c7SXin Chen 
719258bc78c7SXin Chen 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
719358bc78c7SXin Chen 		if (rval != NDI_SUCCESS) {
719458bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
719558bc78c7SXin Chen 			    tgt, lun);
719658bc78c7SXin Chen 			ndi_prop_remove_all(ldip);
719758bc78c7SXin Chen 			(void) ndi_devi_free(ldip);
719858bc78c7SXin Chen 		}
719958bc78c7SXin Chen 	}
720058bc78c7SXin Chen finish:
720158bc78c7SXin Chen 	if (dipp)
720258bc78c7SXin Chen 		*dipp = ldip;
720358bc78c7SXin Chen 
720458bc78c7SXin Chen 	scsi_hba_nodename_compatible_free(nodename, compatible);
720558bc78c7SXin Chen 	return (rval);
720658bc78c7SXin Chen }
720758bc78c7SXin Chen 
720858bc78c7SXin Chen /*ARGSUSED*/
720958bc78c7SXin Chen static int
aac_probe_lun(struct aac_softstate * softs,struct scsi_device * sd)721058bc78c7SXin Chen aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
721158bc78c7SXin Chen {
721258bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
721358bc78c7SXin Chen 	int lun = sd->sd_address.a_lun;
721458bc78c7SXin Chen 
721558bc78c7SXin Chen 	DBCALLED(softs, 2);
721658bc78c7SXin Chen 
721758bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
72180749e8deSXin Chen - Sun Microsystems - Beijing China 		enum aac_cfg_event event;
721958bc78c7SXin Chen 
722058bc78c7SXin Chen 		if (lun == 0) {
722158bc78c7SXin Chen 			mutex_enter(&softs->io_lock);
72220749e8deSXin Chen - Sun Microsystems - Beijing China 			event = aac_probe_container(softs, tgt);
722358bc78c7SXin Chen 			mutex_exit(&softs->io_lock);
72240749e8deSXin Chen - Sun Microsystems - Beijing China 			if ((event != AAC_CFG_NULL_NOEXIST) &&
72250749e8deSXin Chen - Sun Microsystems - Beijing China 			    (event != AAC_CFG_DELETE)) {
722658bc78c7SXin Chen 				if (scsi_hba_probe(sd, NULL) ==
722758bc78c7SXin Chen 				    SCSIPROBE_EXISTS)
722858bc78c7SXin Chen 					return (NDI_SUCCESS);
722958bc78c7SXin Chen 			}
723058bc78c7SXin Chen 		}
723158bc78c7SXin Chen 		return (NDI_FAILURE);
723258bc78c7SXin Chen 	} else {
723358bc78c7SXin Chen 		int dtype;
72343fced439Szhongyan gu - Sun Microsystems - Beijing China 		int qual; /* device qualifier */
723558bc78c7SXin Chen 
723658bc78c7SXin Chen 		if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
723758bc78c7SXin Chen 			return (NDI_FAILURE);
723858bc78c7SXin Chen 
723958bc78c7SXin Chen 		dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
72403fced439Szhongyan gu - Sun Microsystems - Beijing China 		qual = dtype >> 5;
724158bc78c7SXin Chen 
724258bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE,
724358bc78c7SXin Chen 		    "Phys. device found: tgt %d dtype %d: %s",
724458bc78c7SXin Chen 		    tgt, dtype, sd->sd_inq->inq_vid);
724558bc78c7SXin Chen 
72463fced439Szhongyan gu - Sun Microsystems - Beijing China 		/* Only non-DASD and JBOD mode DASD are allowed exposed */
72473fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (dtype == DTYPE_RODIRECT /* CDROM */ ||
72483fced439Szhongyan gu - Sun Microsystems - Beijing China 		    dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
72493fced439Szhongyan gu - Sun Microsystems - Beijing China 		    dtype == DTYPE_ESI /* SES */) {
72503fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_NONDASD))
72513fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (NDI_FAILURE);
72523fced439Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
72533fced439Szhongyan gu - Sun Microsystems - Beijing China 
72543fced439Szhongyan gu - Sun Microsystems - Beijing China 		} else if (dtype == DTYPE_DIRECT) {
72553fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
72563fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (NDI_FAILURE);
72573fced439Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
72583fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
725958bc78c7SXin Chen 
726058bc78c7SXin Chen 		mutex_enter(&softs->io_lock);
726158bc78c7SXin Chen 		softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
726258bc78c7SXin Chen 		mutex_exit(&softs->io_lock);
726358bc78c7SXin Chen 		return (NDI_SUCCESS);
726458bc78c7SXin Chen 	}
726558bc78c7SXin Chen }
726658bc78c7SXin Chen 
726758bc78c7SXin Chen static int
aac_config_lun(struct aac_softstate * softs,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)726858bc78c7SXin Chen aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
726958bc78c7SXin Chen     dev_info_t **ldip)
727058bc78c7SXin Chen {
727158bc78c7SXin Chen 	struct scsi_device sd;
727258bc78c7SXin Chen 	dev_info_t *child;
727358bc78c7SXin Chen 	int rval;
727458bc78c7SXin Chen 
727558bc78c7SXin Chen 	DBCALLED(softs, 2);
727658bc78c7SXin Chen 
727758bc78c7SXin Chen 	if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
727858bc78c7SXin Chen 		if (ldip)
727958bc78c7SXin Chen 			*ldip = child;
728058bc78c7SXin Chen 		return (NDI_SUCCESS);
728158bc78c7SXin Chen 	}
728258bc78c7SXin Chen 
728358bc78c7SXin Chen 	bzero(&sd, sizeof (struct scsi_device));
728458bc78c7SXin Chen 	sd.sd_address.a_hba_tran = softs->hba_tran;
728558bc78c7SXin Chen 	sd.sd_address.a_target = (uint16_t)tgt;
728658bc78c7SXin Chen 	sd.sd_address.a_lun = (uint8_t)lun;
728758bc78c7SXin Chen 	if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
728858bc78c7SXin Chen 		rval = aac_config_child(softs, &sd, ldip);
7289f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* scsi_unprobe is blank now. Free buffer manually */
7290f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (sd.sd_inq) {
7291f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		kmem_free(sd.sd_inq, SUN_INQSIZE);
7292f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		sd.sd_inq = (struct scsi_inquiry *)NULL;
7293f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
729458bc78c7SXin Chen 	return (rval);
729558bc78c7SXin Chen }
729658bc78c7SXin Chen 
729758bc78c7SXin Chen static int
aac_config_tgt(struct aac_softstate * softs,int tgt)729858bc78c7SXin Chen aac_config_tgt(struct aac_softstate *softs, int tgt)
729958bc78c7SXin Chen {
730058bc78c7SXin Chen 	struct scsi_address ap;
730158bc78c7SXin Chen 	struct buf *bp = NULL;
730258bc78c7SXin Chen 	int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
730358bc78c7SXin Chen 	int list_len = 0;
730458bc78c7SXin Chen 	int lun_total = 0;
730558bc78c7SXin Chen 	dev_info_t *ldip;
730658bc78c7SXin Chen 	int i;
730758bc78c7SXin Chen 
730858bc78c7SXin Chen 	ap.a_hba_tran = softs->hba_tran;
730958bc78c7SXin Chen 	ap.a_target = (uint16_t)tgt;
731058bc78c7SXin Chen 	ap.a_lun = 0;
731158bc78c7SXin Chen 
731258bc78c7SXin Chen 	for (i = 0; i < 2; i++) {
731358bc78c7SXin Chen 		struct scsi_pkt *pkt;
731458bc78c7SXin Chen 		uchar_t *cdb;
731558bc78c7SXin Chen 		uchar_t *p;
731658bc78c7SXin Chen 		uint32_t data;
731758bc78c7SXin Chen 
731858bc78c7SXin Chen 		if (bp == NULL) {
731958bc78c7SXin Chen 			if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
732058bc78c7SXin Chen 			    buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
732115c07adcSJohn Levon 				return (AACERR);
732258bc78c7SXin Chen 		}
732358bc78c7SXin Chen 		if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
732458bc78c7SXin Chen 		    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
732558bc78c7SXin Chen 		    NULL, NULL)) == NULL) {
732658bc78c7SXin Chen 			scsi_free_consistent_buf(bp);
732758bc78c7SXin Chen 			return (AACERR);
732858bc78c7SXin Chen 		}
732958bc78c7SXin Chen 		cdb = pkt->pkt_cdbp;
733058bc78c7SXin Chen 		bzero(cdb, CDB_GROUP5);
733158bc78c7SXin Chen 		cdb[0] = SCMD_REPORT_LUNS;
733258bc78c7SXin Chen 
733358bc78c7SXin Chen 		/* Convert buffer len from local to LE_32 */
733458bc78c7SXin Chen 		data = buf_len;
733558bc78c7SXin Chen 		for (p = &cdb[9]; p > &cdb[5]; p--) {
733658bc78c7SXin Chen 			*p = data & 0xff;
733758bc78c7SXin Chen 			data >>= 8;
733858bc78c7SXin Chen 		}
733958bc78c7SXin Chen 
734058bc78c7SXin Chen 		if (scsi_poll(pkt) < 0 ||
734158bc78c7SXin Chen 		    ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
734258bc78c7SXin Chen 			scsi_destroy_pkt(pkt);
734358bc78c7SXin Chen 			break;
734458bc78c7SXin Chen 		}
734558bc78c7SXin Chen 
734658bc78c7SXin Chen 		/* Convert list_len from LE_32 to local */
734758bc78c7SXin Chen 		for (p = (uchar_t *)bp->b_un.b_addr;
734858bc78c7SXin Chen 		    p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
734958bc78c7SXin Chen 			data <<= 8;
735058bc78c7SXin Chen 			data |= *p;
735158bc78c7SXin Chen 		}
735258bc78c7SXin Chen 		list_len = data;
735358bc78c7SXin Chen 		if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
735458bc78c7SXin Chen 			scsi_free_consistent_buf(bp);
735558bc78c7SXin Chen 			bp = NULL;
735658bc78c7SXin Chen 			buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
735758bc78c7SXin Chen 		}
735858bc78c7SXin Chen 		scsi_destroy_pkt(pkt);
735958bc78c7SXin Chen 	}
736058bc78c7SXin Chen 	if (i >= 2) {
736158bc78c7SXin Chen 		uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
736258bc78c7SXin Chen 		    AAC_SCSI_RPTLUNS_HEAD_SIZE);
736358bc78c7SXin Chen 
736458bc78c7SXin Chen 		for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
736558bc78c7SXin Chen 			uint16_t lun;
736658bc78c7SXin Chen 
736758bc78c7SXin Chen 			/* Determine report luns addressing type */
736858bc78c7SXin Chen 			switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
736958bc78c7SXin Chen 			/*
737058bc78c7SXin Chen 			 * Vendors in the field have been found to be
737158bc78c7SXin Chen 			 * concatenating bus/target/lun to equal the
737258bc78c7SXin Chen 			 * complete lun value instead of switching to
737358bc78c7SXin Chen 			 * flat space addressing
737458bc78c7SXin Chen 			 */
737558bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
737658bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
737758bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
737858bc78c7SXin Chen 				lun = ((buf[0] & 0x3f) << 8) | buf[1];
737958bc78c7SXin Chen 				if (lun > UINT8_MAX) {
738058bc78c7SXin Chen 					AACDB_PRINT(softs, CE_WARN,
738158bc78c7SXin Chen 					    "abnormal lun number: %d", lun);
738258bc78c7SXin Chen 					break;
738358bc78c7SXin Chen 				}
738458bc78c7SXin Chen 				if (aac_config_lun(softs, tgt, lun, &ldip) ==
738558bc78c7SXin Chen 				    NDI_SUCCESS)
738658bc78c7SXin Chen 					lun_total++;
738758bc78c7SXin Chen 				break;
738858bc78c7SXin Chen 			}
738958bc78c7SXin Chen 
739058bc78c7SXin Chen 			buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
739158bc78c7SXin Chen 		}
739258bc78c7SXin Chen 	} else {
739358bc78c7SXin Chen 		/* The target may do not support SCMD_REPORT_LUNS. */
739458bc78c7SXin Chen 		if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
739558bc78c7SXin Chen 			lun_total++;
739658bc78c7SXin Chen 	}
739758bc78c7SXin Chen 	scsi_free_consistent_buf(bp);
739858bc78c7SXin Chen 	return (lun_total);
739958bc78c7SXin Chen }
740058bc78c7SXin Chen 
740158bc78c7SXin Chen static void
aac_devcfg(struct aac_softstate * softs,int tgt,int en)740258bc78c7SXin Chen aac_devcfg(struct aac_softstate *softs, int tgt, int en)
740358bc78c7SXin Chen {
740458bc78c7SXin Chen 	struct aac_device *dvp;
740558bc78c7SXin Chen 
740658bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
740758bc78c7SXin Chen 	dvp = AAC_DEV(softs, tgt);
740858bc78c7SXin Chen 	if (en)
740958bc78c7SXin Chen 		dvp->flags |= AAC_DFLAG_CONFIGURING;
741058bc78c7SXin Chen 	else
741158bc78c7SXin Chen 		dvp->flags &= ~AAC_DFLAG_CONFIGURING;
741258bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
741358bc78c7SXin Chen }
741458bc78c7SXin Chen 
741558bc78c7SXin Chen static int
aac_tran_bus_config(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** childp)741658bc78c7SXin Chen aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
741758bc78c7SXin Chen     void *arg, dev_info_t **childp)
741858bc78c7SXin Chen {
741958bc78c7SXin Chen 	struct aac_softstate *softs;
7420c9ffe217SToomas Soome 	int rval = NDI_FAILURE;
742158bc78c7SXin Chen 
742258bc78c7SXin Chen 	if ((softs = ddi_get_soft_state(aac_softstatep,
742358bc78c7SXin Chen 	    ddi_get_instance(parent))) == NULL)
742458bc78c7SXin Chen 		return (NDI_FAILURE);
742558bc78c7SXin Chen 
742658bc78c7SXin Chen 	/* Commands for bus config should be blocked as the bus is quiesced */
742758bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
742858bc78c7SXin Chen 	if (softs->state & AAC_STATE_QUIESCED) {
742958bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE,
7430c9ffe217SToomas Soome 		    "bus_config aborted because bus is quiesced");
743158bc78c7SXin Chen 		mutex_exit(&softs->io_lock);
743258bc78c7SXin Chen 		return (NDI_FAILURE);
743358bc78c7SXin Chen 	}
743458bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
743558bc78c7SXin Chen 
743658bc78c7SXin Chen 	DBCALLED(softs, 1);
743758bc78c7SXin Chen 
743858bc78c7SXin Chen 	/* Hold the nexus across the bus_config */
7439*3fe80ca4SDan Cross 	ndi_devi_enter(parent);
744058bc78c7SXin Chen 	switch (op) {
744158bc78c7SXin Chen 	case BUS_CONFIG_ONE: {
744258bc78c7SXin Chen 		int tgt, lun;
744358bc78c7SXin Chen 
744458bc78c7SXin Chen 		if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
744558bc78c7SXin Chen 			rval = NDI_FAILURE;
744658bc78c7SXin Chen 			break;
744758bc78c7SXin Chen 		}
74483fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (tgt >= AAC_MAX_LD) {
74493fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (tgt >= AAC_MAX_DEV(softs)) {
74503fced439Szhongyan gu - Sun Microsystems - Beijing China 				rval = NDI_FAILURE;
74513fced439Szhongyan gu - Sun Microsystems - Beijing China 				break;
74523fced439Szhongyan gu - Sun Microsystems - Beijing China 			}
74533fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
745458bc78c7SXin Chen 
745558bc78c7SXin Chen 		AAC_DEVCFG_BEGIN(softs, tgt);
745658bc78c7SXin Chen 		rval = aac_config_lun(softs, tgt, lun, childp);
745758bc78c7SXin Chen 		AAC_DEVCFG_END(softs, tgt);
745858bc78c7SXin Chen 		break;
745958bc78c7SXin Chen 	}
746058bc78c7SXin Chen 
746158bc78c7SXin Chen 	case BUS_CONFIG_DRIVER:
746258bc78c7SXin Chen 	case BUS_CONFIG_ALL: {
746358bc78c7SXin Chen 		uint32_t bus, tgt;
746458bc78c7SXin Chen 		int index, total;
746558bc78c7SXin Chen 
746658bc78c7SXin Chen 		for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
746758bc78c7SXin Chen 			AAC_DEVCFG_BEGIN(softs, tgt);
746858bc78c7SXin Chen 			(void) aac_config_lun(softs, tgt, 0, NULL);
746958bc78c7SXin Chen 			AAC_DEVCFG_END(softs, tgt);
747058bc78c7SXin Chen 		}
747158bc78c7SXin Chen 
747258bc78c7SXin Chen 		/* Config the non-DASD devices connected to the card */
747358bc78c7SXin Chen 		total = 0;
747458bc78c7SXin Chen 		index = AAC_MAX_LD;
747558bc78c7SXin Chen 		for (bus = 0; bus < softs->bus_max; bus++) {
747658bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
747758bc78c7SXin Chen 			for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
747858bc78c7SXin Chen 				AAC_DEVCFG_BEGIN(softs, index);
747958bc78c7SXin Chen 				if (aac_config_tgt(softs, index))
748058bc78c7SXin Chen 					total++;
748158bc78c7SXin Chen 				AAC_DEVCFG_END(softs, index);
748258bc78c7SXin Chen 			}
748358bc78c7SXin Chen 		}
748458bc78c7SXin Chen 		AACDB_PRINT(softs, CE_CONT,
748558bc78c7SXin Chen 		    "?Total %d phys. device(s) found", total);
748658bc78c7SXin Chen 		rval = NDI_SUCCESS;
748758bc78c7SXin Chen 		break;
748858bc78c7SXin Chen 	}
748958bc78c7SXin Chen 	}
749058bc78c7SXin Chen 
749158bc78c7SXin Chen 	if (rval == NDI_SUCCESS)
749258bc78c7SXin Chen 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
7493*3fe80ca4SDan Cross 	ndi_devi_exit(parent);
749458bc78c7SXin Chen 	return (rval);
749558bc78c7SXin Chen }
749658bc78c7SXin Chen 
74970749e8deSXin Chen - Sun Microsystems - Beijing China /*ARGSUSED*/
74980749e8deSXin Chen - Sun Microsystems - Beijing China static int
aac_handle_dr(struct aac_softstate * softs,int tgt,int lun,int event)74990749e8deSXin Chen - Sun Microsystems - Beijing China aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
750058bc78c7SXin Chen {
750158bc78c7SXin Chen 	struct aac_device *dvp;
750258bc78c7SXin Chen 	dev_info_t *dip;
750358bc78c7SXin Chen 	int valid;
750458bc78c7SXin Chen 
750558bc78c7SXin Chen 	DBCALLED(softs, 1);
750658bc78c7SXin Chen 
750758bc78c7SXin Chen 	/* Hold the nexus across the bus_config */
75080749e8deSXin Chen - Sun Microsystems - Beijing China 	dvp = AAC_DEV(softs, tgt);
750958bc78c7SXin Chen 	valid = AAC_DEV_IS_VALID(dvp);
751058bc78c7SXin Chen 	dip = dvp->dip;
75110749e8deSXin Chen - Sun Microsystems - Beijing China 	if (!(softs->state & AAC_STATE_RUN))
75120749e8deSXin Chen - Sun Microsystems - Beijing China 		return (AACERR);
751358bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
751458bc78c7SXin Chen 
75150749e8deSXin Chen - Sun Microsystems - Beijing China 	switch (event) {
75160749e8deSXin Chen - Sun Microsystems - Beijing China 	case AAC_CFG_ADD:
75170749e8deSXin Chen - Sun Microsystems - Beijing China 	case AAC_CFG_DELETE:
751858bc78c7SXin Chen 		/* Device onlined */
751958bc78c7SXin Chen 		if (dip == NULL && valid) {
7520*3fe80ca4SDan Cross 			ndi_devi_enter(softs->devinfo_p);
75210749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_config_lun(softs, tgt, 0, NULL);
752258bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
75230749e8deSXin Chen - Sun Microsystems - Beijing China 			    softs->instance, tgt, lun);
7524*3fe80ca4SDan Cross 			ndi_devi_exit(softs->devinfo_p);
752558bc78c7SXin Chen 		}
752658bc78c7SXin Chen 		/* Device offlined */
752758bc78c7SXin Chen 		if (dip && !valid) {
752858bc78c7SXin Chen 			mutex_enter(&softs->io_lock);
752958bc78c7SXin Chen 			(void) aac_do_reset(softs);
753058bc78c7SXin Chen 			mutex_exit(&softs->io_lock);
753158bc78c7SXin Chen 
753258bc78c7SXin Chen 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
753358bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
75340749e8deSXin Chen - Sun Microsystems - Beijing China 			    softs->instance, tgt, lun);
753558bc78c7SXin Chen 		}
753658bc78c7SXin Chen 		break;
753758bc78c7SXin Chen 	}
753858bc78c7SXin Chen 
75390749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
754058bc78c7SXin Chen 	return (AACOK);
754158bc78c7SXin Chen }
754258bc78c7SXin Chen 
75431dd0a2dbSpl #ifdef DEBUG
75447c478bd9Sstevel@tonic-gate 
75457c478bd9Sstevel@tonic-gate /* -------------------------debug aid functions-------------------------- */
7546830d82f7Spl 
7547830d82f7Spl #define	AAC_FIB_CMD_KEY_STRINGS \
7548830d82f7Spl 	TestCommandResponse, "TestCommandResponse", \
7549830d82f7Spl 	TestAdapterCommand, "TestAdapterCommand", \
7550830d82f7Spl 	LastTestCommand, "LastTestCommand", \
7551830d82f7Spl 	ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
7552830d82f7Spl 	ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
7553830d82f7Spl 	ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
7554830d82f7Spl 	ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
7555830d82f7Spl 	ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
7556830d82f7Spl 	ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
7557830d82f7Spl 	ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
7558830d82f7Spl 	ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
7559830d82f7Spl 	InterfaceShutdown, "InterfaceShutdown", \
7560830d82f7Spl 	DmaCommandFib, "DmaCommandFib", \
7561830d82f7Spl 	StartProfile, "StartProfile", \
7562830d82f7Spl 	TermProfile, "TermProfile", \
7563830d82f7Spl 	SpeedTest, "SpeedTest", \
7564830d82f7Spl 	TakeABreakPt, "TakeABreakPt", \
7565830d82f7Spl 	RequestPerfData, "RequestPerfData", \
7566830d82f7Spl 	SetInterruptDefTimer, "SetInterruptDefTimer", \
7567830d82f7Spl 	SetInterruptDefCount, "SetInterruptDefCount", \
7568830d82f7Spl 	GetInterruptDefStatus, "GetInterruptDefStatus", \
7569830d82f7Spl 	LastCommCommand, "LastCommCommand", \
7570830d82f7Spl 	NuFileSystem, "NuFileSystem", \
7571830d82f7Spl 	UFS, "UFS", \
7572830d82f7Spl 	HostFileSystem, "HostFileSystem", \
7573830d82f7Spl 	LastFileSystemCommand, "LastFileSystemCommand", \
7574830d82f7Spl 	ContainerCommand, "ContainerCommand", \
7575830d82f7Spl 	ContainerCommand64, "ContainerCommand64", \
7576830d82f7Spl 	ClusterCommand, "ClusterCommand", \
7577830d82f7Spl 	ScsiPortCommand, "ScsiPortCommand", \
7578830d82f7Spl 	ScsiPortCommandU64, "ScsiPortCommandU64", \
7579830d82f7Spl 	AifRequest, "AifRequest", \
7580830d82f7Spl 	CheckRevision, "CheckRevision", \
7581830d82f7Spl 	FsaHostShutdown, "FsaHostShutdown", \
7582830d82f7Spl 	RequestAdapterInfo, "RequestAdapterInfo", \
7583830d82f7Spl 	IsAdapterPaused, "IsAdapterPaused", \
7584830d82f7Spl 	SendHostTime, "SendHostTime", \
7585830d82f7Spl 	LastMiscCommand, "LastMiscCommand"
7586830d82f7Spl 
7587830d82f7Spl #define	AAC_CTVM_SUBCMD_KEY_STRINGS \
7588830d82f7Spl 	VM_Null, "VM_Null", \
7589830d82f7Spl 	VM_NameServe, "VM_NameServe", \
7590830d82f7Spl 	VM_ContainerConfig, "VM_ContainerConfig", \
7591830d82f7Spl 	VM_Ioctl, "VM_Ioctl", \
7592830d82f7Spl 	VM_FilesystemIoctl, "VM_FilesystemIoctl", \
7593830d82f7Spl 	VM_CloseAll, "VM_CloseAll", \
7594830d82f7Spl 	VM_CtBlockRead, "VM_CtBlockRead", \
7595830d82f7Spl 	VM_CtBlockWrite, "VM_CtBlockWrite", \
7596830d82f7Spl 	VM_SliceBlockRead, "VM_SliceBlockRead", \
7597830d82f7Spl 	VM_SliceBlockWrite, "VM_SliceBlockWrite", \
7598830d82f7Spl 	VM_DriveBlockRead, "VM_DriveBlockRead", \
7599830d82f7Spl 	VM_DriveBlockWrite, "VM_DriveBlockWrite", \
7600830d82f7Spl 	VM_EnclosureMgt, "VM_EnclosureMgt", \
7601830d82f7Spl 	VM_Unused, "VM_Unused", \
7602830d82f7Spl 	VM_CtBlockVerify, "VM_CtBlockVerify", \
7603830d82f7Spl 	VM_CtPerf, "VM_CtPerf", \
7604830d82f7Spl 	VM_CtBlockRead64, "VM_CtBlockRead64", \
7605830d82f7Spl 	VM_CtBlockWrite64, "VM_CtBlockWrite64", \
7606830d82f7Spl 	VM_CtBlockVerify64, "VM_CtBlockVerify64", \
7607830d82f7Spl 	VM_CtHostRead64, "VM_CtHostRead64", \
7608830d82f7Spl 	VM_CtHostWrite64, "VM_CtHostWrite64", \
7609830d82f7Spl 	VM_NameServe64, "VM_NameServe64"
7610830d82f7Spl 
7611830d82f7Spl #define	AAC_CT_SUBCMD_KEY_STRINGS \
7612830d82f7Spl 	CT_Null, "CT_Null", \
7613830d82f7Spl 	CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
7614830d82f7Spl 	CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
7615830d82f7Spl 	CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
7616830d82f7Spl 	CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
7617830d82f7Spl 	CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
7618830d82f7Spl 	CT_WRITE_MBR, "CT_WRITE_MBR", \
7619830d82f7Spl 	CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
7620830d82f7Spl 	CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
7621830d82f7Spl 	CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
7622830d82f7Spl 	CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
7623830d82f7Spl 	CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
7624830d82f7Spl 	CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
7625830d82f7Spl 	CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
7626830d82f7Spl 	CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
7627830d82f7Spl 	CT_READ_MBR, "CT_READ_MBR", \
7628830d82f7Spl 	CT_READ_PARTITION, "CT_READ_PARTITION", \
7629830d82f7Spl 	CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
7630830d82f7Spl 	CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
7631830d82f7Spl 	CT_SLICE_SIZE, "CT_SLICE_SIZE", \
7632830d82f7Spl 	CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
7633830d82f7Spl 	CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
7634830d82f7Spl 	CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
7635830d82f7Spl 	CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
7636830d82f7Spl 	CT_UNMIRROR, "CT_UNMIRROR", \
7637830d82f7Spl 	CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
7638830d82f7Spl 	CT_GEN_MIRROR, "CT_GEN_MIRROR", \
7639830d82f7Spl 	CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
7640830d82f7Spl 	CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
7641830d82f7Spl 	CT_MOVE2, "CT_MOVE2", \
7642830d82f7Spl 	CT_SPLIT, "CT_SPLIT", \
7643830d82f7Spl 	CT_SPLIT2, "CT_SPLIT2", \
7644830d82f7Spl 	CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
7645830d82f7Spl 	CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
7646830d82f7Spl 	CT_RECONFIG, "CT_RECONFIG", \
7647830d82f7Spl 	CT_BREAK2, "CT_BREAK2", \
7648830d82f7Spl 	CT_BREAK, "CT_BREAK", \
7649830d82f7Spl 	CT_MERGE2, "CT_MERGE2", \
7650830d82f7Spl 	CT_MERGE, "CT_MERGE", \
7651830d82f7Spl 	CT_FORCE_ERROR, "CT_FORCE_ERROR", \
7652830d82f7Spl 	CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
7653830d82f7Spl 	CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
7654830d82f7Spl 	CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
7655830d82f7Spl 	CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
7656830d82f7Spl 	CT_VOLUME_ADD, "CT_VOLUME_ADD", \
7657830d82f7Spl 	CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
7658830d82f7Spl 	CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
7659830d82f7Spl 	CT_COPY_STATUS, "CT_COPY_STATUS", \
7660830d82f7Spl 	CT_COPY, "CT_COPY", \
7661830d82f7Spl 	CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
7662830d82f7Spl 	CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
7663830d82f7Spl 	CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
7664830d82f7Spl 	CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
7665830d82f7Spl 	CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
7666830d82f7Spl 	CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
7667830d82f7Spl 	CT_SET, "CT_SET", \
7668830d82f7Spl 	CT_GET, "CT_GET", \
7669830d82f7Spl 	CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
7670830d82f7Spl 	CT_GET_DELAY, "CT_GET_DELAY", \
7671830d82f7Spl 	CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
7672830d82f7Spl 	CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
7673830d82f7Spl 	CT_SCRUB, "CT_SCRUB", \
7674830d82f7Spl 	CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
7675830d82f7Spl 	CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
7676830d82f7Spl 	CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
7677830d82f7Spl 	CT_PAUSE_IO, "CT_PAUSE_IO", \
7678830d82f7Spl 	CT_RELEASE_IO, "CT_RELEASE_IO", \
7679830d82f7Spl 	CT_SCRUB2, "CT_SCRUB2", \
7680830d82f7Spl 	CT_MCHECK, "CT_MCHECK", \
7681830d82f7Spl 	CT_CORRUPT, "CT_CORRUPT", \
7682830d82f7Spl 	CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
7683830d82f7Spl 	CT_PROMOTE, "CT_PROMOTE", \
7684830d82f7Spl 	CT_SET_DEAD, "CT_SET_DEAD", \
7685830d82f7Spl 	CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
7686830d82f7Spl 	CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
7687830d82f7Spl 	CT_GET_PARAM, "CT_GET_PARAM", \
7688830d82f7Spl 	CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
7689830d82f7Spl 	CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
7690830d82f7Spl 	CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
7691830d82f7Spl 	CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
7692830d82f7Spl 	CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
7693830d82f7Spl 	CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
7694830d82f7Spl 	CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
7695830d82f7Spl 	CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
7696830d82f7Spl 	CT_STOP_DATA, "CT_STOP_DATA", \
7697830d82f7Spl 	CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
7698830d82f7Spl 	CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
7699830d82f7Spl 	CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
7700830d82f7Spl 	CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
7701830d82f7Spl 	CT_GET_TIME, "CT_GET_TIME", \
7702830d82f7Spl 	CT_READ_DATA, "CT_READ_DATA", \
7703830d82f7Spl 	CT_CTR, "CT_CTR", \
7704830d82f7Spl 	CT_CTL, "CT_CTL", \
7705830d82f7Spl 	CT_DRAINIO, "CT_DRAINIO", \
7706830d82f7Spl 	CT_RELEASEIO, "CT_RELEASEIO", \
7707830d82f7Spl 	CT_GET_NVRAM, "CT_GET_NVRAM", \
7708830d82f7Spl 	CT_GET_MEMORY, "CT_GET_MEMORY", \
7709830d82f7Spl 	CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
7710830d82f7Spl 	CT_ADD_LEVEL, "CT_ADD_LEVEL", \
7711830d82f7Spl 	CT_NV_ZERO, "CT_NV_ZERO", \
7712830d82f7Spl 	CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
7713830d82f7Spl 	CT_THROTTLE_ON, "CT_THROTTLE_ON", \
7714830d82f7Spl 	CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
7715830d82f7Spl 	CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
7716830d82f7Spl 	CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
7717830d82f7Spl 	CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
7718830d82f7Spl 	CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
7719830d82f7Spl 	CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
7720830d82f7Spl 	CT_MONITOR, "CT_MONITOR", \
7721830d82f7Spl 	CT_GEN_MORPH, "CT_GEN_MORPH", \
7722830d82f7Spl 	CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
7723830d82f7Spl 	CT_CACHE_SET, "CT_CACHE_SET", \
7724830d82f7Spl 	CT_CACHE_STAT, "CT_CACHE_STAT", \
7725830d82f7Spl 	CT_TRACE_START, "CT_TRACE_START", \
7726830d82f7Spl 	CT_TRACE_STOP, "CT_TRACE_STOP", \
7727830d82f7Spl 	CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
7728830d82f7Spl 	CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
7729830d82f7Spl 	CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
7730830d82f7Spl 	CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
7731830d82f7Spl 	CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
7732830d82f7Spl 	CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
7733830d82f7Spl 	CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
7734830d82f7Spl 	CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
7735830d82f7Spl 	CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
7736830d82f7Spl 	CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
7737830d82f7Spl 	CT_STOP_DUMPS, "CT_STOP_DUMPS", \
7738830d82f7Spl 	CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
7739830d82f7Spl 	CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
7740830d82f7Spl 	CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
7741830d82f7Spl 	CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
7742830d82f7Spl 	CT_READ_NAME, "CT_READ_NAME", \
7743830d82f7Spl 	CT_WRITE_NAME, "CT_WRITE_NAME", \
7744830d82f7Spl 	CT_TOSS_CACHE, "CT_TOSS_CACHE", \
7745830d82f7Spl 	CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
7746830d82f7Spl 	CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
7747830d82f7Spl 	CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
7748830d82f7Spl 	CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
7749830d82f7Spl 	CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
7750830d82f7Spl 	CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
7751830d82f7Spl 	CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
7752830d82f7Spl 	CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
7753830d82f7Spl 	CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
7754830d82f7Spl 	CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
7755830d82f7Spl 	CT_FLUSH, "CT_FLUSH", \
7756830d82f7Spl 	CT_REBUILD, "CT_REBUILD", \
7757830d82f7Spl 	CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
7758830d82f7Spl 	CT_RESTART, "CT_RESTART", \
7759830d82f7Spl 	CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
7760830d82f7Spl 	CT_TRACE_FLAG, "CT_TRACE_FLAG", \
7761830d82f7Spl 	CT_RESTART_MORPH, "CT_RESTART_MORPH", \
7762830d82f7Spl 	CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
7763830d82f7Spl 	CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
7764830d82f7Spl 	CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
7765830d82f7Spl 	CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
7766830d82f7Spl 	CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
7767830d82f7Spl 	CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
7768830d82f7Spl 	CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
7769830d82f7Spl 	CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
7770830d82f7Spl 	CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
7771830d82f7Spl 	CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
7772830d82f7Spl 	CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
7773830d82f7Spl 	CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
7774830d82f7Spl 	CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
7775830d82f7Spl 	CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
7776830d82f7Spl 	CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
7777830d82f7Spl 	CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
7778830d82f7Spl 	CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
7779830d82f7Spl 	CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
7780830d82f7Spl 	CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
7781830d82f7Spl 	CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
7782830d82f7Spl 	CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
7783830d82f7Spl 	CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
7784830d82f7Spl 	CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
7785830d82f7Spl 	CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
7786830d82f7Spl 	CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
7787830d82f7Spl 	CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
7788830d82f7Spl 	CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
7789830d82f7Spl 	CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
7790830d82f7Spl 	CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
7791830d82f7Spl 	CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
7792830d82f7Spl 	CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
7793830d82f7Spl 	CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
7794830d82f7Spl 	CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
7795830d82f7Spl 	CT_IS_CONTAINER_MEATADATA_STANDARD, \
7796c9487164Spl 	    "CT_IS_CONTAINER_MEATADATA_STANDARD", \
7797830d82f7Spl 	CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
7798830d82f7Spl 	CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
7799830d82f7Spl 	CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
7800830d82f7Spl 	CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
7801830d82f7Spl 	CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
7802830d82f7Spl 	CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
7803830d82f7Spl 	CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
7804830d82f7Spl 	CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
7805830d82f7Spl 	CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
7806830d82f7Spl 	CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
7807830d82f7Spl 	CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
7808830d82f7Spl 	CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
7809830d82f7Spl 	CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
7810830d82f7Spl 	CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
7811830d82f7Spl 	CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
7812830d82f7Spl 	CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
7813830d82f7Spl 	CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
7814830d82f7Spl 	CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
7815830d82f7Spl 	CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
7816830d82f7Spl 
7817830d82f7Spl #define	AAC_CL_SUBCMD_KEY_STRINGS \
7818830d82f7Spl 	CL_NULL, "CL_NULL", \
7819830d82f7Spl 	DS_INIT, "DS_INIT", \
7820830d82f7Spl 	DS_RESCAN, "DS_RESCAN", \
7821830d82f7Spl 	DS_CREATE, "DS_CREATE", \
7822830d82f7Spl 	DS_DELETE, "DS_DELETE", \
7823830d82f7Spl 	DS_ADD_DISK, "DS_ADD_DISK", \
7824830d82f7Spl 	DS_REMOVE_DISK, "DS_REMOVE_DISK", \
7825830d82f7Spl 	DS_MOVE_DISK, "DS_MOVE_DISK", \
7826830d82f7Spl 	DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
7827830d82f7Spl 	DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
7828830d82f7Spl 	DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
7829830d82f7Spl 	DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
7830830d82f7Spl 	DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
7831830d82f7Spl 	DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
7832830d82f7Spl 	DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
7833830d82f7Spl 	DS_GET_DRIVES, "DS_GET_DRIVES", \
7834830d82f7Spl 	DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
7835830d82f7Spl 	DS_ONLINE, "DS_ONLINE", \
7836830d82f7Spl 	DS_OFFLINE, "DS_OFFLINE", \
7837830d82f7Spl 	DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
7838830d82f7Spl 	DS_FSAPRINT, "DS_FSAPRINT", \
7839830d82f7Spl 	CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
7840830d82f7Spl 	CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
7841830d82f7Spl 	CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
7842830d82f7Spl 	CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
7843830d82f7Spl 	CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
7844830d82f7Spl 	CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
7845830d82f7Spl 	CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
7846830d82f7Spl 	CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
7847830d82f7Spl 	CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
7848830d82f7Spl 	CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
7849830d82f7Spl 	CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
7850830d82f7Spl 	CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
7851830d82f7Spl 	CC_GET_BUSINFO, "CC_GET_BUSINFO", \
7852830d82f7Spl 	CC_GET_PORTINFO, "CC_GET_PORTINFO", \
7853830d82f7Spl 	CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
7854830d82f7Spl 	CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
7855830d82f7Spl 	CQ_QUORUM_OP, "CQ_QUORUM_OP"
7856830d82f7Spl 
7857830d82f7Spl #define	AAC_AIF_SUBCMD_KEY_STRINGS \
7858830d82f7Spl 	AifCmdEventNotify, "AifCmdEventNotify", \
7859830d82f7Spl 	AifCmdJobProgress, "AifCmdJobProgress", \
7860830d82f7Spl 	AifCmdAPIReport, "AifCmdAPIReport", \
7861830d82f7Spl 	AifCmdDriverNotify, "AifCmdDriverNotify", \
7862830d82f7Spl 	AifReqJobList, "AifReqJobList", \
7863830d82f7Spl 	AifReqJobsForCtr, "AifReqJobsForCtr", \
7864830d82f7Spl 	AifReqJobsForScsi, "AifReqJobsForScsi", \
7865830d82f7Spl 	AifReqJobReport, "AifReqJobReport", \
7866830d82f7Spl 	AifReqTerminateJob, "AifReqTerminateJob", \
7867830d82f7Spl 	AifReqSuspendJob, "AifReqSuspendJob", \
7868830d82f7Spl 	AifReqResumeJob, "AifReqResumeJob", \
7869830d82f7Spl 	AifReqSendAPIReport, "AifReqSendAPIReport", \
7870830d82f7Spl 	AifReqAPIJobStart, "AifReqAPIJobStart", \
7871830d82f7Spl 	AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
7872830d82f7Spl 	AifReqAPIJobFinish, "AifReqAPIJobFinish"
7873830d82f7Spl 
7874830d82f7Spl #define	AAC_IOCTL_SUBCMD_KEY_STRINGS \
7875830d82f7Spl 	Reserved_IOCTL, "Reserved_IOCTL", \
7876830d82f7Spl 	GetDeviceHandle, "GetDeviceHandle", \
7877830d82f7Spl 	BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
7878830d82f7Spl 	DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
7879830d82f7Spl 	RescanBus, "RescanBus", \
7880830d82f7Spl 	GetDeviceProbeInfo, "GetDeviceProbeInfo", \
7881830d82f7Spl 	GetDeviceCapacity, "GetDeviceCapacity", \
7882830d82f7Spl 	GetContainerProbeInfo, "GetContainerProbeInfo", \
7883830d82f7Spl 	GetRequestedMemorySize, "GetRequestedMemorySize", \
7884830d82f7Spl 	GetBusInfo, "GetBusInfo", \
7885830d82f7Spl 	GetVendorSpecific, "GetVendorSpecific", \
7886830d82f7Spl 	EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
7887830d82f7Spl 	EnhancedGetBusInfo, "EnhancedGetBusInfo", \
7888830d82f7Spl 	SetupExtendedCounters, "SetupExtendedCounters", \
7889830d82f7Spl 	GetPerformanceCounters, "GetPerformanceCounters", \
7890830d82f7Spl 	ResetPerformanceCounters, "ResetPerformanceCounters", \
7891830d82f7Spl 	ReadModePage, "ReadModePage", \
7892830d82f7Spl 	WriteModePage, "WriteModePage", \
7893830d82f7Spl 	ReadDriveParameter, "ReadDriveParameter", \
7894830d82f7Spl 	WriteDriveParameter, "WriteDriveParameter", \
7895830d82f7Spl 	ResetAdapter, "ResetAdapter", \
7896830d82f7Spl 	ResetBus, "ResetBus", \
7897830d82f7Spl 	ResetBusDevice, "ResetBusDevice", \
7898830d82f7Spl 	ExecuteSrb, "ExecuteSrb", \
7899830d82f7Spl 	Create_IO_Task, "Create_IO_Task", \
7900830d82f7Spl 	Delete_IO_Task, "Delete_IO_Task", \
7901830d82f7Spl 	Get_IO_Task_Info, "Get_IO_Task_Info", \
7902830d82f7Spl 	Check_Task_Progress, "Check_Task_Progress", \
7903830d82f7Spl 	InjectError, "InjectError", \
7904830d82f7Spl 	GetDeviceDefectCounts, "GetDeviceDefectCounts", \
7905830d82f7Spl 	GetDeviceDefectInfo, "GetDeviceDefectInfo", \
7906830d82f7Spl 	GetDeviceStatus, "GetDeviceStatus", \
7907830d82f7Spl 	ClearDeviceStatus, "ClearDeviceStatus", \
7908830d82f7Spl 	DiskSpinControl, "DiskSpinControl", \
7909830d82f7Spl 	DiskSmartControl, "DiskSmartControl", \
7910830d82f7Spl 	WriteSame, "WriteSame", \
7911830d82f7Spl 	ReadWriteLong, "ReadWriteLong", \
7912830d82f7Spl 	FormatUnit, "FormatUnit", \
7913830d82f7Spl 	TargetDeviceControl, "TargetDeviceControl", \
7914830d82f7Spl 	TargetChannelControl, "TargetChannelControl", \
7915830d82f7Spl 	FlashNewCode, "FlashNewCode", \
7916830d82f7Spl 	DiskCheck, "DiskCheck", \
7917830d82f7Spl 	RequestSense, "RequestSense", \
7918830d82f7Spl 	DiskPERControl, "DiskPERControl", \
7919830d82f7Spl 	Read10, "Read10", \
7920830d82f7Spl 	Write10, "Write10"
7921830d82f7Spl 
7922830d82f7Spl #define	AAC_AIFEN_KEY_STRINGS \
7923830d82f7Spl 	AifEnGeneric, "Generic", \
7924830d82f7Spl 	AifEnTaskComplete, "TaskComplete", \
7925830d82f7Spl 	AifEnConfigChange, "Config change", \
7926830d82f7Spl 	AifEnContainerChange, "Container change", \
7927830d82f7Spl 	AifEnDeviceFailure, "device failed", \
7928830d82f7Spl 	AifEnMirrorFailover, "Mirror failover", \
7929830d82f7Spl 	AifEnContainerEvent, "container event", \
7930830d82f7Spl 	AifEnFileSystemChange, "File system changed", \
7931830d82f7Spl 	AifEnConfigPause, "Container pause event", \
7932830d82f7Spl 	AifEnConfigResume, "Container resume event", \
7933830d82f7Spl 	AifEnFailoverChange, "Failover space assignment changed", \
7934830d82f7Spl 	AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
7935830d82f7Spl 	AifEnEnclosureManagement, "Enclosure management event", \
7936830d82f7Spl 	AifEnBatteryEvent, "battery event", \
7937830d82f7Spl 	AifEnAddContainer, "Add container", \
7938830d82f7Spl 	AifEnDeleteContainer, "Delete container", \
7939830d82f7Spl 	AifEnSMARTEvent, "SMART Event", \
7940830d82f7Spl 	AifEnBatteryNeedsRecond, "battery needs reconditioning", \
7941830d82f7Spl 	AifEnClusterEvent, "cluster event", \
7942830d82f7Spl 	AifEnDiskSetEvent, "disk set event occured", \
7943830d82f7Spl 	AifDenMorphComplete, "morph operation completed", \
7944830d82f7Spl 	AifDenVolumeExtendComplete, "VolumeExtendComplete"
7945830d82f7Spl 
7946830d82f7Spl struct aac_key_strings {
7947830d82f7Spl 	int key;
7948830d82f7Spl 	char *message;
7949830d82f7Spl };
7950830d82f7Spl 
7951830d82f7Spl extern struct scsi_key_strings scsi_cmds[];
7952830d82f7Spl 
7953830d82f7Spl static struct aac_key_strings aac_fib_cmds[] = {
7954830d82f7Spl 	AAC_FIB_CMD_KEY_STRINGS,
7955830d82f7Spl 	-1,			NULL
7956830d82f7Spl };
7957830d82f7Spl 
7958830d82f7Spl static struct aac_key_strings aac_ctvm_subcmds[] = {
7959830d82f7Spl 	AAC_CTVM_SUBCMD_KEY_STRINGS,
7960830d82f7Spl 	-1,			NULL
7961830d82f7Spl };
7962830d82f7Spl 
7963830d82f7Spl static struct aac_key_strings aac_ct_subcmds[] = {
7964830d82f7Spl 	AAC_CT_SUBCMD_KEY_STRINGS,
7965830d82f7Spl 	-1,			NULL
7966830d82f7Spl };
7967830d82f7Spl 
7968830d82f7Spl static struct aac_key_strings aac_cl_subcmds[] = {
7969830d82f7Spl 	AAC_CL_SUBCMD_KEY_STRINGS,
7970830d82f7Spl 	-1,			NULL
7971830d82f7Spl };
7972830d82f7Spl 
7973830d82f7Spl static struct aac_key_strings aac_aif_subcmds[] = {
7974830d82f7Spl 	AAC_AIF_SUBCMD_KEY_STRINGS,
7975830d82f7Spl 	-1,			NULL
7976830d82f7Spl };
7977830d82f7Spl 
7978830d82f7Spl static struct aac_key_strings aac_ioctl_subcmds[] = {
7979830d82f7Spl 	AAC_IOCTL_SUBCMD_KEY_STRINGS,
7980830d82f7Spl 	-1,			NULL
7981830d82f7Spl };
7982830d82f7Spl 
7983830d82f7Spl static struct aac_key_strings aac_aifens[] = {
7984830d82f7Spl 	AAC_AIFEN_KEY_STRINGS,
7985830d82f7Spl 	-1,			NULL
79867c478bd9Sstevel@tonic-gate };
79877c478bd9Sstevel@tonic-gate 
79881dd0a2dbSpl /*
79891dd0a2dbSpl  * The following function comes from Adaptec:
79901dd0a2dbSpl  *
79911dd0a2dbSpl  * Get the firmware print buffer parameters from the firmware,
79921dd0a2dbSpl  * if the command was successful map in the address.
79931dd0a2dbSpl  */
79941dd0a2dbSpl static int
aac_get_fw_debug_buffer(struct aac_softstate * softs)79951dd0a2dbSpl aac_get_fw_debug_buffer(struct aac_softstate *softs)
79961dd0a2dbSpl {
79971dd0a2dbSpl 	if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
79981dd0a2dbSpl 	    0, 0, 0, 0, NULL) == AACOK) {
79991dd0a2dbSpl 		uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
80001dd0a2dbSpl 		uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
80011dd0a2dbSpl 		uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
80021dd0a2dbSpl 		uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
80031dd0a2dbSpl 
80041dd0a2dbSpl 		if (mondrv_buf_size) {
80051dd0a2dbSpl 			uint32_t offset = mondrv_buf_paddrl - \
80061dd0a2dbSpl 			    softs->pci_mem_base_paddr;
80071dd0a2dbSpl 
80081dd0a2dbSpl 			/*
80091dd0a2dbSpl 			 * See if the address is already mapped in, and
80101dd0a2dbSpl 			 * if so set it up from the base address
80111dd0a2dbSpl 			 */
80121dd0a2dbSpl 			if ((mondrv_buf_paddrh == 0) &&
80131dd0a2dbSpl 			    (offset + mondrv_buf_size < softs->map_size)) {
8014942c5e3cSpl 				mutex_enter(&aac_prt_mutex);
80151dd0a2dbSpl 				softs->debug_buf_offset = offset;
80161dd0a2dbSpl 				softs->debug_header_size = mondrv_hdr_size;
80171dd0a2dbSpl 				softs->debug_buf_size = mondrv_buf_size;
80181dd0a2dbSpl 				softs->debug_fw_flags = 0;
8019942c5e3cSpl 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8020942c5e3cSpl 				mutex_exit(&aac_prt_mutex);
80211dd0a2dbSpl 
80221dd0a2dbSpl 				return (AACOK);
80231dd0a2dbSpl 			}
80241dd0a2dbSpl 		}
80251dd0a2dbSpl 	}
80261dd0a2dbSpl 	return (AACERR);
80271dd0a2dbSpl }
80281dd0a2dbSpl 
80291dd0a2dbSpl int
aac_dbflag_on(struct aac_softstate * softs,int flag)80301dd0a2dbSpl aac_dbflag_on(struct aac_softstate *softs, int flag)
80311dd0a2dbSpl {
80321dd0a2dbSpl 	int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
80331dd0a2dbSpl 
80341dd0a2dbSpl 	return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
80351dd0a2dbSpl 	    AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
80361dd0a2dbSpl }
80371dd0a2dbSpl 
8038942c5e3cSpl static void
aac_cmn_err(struct aac_softstate * softs,uint_t lev,char sl,int noheader)8039942c5e3cSpl aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
8040942c5e3cSpl {
8041942c5e3cSpl 	if (noheader) {
8042942c5e3cSpl 		if (sl) {
8043942c5e3cSpl 			aac_fmt[0] = sl;
8044942c5e3cSpl 			cmn_err(lev, aac_fmt, aac_prt_buf);
8045942c5e3cSpl 		} else {
8046942c5e3cSpl 			cmn_err(lev, &aac_fmt[1], aac_prt_buf);
8047942c5e3cSpl 		}
8048942c5e3cSpl 	} else {
8049942c5e3cSpl 		if (sl) {
8050942c5e3cSpl 			aac_fmt_header[0] = sl;
8051942c5e3cSpl 			cmn_err(lev, aac_fmt_header,
8052942c5e3cSpl 			    softs->vendor_name, softs->instance,
8053942c5e3cSpl 			    aac_prt_buf);
8054942c5e3cSpl 		} else {
8055942c5e3cSpl 			cmn_err(lev, &aac_fmt_header[1],
8056942c5e3cSpl 			    softs->vendor_name, softs->instance,
8057942c5e3cSpl 			    aac_prt_buf);
8058942c5e3cSpl 		}
8059942c5e3cSpl 	}
8060942c5e3cSpl }
8061942c5e3cSpl 
80621dd0a2dbSpl /*
80631dd0a2dbSpl  * The following function comes from Adaptec:
80641dd0a2dbSpl  *
80651dd0a2dbSpl  * Format and print out the data passed in to UART or console
80661dd0a2dbSpl  * as specified by debug flags.
80671dd0a2dbSpl  */
80681dd0a2dbSpl void
aac_printf(struct aac_softstate * softs,uint_t lev,const char * fmt,...)80691dd0a2dbSpl aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
80701dd0a2dbSpl {
80711dd0a2dbSpl 	va_list args;
8072942c5e3cSpl 	char sl; /* system log character */
80731dd0a2dbSpl 
80741dd0a2dbSpl 	mutex_enter(&aac_prt_mutex);
8075942c5e3cSpl 	/* Set up parameters and call sprintf function to format the data */
8076942c5e3cSpl 	if (strchr("^!?", fmt[0]) == NULL) {
8077942c5e3cSpl 		sl = 0;
8078942c5e3cSpl 	} else {
8079942c5e3cSpl 		sl = fmt[0];
8080942c5e3cSpl 		fmt++;
8081942c5e3cSpl 	}
80821dd0a2dbSpl 	va_start(args, fmt);
80831dd0a2dbSpl 	(void) vsprintf(aac_prt_buf, fmt, args);
80841dd0a2dbSpl 	va_end(args);
80851dd0a2dbSpl 
8086942c5e3cSpl 	/* Make sure the softs structure has been passed in for this section */
8087942c5e3cSpl 	if (softs) {
8088942c5e3cSpl 		if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
8089942c5e3cSpl 		    /* If we are set up for a Firmware print */
8090942c5e3cSpl 		    (softs->debug_buf_size)) {
8091942c5e3cSpl 			uint32_t count, i;
80921dd0a2dbSpl 
8093942c5e3cSpl 			/* Make sure the string size is within boundaries */
8094942c5e3cSpl 			count = strlen(aac_prt_buf);
8095942c5e3cSpl 			if (count > softs->debug_buf_size)
8096942c5e3cSpl 				count = (uint16_t)softs->debug_buf_size;
80971dd0a2dbSpl 
8098942c5e3cSpl 			/*
8099942c5e3cSpl 			 * Wait for no more than AAC_PRINT_TIMEOUT for the
8100942c5e3cSpl 			 * previous message length to clear (the handshake).
8101942c5e3cSpl 			 */
8102942c5e3cSpl 			for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
8103942c5e3cSpl 				if (!PCI_MEM_GET32(softs,
8104942c5e3cSpl 				    softs->debug_buf_offset + \
8105942c5e3cSpl 				    AAC_FW_DBG_STRLEN_OFFSET))
8106942c5e3cSpl 					break;
81071dd0a2dbSpl 
8108942c5e3cSpl 				drv_usecwait(1000);
8109942c5e3cSpl 			}
8110942c5e3cSpl 
8111942c5e3cSpl 			/*
8112942c5e3cSpl 			 * If the length is clear, copy over the message, the
8113942c5e3cSpl 			 * flags, and the length. Make sure the length is the
8114942c5e3cSpl 			 * last because that is the signal for the Firmware to
8115942c5e3cSpl 			 * pick it up.
8116942c5e3cSpl 			 */
8117942c5e3cSpl 			if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
8118942c5e3cSpl 			    AAC_FW_DBG_STRLEN_OFFSET)) {
8119942c5e3cSpl 				PCI_MEM_REP_PUT8(softs,
8120942c5e3cSpl 				    softs->debug_buf_offset + \
8121942c5e3cSpl 				    softs->debug_header_size,
8122942c5e3cSpl 				    aac_prt_buf, count);
8123942c5e3cSpl 				PCI_MEM_PUT32(softs,
8124942c5e3cSpl 				    softs->debug_buf_offset + \
8125942c5e3cSpl 				    AAC_FW_DBG_FLAGS_OFFSET,
8126942c5e3cSpl 				    softs->debug_fw_flags);
8127942c5e3cSpl 				PCI_MEM_PUT32(softs,
8128942c5e3cSpl 				    softs->debug_buf_offset + \
8129942c5e3cSpl 				    AAC_FW_DBG_STRLEN_OFFSET, count);
8130942c5e3cSpl 			} else {
8131942c5e3cSpl 				cmn_err(CE_WARN, "UART output fail");
8132942c5e3cSpl 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8133942c5e3cSpl 			}
81341dd0a2dbSpl 		}
81351dd0a2dbSpl 
81361dd0a2dbSpl 		/*
8137942c5e3cSpl 		 * If the Kernel Debug Print flag is set, send it off
8138942c5e3cSpl 		 * to the Kernel Debugger
81391dd0a2dbSpl 		 */
8140942c5e3cSpl 		if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8141942c5e3cSpl 			aac_cmn_err(softs, lev, sl,
8142942c5e3cSpl 			    (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
8143942c5e3cSpl 	} else {
8144942c5e3cSpl 		/* Driver not initialized yet, no firmware or header output */
8145942c5e3cSpl 		if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8146942c5e3cSpl 			aac_cmn_err(softs, lev, sl, 1);
81471dd0a2dbSpl 	}
81481dd0a2dbSpl 	mutex_exit(&aac_prt_mutex);
81491dd0a2dbSpl }
81501dd0a2dbSpl 
8151830d82f7Spl /*
8152830d82f7Spl  * Translate command number to description string
8153830d82f7Spl  */
81547c478bd9Sstevel@tonic-gate static char *
aac_cmd_name(int cmd,struct aac_key_strings * cmdlist)8155830d82f7Spl aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
8156830d82f7Spl {
8157830d82f7Spl 	int i;
8158830d82f7Spl 
8159830d82f7Spl 	for (i = 0; cmdlist[i].key != -1; i++) {
8160830d82f7Spl 		if (cmd == cmdlist[i].key)
8161830d82f7Spl 			return (cmdlist[i].message);
8162830d82f7Spl 	}
8163830d82f7Spl 	return (NULL);
8164830d82f7Spl }
8165830d82f7Spl 
8166830d82f7Spl static void
aac_print_scmd(struct aac_softstate * softs,struct aac_cmd * acp)81671dd0a2dbSpl aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
81687c478bd9Sstevel@tonic-gate {
81691dd0a2dbSpl 	struct scsi_pkt *pkt = acp->pkt;
8170830d82f7Spl 	struct scsi_address *ap = &pkt->pkt_address;
817158bc78c7SXin Chen 	int is_pd = 0;
81721dd0a2dbSpl 	int ctl = ddi_get_instance(softs->devinfo_p);
8173830d82f7Spl 	int tgt = ap->a_target;
8174830d82f7Spl 	int lun = ap->a_lun;
8175a74f7440Spl 	union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
8176830d82f7Spl 	uchar_t cmd = cdbp->scc_cmd;
8177830d82f7Spl 	char *desc;
8178830d82f7Spl 
817958bc78c7SXin Chen 	if (tgt >= AAC_MAX_LD) {
818058bc78c7SXin Chen 		is_pd = 1;
818158bc78c7SXin Chen 		ctl = ((struct aac_nondasd *)acp->dvp)->bus;
818258bc78c7SXin Chen 		tgt = ((struct aac_nondasd *)acp->dvp)->tid;
818358bc78c7SXin Chen 		lun = 0;
818458bc78c7SXin Chen 	}
818558bc78c7SXin Chen 
8186830d82f7Spl 	if ((desc = aac_cmd_name(cmd,
8187c9487164Spl 	    (struct aac_key_strings *)scsi_cmds)) == NULL) {
81881dd0a2dbSpl 		aac_printf(softs, CE_NOTE,
818958bc78c7SXin Chen 		    "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
819058bc78c7SXin Chen 		    cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
8191830d82f7Spl 		return;
8192830d82f7Spl 	}
8193830d82f7Spl 
81947c478bd9Sstevel@tonic-gate 	switch (cmd) {
8195830d82f7Spl 	case SCMD_READ:
8196830d82f7Spl 	case SCMD_WRITE:
81971dd0a2dbSpl 		aac_printf(softs, CE_NOTE,
819858bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
81991dd0a2dbSpl 		    desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
82001dd0a2dbSpl 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
820158bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8202830d82f7Spl 		break;
8203830d82f7Spl 	case SCMD_READ_G1:
8204830d82f7Spl 	case SCMD_WRITE_G1:
82051dd0a2dbSpl 		aac_printf(softs, CE_NOTE,
820658bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
82071dd0a2dbSpl 		    desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
82081dd0a2dbSpl 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
820958bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8210830d82f7Spl 		break;
8211830d82f7Spl 	case SCMD_READ_G4:
8212830d82f7Spl 	case SCMD_WRITE_G4:
82131dd0a2dbSpl 		aac_printf(softs, CE_NOTE,
821458bc78c7SXin Chen 		    "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
82151dd0a2dbSpl 		    desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
82161dd0a2dbSpl 		    GETG4COUNT(cdbp),
82171dd0a2dbSpl 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
821858bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
821958bc78c7SXin Chen 		break;
822058bc78c7SXin Chen 	case SCMD_READ_G5:
822158bc78c7SXin Chen 	case SCMD_WRITE_G5:
822258bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
822358bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
822458bc78c7SXin Chen 		    desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
822558bc78c7SXin Chen 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
822658bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8227830d82f7Spl 		break;
8228830d82f7Spl 	default:
822958bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
823058bc78c7SXin Chen 		    desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
8231830d82f7Spl 	}
8232830d82f7Spl }
8233830d82f7Spl 
8234830d82f7Spl void
aac_print_fib(struct aac_softstate * softs,struct aac_slot * slotp)823558bc78c7SXin Chen aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
8236830d82f7Spl {
823758bc78c7SXin Chen 	struct aac_cmd *acp = slotp->acp;
823858bc78c7SXin Chen 	struct aac_fib *fibp = slotp->fibp;
823958bc78c7SXin Chen 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
8240942c5e3cSpl 	uint16_t fib_size;
824158bc78c7SXin Chen 	uint32_t fib_cmd, sub_cmd;
8242830d82f7Spl 	char *cmdstr, *subcmdstr;
824358bc78c7SXin Chen 	char *caller;
824458bc78c7SXin Chen 	int i;
824558bc78c7SXin Chen 
824658bc78c7SXin Chen 	if (acp) {
824758bc78c7SXin Chen 		if (!(softs->debug_fib_flags & acp->fib_flags))
824858bc78c7SXin Chen 			return;
824958bc78c7SXin Chen 		if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
825058bc78c7SXin Chen 			caller = "SCMD";
825158bc78c7SXin Chen 		else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
825258bc78c7SXin Chen 			caller = "IOCTL";
825358bc78c7SXin Chen 		else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
825458bc78c7SXin Chen 			caller = "SRB";
825558bc78c7SXin Chen 		else
825658bc78c7SXin Chen 			return;
825758bc78c7SXin Chen 	} else {
825858bc78c7SXin Chen 		if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
825958bc78c7SXin Chen 			return;
826058bc78c7SXin Chen 		caller = "SYNC";
826158bc78c7SXin Chen 	}
8262830d82f7Spl 
826358bc78c7SXin Chen 	fib_cmd = ddi_get16(acc, &fibp->Header.Command);
8264830d82f7Spl 	cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
826558bc78c7SXin Chen 	sub_cmd = (uint32_t)-1;
8266830d82f7Spl 	subcmdstr = NULL;
8267830d82f7Spl 
826858bc78c7SXin Chen 	/* Print FIB header */
826958bc78c7SXin Chen 	if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
827058bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
827158bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     XferState  %d",
827258bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.XferState));
827358bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Command    %d",
827458bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.Command));
827558bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     StructType %d",
827658bc78c7SXin Chen 		    ddi_get8(acc, &fibp->Header.StructType));
827758bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Flags      0x%x",
827858bc78c7SXin Chen 		    ddi_get8(acc, &fibp->Header.Flags));
827958bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Size       %d",
828058bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.Size));
828158bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderSize %d",
828258bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.SenderSize));
828358bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderAddr 0x%x",
828458bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.SenderFibAddress));
828558bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     RcvrAddr   0x%x",
828658bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
828758bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderData 0x%x",
828858bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.SenderData));
828958bc78c7SXin Chen 	}
829058bc78c7SXin Chen 
829158bc78c7SXin Chen 	/* Print FIB data */
8292830d82f7Spl 	switch (fib_cmd) {
8293830d82f7Spl 	case ContainerCommand:
829458bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
829558bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
8296830d82f7Spl 		subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
8297830d82f7Spl 		if (subcmdstr == NULL)
8298830d82f7Spl 			break;
8299830d82f7Spl 
830058bc78c7SXin Chen 		switch (sub_cmd) {
830158bc78c7SXin Chen 		case VM_ContainerConfig: {
830258bc78c7SXin Chen 			struct aac_Container *pContainer =
830358bc78c7SXin Chen 			    (struct aac_Container *)fibp->data;
830458bc78c7SXin Chen 
830558bc78c7SXin Chen 			fib_cmd = sub_cmd;
830658bc78c7SXin Chen 			cmdstr = subcmdstr;
830758bc78c7SXin Chen 			sub_cmd = (uint32_t)-1;
830858bc78c7SXin Chen 			subcmdstr = NULL;
830958bc78c7SXin Chen 
831058bc78c7SXin Chen 			sub_cmd = ddi_get32(acc,
831158bc78c7SXin Chen 			    &pContainer->CTCommand.command);
8312830d82f7Spl 			subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
8313830d82f7Spl 			if (subcmdstr == NULL)
8314830d82f7Spl 				break;
83151dd0a2dbSpl 			aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
8316c9487164Spl 			    subcmdstr,
831758bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[0]),
831858bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[1]),
831958bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[2]));
8320830d82f7Spl 			return;
832158bc78c7SXin Chen 		}
832258bc78c7SXin Chen 
8323830d82f7Spl 		case VM_Ioctl:
832458bc78c7SXin Chen 			fib_cmd = sub_cmd;
832558bc78c7SXin Chen 			cmdstr = subcmdstr;
832658bc78c7SXin Chen 			sub_cmd = (uint32_t)-1;
832758bc78c7SXin Chen 			subcmdstr = NULL;
832858bc78c7SXin Chen 
832958bc78c7SXin Chen 			sub_cmd = ddi_get32(acc,
833058bc78c7SXin Chen 			    (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
8331830d82f7Spl 			subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
8332830d82f7Spl 			break;
833358bc78c7SXin Chen 
833458bc78c7SXin Chen 		case VM_CtBlockRead:
833558bc78c7SXin Chen 		case VM_CtBlockWrite: {
833658bc78c7SXin Chen 			struct aac_blockread *br =
833758bc78c7SXin Chen 			    (struct aac_blockread *)fibp->data;
833858bc78c7SXin Chen 			struct aac_sg_table *sg = &br->SgMap;
833958bc78c7SXin Chen 			uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
834058bc78c7SXin Chen 
834158bc78c7SXin Chen 			aac_printf(softs, CE_NOTE,
834258bc78c7SXin Chen 			    "FIB> %s Container %d  0x%x/%d", subcmdstr,
834358bc78c7SXin Chen 			    ddi_get32(acc, &br->ContainerId),
834458bc78c7SXin Chen 			    ddi_get32(acc, &br->BlockNumber),
834558bc78c7SXin Chen 			    ddi_get32(acc, &br->ByteCount));
834658bc78c7SXin Chen 			for (i = 0; i < sgcount; i++)
834758bc78c7SXin Chen 				aac_printf(softs, CE_NOTE,
834858bc78c7SXin Chen 				    "     %d: 0x%08x/%d", i,
834958bc78c7SXin Chen 				    ddi_get32(acc, &sg->SgEntry[i].SgAddress),
835058bc78c7SXin Chen 				    ddi_get32(acc, &sg->SgEntry[i]. \
835158bc78c7SXin Chen 				    SgByteCount));
835258bc78c7SXin Chen 			return;
835358bc78c7SXin Chen 		}
8354830d82f7Spl 		}
8355830d82f7Spl 		break;
8356830d82f7Spl 
835758bc78c7SXin Chen 	case ContainerCommand64: {
835858bc78c7SXin Chen 		struct aac_blockread64 *br =
835958bc78c7SXin Chen 		    (struct aac_blockread64 *)fibp->data;
836058bc78c7SXin Chen 		struct aac_sg_table64 *sg = &br->SgMap64;
836158bc78c7SXin Chen 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
836258bc78c7SXin Chen 		uint64_t sgaddr;
836358bc78c7SXin Chen 
836458bc78c7SXin Chen 		sub_cmd = br->Command;
836558bc78c7SXin Chen 		subcmdstr = NULL;
836658bc78c7SXin Chen 		if (sub_cmd == VM_CtHostRead64)
836758bc78c7SXin Chen 			subcmdstr = "VM_CtHostRead64";
836858bc78c7SXin Chen 		else if (sub_cmd == VM_CtHostWrite64)
836958bc78c7SXin Chen 			subcmdstr = "VM_CtHostWrite64";
837058bc78c7SXin Chen 		else
837158bc78c7SXin Chen 			break;
837258bc78c7SXin Chen 
837358bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
837458bc78c7SXin Chen 		    "FIB> %s Container %d  0x%x/%d", subcmdstr,
837558bc78c7SXin Chen 		    ddi_get16(acc, &br->ContainerId),
837658bc78c7SXin Chen 		    ddi_get32(acc, &br->BlockNumber),
837758bc78c7SXin Chen 		    ddi_get16(acc, &br->SectorCount));
837858bc78c7SXin Chen 		for (i = 0; i < sgcount; i++) {
837958bc78c7SXin Chen 			sgaddr = ddi_get64(acc,
838058bc78c7SXin Chen 			    &sg->SgEntry64[i].SgAddress);
838158bc78c7SXin Chen 			aac_printf(softs, CE_NOTE,
838258bc78c7SXin Chen 			    "     %d: 0x%08x.%08x/%d", i,
838358bc78c7SXin Chen 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
838458bc78c7SXin Chen 			    ddi_get32(acc, &sg->SgEntry64[i]. \
838558bc78c7SXin Chen 			    SgByteCount));
838658bc78c7SXin Chen 		}
838758bc78c7SXin Chen 		return;
838858bc78c7SXin Chen 	}
838958bc78c7SXin Chen 
839058bc78c7SXin Chen 	case RawIo: {
839158bc78c7SXin Chen 		struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
839258bc78c7SXin Chen 		struct aac_sg_tableraw *sg = &io->SgMapRaw;
839358bc78c7SXin Chen 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
839458bc78c7SXin Chen 		uint64_t sgaddr;
839558bc78c7SXin Chen 
839658bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
839758bc78c7SXin Chen 		    "FIB> RawIo Container %d  0x%llx/%d 0x%x",
839858bc78c7SXin Chen 		    ddi_get16(acc, &io->ContainerId),
839958bc78c7SXin Chen 		    ddi_get64(acc, &io->BlockNumber),
840058bc78c7SXin Chen 		    ddi_get32(acc, &io->ByteCount),
840158bc78c7SXin Chen 		    ddi_get16(acc, &io->Flags));
840258bc78c7SXin Chen 		for (i = 0; i < sgcount; i++) {
840358bc78c7SXin Chen 			sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
840458bc78c7SXin Chen 			aac_printf(softs, CE_NOTE, "     %d: 0x%08x.%08x/%d", i,
840558bc78c7SXin Chen 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
840658bc78c7SXin Chen 			    ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
840758bc78c7SXin Chen 		}
840858bc78c7SXin Chen 		return;
840958bc78c7SXin Chen 	}
841058bc78c7SXin Chen 
8411830d82f7Spl 	case ClusterCommand:
841258bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
841358bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8414830d82f7Spl 		subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
8415830d82f7Spl 		break;
8416830d82f7Spl 
8417830d82f7Spl 	case AifRequest:
841858bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
841958bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8420830d82f7Spl 		subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
8421830d82f7Spl 		break;
8422830d82f7Spl 
8423830d82f7Spl 	default:
8424830d82f7Spl 		break;
8425830d82f7Spl 	}
8426830d82f7Spl 
842758bc78c7SXin Chen 	fib_size = ddi_get16(acc, &(fibp->Header.Size));
8428830d82f7Spl 	if (subcmdstr)
84291dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8430942c5e3cSpl 		    subcmdstr, fib_size);
843158bc78c7SXin Chen 	else if (cmdstr && sub_cmd == (uint32_t)-1)
84321dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8433942c5e3cSpl 		    cmdstr, fib_size);
8434830d82f7Spl 	else if (cmdstr)
84351dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
8436942c5e3cSpl 		    cmdstr, sub_cmd, fib_size);
8437830d82f7Spl 	else
84381dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
8439942c5e3cSpl 		    fib_cmd, fib_size);
8440830d82f7Spl }
8441830d82f7Spl 
8442830d82f7Spl static void
aac_print_aif(struct aac_softstate * softs,struct aac_aif_command * aif)84431dd0a2dbSpl aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
8444830d82f7Spl {
8445942c5e3cSpl 	int aif_command;
8446942c5e3cSpl 	uint32_t aif_seqnumber;
8447942c5e3cSpl 	int aif_en_type;
8448830d82f7Spl 	char *str;
8449830d82f7Spl 
8450942c5e3cSpl 	aif_command = LE_32(aif->command);
8451942c5e3cSpl 	aif_seqnumber = LE_32(aif->seqNumber);
8452942c5e3cSpl 	aif_en_type = LE_32(aif->data.EN.type);
8453942c5e3cSpl 
8454942c5e3cSpl 	switch (aif_command) {
8455830d82f7Spl 	case AifCmdEventNotify:
8456942c5e3cSpl 		str = aac_cmd_name(aif_en_type, aac_aifens);
8457830d82f7Spl 		if (str)
84581dd0a2dbSpl 			aac_printf(softs, CE_NOTE, "AIF! %s", str);
8459830d82f7Spl 		else
84601dd0a2dbSpl 			aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
8461942c5e3cSpl 			    aif_en_type);
8462830d82f7Spl 		break;
8463830d82f7Spl 
8464830d82f7Spl 	case AifCmdJobProgress:
8465942c5e3cSpl 		switch (LE_32(aif->data.PR[0].status)) {
8466830d82f7Spl 		case AifJobStsSuccess:
8467830d82f7Spl 			str = "success"; break;
8468830d82f7Spl 		case AifJobStsFinished:
8469830d82f7Spl 			str = "finished"; break;
8470830d82f7Spl 		case AifJobStsAborted:
8471830d82f7Spl 			str = "aborted"; break;
8472830d82f7Spl 		case AifJobStsFailed:
8473830d82f7Spl 			str = "failed"; break;
8474830d82f7Spl 		case AifJobStsSuspended:
8475830d82f7Spl 			str = "suspended"; break;
8476830d82f7Spl 		case AifJobStsRunning:
8477830d82f7Spl 			str = "running"; break;
84787c478bd9Sstevel@tonic-gate 		default:
8479830d82f7Spl 			str = "unknown"; break;
8480830d82f7Spl 		}
84811dd0a2dbSpl 		aac_printf(softs, CE_NOTE,
84821dd0a2dbSpl 		    "AIF! JobProgress (%d) - %s (%d, %d)",
8483942c5e3cSpl 		    aif_seqnumber, str,
8484942c5e3cSpl 		    LE_32(aif->data.PR[0].currentTick),
8485942c5e3cSpl 		    LE_32(aif->data.PR[0].finalTick));
8486830d82f7Spl 		break;
8487830d82f7Spl 
8488830d82f7Spl 	case AifCmdAPIReport:
84891dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
8490942c5e3cSpl 		    aif_seqnumber);
8491830d82f7Spl 		break;
8492830d82f7Spl 
8493830d82f7Spl 	case AifCmdDriverNotify:
84941dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
8495942c5e3cSpl 		    aif_seqnumber);
8496830d82f7Spl 		break;
8497830d82f7Spl 
8498830d82f7Spl 	default:
84991dd0a2dbSpl 		aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
8500942c5e3cSpl 		    aif_command, aif_seqnumber);
8501830d82f7Spl 		break;
85027c478bd9Sstevel@tonic-gate 	}
85037c478bd9Sstevel@tonic-gate }
85047c478bd9Sstevel@tonic-gate 
85051dd0a2dbSpl #endif /* DEBUG */
8506