xref: /titanic_50/usr/src/uts/common/io/aac/aac.c (revision 3ce33fb052b375020ea4249290d33b834d9f9e75)
1942c5e3cSpl196000 /*
23fced439Szhongyan gu - Sun Microsystems - Beijing China  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3942c5e3cSpl196000  */
4942c5e3cSpl196000 
5942c5e3cSpl196000 /*
658bc78c7SXin Chen  * Copyright 2005-08 Adaptec, Inc.
758bc78c7SXin Chen  * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
8942c5e3cSpl196000  * Copyright (c) 2000 Michael Smith
9942c5e3cSpl196000  * Copyright (c) 2001 Scott Long
10942c5e3cSpl196000  * Copyright (c) 2000 BSDi
11942c5e3cSpl196000  * All rights reserved.
12942c5e3cSpl196000  *
13942c5e3cSpl196000  * Redistribution and use in source and binary forms, with or without
14942c5e3cSpl196000  * modification, are permitted provided that the following conditions
15942c5e3cSpl196000  * are met:
16942c5e3cSpl196000  * 1. Redistributions of source code must retain the above copyright
17942c5e3cSpl196000  *    notice, this list of conditions and the following disclaimer.
18942c5e3cSpl196000  * 2. Redistributions in binary form must reproduce the above copyright
19942c5e3cSpl196000  *    notice, this list of conditions and the following disclaimer in the
20942c5e3cSpl196000  *    documentation and/or other materials provided with the distribution.
21942c5e3cSpl196000  *
22942c5e3cSpl196000  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23942c5e3cSpl196000  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24942c5e3cSpl196000  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25942c5e3cSpl196000  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26942c5e3cSpl196000  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27942c5e3cSpl196000  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28942c5e3cSpl196000  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29942c5e3cSpl196000  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30942c5e3cSpl196000  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31942c5e3cSpl196000  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32942c5e3cSpl196000  * SUCH DAMAGE.
33942c5e3cSpl196000  */
34942c5e3cSpl196000 #include <sys/modctl.h>
35942c5e3cSpl196000 #include <sys/conf.h>
36942c5e3cSpl196000 #include <sys/cmn_err.h>
37942c5e3cSpl196000 #include <sys/ddi.h>
38942c5e3cSpl196000 #include <sys/devops.h>
39942c5e3cSpl196000 #include <sys/pci.h>
40942c5e3cSpl196000 #include <sys/types.h>
41942c5e3cSpl196000 #include <sys/ddidmareq.h>
42942c5e3cSpl196000 #include <sys/scsi/scsi.h>
43942c5e3cSpl196000 #include <sys/ksynch.h>
44942c5e3cSpl196000 #include <sys/sunddi.h>
45942c5e3cSpl196000 #include <sys/byteorder.h>
46942c5e3cSpl196000 #include "aac_regs.h"
47942c5e3cSpl196000 #include "aac.h"
48942c5e3cSpl196000 
49942c5e3cSpl196000 /*
50942c5e3cSpl196000  * FMA header files
51942c5e3cSpl196000  */
52942c5e3cSpl196000 #include <sys/ddifm.h>
53942c5e3cSpl196000 #include <sys/fm/protocol.h>
54942c5e3cSpl196000 #include <sys/fm/util.h>
55942c5e3cSpl196000 #include <sys/fm/io/ddi.h>
56942c5e3cSpl196000 
57942c5e3cSpl196000 /*
58942c5e3cSpl196000  * For minor nodes created by the SCSA framework, minor numbers are
59942c5e3cSpl196000  * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
60942c5e3cSpl196000  * number less than 64.
61942c5e3cSpl196000  *
62942c5e3cSpl196000  * To support cfgadm, need to confirm the SCSA framework by creating
63942c5e3cSpl196000  * devctl/scsi and driver specific minor nodes under SCSA format,
64942c5e3cSpl196000  * and calling scsi_hba_xxx() functions aacordingly.
65942c5e3cSpl196000  */
66942c5e3cSpl196000 
67942c5e3cSpl196000 #define	AAC_MINOR		32
68942c5e3cSpl196000 #define	INST2AAC(x)		(((x) << INST_MINOR_SHIFT) | AAC_MINOR)
69942c5e3cSpl196000 #define	AAC_SCSA_MINOR(x)	((x) & TRAN_MINOR_MASK)
70942c5e3cSpl196000 #define	AAC_IS_SCSA_NODE(x)	((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
71942c5e3cSpl196000 
7258bc78c7SXin Chen #define	SD2TRAN(sd)		((sd)->sd_address.a_hba_tran)
73942c5e3cSpl196000 #define	AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
74942c5e3cSpl196000 #define	AAC_DIP2TRAN(dip)	((scsi_hba_tran_t *)ddi_get_driver_private(dip))
75942c5e3cSpl196000 #define	AAC_DIP2SOFTS(dip)	(AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
7658bc78c7SXin Chen #define	SD2AAC(sd)		(AAC_TRAN2SOFTS(SD2TRAN(sd)))
7758bc78c7SXin Chen #define	AAC_PD(t)		((t) - AAC_MAX_LD)
7858bc78c7SXin Chen #define	AAC_DEV(softs, t)	(((t) < AAC_MAX_LD) ? \
7958bc78c7SXin Chen 				&(softs)->containers[(t)].dev : \
8058bc78c7SXin Chen 				((t) < AAC_MAX_DEV(softs)) ? \
8158bc78c7SXin Chen 				&(softs)->nondasds[AAC_PD(t)].dev : NULL)
8258bc78c7SXin Chen #define	AAC_DEVCFG_BEGIN(softs, tgt) \
8358bc78c7SXin Chen 				aac_devcfg((softs), (tgt), 1)
8458bc78c7SXin Chen #define	AAC_DEVCFG_END(softs, tgt) \
8558bc78c7SXin Chen 				aac_devcfg((softs), (tgt), 0)
86942c5e3cSpl196000 #define	PKT2AC(pkt)		((struct aac_cmd *)(pkt)->pkt_ha_private)
87942c5e3cSpl196000 #define	AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
88942c5e3cSpl196000 		if (!(cond)) { \
89942c5e3cSpl196000 			int count = (timeout) * 10; \
90942c5e3cSpl196000 			while (count) { \
91942c5e3cSpl196000 				drv_usecwait(100); \
92942c5e3cSpl196000 				if (cond) \
93942c5e3cSpl196000 					break; \
94942c5e3cSpl196000 				count--; \
95942c5e3cSpl196000 			} \
96942c5e3cSpl196000 			(timeout) = (count + 9) / 10; \
97942c5e3cSpl196000 		} \
98942c5e3cSpl196000 	}
99942c5e3cSpl196000 
100942c5e3cSpl196000 #define	AAC_SENSE_DATA_DESCR_LEN \
101942c5e3cSpl196000 	(sizeof (struct scsi_descr_sense_hdr) + \
102942c5e3cSpl196000 	sizeof (struct scsi_information_sense_descr))
103942c5e3cSpl196000 #define	AAC_ARQ64_LENGTH \
104942c5e3cSpl196000 	(sizeof (struct scsi_arq_status) + \
105942c5e3cSpl196000 	AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
106942c5e3cSpl196000 
107942c5e3cSpl196000 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
108942c5e3cSpl196000 #define	AAC_GETGXADDR(cmdlen, cdbp) \
109942c5e3cSpl196000 	((cmdlen == 6) ? GETG0ADDR(cdbp) : \
110942c5e3cSpl196000 	(cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
111942c5e3cSpl196000 	((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
112942c5e3cSpl196000 
113942c5e3cSpl196000 #define	AAC_CDB_INQUIRY_CMDDT	0x02
114942c5e3cSpl196000 #define	AAC_CDB_INQUIRY_EVPD	0x01
115942c5e3cSpl196000 #define	AAC_VPD_PAGE_CODE	1
116942c5e3cSpl196000 #define	AAC_VPD_PAGE_LENGTH	3
117942c5e3cSpl196000 #define	AAC_VPD_PAGE_DATA	4
118942c5e3cSpl196000 #define	AAC_VPD_ID_CODESET	0
119942c5e3cSpl196000 #define	AAC_VPD_ID_TYPE		1
120942c5e3cSpl196000 #define	AAC_VPD_ID_LENGTH	3
121942c5e3cSpl196000 #define	AAC_VPD_ID_DATA		4
122942c5e3cSpl196000 
12358bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_HEAD_SIZE			0x08
12458bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_SIZE			0x08
12558bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_MASK			0xC0
12658bc78c7SXin Chen /* 00b - peripheral device addressing method */
12758bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL		0x00
12858bc78c7SXin Chen /* 01b - flat space addressing method */
12958bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE		0x40
13058bc78c7SXin Chen /* 10b - logical unit addressing method */
13158bc78c7SXin Chen #define	AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT		0x80
13258bc78c7SXin Chen 
133942c5e3cSpl196000 /* Return the size of FIB with data part type data_type */
134942c5e3cSpl196000 #define	AAC_FIB_SIZEOF(data_type) \
135942c5e3cSpl196000 	(sizeof (struct aac_fib_header) + sizeof (data_type))
136942c5e3cSpl196000 /* Return the container size defined in mir */
137942c5e3cSpl196000 #define	AAC_MIR_SIZE(softs, acc, mir) \
138942c5e3cSpl196000 	(((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
139942c5e3cSpl196000 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
140942c5e3cSpl196000 	((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
141942c5e3cSpl196000 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
142942c5e3cSpl196000 
143942c5e3cSpl196000 /* The last entry of aac_cards[] is for unknown cards */
144942c5e3cSpl196000 #define	AAC_UNKNOWN_CARD \
145942c5e3cSpl196000 	(sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
146942c5e3cSpl196000 #define	CARD_IS_UNKNOWN(i)	(i == AAC_UNKNOWN_CARD)
147942c5e3cSpl196000 #define	BUF_IS_READ(bp)		((bp)->b_flags & B_READ)
148942c5e3cSpl196000 #define	AAC_IS_Q_EMPTY(q)	((q)->q_head == NULL)
149942c5e3cSpl196000 #define	AAC_CMDQ(acp)		(!((acp)->flags & AAC_CMD_SYNC))
150942c5e3cSpl196000 
151942c5e3cSpl196000 #define	PCI_MEM_GET32(softs, off) \
152942c5e3cSpl196000 	ddi_get32((softs)->pci_mem_handle, \
153a74f7440Spl196000 	    (void *)((softs)->pci_mem_base_vaddr + (off)))
154942c5e3cSpl196000 #define	PCI_MEM_PUT32(softs, off, val) \
155942c5e3cSpl196000 	ddi_put32((softs)->pci_mem_handle, \
156a74f7440Spl196000 	    (void *)((softs)->pci_mem_base_vaddr + (off)), \
157942c5e3cSpl196000 	    (uint32_t)(val))
158942c5e3cSpl196000 #define	PCI_MEM_GET16(softs, off) \
159942c5e3cSpl196000 	ddi_get16((softs)->pci_mem_handle, \
160a74f7440Spl196000 	(void *)((softs)->pci_mem_base_vaddr + (off)))
161942c5e3cSpl196000 #define	PCI_MEM_PUT16(softs, off, val) \
162942c5e3cSpl196000 	ddi_put16((softs)->pci_mem_handle, \
163a74f7440Spl196000 	(void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
164942c5e3cSpl196000 /* Write host data at valp to device mem[off] repeatedly count times */
165942c5e3cSpl196000 #define	PCI_MEM_REP_PUT8(softs, off, valp, count) \
166942c5e3cSpl196000 	ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
167942c5e3cSpl196000 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
168942c5e3cSpl196000 	    count, DDI_DEV_AUTOINCR)
169942c5e3cSpl196000 /* Read device data at mem[off] to host addr valp repeatedly count times */
170942c5e3cSpl196000 #define	PCI_MEM_REP_GET8(softs, off, valp, count) \
171942c5e3cSpl196000 	ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
172942c5e3cSpl196000 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
173942c5e3cSpl196000 	    count, DDI_DEV_AUTOINCR)
174942c5e3cSpl196000 #define	AAC_GET_FIELD8(acc, d, s, field) \
175942c5e3cSpl196000 	(d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
176942c5e3cSpl196000 #define	AAC_GET_FIELD32(acc, d, s, field) \
177942c5e3cSpl196000 	(d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
178942c5e3cSpl196000 #define	AAC_GET_FIELD64(acc, d, s, field) \
179942c5e3cSpl196000 	(d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
180942c5e3cSpl196000 #define	AAC_REP_GET_FIELD8(acc, d, s, field, r) \
181942c5e3cSpl196000 	ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
182942c5e3cSpl196000 	    (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
183942c5e3cSpl196000 #define	AAC_REP_GET_FIELD32(acc, d, s, field, r) \
184942c5e3cSpl196000 	ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
185942c5e3cSpl196000 	    (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
186942c5e3cSpl196000 
187942c5e3cSpl196000 #define	AAC_ENABLE_INTR(softs) { \
188942c5e3cSpl196000 		if (softs->flags & AAC_FLAGS_NEW_COMM) \
189942c5e3cSpl196000 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
190942c5e3cSpl196000 		else \
191942c5e3cSpl196000 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
1921ee13a44SXinChen 		softs->state |= AAC_STATE_INTR; \
193942c5e3cSpl196000 	}
194942c5e3cSpl196000 
1951ee13a44SXinChen #define	AAC_DISABLE_INTR(softs)	{ \
1961ee13a44SXinChen 		PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
1971ee13a44SXinChen 		softs->state &= ~AAC_STATE_INTR; \
1981ee13a44SXinChen 	}
199942c5e3cSpl196000 #define	AAC_STATUS_CLR(softs, mask)	PCI_MEM_PUT32(softs, AAC_ODBR, mask)
200942c5e3cSpl196000 #define	AAC_STATUS_GET(softs)		PCI_MEM_GET32(softs, AAC_ODBR)
201942c5e3cSpl196000 #define	AAC_NOTIFY(softs, val)		PCI_MEM_PUT32(softs, AAC_IDBR, val)
202942c5e3cSpl196000 #define	AAC_OUTB_GET(softs)		PCI_MEM_GET32(softs, AAC_OQUE)
203942c5e3cSpl196000 #define	AAC_OUTB_SET(softs, val)	PCI_MEM_PUT32(softs, AAC_OQUE, val)
204942c5e3cSpl196000 #define	AAC_FWSTATUS_GET(softs)	\
205942c5e3cSpl196000 	((softs)->aac_if.aif_get_fwstatus(softs))
206942c5e3cSpl196000 #define	AAC_MAILBOX_GET(softs, mb) \
207942c5e3cSpl196000 	((softs)->aac_if.aif_get_mailbox((softs), (mb)))
208942c5e3cSpl196000 #define	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
209942c5e3cSpl196000 	((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
210942c5e3cSpl196000 	    (arg0), (arg1), (arg2), (arg3)))
211942c5e3cSpl196000 
212f42c2f53Szhongyan gu - Sun Microsystems - Beijing China #define	AAC_MGT_SLOT_NUM	2
213942c5e3cSpl196000 #define	AAC_THROTTLE_DRAIN	-1
214942c5e3cSpl196000 
215942c5e3cSpl196000 #define	AAC_QUIESCE_TICK	1	/* 1 second */
21658bc78c7SXin Chen #define	AAC_QUIESCE_TIMEOUT	180	/* 180 seconds */
217942c5e3cSpl196000 #define	AAC_DEFAULT_TICK	10	/* 10 seconds */
218942c5e3cSpl196000 #define	AAC_SYNC_TICK		(30*60)	/* 30 minutes */
219942c5e3cSpl196000 
220942c5e3cSpl196000 /* Poll time for aac_do_poll_io() */
221942c5e3cSpl196000 #define	AAC_POLL_TIME		60	/* 60 seconds */
222942c5e3cSpl196000 
22358bc78c7SXin Chen /* IOP reset */
22458bc78c7SXin Chen #define	AAC_IOP_RESET_SUCCEED		0	/* IOP reset succeed */
22558bc78c7SXin Chen #define	AAC_IOP_RESET_FAILED		-1	/* IOP reset failed */
22658bc78c7SXin Chen #define	AAC_IOP_RESET_ABNORMAL		-2	/* Reset operation abnormal */
22758bc78c7SXin Chen 
228942c5e3cSpl196000 /*
229942c5e3cSpl196000  * Hardware access functions
230942c5e3cSpl196000  */
231942c5e3cSpl196000 static int aac_rx_get_fwstatus(struct aac_softstate *);
232942c5e3cSpl196000 static int aac_rx_get_mailbox(struct aac_softstate *, int);
233942c5e3cSpl196000 static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
234942c5e3cSpl196000     uint32_t, uint32_t, uint32_t);
235942c5e3cSpl196000 static int aac_rkt_get_fwstatus(struct aac_softstate *);
236942c5e3cSpl196000 static int aac_rkt_get_mailbox(struct aac_softstate *, int);
237942c5e3cSpl196000 static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
238942c5e3cSpl196000     uint32_t, uint32_t, uint32_t);
239942c5e3cSpl196000 
240942c5e3cSpl196000 /*
241942c5e3cSpl196000  * SCSA function prototypes
242942c5e3cSpl196000  */
243942c5e3cSpl196000 static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
244942c5e3cSpl196000 static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
245942c5e3cSpl196000 static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
24619397407SSherry Moore static int aac_quiesce(dev_info_t *);
247f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
248942c5e3cSpl196000 
249942c5e3cSpl196000 /*
250942c5e3cSpl196000  * Interrupt handler functions
251942c5e3cSpl196000  */
252b6094a86Sjd218194 static int aac_query_intrs(struct aac_softstate *, int);
253b6094a86Sjd218194 static int aac_add_intrs(struct aac_softstate *);
254b6094a86Sjd218194 static void aac_remove_intrs(struct aac_softstate *);
255f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_enable_intrs(struct aac_softstate *);
256f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_disable_intrs(struct aac_softstate *);
257942c5e3cSpl196000 static uint_t aac_intr_old(caddr_t);
258942c5e3cSpl196000 static uint_t aac_intr_new(caddr_t);
259942c5e3cSpl196000 static uint_t aac_softintr(caddr_t);
260942c5e3cSpl196000 
261942c5e3cSpl196000 /*
262942c5e3cSpl196000  * Internal functions in attach
263942c5e3cSpl196000  */
264942c5e3cSpl196000 static int aac_check_card_type(struct aac_softstate *);
265942c5e3cSpl196000 static int aac_check_firmware(struct aac_softstate *);
266942c5e3cSpl196000 static int aac_common_attach(struct aac_softstate *);
267942c5e3cSpl196000 static void aac_common_detach(struct aac_softstate *);
268942c5e3cSpl196000 static int aac_probe_containers(struct aac_softstate *);
269942c5e3cSpl196000 static int aac_alloc_comm_space(struct aac_softstate *);
270942c5e3cSpl196000 static int aac_setup_comm_space(struct aac_softstate *);
271942c5e3cSpl196000 static void aac_free_comm_space(struct aac_softstate *);
272942c5e3cSpl196000 static int aac_hba_setup(struct aac_softstate *);
273942c5e3cSpl196000 
274942c5e3cSpl196000 /*
275942c5e3cSpl196000  * Sync FIB operation functions
276942c5e3cSpl196000  */
277942c5e3cSpl196000 int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
278942c5e3cSpl196000     uint32_t, uint32_t, uint32_t, uint32_t *);
279942c5e3cSpl196000 static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
280942c5e3cSpl196000 
281942c5e3cSpl196000 /*
282942c5e3cSpl196000  * Command queue operation functions
283942c5e3cSpl196000  */
284942c5e3cSpl196000 static void aac_cmd_initq(struct aac_cmd_queue *);
285942c5e3cSpl196000 static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
286942c5e3cSpl196000 static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
287942c5e3cSpl196000 static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
288942c5e3cSpl196000 
289942c5e3cSpl196000 /*
290942c5e3cSpl196000  * FIB queue operation functions
291942c5e3cSpl196000  */
292942c5e3cSpl196000 static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
293942c5e3cSpl196000 static int aac_fib_dequeue(struct aac_softstate *, int, int *);
294942c5e3cSpl196000 
295942c5e3cSpl196000 /*
296942c5e3cSpl196000  * Slot operation functions
297942c5e3cSpl196000  */
298942c5e3cSpl196000 static int aac_create_slots(struct aac_softstate *);
299942c5e3cSpl196000 static void aac_destroy_slots(struct aac_softstate *);
300942c5e3cSpl196000 static void aac_alloc_fibs(struct aac_softstate *);
301942c5e3cSpl196000 static void aac_destroy_fibs(struct aac_softstate *);
302942c5e3cSpl196000 static struct aac_slot *aac_get_slot(struct aac_softstate *);
303942c5e3cSpl196000 static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
304942c5e3cSpl196000 static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
305942c5e3cSpl196000 static void aac_free_fib(struct aac_slot *);
306942c5e3cSpl196000 
307942c5e3cSpl196000 /*
308942c5e3cSpl196000  * Internal functions
309942c5e3cSpl196000  */
310f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
311f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     uint16_t);
312942c5e3cSpl196000 static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
313942c5e3cSpl196000 static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
314942c5e3cSpl196000 static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
315942c5e3cSpl196000 static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
316942c5e3cSpl196000 static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
317942c5e3cSpl196000 static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
318b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
319942c5e3cSpl196000 static void aac_start_waiting_io(struct aac_softstate *);
320942c5e3cSpl196000 static void aac_drain_comp_q(struct aac_softstate *);
321942c5e3cSpl196000 int aac_do_io(struct aac_softstate *, struct aac_cmd *);
322f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
323f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
324f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
325942c5e3cSpl196000 static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
326942c5e3cSpl196000 static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
327942c5e3cSpl196000 static int aac_send_command(struct aac_softstate *, struct aac_slot *);
32858bc78c7SXin Chen static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
329942c5e3cSpl196000 static int aac_dma_sync_ac(struct aac_cmd *);
330942c5e3cSpl196000 static int aac_shutdown(struct aac_softstate *);
331942c5e3cSpl196000 static int aac_reset_adapter(struct aac_softstate *);
332942c5e3cSpl196000 static int aac_do_quiesce(struct aac_softstate *softs);
333942c5e3cSpl196000 static int aac_do_unquiesce(struct aac_softstate *softs);
334942c5e3cSpl196000 static void aac_unhold_bus(struct aac_softstate *, int);
33558bc78c7SXin Chen static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
336942c5e3cSpl196000     int, int);
337942c5e3cSpl196000 
338942c5e3cSpl196000 /*
339942c5e3cSpl196000  * Adapter Initiated FIB handling function
340942c5e3cSpl196000  */
3410749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
3420749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib *, int);
3430749e8deSXin Chen - Sun Microsystems - Beijing China static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
344942c5e3cSpl196000 
345942c5e3cSpl196000 /*
3460749e8deSXin Chen - Sun Microsystems - Beijing China  * Event handling related functions
347942c5e3cSpl196000  */
3480749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_timer(void *);
3490749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_event_thread(struct aac_softstate *);
3500749e8deSXin Chen - Sun Microsystems - Beijing China static void aac_event_disp(struct aac_softstate *, int);
351942c5e3cSpl196000 
352942c5e3cSpl196000 /*
353942c5e3cSpl196000  * IOCTL interface related functions
354942c5e3cSpl196000  */
355942c5e3cSpl196000 static int aac_open(dev_t *, int, int, cred_t *);
356942c5e3cSpl196000 static int aac_close(dev_t, int, int, cred_t *);
357942c5e3cSpl196000 static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
358942c5e3cSpl196000 extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
359942c5e3cSpl196000 
360942c5e3cSpl196000 /*
361942c5e3cSpl196000  * FMA Prototypes
362942c5e3cSpl196000  */
363942c5e3cSpl196000 static void aac_fm_init(struct aac_softstate *);
364942c5e3cSpl196000 static void aac_fm_fini(struct aac_softstate *);
365942c5e3cSpl196000 static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
366942c5e3cSpl196000 int aac_check_acc_handle(ddi_acc_handle_t);
367942c5e3cSpl196000 int aac_check_dma_handle(ddi_dma_handle_t);
368942c5e3cSpl196000 void aac_fm_ereport(struct aac_softstate *, char *);
369942c5e3cSpl196000 
37058bc78c7SXin Chen /*
37158bc78c7SXin Chen  * Auto enumeration functions
37258bc78c7SXin Chen  */
37358bc78c7SXin Chen static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
37458bc78c7SXin Chen static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
37558bc78c7SXin Chen     void *, dev_info_t **);
3760749e8deSXin Chen - Sun Microsystems - Beijing China static int aac_handle_dr(struct aac_softstate *, int, int, int);
3770749e8deSXin Chen - Sun Microsystems - Beijing China 
3780749e8deSXin Chen - Sun Microsystems - Beijing China extern pri_t minclsyspri;
37958bc78c7SXin Chen 
380942c5e3cSpl196000 #ifdef DEBUG
381942c5e3cSpl196000 /*
382942c5e3cSpl196000  * UART	debug output support
383942c5e3cSpl196000  */
384942c5e3cSpl196000 
385942c5e3cSpl196000 #define	AAC_PRINT_BUFFER_SIZE		512
386942c5e3cSpl196000 #define	AAC_PRINT_TIMEOUT		250	/* 1/4 sec. = 250 msec. */
387942c5e3cSpl196000 
388942c5e3cSpl196000 #define	AAC_FW_DBG_STRLEN_OFFSET	0x00
389942c5e3cSpl196000 #define	AAC_FW_DBG_FLAGS_OFFSET		0x04
390942c5e3cSpl196000 #define	AAC_FW_DBG_BLED_OFFSET		0x08
391942c5e3cSpl196000 
392942c5e3cSpl196000 static int aac_get_fw_debug_buffer(struct aac_softstate *);
393942c5e3cSpl196000 static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
394942c5e3cSpl196000 static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
395942c5e3cSpl196000 
396942c5e3cSpl196000 static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
397942c5e3cSpl196000 static char aac_fmt[] = " %s";
398942c5e3cSpl196000 static char aac_fmt_header[] = " %s.%d: %s";
399942c5e3cSpl196000 static kmutex_t aac_prt_mutex;
400942c5e3cSpl196000 
401942c5e3cSpl196000 /*
402942c5e3cSpl196000  * Debug flags to be put into the softstate flags field
403942c5e3cSpl196000  * when initialized
404942c5e3cSpl196000  */
405942c5e3cSpl196000 uint32_t aac_debug_flags =
406942c5e3cSpl196000 /*    AACDB_FLAGS_KERNEL_PRINT | */
407942c5e3cSpl196000 /*    AACDB_FLAGS_FW_PRINT |	*/
408942c5e3cSpl196000 /*    AACDB_FLAGS_MISC |	*/
409942c5e3cSpl196000 /*    AACDB_FLAGS_FUNC1 |	*/
410942c5e3cSpl196000 /*    AACDB_FLAGS_FUNC2 |	*/
411942c5e3cSpl196000 /*    AACDB_FLAGS_SCMD |	*/
412942c5e3cSpl196000 /*    AACDB_FLAGS_AIF |		*/
413942c5e3cSpl196000 /*    AACDB_FLAGS_FIB |		*/
414942c5e3cSpl196000 /*    AACDB_FLAGS_IOCTL |	*/
415942c5e3cSpl196000 0;
41658bc78c7SXin Chen uint32_t aac_debug_fib_flags =
41758bc78c7SXin Chen /*    AACDB_FLAGS_FIB_RW |	*/
41858bc78c7SXin Chen /*    AACDB_FLAGS_FIB_IOCTL |	*/
41958bc78c7SXin Chen /*    AACDB_FLAGS_FIB_SRB |	*/
42058bc78c7SXin Chen /*    AACDB_FLAGS_FIB_SYNC |	*/
42158bc78c7SXin Chen /*    AACDB_FLAGS_FIB_HEADER |	*/
42258bc78c7SXin Chen /*    AACDB_FLAGS_FIB_TIMEOUT |	*/
42358bc78c7SXin Chen 0;
424942c5e3cSpl196000 
425942c5e3cSpl196000 #endif /* DEBUG */
426942c5e3cSpl196000 
427942c5e3cSpl196000 static struct cb_ops aac_cb_ops = {
428942c5e3cSpl196000 	aac_open,	/* open */
429942c5e3cSpl196000 	aac_close,	/* close */
430942c5e3cSpl196000 	nodev,		/* strategy */
431942c5e3cSpl196000 	nodev,		/* print */
432942c5e3cSpl196000 	nodev,		/* dump */
433942c5e3cSpl196000 	nodev,		/* read */
434942c5e3cSpl196000 	nodev,		/* write */
435942c5e3cSpl196000 	aac_ioctl,	/* ioctl */
436942c5e3cSpl196000 	nodev,		/* devmap */
437942c5e3cSpl196000 	nodev,		/* mmap */
438942c5e3cSpl196000 	nodev,		/* segmap */
439942c5e3cSpl196000 	nochpoll,	/* poll */
440942c5e3cSpl196000 	ddi_prop_op,	/* cb_prop_op */
441942c5e3cSpl196000 	NULL,		/* streamtab */
442942c5e3cSpl196000 	D_64BIT | D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
443942c5e3cSpl196000 	CB_REV,		/* cb_rev */
444942c5e3cSpl196000 	nodev,		/* async I/O read entry point */
445942c5e3cSpl196000 	nodev		/* async I/O write entry point */
446942c5e3cSpl196000 };
447942c5e3cSpl196000 
448942c5e3cSpl196000 static struct dev_ops aac_dev_ops = {
449942c5e3cSpl196000 	DEVO_REV,
450942c5e3cSpl196000 	0,
451f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_getinfo,
452942c5e3cSpl196000 	nulldev,
453942c5e3cSpl196000 	nulldev,
454942c5e3cSpl196000 	aac_attach,
455942c5e3cSpl196000 	aac_detach,
456942c5e3cSpl196000 	aac_reset,
457942c5e3cSpl196000 	&aac_cb_ops,
458942c5e3cSpl196000 	NULL,
45919397407SSherry Moore 	NULL,
46019397407SSherry Moore 	aac_quiesce,
461942c5e3cSpl196000 };
462942c5e3cSpl196000 
463942c5e3cSpl196000 static struct modldrv aac_modldrv = {
464942c5e3cSpl196000 	&mod_driverops,
465942c5e3cSpl196000 	"AAC Driver " AAC_DRIVER_VERSION,
466942c5e3cSpl196000 	&aac_dev_ops,
467942c5e3cSpl196000 };
468942c5e3cSpl196000 
469942c5e3cSpl196000 static struct modlinkage aac_modlinkage = {
470942c5e3cSpl196000 	MODREV_1,
471942c5e3cSpl196000 	&aac_modldrv,
472942c5e3cSpl196000 	NULL
473942c5e3cSpl196000 };
474942c5e3cSpl196000 
475942c5e3cSpl196000 static struct aac_softstate  *aac_softstatep;
476942c5e3cSpl196000 
477942c5e3cSpl196000 /*
478942c5e3cSpl196000  * Supported card list
479942c5e3cSpl196000  * ordered in vendor id, subvendor id, subdevice id, and device id
480942c5e3cSpl196000  */
481942c5e3cSpl196000 static struct aac_card_type aac_cards[] = {
482942c5e3cSpl196000 	{0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
483942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
484942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
485942c5e3cSpl196000 	{0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
486942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
487942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
488942c5e3cSpl196000 	{0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
489942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
490942c5e3cSpl196000 	    "Dell", "PERC 3/Si"},
491942c5e3cSpl196000 	{0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
492942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
493942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
494942c5e3cSpl196000 	{0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
495942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
496942c5e3cSpl196000 	    "Dell", "PERC 3/Si"},
497942c5e3cSpl196000 	{0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
498942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
499942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
500942c5e3cSpl196000 	{0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
501942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
502942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
503942c5e3cSpl196000 	{0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
504942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
505942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
506942c5e3cSpl196000 	{0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
507942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
508942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
509942c5e3cSpl196000 	{0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
510942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
511942c5e3cSpl196000 	    "Dell", "PERC 3/Di"},
512942c5e3cSpl196000 	{0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
513942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
514942c5e3cSpl196000 	    "Dell", "PERC 320/DC"},
515942c5e3cSpl196000 	{0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
516942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
517942c5e3cSpl196000 
518942c5e3cSpl196000 	{0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
519942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
520942c5e3cSpl196000 	{0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
521942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
522942c5e3cSpl196000 	{0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
523942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
524942c5e3cSpl196000 
525942c5e3cSpl196000 	{0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
526942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
527942c5e3cSpl196000 	{0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
528942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
529942c5e3cSpl196000 
530942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
531942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
532942c5e3cSpl196000 	    "Adaptec", "2200S"},
533942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
534942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
535942c5e3cSpl196000 	    "Adaptec", "2120S"},
536942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
537942c5e3cSpl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
538942c5e3cSpl196000 	    "Adaptec", "2200S"},
539942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
540942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
541942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
542942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
543942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
544942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
545942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
546942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
547942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
548942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
549942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
550942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
551942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
552942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
553942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
554942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
555942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
556942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
557942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
558942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
559942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
560942c5e3cSpl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
561942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
562942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
563942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
564942c5e3cSpl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
565942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
566942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
567942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
568942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
569942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
570942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
571942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
572942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
573942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
574942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
575942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
576942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
577942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
578942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
579942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
580942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "ICP", "9024RO"},
581942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
582942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "ICP", "9014RO"},
583942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
584942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "ICP", "9047MA"},
585942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
586942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "ICP", "9087MA"},
587942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
588942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "ICP", "9085LI"},
589942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
590942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "ICP", "5085BR"},
591942c5e3cSpl196000 	{0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
592942c5e3cSpl196000 	    0, AAC_TYPE_SATA, "ICP", "9067MA"},
593942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
594942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
595942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
596942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
597942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
598942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
599942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
600942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
601942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
602942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
603942c5e3cSpl196000 	{0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
604942c5e3cSpl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
605942c5e3cSpl196000 
606942c5e3cSpl196000 	{0, 0, 0, 0, AAC_HWIF_UNKNOWN,
607942c5e3cSpl196000 	    0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
608942c5e3cSpl196000 };
609942c5e3cSpl196000 
610942c5e3cSpl196000 /*
611942c5e3cSpl196000  * Hardware access functions for i960 based cards
612942c5e3cSpl196000  */
613942c5e3cSpl196000 static struct aac_interface aac_rx_interface = {
614942c5e3cSpl196000 	aac_rx_get_fwstatus,
615942c5e3cSpl196000 	aac_rx_get_mailbox,
616942c5e3cSpl196000 	aac_rx_set_mailbox
617942c5e3cSpl196000 };
618942c5e3cSpl196000 
619942c5e3cSpl196000 /*
620942c5e3cSpl196000  * Hardware access functions for Rocket based cards
621942c5e3cSpl196000  */
622942c5e3cSpl196000 static struct aac_interface aac_rkt_interface = {
623942c5e3cSpl196000 	aac_rkt_get_fwstatus,
624942c5e3cSpl196000 	aac_rkt_get_mailbox,
625942c5e3cSpl196000 	aac_rkt_set_mailbox
626942c5e3cSpl196000 };
627942c5e3cSpl196000 
628942c5e3cSpl196000 ddi_device_acc_attr_t aac_acc_attr = {
629837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
630942c5e3cSpl196000 	DDI_STRUCTURE_LE_ACC,
631837c1ac4SStephen Hanson 	DDI_STRICTORDER_ACC,
632837c1ac4SStephen Hanson 	DDI_DEFAULT_ACC
633942c5e3cSpl196000 };
634942c5e3cSpl196000 
635942c5e3cSpl196000 static struct {
636942c5e3cSpl196000 	int	size;
637942c5e3cSpl196000 	int	notify;
638942c5e3cSpl196000 } aac_qinfo[] = {
639942c5e3cSpl196000 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
640942c5e3cSpl196000 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
641942c5e3cSpl196000 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
642942c5e3cSpl196000 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
643942c5e3cSpl196000 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
644942c5e3cSpl196000 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
645942c5e3cSpl196000 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
646942c5e3cSpl196000 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
647942c5e3cSpl196000 };
648942c5e3cSpl196000 
649942c5e3cSpl196000 /*
650942c5e3cSpl196000  * Default aac dma attributes
651942c5e3cSpl196000  */
652942c5e3cSpl196000 static ddi_dma_attr_t aac_dma_attr = {
653942c5e3cSpl196000 	DMA_ATTR_V0,
654942c5e3cSpl196000 	0,		/* lowest usable address */
655942c5e3cSpl196000 	0xffffffffull,	/* high DMA address range */
656942c5e3cSpl196000 	0xffffffffull,	/* DMA counter register */
657942c5e3cSpl196000 	AAC_DMA_ALIGN,	/* DMA address alignment */
658942c5e3cSpl196000 	1,		/* DMA burstsizes */
659942c5e3cSpl196000 	1,		/* min effective DMA size */
660942c5e3cSpl196000 	0xffffffffull,	/* max DMA xfer size */
661942c5e3cSpl196000 	0xffffffffull,	/* segment boundary */
662942c5e3cSpl196000 	1,		/* s/g list length */
663942c5e3cSpl196000 	AAC_BLK_SIZE,	/* granularity of device */
66458bc78c7SXin Chen 	0		/* DMA transfer flags */
66558bc78c7SXin Chen };
66658bc78c7SXin Chen 
667942c5e3cSpl196000 static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
668942c5e3cSpl196000 static uint32_t aac_timebase = 0;	/* internal timer in seconds */
669942c5e3cSpl196000 
670942c5e3cSpl196000 /*
671942c5e3cSpl196000  * Warlock directives
672942c5e3cSpl196000  *
673942c5e3cSpl196000  * Different variables with the same types have to be protected by the
674942c5e3cSpl196000  * same mutex; otherwise, warlock will complain with "variables don't
675942c5e3cSpl196000  * seem to be protected consistently". For example,
676942c5e3cSpl196000  * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
677942c5e3cSpl196000  * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
678942c5e3cSpl196000  * declare them as protected explictly at aac_cmd_dequeue().
679942c5e3cSpl196000  */
680942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
681942c5e3cSpl196000     scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
682942c5e3cSpl196000     mode_format mode_geometry mode_header aac_cmd))
683942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
684942c5e3cSpl196000     aac_sge))
685942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
686942c5e3cSpl196000     aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
687942c5e3cSpl196000     aac_sg_table aac_srb))
688942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
689942c5e3cSpl196000 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
69058bc78c7SXin Chen _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
691942c5e3cSpl196000 
692942c5e3cSpl196000 int
_init(void)693942c5e3cSpl196000 _init(void)
694942c5e3cSpl196000 {
695942c5e3cSpl196000 	int rval = 0;
696942c5e3cSpl196000 
697942c5e3cSpl196000 #ifdef DEBUG
698942c5e3cSpl196000 	mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
699942c5e3cSpl196000 #endif
700942c5e3cSpl196000 	DBCALLED(NULL, 1);
701942c5e3cSpl196000 
702942c5e3cSpl196000 	if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
703942c5e3cSpl196000 	    sizeof (struct aac_softstate), 0)) != 0)
704942c5e3cSpl196000 		goto error;
705942c5e3cSpl196000 
706942c5e3cSpl196000 	if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
707942c5e3cSpl196000 		ddi_soft_state_fini((void *)&aac_softstatep);
708942c5e3cSpl196000 		goto error;
709942c5e3cSpl196000 	}
710942c5e3cSpl196000 
711942c5e3cSpl196000 	if ((rval = mod_install(&aac_modlinkage)) != 0) {
712942c5e3cSpl196000 		ddi_soft_state_fini((void *)&aac_softstatep);
713942c5e3cSpl196000 		scsi_hba_fini(&aac_modlinkage);
714942c5e3cSpl196000 		goto error;
715942c5e3cSpl196000 	}
716942c5e3cSpl196000 	return (rval);
717942c5e3cSpl196000 
718942c5e3cSpl196000 error:
719942c5e3cSpl196000 	AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
720942c5e3cSpl196000 #ifdef DEBUG
721942c5e3cSpl196000 	mutex_destroy(&aac_prt_mutex);
722942c5e3cSpl196000 #endif
723942c5e3cSpl196000 	return (rval);
724942c5e3cSpl196000 }
725942c5e3cSpl196000 
726942c5e3cSpl196000 int
_info(struct modinfo * modinfop)727942c5e3cSpl196000 _info(struct modinfo *modinfop)
728942c5e3cSpl196000 {
729942c5e3cSpl196000 	DBCALLED(NULL, 1);
730942c5e3cSpl196000 	return (mod_info(&aac_modlinkage, modinfop));
731942c5e3cSpl196000 }
732942c5e3cSpl196000 
733942c5e3cSpl196000 /*
734942c5e3cSpl196000  * An HBA driver cannot be unload unless you reboot,
735942c5e3cSpl196000  * so this function will be of no use.
736942c5e3cSpl196000  */
737942c5e3cSpl196000 int
_fini(void)738942c5e3cSpl196000 _fini(void)
739942c5e3cSpl196000 {
740942c5e3cSpl196000 	int rval;
741942c5e3cSpl196000 
742942c5e3cSpl196000 	DBCALLED(NULL, 1);
743942c5e3cSpl196000 
744942c5e3cSpl196000 	if ((rval = mod_remove(&aac_modlinkage)) != 0)
745942c5e3cSpl196000 		goto error;
746942c5e3cSpl196000 
747942c5e3cSpl196000 	scsi_hba_fini(&aac_modlinkage);
748942c5e3cSpl196000 	ddi_soft_state_fini((void *)&aac_softstatep);
749942c5e3cSpl196000 #ifdef DEBUG
750942c5e3cSpl196000 	mutex_destroy(&aac_prt_mutex);
751942c5e3cSpl196000 #endif
752942c5e3cSpl196000 	return (0);
753942c5e3cSpl196000 
754942c5e3cSpl196000 error:
755942c5e3cSpl196000 	AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
756942c5e3cSpl196000 	return (rval);
757942c5e3cSpl196000 }
758942c5e3cSpl196000 
759942c5e3cSpl196000 static int
aac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)760942c5e3cSpl196000 aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
761942c5e3cSpl196000 {
762942c5e3cSpl196000 	int instance, i;
763942c5e3cSpl196000 	struct aac_softstate *softs = NULL;
764942c5e3cSpl196000 	int attach_state = 0;
76558bc78c7SXin Chen 	char *data;
766942c5e3cSpl196000 
767942c5e3cSpl196000 	DBCALLED(NULL, 1);
768942c5e3cSpl196000 
769942c5e3cSpl196000 	switch (cmd) {
770942c5e3cSpl196000 	case DDI_ATTACH:
771942c5e3cSpl196000 		break;
772942c5e3cSpl196000 	case DDI_RESUME:
773942c5e3cSpl196000 		return (DDI_FAILURE);
774942c5e3cSpl196000 	default:
775942c5e3cSpl196000 		return (DDI_FAILURE);
776942c5e3cSpl196000 	}
777942c5e3cSpl196000 
778942c5e3cSpl196000 	instance = ddi_get_instance(dip);
779942c5e3cSpl196000 
780942c5e3cSpl196000 	/* Get soft state */
781942c5e3cSpl196000 	if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
782942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
783942c5e3cSpl196000 		goto error;
784942c5e3cSpl196000 	}
785942c5e3cSpl196000 	softs = ddi_get_soft_state(aac_softstatep, instance);
786942c5e3cSpl196000 	attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
787942c5e3cSpl196000 
788942c5e3cSpl196000 	softs->instance = instance;
789942c5e3cSpl196000 	softs->devinfo_p = dip;
790942c5e3cSpl196000 	softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
791942c5e3cSpl196000 	softs->addr_dma_attr.dma_attr_granular = 1;
79258bc78c7SXin Chen 	softs->acc_attr = aac_acc_attr;
793837c1ac4SStephen Hanson 	softs->reg_attr = aac_acc_attr;
794942c5e3cSpl196000 	softs->card = AAC_UNKNOWN_CARD;
795942c5e3cSpl196000 #ifdef DEBUG
796942c5e3cSpl196000 	softs->debug_flags = aac_debug_flags;
79758bc78c7SXin Chen 	softs->debug_fib_flags = aac_debug_fib_flags;
798942c5e3cSpl196000 #endif
799942c5e3cSpl196000 
80058bc78c7SXin Chen 	/* Initialize FMA */
80158bc78c7SXin Chen 	aac_fm_init(softs);
80258bc78c7SXin Chen 
803942c5e3cSpl196000 	/* Check the card type */
804942c5e3cSpl196000 	if (aac_check_card_type(softs) == AACERR) {
805942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Card not supported");
806942c5e3cSpl196000 		goto error;
807942c5e3cSpl196000 	}
808942c5e3cSpl196000 	/* We have found the right card and everything is OK */
809942c5e3cSpl196000 	attach_state |= AAC_ATTACH_CARD_DETECTED;
810942c5e3cSpl196000 
811942c5e3cSpl196000 	/* Map PCI mem space */
812942c5e3cSpl196000 	if (ddi_regs_map_setup(dip, 1,
813942c5e3cSpl196000 	    (caddr_t *)&softs->pci_mem_base_vaddr, 0,
814837c1ac4SStephen Hanson 	    softs->map_size_min, &softs->reg_attr,
815942c5e3cSpl196000 	    &softs->pci_mem_handle) != DDI_SUCCESS)
816942c5e3cSpl196000 		goto error;
817942c5e3cSpl196000 
818942c5e3cSpl196000 	softs->map_size = softs->map_size_min;
819942c5e3cSpl196000 	attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
820942c5e3cSpl196000 
821942c5e3cSpl196000 	AAC_DISABLE_INTR(softs);
822942c5e3cSpl196000 
823f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Init mutexes and condvars */
8240749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
8250749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8260749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
8270749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8280749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->time_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->ev_lock, NULL, MUTEX_DRIVER,
8310749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_INTR_PRI(softs->intr_pri));
8320749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_init(&softs->aifq_mutex, NULL,
833b6094a86Sjd218194 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
834942c5e3cSpl196000 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
8351ee13a44SXinChen 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
836942c5e3cSpl196000 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
8370749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
8380749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
8390749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
840942c5e3cSpl196000 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
841942c5e3cSpl196000 
842f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Init the cmd queues */
843f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	for (i = 0; i < AAC_CMDQ_NUM; i++)
844f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_cmd_initq(&softs->q_wait[i]);
845f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_initq(&softs->q_busy);
846f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_initq(&softs->q_comp);
847f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
84858bc78c7SXin Chen 	/* Check for legacy device naming support */
84958bc78c7SXin Chen 	softs->legacy = 1; /* default to use legacy name */
85058bc78c7SXin Chen 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
85158bc78c7SXin Chen 	    "legacy-name-enable", &data) == DDI_SUCCESS)) {
85258bc78c7SXin Chen 		if (strcmp(data, "no") == 0) {
85358bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
85458bc78c7SXin Chen 			softs->legacy = 0;
85558bc78c7SXin Chen 		}
85658bc78c7SXin Chen 		ddi_prop_free(data);
85758bc78c7SXin Chen 	}
85858bc78c7SXin Chen 
859942c5e3cSpl196000 	/*
860942c5e3cSpl196000 	 * Everything has been set up till now,
861942c5e3cSpl196000 	 * we will do some common attach.
862942c5e3cSpl196000 	 */
863f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
864f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_common_attach(softs) == AACERR) {
865f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		mutex_exit(&softs->io_lock);
866942c5e3cSpl196000 		goto error;
867f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
868f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
869942c5e3cSpl196000 	attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
870942c5e3cSpl196000 
87172888e72Speng liu - Sun Microsystems - Beijing China 	/* Check for buf breakup support */
87272888e72Speng liu - Sun Microsystems - Beijing China 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
87372888e72Speng liu - Sun Microsystems - Beijing China 	    "breakup-enable", &data) == DDI_SUCCESS)) {
87472888e72Speng liu - Sun Microsystems - Beijing China 		if (strcmp(data, "yes") == 0) {
87572888e72Speng liu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
87672888e72Speng liu - Sun Microsystems - Beijing China 			softs->flags |= AAC_FLAGS_BRKUP;
87772888e72Speng liu - Sun Microsystems - Beijing China 		}
87872888e72Speng liu - Sun Microsystems - Beijing China 		ddi_prop_free(data);
87972888e72Speng liu - Sun Microsystems - Beijing China 	}
88072888e72Speng liu - Sun Microsystems - Beijing China 	softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
88172888e72Speng liu - Sun Microsystems - Beijing China 	if (softs->flags & AAC_FLAGS_BRKUP) {
88272888e72Speng liu - Sun Microsystems - Beijing China 		softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
88372888e72Speng liu - Sun Microsystems - Beijing China 		    DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
88472888e72Speng liu - Sun Microsystems - Beijing China 	}
88572888e72Speng liu - Sun Microsystems - Beijing China 
886942c5e3cSpl196000 	if (aac_hba_setup(softs) != AACOK)
887942c5e3cSpl196000 		goto error;
888942c5e3cSpl196000 	attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
889942c5e3cSpl196000 
890942c5e3cSpl196000 	/* Create devctl/scsi nodes for cfgadm */
891942c5e3cSpl196000 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
892942c5e3cSpl196000 	    INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
893942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
894942c5e3cSpl196000 		goto error;
895942c5e3cSpl196000 	}
896942c5e3cSpl196000 	attach_state |= AAC_ATTACH_CREATE_DEVCTL;
897942c5e3cSpl196000 
898942c5e3cSpl196000 	if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
899942c5e3cSpl196000 	    DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
900942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
901942c5e3cSpl196000 		goto error;
902942c5e3cSpl196000 	}
903942c5e3cSpl196000 	attach_state |= AAC_ATTACH_CREATE_SCSI;
904942c5e3cSpl196000 
905942c5e3cSpl196000 	/* Create aac node for app. to issue ioctls */
906942c5e3cSpl196000 	if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
907942c5e3cSpl196000 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
908942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
909942c5e3cSpl196000 		goto error;
910942c5e3cSpl196000 	}
911942c5e3cSpl196000 
9120749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Common attach is OK, so we are attached! */
9130749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->state |= AAC_STATE_RUN;
9140749e8deSXin Chen - Sun Microsystems - Beijing China 
9150749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Create event thread */
9160749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->fibctx_p = &softs->aifctx;
9170749e8deSXin Chen - Sun Microsystems - Beijing China 	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
9180749e8deSXin Chen - Sun Microsystems - Beijing China 	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
9190749e8deSXin Chen - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
9200749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->state &= ~AAC_STATE_RUN;
92158bc78c7SXin Chen 		goto error;
92258bc78c7SXin Chen 	}
92358bc78c7SXin Chen 
924942c5e3cSpl196000 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
925942c5e3cSpl196000 
926942c5e3cSpl196000 	/* Create a thread for command timeout */
9270749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->timeout_id = timeout(aac_timer, (void *)softs,
9280749e8deSXin Chen - Sun Microsystems - Beijing China 	    (aac_tick * drv_usectohz(1000000)));
929942c5e3cSpl196000 
930942c5e3cSpl196000 	/* Common attach is OK, so we are attached! */
931942c5e3cSpl196000 	ddi_report_dev(dip);
932942c5e3cSpl196000 	AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
933942c5e3cSpl196000 	return (DDI_SUCCESS);
934942c5e3cSpl196000 
935942c5e3cSpl196000 error:
936942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
937942c5e3cSpl196000 		ddi_remove_minor_node(dip, "scsi");
938942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
939942c5e3cSpl196000 		ddi_remove_minor_node(dip, "devctl");
940942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
941942c5e3cSpl196000 		aac_common_detach(softs);
942942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
943942c5e3cSpl196000 		(void) scsi_hba_detach(dip);
944942c5e3cSpl196000 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
945942c5e3cSpl196000 	}
946942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
9470749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->io_lock);
948942c5e3cSpl196000 		mutex_destroy(&softs->q_comp_mutex);
9490749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->time_mutex);
9500749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->ev_lock);
9510749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_destroy(&softs->aifq_mutex);
952942c5e3cSpl196000 		cv_destroy(&softs->event);
9531ee13a44SXinChen 		cv_destroy(&softs->sync_fib_cv);
954942c5e3cSpl196000 		cv_destroy(&softs->drain_cv);
9550749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->event_wait_cv);
9560749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->event_disp_cv);
9570749e8deSXin Chen - Sun Microsystems - Beijing China 		cv_destroy(&softs->aifq_cv);
958942c5e3cSpl196000 	}
959942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
960942c5e3cSpl196000 		ddi_regs_map_free(&softs->pci_mem_handle);
961942c5e3cSpl196000 	aac_fm_fini(softs);
962942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_CARD_DETECTED)
963942c5e3cSpl196000 		softs->card = AACERR;
964942c5e3cSpl196000 	if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
965942c5e3cSpl196000 		ddi_soft_state_free(aac_softstatep, instance);
966942c5e3cSpl196000 	return (DDI_FAILURE);
967942c5e3cSpl196000 }
968942c5e3cSpl196000 
969942c5e3cSpl196000 static int
aac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)970942c5e3cSpl196000 aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
971942c5e3cSpl196000 {
972942c5e3cSpl196000 	scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
973942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
974942c5e3cSpl196000 
975942c5e3cSpl196000 	DBCALLED(softs, 1);
976942c5e3cSpl196000 
977942c5e3cSpl196000 	switch (cmd) {
978942c5e3cSpl196000 	case DDI_DETACH:
979942c5e3cSpl196000 		break;
980942c5e3cSpl196000 	case DDI_SUSPEND:
981942c5e3cSpl196000 		return (DDI_FAILURE);
982942c5e3cSpl196000 	default:
983942c5e3cSpl196000 		return (DDI_FAILURE);
984942c5e3cSpl196000 	}
985942c5e3cSpl196000 
986942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
987942c5e3cSpl196000 	AAC_DISABLE_INTR(softs);
988942c5e3cSpl196000 	softs->state = AAC_STATE_STOPPED;
989942c5e3cSpl196000 
990942c5e3cSpl196000 	ddi_remove_minor_node(dip, "aac");
991942c5e3cSpl196000 	ddi_remove_minor_node(dip, "scsi");
992942c5e3cSpl196000 	ddi_remove_minor_node(dip, "devctl");
993942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
994942c5e3cSpl196000 
995942c5e3cSpl196000 	aac_common_detach(softs);
996942c5e3cSpl196000 
997f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
998942c5e3cSpl196000 	(void) scsi_hba_detach(dip);
999942c5e3cSpl196000 	scsi_hba_tran_free(tran);
1000f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
1001942c5e3cSpl196000 
10020749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Stop timer */
10030749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
10040749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->timeout_id) {
10050749e8deSXin Chen - Sun Microsystems - Beijing China 		timeout_id_t tid = softs->timeout_id;
10060749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->timeout_id = 0;
10070749e8deSXin Chen - Sun Microsystems - Beijing China 
10080749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->time_mutex);
10090749e8deSXin Chen - Sun Microsystems - Beijing China 		(void) untimeout(tid);
10100749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_enter(&softs->time_mutex);
10110749e8deSXin Chen - Sun Microsystems - Beijing China 	}
10120749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
10130749e8deSXin Chen - Sun Microsystems - Beijing China 
10140749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Destroy event thread */
10150749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
10160749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_signal(&softs->event_disp_cv);
10170749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
10180749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
10190749e8deSXin Chen - Sun Microsystems - Beijing China 
10200749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->aifq_cv);
10210749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event_disp_cv);
10220749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event_wait_cv);
1023942c5e3cSpl196000 	cv_destroy(&softs->drain_cv);
10240749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->sync_fib_cv);
10250749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_destroy(&softs->event);
10260749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->aifq_mutex);
10270749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->ev_lock);
10280749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->time_mutex);
10290749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_destroy(&softs->q_comp_mutex);
1030942c5e3cSpl196000 	mutex_destroy(&softs->io_lock);
1031942c5e3cSpl196000 
1032942c5e3cSpl196000 	ddi_regs_map_free(&softs->pci_mem_handle);
1033942c5e3cSpl196000 	aac_fm_fini(softs);
1034942c5e3cSpl196000 	softs->hwif = AAC_HWIF_UNKNOWN;
1035942c5e3cSpl196000 	softs->card = AAC_UNKNOWN_CARD;
1036942c5e3cSpl196000 	ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
1037942c5e3cSpl196000 
1038942c5e3cSpl196000 	return (DDI_SUCCESS);
1039942c5e3cSpl196000 }
1040942c5e3cSpl196000 
1041942c5e3cSpl196000 /*ARGSUSED*/
1042942c5e3cSpl196000 static int
aac_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)1043942c5e3cSpl196000 aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
1044942c5e3cSpl196000 {
1045942c5e3cSpl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
1046942c5e3cSpl196000 
1047942c5e3cSpl196000 	DBCALLED(softs, 1);
1048942c5e3cSpl196000 
1049942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
10501ee13a44SXinChen 	AAC_DISABLE_INTR(softs);
1051942c5e3cSpl196000 	(void) aac_shutdown(softs);
1052942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
1053942c5e3cSpl196000 
1054942c5e3cSpl196000 	return (DDI_SUCCESS);
1055942c5e3cSpl196000 }
1056942c5e3cSpl196000 
1057942c5e3cSpl196000 /*
105819397407SSherry Moore  * quiesce(9E) entry point.
105919397407SSherry Moore  *
106019397407SSherry Moore  * This function is called when the system is single-threaded at high
106119397407SSherry Moore  * PIL with preemption disabled. Therefore, this function must not be
106219397407SSherry Moore  * blocked.
106319397407SSherry Moore  *
106419397407SSherry Moore  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
106519397407SSherry Moore  * DDI_FAILURE indicates an error condition and should almost never happen.
106619397407SSherry Moore  */
106719397407SSherry Moore static int
aac_quiesce(dev_info_t * dip)106819397407SSherry Moore aac_quiesce(dev_info_t *dip)
106919397407SSherry Moore {
107019397407SSherry Moore 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
107119397407SSherry Moore 
107219397407SSherry Moore 	if (softs == NULL)
107319397407SSherry Moore 		return (DDI_FAILURE);
107419397407SSherry Moore 
10750749e8deSXin Chen - Sun Microsystems - Beijing China 	_NOTE(ASSUMING_PROTECTED(softs->state))
107619397407SSherry Moore 	AAC_DISABLE_INTR(softs);
107719397407SSherry Moore 
107819397407SSherry Moore 	return (DDI_SUCCESS);
107919397407SSherry Moore }
108019397407SSherry Moore 
1081f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /* ARGSUSED */
1082f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_getinfo(dev_info_t * self,ddi_info_cmd_t infocmd,void * arg,void ** result)1083f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
1084f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     void **result)
1085f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1086f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int error = DDI_SUCCESS;
1087f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1088f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	switch (infocmd) {
1089f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	case DDI_INFO_DEVT2INSTANCE:
1090f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		*result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
1091f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		break;
1092f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	default:
1093f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		error = DDI_FAILURE;
1094f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1095f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (error);
1096f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1097f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
109819397407SSherry Moore /*
1099942c5e3cSpl196000  * Bring the controller down to a dormant state and detach all child devices.
1100942c5e3cSpl196000  * This function is called before detach or system shutdown.
1101942c5e3cSpl196000  * Note: we can assume that the q_wait on the controller is empty, as we
1102942c5e3cSpl196000  * won't allow shutdown if any device is open.
1103942c5e3cSpl196000  */
1104942c5e3cSpl196000 static int
aac_shutdown(struct aac_softstate * softs)1105942c5e3cSpl196000 aac_shutdown(struct aac_softstate *softs)
1106942c5e3cSpl196000 {
1107f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
1108f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_close_command *cc;
1109942c5e3cSpl196000 	int rval;
1110942c5e3cSpl196000 
1111f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
1112f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
1113f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1114f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
1115f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1116942c5e3cSpl196000 	ddi_put32(acc, &cc->Command, VM_CloseAll);
1117942c5e3cSpl196000 	ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
1118942c5e3cSpl196000 
1119942c5e3cSpl196000 	/* Flush all caches, set FW to write through mode */
1120942c5e3cSpl196000 	rval = aac_sync_fib(softs, ContainerCommand,
1121942c5e3cSpl196000 	    AAC_FIB_SIZEOF(struct aac_close_command));
1122f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
1123942c5e3cSpl196000 
1124942c5e3cSpl196000 	AACDB_PRINT(softs, CE_NOTE,
1125942c5e3cSpl196000 	    "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
1126942c5e3cSpl196000 	return (rval);
1127942c5e3cSpl196000 }
1128942c5e3cSpl196000 
1129942c5e3cSpl196000 static uint_t
aac_softintr(caddr_t arg)1130942c5e3cSpl196000 aac_softintr(caddr_t arg)
1131942c5e3cSpl196000 {
1132a74f7440Spl196000 	struct aac_softstate *softs = (void *)arg;
1133942c5e3cSpl196000 
1134942c5e3cSpl196000 	if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
1135942c5e3cSpl196000 		aac_drain_comp_q(softs);
1136942c5e3cSpl196000 	}
1137f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (DDI_INTR_CLAIMED);
1138942c5e3cSpl196000 }
1139942c5e3cSpl196000 
1140942c5e3cSpl196000 /*
1141942c5e3cSpl196000  * Setup auto sense data for pkt
1142942c5e3cSpl196000  */
1143942c5e3cSpl196000 static void
aac_set_arq_data(struct scsi_pkt * pkt,uchar_t key,uchar_t add_code,uchar_t qual_code,uint64_t info)1144942c5e3cSpl196000 aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
1145942c5e3cSpl196000     uchar_t add_code, uchar_t qual_code, uint64_t info)
1146942c5e3cSpl196000 {
114758bc78c7SXin Chen 	struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
1148942c5e3cSpl196000 
114958bc78c7SXin Chen 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
115058bc78c7SXin Chen 	pkt->pkt_state |= STATE_ARQ_DONE;
1151942c5e3cSpl196000 
115258bc78c7SXin Chen 	*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
1153942c5e3cSpl196000 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
1154942c5e3cSpl196000 	arqstat->sts_rqpkt_resid = 0;
1155942c5e3cSpl196000 	arqstat->sts_rqpkt_state =
1156942c5e3cSpl196000 	    STATE_GOT_BUS |
1157942c5e3cSpl196000 	    STATE_GOT_TARGET |
1158942c5e3cSpl196000 	    STATE_SENT_CMD |
1159942c5e3cSpl196000 	    STATE_XFERRED_DATA;
1160942c5e3cSpl196000 	arqstat->sts_rqpkt_statistics = 0;
1161942c5e3cSpl196000 
1162942c5e3cSpl196000 	if (info <= 0xfffffffful) {
1163942c5e3cSpl196000 		arqstat->sts_sensedata.es_valid = 1;
1164942c5e3cSpl196000 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
1165942c5e3cSpl196000 		arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
1166942c5e3cSpl196000 		arqstat->sts_sensedata.es_key = key;
1167942c5e3cSpl196000 		arqstat->sts_sensedata.es_add_code = add_code;
1168942c5e3cSpl196000 		arqstat->sts_sensedata.es_qual_code = qual_code;
1169942c5e3cSpl196000 
1170942c5e3cSpl196000 		arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
1171942c5e3cSpl196000 		arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
1172942c5e3cSpl196000 		arqstat->sts_sensedata.es_info_3 = (info >>  8) & 0xFF;
1173942c5e3cSpl196000 		arqstat->sts_sensedata.es_info_4 = info & 0xFF;
1174942c5e3cSpl196000 	} else { /* 64-bit LBA */
1175942c5e3cSpl196000 		struct scsi_descr_sense_hdr *dsp;
1176942c5e3cSpl196000 		struct scsi_information_sense_descr *isd;
1177942c5e3cSpl196000 
1178942c5e3cSpl196000 		dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
1179942c5e3cSpl196000 		dsp->ds_class = CLASS_EXTENDED_SENSE;
1180942c5e3cSpl196000 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
1181942c5e3cSpl196000 		dsp->ds_key = key;
1182942c5e3cSpl196000 		dsp->ds_add_code = add_code;
1183942c5e3cSpl196000 		dsp->ds_qual_code = qual_code;
1184942c5e3cSpl196000 		dsp->ds_addl_sense_length =
1185942c5e3cSpl196000 		    sizeof (struct scsi_information_sense_descr);
1186942c5e3cSpl196000 
1187942c5e3cSpl196000 		isd = (struct scsi_information_sense_descr *)(dsp+1);
1188942c5e3cSpl196000 		isd->isd_descr_type = DESCR_INFORMATION;
1189942c5e3cSpl196000 		isd->isd_valid = 1;
1190942c5e3cSpl196000 		isd->isd_information[0] = (info >> 56) & 0xFF;
1191942c5e3cSpl196000 		isd->isd_information[1] = (info >> 48) & 0xFF;
1192942c5e3cSpl196000 		isd->isd_information[2] = (info >> 40) & 0xFF;
1193942c5e3cSpl196000 		isd->isd_information[3] = (info >> 32) & 0xFF;
1194942c5e3cSpl196000 		isd->isd_information[4] = (info >> 24) & 0xFF;
1195942c5e3cSpl196000 		isd->isd_information[5] = (info >> 16) & 0xFF;
1196942c5e3cSpl196000 		isd->isd_information[6] = (info >>  8) & 0xFF;
1197942c5e3cSpl196000 		isd->isd_information[7] = (info) & 0xFF;
1198942c5e3cSpl196000 	}
1199942c5e3cSpl196000 }
1200942c5e3cSpl196000 
1201942c5e3cSpl196000 /*
1202942c5e3cSpl196000  * Setup auto sense data for HARDWARE ERROR
1203942c5e3cSpl196000  */
1204942c5e3cSpl196000 static void
aac_set_arq_data_hwerr(struct aac_cmd * acp)1205942c5e3cSpl196000 aac_set_arq_data_hwerr(struct aac_cmd *acp)
1206942c5e3cSpl196000 {
1207942c5e3cSpl196000 	union scsi_cdb *cdbp;
1208942c5e3cSpl196000 	uint64_t err_blkno;
1209942c5e3cSpl196000 
1210a74f7440Spl196000 	cdbp = (void *)acp->pkt->pkt_cdbp;
1211942c5e3cSpl196000 	err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
1212942c5e3cSpl196000 	aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
1213942c5e3cSpl196000 }
1214942c5e3cSpl196000 
1215942c5e3cSpl196000 /*
1216942c5e3cSpl196000  * Send a command to the adapter in New Comm. interface
1217942c5e3cSpl196000  */
1218942c5e3cSpl196000 static int
aac_send_command(struct aac_softstate * softs,struct aac_slot * slotp)1219942c5e3cSpl196000 aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
1220942c5e3cSpl196000 {
1221942c5e3cSpl196000 	uint32_t index, device;
1222942c5e3cSpl196000 
1223942c5e3cSpl196000 	index = PCI_MEM_GET32(softs, AAC_IQUE);
1224942c5e3cSpl196000 	if (index == 0xffffffffUL) {
1225942c5e3cSpl196000 		index = PCI_MEM_GET32(softs, AAC_IQUE);
1226942c5e3cSpl196000 		if (index == 0xffffffffUL)
1227942c5e3cSpl196000 			return (AACERR);
1228942c5e3cSpl196000 	}
1229942c5e3cSpl196000 
1230942c5e3cSpl196000 	device = index;
1231942c5e3cSpl196000 	PCI_MEM_PUT32(softs, device,
1232942c5e3cSpl196000 	    (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
1233942c5e3cSpl196000 	device += 4;
1234942c5e3cSpl196000 	PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
1235942c5e3cSpl196000 	device += 4;
1236942c5e3cSpl196000 	PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
1237942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_IQUE, index);
1238942c5e3cSpl196000 	return (AACOK);
1239942c5e3cSpl196000 }
1240942c5e3cSpl196000 
1241942c5e3cSpl196000 static void
aac_end_io(struct aac_softstate * softs,struct aac_cmd * acp)1242942c5e3cSpl196000 aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
1243942c5e3cSpl196000 {
124458bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
1245942c5e3cSpl196000 	int q = AAC_CMDQ(acp);
1246942c5e3cSpl196000 
1247942c5e3cSpl196000 	if (acp->slotp) { /* outstanding cmd */
1248f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
1249942c5e3cSpl196000 			aac_release_slot(softs, acp->slotp);
1250942c5e3cSpl196000 			acp->slotp = NULL;
1251f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1252942c5e3cSpl196000 		if (dvp) {
1253942c5e3cSpl196000 			dvp->ncmds[q]--;
1254942c5e3cSpl196000 			if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
1255942c5e3cSpl196000 			    dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
1256942c5e3cSpl196000 				aac_set_throttle(softs, dvp, q,
1257942c5e3cSpl196000 				    softs->total_slots);
1258f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			/*
1259f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Setup auto sense data for UNIT ATTENTION
1260f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Each lun should generate a unit attention
1261f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * condition when reset.
1262f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * Phys. drives are treated as logical ones
1263f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 * during error recovery.
1264f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			 */
1265f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (dvp->type == AAC_DEV_LD) {
1266f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				struct aac_container *ctp =
1267f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    (struct aac_container *)dvp;
1268f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				if (ctp->reset == 0)
1269f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 					goto noreset;
1270f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1271f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				AACDB_PRINT(softs, CE_NOTE,
1272f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    "Unit attention: reset");
1273f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				ctp->reset = 0;
1274f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
1275f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    0x29, 0x02, 0);
1276942c5e3cSpl196000 			}
1277f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1278f42c2f53Szhongyan gu - Sun Microsystems - Beijing China noreset:
1279942c5e3cSpl196000 		softs->bus_ncmds[q]--;
1280f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_cmd_delete(&softs->q_busy, acp);
1281942c5e3cSpl196000 	} else { /* cmd in waiting queue */
1282942c5e3cSpl196000 		aac_cmd_delete(&softs->q_wait[q], acp);
1283942c5e3cSpl196000 	}
1284942c5e3cSpl196000 
1285942c5e3cSpl196000 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
1286942c5e3cSpl196000 		mutex_enter(&softs->q_comp_mutex);
1287942c5e3cSpl196000 		aac_cmd_enqueue(&softs->q_comp, acp);
1288942c5e3cSpl196000 		mutex_exit(&softs->q_comp_mutex);
1289942c5e3cSpl196000 	} else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
1290942c5e3cSpl196000 		cv_broadcast(&softs->event);
1291942c5e3cSpl196000 	}
1292942c5e3cSpl196000 }
1293942c5e3cSpl196000 
1294942c5e3cSpl196000 static void
aac_handle_io(struct aac_softstate * softs,int index)1295942c5e3cSpl196000 aac_handle_io(struct aac_softstate *softs, int index)
1296942c5e3cSpl196000 {
1297942c5e3cSpl196000 	struct aac_slot *slotp;
1298942c5e3cSpl196000 	struct aac_cmd *acp;
1299942c5e3cSpl196000 	uint32_t fast;
1300942c5e3cSpl196000 
1301942c5e3cSpl196000 	fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
1302942c5e3cSpl196000 	index >>= 2;
1303942c5e3cSpl196000 
1304942c5e3cSpl196000 	/* Make sure firmware reported index is valid */
1305942c5e3cSpl196000 	ASSERT(index >= 0 && index < softs->total_slots);
1306942c5e3cSpl196000 	slotp = &softs->io_slot[index];
1307942c5e3cSpl196000 	ASSERT(slotp->index == index);
1308942c5e3cSpl196000 	acp = slotp->acp;
130958bc78c7SXin Chen 
131058bc78c7SXin Chen 	if (acp == NULL || acp->slotp != slotp) {
131158bc78c7SXin Chen 		cmn_err(CE_WARN,
131258bc78c7SXin Chen 		    "Firmware error: invalid slot index received from FW");
131358bc78c7SXin Chen 		return;
131458bc78c7SXin Chen 	}
1315942c5e3cSpl196000 
1316942c5e3cSpl196000 	acp->flags |= AAC_CMD_CMPLT;
1317942c5e3cSpl196000 	(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
1318942c5e3cSpl196000 
1319942c5e3cSpl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
1320942c5e3cSpl196000 		/*
1321942c5e3cSpl196000 		 * For fast response IO, the firmware do not return any FIB
1322942c5e3cSpl196000 		 * data, so we need to fill in the FIB status and state so that
1323942c5e3cSpl196000 		 * FIB users can handle it correctly.
1324942c5e3cSpl196000 		 */
1325942c5e3cSpl196000 		if (fast) {
1326942c5e3cSpl196000 			uint32_t state;
1327942c5e3cSpl196000 
1328942c5e3cSpl196000 			state = ddi_get32(slotp->fib_acc_handle,
1329942c5e3cSpl196000 			    &slotp->fibp->Header.XferState);
1330942c5e3cSpl196000 			/*
1331942c5e3cSpl196000 			 * Update state for CPU not for device, no DMA sync
1332942c5e3cSpl196000 			 * needed
1333942c5e3cSpl196000 			 */
1334942c5e3cSpl196000 			ddi_put32(slotp->fib_acc_handle,
1335942c5e3cSpl196000 			    &slotp->fibp->Header.XferState,
1336942c5e3cSpl196000 			    state | AAC_FIBSTATE_DONEADAP);
1337942c5e3cSpl196000 			ddi_put32(slotp->fib_acc_handle,
1338a74f7440Spl196000 			    (void *)&slotp->fibp->data[0], ST_OK);
1339942c5e3cSpl196000 		}
1340942c5e3cSpl196000 
1341942c5e3cSpl196000 		/* Handle completed ac */
1342942c5e3cSpl196000 		acp->ac_comp(softs, acp);
1343942c5e3cSpl196000 	} else {
1344942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1345942c5e3cSpl196000 		acp->flags |= AAC_CMD_ERR;
1346942c5e3cSpl196000 		if (acp->pkt) {
1347942c5e3cSpl196000 			acp->pkt->pkt_reason = CMD_TRAN_ERR;
1348942c5e3cSpl196000 			acp->pkt->pkt_statistics = 0;
1349942c5e3cSpl196000 		}
1350942c5e3cSpl196000 	}
1351942c5e3cSpl196000 	aac_end_io(softs, acp);
1352942c5e3cSpl196000 }
1353942c5e3cSpl196000 
1354942c5e3cSpl196000 /*
1355942c5e3cSpl196000  * Interrupt handler for New Comm. interface
1356942c5e3cSpl196000  * New Comm. interface use a different mechanism for interrupt. No explict
1357942c5e3cSpl196000  * message queues, and driver need only accesses the mapped PCI mem space to
1358942c5e3cSpl196000  * find the completed FIB or AIF.
1359942c5e3cSpl196000  */
1360942c5e3cSpl196000 static int
aac_process_intr_new(struct aac_softstate * softs)1361942c5e3cSpl196000 aac_process_intr_new(struct aac_softstate *softs)
1362942c5e3cSpl196000 {
1363942c5e3cSpl196000 	uint32_t index;
1364942c5e3cSpl196000 
1365942c5e3cSpl196000 	index = AAC_OUTB_GET(softs);
1366942c5e3cSpl196000 	if (index == 0xfffffffful)
1367942c5e3cSpl196000 		index = AAC_OUTB_GET(softs);
1368942c5e3cSpl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1369942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
137058bc78c7SXin Chen 		return (0);
1371942c5e3cSpl196000 	}
1372942c5e3cSpl196000 	if (index != 0xfffffffful) {
1373942c5e3cSpl196000 		do {
1374942c5e3cSpl196000 			if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
1375942c5e3cSpl196000 				aac_handle_io(softs, index);
1376942c5e3cSpl196000 			} else if (index != 0xfffffffeul) {
1377942c5e3cSpl196000 				struct aac_fib *fibp;	/* FIB in AIF queue */
13780749e8deSXin Chen - Sun Microsystems - Beijing China 				uint16_t fib_size;
1379942c5e3cSpl196000 
1380942c5e3cSpl196000 				/*
1381942c5e3cSpl196000 				 * 0xfffffffe means that the controller wants
1382942c5e3cSpl196000 				 * more work, ignore it for now. Otherwise,
1383942c5e3cSpl196000 				 * AIF received.
1384942c5e3cSpl196000 				 */
1385942c5e3cSpl196000 				index &= ~2;
1386942c5e3cSpl196000 
13870749e8deSXin Chen - Sun Microsystems - Beijing China 				fibp = (struct aac_fib *)(softs-> \
13880749e8deSXin Chen - Sun Microsystems - Beijing China 				    pci_mem_base_vaddr + index);
13890749e8deSXin Chen - Sun Microsystems - Beijing China 				fib_size = PCI_MEM_GET16(softs, index + \
1390942c5e3cSpl196000 				    offsetof(struct aac_fib, Header.Size));
1391942c5e3cSpl196000 
13920749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_save_aif(softs, softs->pci_mem_handle,
13930749e8deSXin Chen - Sun Microsystems - Beijing China 				    fibp, fib_size);
1394942c5e3cSpl196000 
1395942c5e3cSpl196000 				/*
1396942c5e3cSpl196000 				 * AIF memory is owned by the adapter, so let it
1397942c5e3cSpl196000 				 * know that we are done with it.
1398942c5e3cSpl196000 				 */
1399942c5e3cSpl196000 				AAC_OUTB_SET(softs, index);
1400942c5e3cSpl196000 				AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1401942c5e3cSpl196000 			}
1402942c5e3cSpl196000 
1403942c5e3cSpl196000 			index = AAC_OUTB_GET(softs);
1404942c5e3cSpl196000 		} while (index != 0xfffffffful);
1405942c5e3cSpl196000 
1406942c5e3cSpl196000 		/*
1407942c5e3cSpl196000 		 * Process waiting cmds before start new ones to
1408942c5e3cSpl196000 		 * ensure first IOs are serviced first.
1409942c5e3cSpl196000 		 */
1410942c5e3cSpl196000 		aac_start_waiting_io(softs);
1411942c5e3cSpl196000 		return (AAC_DB_COMMAND_READY);
1412942c5e3cSpl196000 	} else {
1413942c5e3cSpl196000 		return (0);
1414942c5e3cSpl196000 	}
1415942c5e3cSpl196000 }
1416942c5e3cSpl196000 
1417942c5e3cSpl196000 static uint_t
aac_intr_new(caddr_t arg)1418942c5e3cSpl196000 aac_intr_new(caddr_t arg)
1419942c5e3cSpl196000 {
1420a74f7440Spl196000 	struct aac_softstate *softs = (void *)arg;
1421942c5e3cSpl196000 	uint_t rval;
1422942c5e3cSpl196000 
1423942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
1424942c5e3cSpl196000 	if (aac_process_intr_new(softs))
1425942c5e3cSpl196000 		rval = DDI_INTR_CLAIMED;
1426942c5e3cSpl196000 	else
1427942c5e3cSpl196000 		rval = DDI_INTR_UNCLAIMED;
1428942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
1429942c5e3cSpl196000 
1430942c5e3cSpl196000 	aac_drain_comp_q(softs);
1431942c5e3cSpl196000 	return (rval);
1432942c5e3cSpl196000 }
1433942c5e3cSpl196000 
1434942c5e3cSpl196000 /*
1435942c5e3cSpl196000  * Interrupt handler for old interface
1436942c5e3cSpl196000  * Explicit message queues are used to send FIB to and get completed FIB from
1437942c5e3cSpl196000  * the adapter. Driver and adapter maitain the queues in the producer/consumer
1438942c5e3cSpl196000  * manner. The driver has to query the queues to find the completed FIB.
1439942c5e3cSpl196000  */
1440942c5e3cSpl196000 static int
aac_process_intr_old(struct aac_softstate * softs)1441942c5e3cSpl196000 aac_process_intr_old(struct aac_softstate *softs)
1442942c5e3cSpl196000 {
1443942c5e3cSpl196000 	uint16_t status;
1444942c5e3cSpl196000 
1445942c5e3cSpl196000 	status = AAC_STATUS_GET(softs);
1446942c5e3cSpl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
1447942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
1448942c5e3cSpl196000 		return (DDI_INTR_UNCLAIMED);
1449942c5e3cSpl196000 	}
1450942c5e3cSpl196000 	if (status & AAC_DB_RESPONSE_READY) {
1451942c5e3cSpl196000 		int slot_idx;
1452942c5e3cSpl196000 
1453942c5e3cSpl196000 		/* ACK the intr */
1454942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
1455942c5e3cSpl196000 		(void) AAC_STATUS_GET(softs);
1456942c5e3cSpl196000 		while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
1457942c5e3cSpl196000 		    &slot_idx) == AACOK)
1458942c5e3cSpl196000 			aac_handle_io(softs, slot_idx);
1459942c5e3cSpl196000 
1460942c5e3cSpl196000 		/*
1461942c5e3cSpl196000 		 * Process waiting cmds before start new ones to
1462942c5e3cSpl196000 		 * ensure first IOs are serviced first.
1463942c5e3cSpl196000 		 */
1464942c5e3cSpl196000 		aac_start_waiting_io(softs);
1465942c5e3cSpl196000 		return (AAC_DB_RESPONSE_READY);
1466942c5e3cSpl196000 	} else if (status & AAC_DB_COMMAND_READY) {
1467942c5e3cSpl196000 		int aif_idx;
1468942c5e3cSpl196000 
1469942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
1470942c5e3cSpl196000 		(void) AAC_STATUS_GET(softs);
1471942c5e3cSpl196000 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
1472942c5e3cSpl196000 		    AACOK) {
1473942c5e3cSpl196000 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
14740749e8deSXin Chen - Sun Microsystems - Beijing China 			struct aac_fib *fibp;	/* FIB in communication space */
14750749e8deSXin Chen - Sun Microsystems - Beijing China 			uint16_t fib_size;
1476942c5e3cSpl196000 			uint32_t fib_xfer_state;
1477942c5e3cSpl196000 			uint32_t addr, size;
1478942c5e3cSpl196000 
1479942c5e3cSpl196000 			ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
1480942c5e3cSpl196000 
1481942c5e3cSpl196000 #define	AAC_SYNC_AIF(softs, aif_idx, type) \
1482942c5e3cSpl196000 	{ (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
1483942c5e3cSpl196000 	    offsetof(struct aac_comm_space, \
1484942c5e3cSpl196000 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
1485942c5e3cSpl196000 	    (type)); }
1486942c5e3cSpl196000 
1487942c5e3cSpl196000 			/* Copy AIF from adapter to the empty AIF slot */
1488942c5e3cSpl196000 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
14890749e8deSXin Chen - Sun Microsystems - Beijing China 			fibp = &softs->comm_space->adapter_fibs[aif_idx];
14900749e8deSXin Chen - Sun Microsystems - Beijing China 			fib_size = ddi_get16(acc, &fibp->Header.Size);
1491942c5e3cSpl196000 
14920749e8deSXin Chen - Sun Microsystems - Beijing China 			aac_save_aif(softs, acc, fibp, fib_size);
1493942c5e3cSpl196000 
1494942c5e3cSpl196000 			/* Complete AIF back to adapter with good status */
1495942c5e3cSpl196000 			fib_xfer_state = LE_32(fibp->Header.XferState);
1496942c5e3cSpl196000 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
14970749e8deSXin Chen - Sun Microsystems - Beijing China 				ddi_put32(acc, &fibp->Header.XferState,
1498942c5e3cSpl196000 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
14990749e8deSXin Chen - Sun Microsystems - Beijing China 				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
15000749e8deSXin Chen - Sun Microsystems - Beijing China 				if (fib_size > AAC_FIB_SIZE)
15010749e8deSXin Chen - Sun Microsystems - Beijing China 					ddi_put16(acc, &fibp->Header.Size,
1502942c5e3cSpl196000 					    AAC_FIB_SIZE);
1503942c5e3cSpl196000 				AAC_SYNC_AIF(softs, aif_idx,
1504942c5e3cSpl196000 				    DDI_DMA_SYNC_FORDEV);
1505942c5e3cSpl196000 			}
1506942c5e3cSpl196000 
1507942c5e3cSpl196000 			/* Put the AIF response on the response queue */
1508942c5e3cSpl196000 			addr = ddi_get32(acc,
1509942c5e3cSpl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1510942c5e3cSpl196000 			    Header.SenderFibAddress);
1511942c5e3cSpl196000 			size = (uint32_t)ddi_get16(acc,
1512942c5e3cSpl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1513942c5e3cSpl196000 			    Header.Size);
1514942c5e3cSpl196000 			ddi_put32(acc,
1515942c5e3cSpl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
1516942c5e3cSpl196000 			    Header.ReceiverFibAddress, addr);
1517942c5e3cSpl196000 			if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
1518942c5e3cSpl196000 			    addr, size) == AACERR)
1519942c5e3cSpl196000 				cmn_err(CE_NOTE, "!AIF ack failed");
1520942c5e3cSpl196000 		}
1521942c5e3cSpl196000 		return (AAC_DB_COMMAND_READY);
1522942c5e3cSpl196000 	} else if (status & AAC_DB_PRINTF_READY) {
1523942c5e3cSpl196000 		/* ACK the intr */
1524942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
1525942c5e3cSpl196000 		(void) AAC_STATUS_GET(softs);
1526942c5e3cSpl196000 		(void) ddi_dma_sync(softs->comm_space_dma_handle,
1527942c5e3cSpl196000 		    offsetof(struct aac_comm_space, adapter_print_buf),
1528942c5e3cSpl196000 		    AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
1529942c5e3cSpl196000 		if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
1530942c5e3cSpl196000 		    DDI_SUCCESS)
1531942c5e3cSpl196000 			cmn_err(CE_NOTE, "MSG From Adapter: %s",
1532942c5e3cSpl196000 			    softs->comm_space->adapter_print_buf);
1533942c5e3cSpl196000 		else
1534942c5e3cSpl196000 			ddi_fm_service_impact(softs->devinfo_p,
1535942c5e3cSpl196000 			    DDI_SERVICE_UNAFFECTED);
1536942c5e3cSpl196000 		AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
1537942c5e3cSpl196000 		return (AAC_DB_PRINTF_READY);
1538942c5e3cSpl196000 	} else if (status & AAC_DB_COMMAND_NOT_FULL) {
1539942c5e3cSpl196000 		/*
1540942c5e3cSpl196000 		 * Without these two condition statements, the OS could hang
1541942c5e3cSpl196000 		 * after a while, especially if there are a lot of AIF's to
1542942c5e3cSpl196000 		 * handle, for instance if a drive is pulled from an array
1543942c5e3cSpl196000 		 * under heavy load.
1544942c5e3cSpl196000 		 */
1545942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1546942c5e3cSpl196000 		return (AAC_DB_COMMAND_NOT_FULL);
1547942c5e3cSpl196000 	} else if (status & AAC_DB_RESPONSE_NOT_FULL) {
1548942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
1549942c5e3cSpl196000 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
1550942c5e3cSpl196000 		return (AAC_DB_RESPONSE_NOT_FULL);
1551942c5e3cSpl196000 	} else {
1552942c5e3cSpl196000 		return (0);
1553942c5e3cSpl196000 	}
1554942c5e3cSpl196000 }
1555942c5e3cSpl196000 
1556942c5e3cSpl196000 static uint_t
aac_intr_old(caddr_t arg)1557942c5e3cSpl196000 aac_intr_old(caddr_t arg)
1558942c5e3cSpl196000 {
1559a74f7440Spl196000 	struct aac_softstate *softs = (void *)arg;
1560942c5e3cSpl196000 	int rval;
1561942c5e3cSpl196000 
1562942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
1563942c5e3cSpl196000 	if (aac_process_intr_old(softs))
1564942c5e3cSpl196000 		rval = DDI_INTR_CLAIMED;
1565942c5e3cSpl196000 	else
1566942c5e3cSpl196000 		rval = DDI_INTR_UNCLAIMED;
1567942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
1568942c5e3cSpl196000 
1569942c5e3cSpl196000 	aac_drain_comp_q(softs);
1570942c5e3cSpl196000 	return (rval);
1571942c5e3cSpl196000 }
1572942c5e3cSpl196000 
1573942c5e3cSpl196000 /*
1574b6094a86Sjd218194  * Query FIXED or MSI interrupts
1575b6094a86Sjd218194  */
1576b6094a86Sjd218194 static int
aac_query_intrs(struct aac_softstate * softs,int intr_type)1577b6094a86Sjd218194 aac_query_intrs(struct aac_softstate *softs, int intr_type)
1578b6094a86Sjd218194 {
1579b6094a86Sjd218194 	dev_info_t *dip = softs->devinfo_p;
1580f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int avail, actual, count;
1581b6094a86Sjd218194 	int i, flag, ret;
1582b6094a86Sjd218194 
1583b6094a86Sjd218194 	AACDB_PRINT(softs, CE_NOTE,
1584b6094a86Sjd218194 	    "aac_query_intrs:interrupt type 0x%x", intr_type);
1585b6094a86Sjd218194 
1586b6094a86Sjd218194 	/* Get number of interrupts */
1587b6094a86Sjd218194 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
1588b6094a86Sjd218194 	if ((ret != DDI_SUCCESS) || (count == 0)) {
1589b6094a86Sjd218194 		AACDB_PRINT(softs, CE_WARN,
1590b6094a86Sjd218194 		    "ddi_intr_get_nintrs() failed, ret %d count %d",
1591b6094a86Sjd218194 		    ret, count);
1592b6094a86Sjd218194 		return (DDI_FAILURE);
1593b6094a86Sjd218194 	}
1594b6094a86Sjd218194 
1595b6094a86Sjd218194 	/* Get number of available interrupts */
1596b6094a86Sjd218194 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
1597b6094a86Sjd218194 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
1598b6094a86Sjd218194 		AACDB_PRINT(softs, CE_WARN,
1599b6094a86Sjd218194 		    "ddi_intr_get_navail() failed, ret %d avail %d",
1600b6094a86Sjd218194 		    ret, avail);
1601b6094a86Sjd218194 		return (DDI_FAILURE);
1602b6094a86Sjd218194 	}
1603b6094a86Sjd218194 
1604b6094a86Sjd218194 	AACDB_PRINT(softs, CE_NOTE,
1605b6094a86Sjd218194 	    "ddi_intr_get_nvail returned %d, navail() returned %d",
1606b6094a86Sjd218194 	    count, avail);
1607b6094a86Sjd218194 
1608b6094a86Sjd218194 	/* Allocate an array of interrupt handles */
1609f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	softs->intr_size = count * sizeof (ddi_intr_handle_t);
1610f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
1611b6094a86Sjd218194 
1612b6094a86Sjd218194 	if (intr_type == DDI_INTR_TYPE_MSI) {
1613b6094a86Sjd218194 		count = 1; /* only one vector needed by now */
1614b6094a86Sjd218194 		flag = DDI_INTR_ALLOC_STRICT;
1615b6094a86Sjd218194 	} else { /* must be DDI_INTR_TYPE_FIXED */
1616b6094a86Sjd218194 		flag = DDI_INTR_ALLOC_NORMAL;
1617b6094a86Sjd218194 	}
1618b6094a86Sjd218194 
1619b6094a86Sjd218194 	/* Call ddi_intr_alloc() */
1620b6094a86Sjd218194 	ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
1621b6094a86Sjd218194 	    count, &actual, flag);
1622b6094a86Sjd218194 
1623b6094a86Sjd218194 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
1624b6094a86Sjd218194 		AACDB_PRINT(softs, CE_WARN,
1625b6094a86Sjd218194 		    "ddi_intr_alloc() failed, ret = %d", ret);
1626b6094a86Sjd218194 		actual = 0;
1627b6094a86Sjd218194 		goto error;
1628b6094a86Sjd218194 	}
1629b6094a86Sjd218194 
1630b6094a86Sjd218194 	if (actual < count) {
1631b6094a86Sjd218194 		AACDB_PRINT(softs, CE_NOTE,
1632b6094a86Sjd218194 		    "Requested: %d, Received: %d", count, actual);
1633b6094a86Sjd218194 		goto error;
1634b6094a86Sjd218194 	}
1635b6094a86Sjd218194 
1636b6094a86Sjd218194 	softs->intr_cnt = actual;
1637b6094a86Sjd218194 
1638b6094a86Sjd218194 	/* Get priority for first msi, assume remaining are all the same */
1639b6094a86Sjd218194 	if ((ret = ddi_intr_get_pri(softs->htable[0],
1640b6094a86Sjd218194 	    &softs->intr_pri)) != DDI_SUCCESS) {
1641b6094a86Sjd218194 		AACDB_PRINT(softs, CE_WARN,
1642b6094a86Sjd218194 		    "ddi_intr_get_pri() failed, ret = %d", ret);
1643b6094a86Sjd218194 		goto error;
1644b6094a86Sjd218194 	}
1645b6094a86Sjd218194 
1646b6094a86Sjd218194 	/* Test for high level mutex */
1647b6094a86Sjd218194 	if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
1648b6094a86Sjd218194 		AACDB_PRINT(softs, CE_WARN,
1649b6094a86Sjd218194 		    "aac_query_intrs: Hi level interrupt not supported");
1650b6094a86Sjd218194 		goto error;
1651b6094a86Sjd218194 	}
1652b6094a86Sjd218194 
1653b6094a86Sjd218194 	return (DDI_SUCCESS);
1654b6094a86Sjd218194 
1655b6094a86Sjd218194 error:
1656b6094a86Sjd218194 	/* Free already allocated intr */
1657b6094a86Sjd218194 	for (i = 0; i < actual; i++)
1658b6094a86Sjd218194 		(void) ddi_intr_free(softs->htable[i]);
1659b6094a86Sjd218194 
1660f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	kmem_free(softs->htable, softs->intr_size);
1661b6094a86Sjd218194 	return (DDI_FAILURE);
1662b6094a86Sjd218194 }
1663b6094a86Sjd218194 
1664349b53ddSStuart Maybee 
1665b6094a86Sjd218194 /*
1666b6094a86Sjd218194  * Register FIXED or MSI interrupts, and enable them
1667b6094a86Sjd218194  */
1668b6094a86Sjd218194 static int
aac_add_intrs(struct aac_softstate * softs)1669b6094a86Sjd218194 aac_add_intrs(struct aac_softstate *softs)
1670b6094a86Sjd218194 {
1671b6094a86Sjd218194 	int i, ret;
1672f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int actual;
1673b6094a86Sjd218194 	ddi_intr_handler_t *aac_intr;
1674b6094a86Sjd218194 
1675b6094a86Sjd218194 	actual = softs->intr_cnt;
1676b6094a86Sjd218194 	aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
1677b6094a86Sjd218194 	    aac_intr_new : aac_intr_old);
1678b6094a86Sjd218194 
1679b6094a86Sjd218194 	/* Call ddi_intr_add_handler() */
1680b6094a86Sjd218194 	for (i = 0; i < actual; i++) {
1681b6094a86Sjd218194 		if ((ret = ddi_intr_add_handler(softs->htable[i],
1682b6094a86Sjd218194 		    aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
1683b6094a86Sjd218194 			cmn_err(CE_WARN,
1684b6094a86Sjd218194 			    "ddi_intr_add_handler() failed ret = %d", ret);
1685b6094a86Sjd218194 
1686b6094a86Sjd218194 			/* Free already allocated intr */
1687b6094a86Sjd218194 			for (i = 0; i < actual; i++)
1688b6094a86Sjd218194 				(void) ddi_intr_free(softs->htable[i]);
1689b6094a86Sjd218194 
1690f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			kmem_free(softs->htable, softs->intr_size);
1691b6094a86Sjd218194 			return (DDI_FAILURE);
1692b6094a86Sjd218194 		}
1693b6094a86Sjd218194 	}
1694b6094a86Sjd218194 
1695b6094a86Sjd218194 	if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
1696b6094a86Sjd218194 	    != DDI_SUCCESS) {
1697b6094a86Sjd218194 		cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
1698b6094a86Sjd218194 
1699b6094a86Sjd218194 		/* Free already allocated intr */
1700b6094a86Sjd218194 		for (i = 0; i < actual; i++)
1701b6094a86Sjd218194 			(void) ddi_intr_free(softs->htable[i]);
1702b6094a86Sjd218194 
1703f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		kmem_free(softs->htable, softs->intr_size);
1704b6094a86Sjd218194 		return (DDI_FAILURE);
1705b6094a86Sjd218194 	}
1706b6094a86Sjd218194 
1707b6094a86Sjd218194 	return (DDI_SUCCESS);
1708b6094a86Sjd218194 }
1709b6094a86Sjd218194 
1710b6094a86Sjd218194 /*
1711b6094a86Sjd218194  * Unregister FIXED or MSI interrupts
1712b6094a86Sjd218194  */
1713b6094a86Sjd218194 static void
aac_remove_intrs(struct aac_softstate * softs)1714b6094a86Sjd218194 aac_remove_intrs(struct aac_softstate *softs)
1715b6094a86Sjd218194 {
1716b6094a86Sjd218194 	int i;
1717b6094a86Sjd218194 
1718b6094a86Sjd218194 	/* Disable all interrupts */
1719f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_disable_intrs(softs);
1720b6094a86Sjd218194 	/* Call ddi_intr_remove_handler() */
1721b6094a86Sjd218194 	for (i = 0; i < softs->intr_cnt; i++) {
1722b6094a86Sjd218194 		(void) ddi_intr_remove_handler(softs->htable[i]);
1723b6094a86Sjd218194 		(void) ddi_intr_free(softs->htable[i]);
1724b6094a86Sjd218194 	}
1725b6094a86Sjd218194 
1726f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	kmem_free(softs->htable, softs->intr_size);
1727f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1728f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1729f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_enable_intrs(struct aac_softstate * softs)1730f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_enable_intrs(struct aac_softstate *softs)
1731f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1732f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval = AACOK;
1733f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1734f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1735f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* for MSI block enable */
1736f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
1737f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    DDI_SUCCESS)
1738f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
1739f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
1740f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		int i;
1741f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1742f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* Call ddi_intr_enable() for legacy/MSI non block enable */
1743f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		for (i = 0; i < softs->intr_cnt; i++) {
1744f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
1745f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				rval = AACERR;
1746f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1747f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1748f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
1749f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
1750f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1751f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_disable_intrs(struct aac_softstate * softs)1752f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_disable_intrs(struct aac_softstate *softs)
1753f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
1754f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval = AACOK;
1755f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1756f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
1757f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		/* Call ddi_intr_block_disable() */
1758f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
1759f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    DDI_SUCCESS)
1760f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
1761f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
1762f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		int i;
1763f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
1764f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		for (i = 0; i < softs->intr_cnt; i++) {
1765f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
1766f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				rval = AACERR;
1767f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
1768f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
1769f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
1770b6094a86Sjd218194 }
1771b6094a86Sjd218194 
1772b6094a86Sjd218194 /*
1773942c5e3cSpl196000  * Set pkt_reason and OR in pkt_statistics flag
1774942c5e3cSpl196000  */
1775942c5e3cSpl196000 static void
aac_set_pkt_reason(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason,uint_t stat)1776942c5e3cSpl196000 aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
1777942c5e3cSpl196000     uchar_t reason, uint_t stat)
1778942c5e3cSpl196000 {
1779942c5e3cSpl196000 #ifndef __lock_lint
1780942c5e3cSpl196000 	_NOTE(ARGUNUSED(softs))
1781942c5e3cSpl196000 #endif
1782942c5e3cSpl196000 	if (acp->pkt->pkt_reason == CMD_CMPLT)
1783942c5e3cSpl196000 		acp->pkt->pkt_reason = reason;
1784942c5e3cSpl196000 	acp->pkt->pkt_statistics |= stat;
1785942c5e3cSpl196000 }
1786942c5e3cSpl196000 
1787942c5e3cSpl196000 /*
1788942c5e3cSpl196000  * Handle a finished pkt of soft SCMD
1789942c5e3cSpl196000  */
1790942c5e3cSpl196000 static void
aac_soft_callback(struct aac_softstate * softs,struct aac_cmd * acp)1791942c5e3cSpl196000 aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
1792942c5e3cSpl196000 {
1793942c5e3cSpl196000 	ASSERT(acp->pkt);
1794942c5e3cSpl196000 
1795942c5e3cSpl196000 	acp->flags |= AAC_CMD_CMPLT;
1796942c5e3cSpl196000 
1797942c5e3cSpl196000 	acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
179858bc78c7SXin Chen 	    STATE_SENT_CMD | STATE_GOT_STATUS;
1799942c5e3cSpl196000 	if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
1800942c5e3cSpl196000 		acp->pkt->pkt_resid = 0;
1801942c5e3cSpl196000 
1802942c5e3cSpl196000 	/* AAC_CMD_NO_INTR means no complete callback */
1803942c5e3cSpl196000 	if (!(acp->flags & AAC_CMD_NO_INTR)) {
1804942c5e3cSpl196000 		mutex_enter(&softs->q_comp_mutex);
1805942c5e3cSpl196000 		aac_cmd_enqueue(&softs->q_comp, acp);
1806942c5e3cSpl196000 		mutex_exit(&softs->q_comp_mutex);
1807942c5e3cSpl196000 		ddi_trigger_softintr(softs->softint_id);
1808942c5e3cSpl196000 	}
1809942c5e3cSpl196000 }
1810942c5e3cSpl196000 
1811942c5e3cSpl196000 /*
1812942c5e3cSpl196000  * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
1813942c5e3cSpl196000  */
1814942c5e3cSpl196000 
1815942c5e3cSpl196000 /*
1816942c5e3cSpl196000  * Handle completed logical device IO command
1817942c5e3cSpl196000  */
1818942c5e3cSpl196000 /*ARGSUSED*/
1819942c5e3cSpl196000 static void
aac_ld_complete(struct aac_softstate * softs,struct aac_cmd * acp)1820942c5e3cSpl196000 aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
1821942c5e3cSpl196000 {
1822942c5e3cSpl196000 	struct aac_slot *slotp = acp->slotp;
1823942c5e3cSpl196000 	struct aac_blockread_response *resp;
1824942c5e3cSpl196000 	uint32_t status;
1825942c5e3cSpl196000 
1826942c5e3cSpl196000 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
1827942c5e3cSpl196000 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
1828942c5e3cSpl196000 
182958bc78c7SXin Chen 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
183058bc78c7SXin Chen 
1831942c5e3cSpl196000 	/*
1832942c5e3cSpl196000 	 * block_read/write has a similar response header, use blockread
1833942c5e3cSpl196000 	 * response for both.
1834942c5e3cSpl196000 	 */
1835942c5e3cSpl196000 	resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
1836942c5e3cSpl196000 	status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
1837942c5e3cSpl196000 	if (status == ST_OK) {
1838942c5e3cSpl196000 		acp->pkt->pkt_resid = 0;
1839942c5e3cSpl196000 		acp->pkt->pkt_state |= STATE_XFERRED_DATA;
1840942c5e3cSpl196000 	} else {
1841942c5e3cSpl196000 		aac_set_arq_data_hwerr(acp);
1842942c5e3cSpl196000 	}
1843942c5e3cSpl196000 }
1844942c5e3cSpl196000 
1845942c5e3cSpl196000 /*
184658bc78c7SXin Chen  * Handle completed phys. device IO command
184758bc78c7SXin Chen  */
184858bc78c7SXin Chen static void
aac_pd_complete(struct aac_softstate * softs,struct aac_cmd * acp)184958bc78c7SXin Chen aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
185058bc78c7SXin Chen {
185158bc78c7SXin Chen 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
185258bc78c7SXin Chen 	struct aac_fib *fibp = acp->slotp->fibp;
185358bc78c7SXin Chen 	struct scsi_pkt *pkt = acp->pkt;
185458bc78c7SXin Chen 	struct aac_srb_reply *resp;
185558bc78c7SXin Chen 	uint32_t resp_status;
185658bc78c7SXin Chen 
185758bc78c7SXin Chen 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
185858bc78c7SXin Chen 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
185958bc78c7SXin Chen 
186058bc78c7SXin Chen 	resp = (struct aac_srb_reply *)&fibp->data[0];
186158bc78c7SXin Chen 	resp_status = ddi_get32(acc, &resp->status);
186258bc78c7SXin Chen 
186358bc78c7SXin Chen 	/* First check FIB status */
186458bc78c7SXin Chen 	if (resp_status == ST_OK) {
186558bc78c7SXin Chen 		uint32_t scsi_status;
186658bc78c7SXin Chen 		uint32_t srb_status;
186758bc78c7SXin Chen 		uint32_t data_xfer_length;
186858bc78c7SXin Chen 
186958bc78c7SXin Chen 		scsi_status = ddi_get32(acc, &resp->scsi_status);
187058bc78c7SXin Chen 		srb_status = ddi_get32(acc, &resp->srb_status);
187158bc78c7SXin Chen 		data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
187258bc78c7SXin Chen 
187358bc78c7SXin Chen 		*pkt->pkt_scbp = (uint8_t)scsi_status;
187458bc78c7SXin Chen 		pkt->pkt_state |= STATE_GOT_STATUS;
187558bc78c7SXin Chen 		if (scsi_status == STATUS_GOOD) {
187658bc78c7SXin Chen 			uchar_t cmd = ((union scsi_cdb *)(void *)
187758bc78c7SXin Chen 			    (pkt->pkt_cdbp))->scc_cmd;
187858bc78c7SXin Chen 
187958bc78c7SXin Chen 			/* Next check SRB status */
188058bc78c7SXin Chen 			switch (srb_status & 0x3f) {
188158bc78c7SXin Chen 			case SRB_STATUS_DATA_OVERRUN:
188258bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
188358bc78c7SXin Chen 				    "scmd=%d, xfer=%d, buflen=%d",
188458bc78c7SXin Chen 				    (uint32_t)cmd, data_xfer_length,
188558bc78c7SXin Chen 				    acp->bcount);
188658bc78c7SXin Chen 
188758bc78c7SXin Chen 				switch (cmd) {
188858bc78c7SXin Chen 				case SCMD_READ:
188958bc78c7SXin Chen 				case SCMD_WRITE:
189058bc78c7SXin Chen 				case SCMD_READ_G1:
189158bc78c7SXin Chen 				case SCMD_WRITE_G1:
189258bc78c7SXin Chen 				case SCMD_READ_G4:
189358bc78c7SXin Chen 				case SCMD_WRITE_G4:
189458bc78c7SXin Chen 				case SCMD_READ_G5:
189558bc78c7SXin Chen 				case SCMD_WRITE_G5:
189658bc78c7SXin Chen 					aac_set_pkt_reason(softs, acp,
189758bc78c7SXin Chen 					    CMD_DATA_OVR, 0);
189858bc78c7SXin Chen 					break;
189958bc78c7SXin Chen 				}
190058bc78c7SXin Chen 				/*FALLTHRU*/
190158bc78c7SXin Chen 			case SRB_STATUS_ERROR_RECOVERY:
190258bc78c7SXin Chen 			case SRB_STATUS_PENDING:
190358bc78c7SXin Chen 			case SRB_STATUS_SUCCESS:
190458bc78c7SXin Chen 				/*
190558bc78c7SXin Chen 				 * pkt_resid should only be calculated if the
190658bc78c7SXin Chen 				 * status is ERROR_RECOVERY/PENDING/SUCCESS/
190758bc78c7SXin Chen 				 * OVERRUN/UNDERRUN
190858bc78c7SXin Chen 				 */
190958bc78c7SXin Chen 				if (data_xfer_length) {
191058bc78c7SXin Chen 					pkt->pkt_state |= STATE_XFERRED_DATA;
191158bc78c7SXin Chen 					pkt->pkt_resid = acp->bcount - \
191258bc78c7SXin Chen 					    data_xfer_length;
191358bc78c7SXin Chen 					ASSERT(pkt->pkt_resid >= 0);
191458bc78c7SXin Chen 				}
191558bc78c7SXin Chen 				break;
191658bc78c7SXin Chen 			case SRB_STATUS_ABORTED:
191758bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
191858bc78c7SXin Chen 				    "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
191958bc78c7SXin Chen 				    data_xfer_length, pkt->pkt_resid);
192058bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_ABORTED,
192158bc78c7SXin Chen 				    STAT_ABORTED);
192258bc78c7SXin Chen 				break;
192358bc78c7SXin Chen 			case SRB_STATUS_ABORT_FAILED:
192458bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
192558bc78c7SXin Chen 				    "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
192658bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
192758bc78c7SXin Chen 				    pkt->pkt_resid);
192858bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
192958bc78c7SXin Chen 				    0);
193058bc78c7SXin Chen 				break;
193158bc78c7SXin Chen 			case SRB_STATUS_PARITY_ERROR:
193258bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
193358bc78c7SXin Chen 				    "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
193458bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
193558bc78c7SXin Chen 				    pkt->pkt_resid);
193658bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
193758bc78c7SXin Chen 				break;
193858bc78c7SXin Chen 			case SRB_STATUS_NO_DEVICE:
193958bc78c7SXin Chen 			case SRB_STATUS_INVALID_PATH_ID:
194058bc78c7SXin Chen 			case SRB_STATUS_INVALID_TARGET_ID:
194158bc78c7SXin Chen 			case SRB_STATUS_INVALID_LUN:
194258bc78c7SXin Chen 			case SRB_STATUS_SELECTION_TIMEOUT:
194358bc78c7SXin Chen #ifdef DEBUG
194458bc78c7SXin Chen 				if (AAC_DEV_IS_VALID(acp->dvp)) {
194558bc78c7SXin Chen 					AACDB_PRINT(softs, CE_NOTE,
194658bc78c7SXin Chen 					    "SRB_STATUS_NO_DEVICE(%d), " \
194758bc78c7SXin Chen 					    "xfer=%d, resid=%d ",
194858bc78c7SXin Chen 					    srb_status & 0x3f,
194958bc78c7SXin Chen 					    data_xfer_length, pkt->pkt_resid);
195058bc78c7SXin Chen 				}
195158bc78c7SXin Chen #endif
195258bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
195358bc78c7SXin Chen 				break;
195458bc78c7SXin Chen 			case SRB_STATUS_COMMAND_TIMEOUT:
195558bc78c7SXin Chen 			case SRB_STATUS_TIMEOUT:
195658bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
195758bc78c7SXin Chen 				    "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
195858bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
195958bc78c7SXin Chen 				    pkt->pkt_resid);
196058bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
196158bc78c7SXin Chen 				    STAT_TIMEOUT);
196258bc78c7SXin Chen 				break;
196358bc78c7SXin Chen 			case SRB_STATUS_BUS_RESET:
196458bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
196558bc78c7SXin Chen 				    "SRB_STATUS_BUS_RESET, xfer=%d, " \
196658bc78c7SXin Chen 				    "resid=%d", data_xfer_length,
196758bc78c7SXin Chen 				    pkt->pkt_resid);
196858bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_RESET,
196958bc78c7SXin Chen 				    STAT_BUS_RESET);
197058bc78c7SXin Chen 				break;
197158bc78c7SXin Chen 			default:
197258bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
197358bc78c7SXin Chen 				    "xfer=%d, resid=%d", srb_status & 0x3f,
197458bc78c7SXin Chen 				    data_xfer_length, pkt->pkt_resid);
197558bc78c7SXin Chen 				aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
197658bc78c7SXin Chen 				break;
197758bc78c7SXin Chen 			}
197858bc78c7SXin Chen 		} else if (scsi_status == STATUS_CHECK) {
197958bc78c7SXin Chen 			/* CHECK CONDITION */
198058bc78c7SXin Chen 			struct scsi_arq_status *arqstat =
198158bc78c7SXin Chen 			    (void *)(pkt->pkt_scbp);
198258bc78c7SXin Chen 			uint32_t sense_data_size;
198358bc78c7SXin Chen 
198458bc78c7SXin Chen 			pkt->pkt_state |= STATE_ARQ_DONE;
198558bc78c7SXin Chen 
198658bc78c7SXin Chen 			*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
198758bc78c7SXin Chen 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
198858bc78c7SXin Chen 			arqstat->sts_rqpkt_resid = 0;
198958bc78c7SXin Chen 			arqstat->sts_rqpkt_state =
199058bc78c7SXin Chen 			    STATE_GOT_BUS |
199158bc78c7SXin Chen 			    STATE_GOT_TARGET |
199258bc78c7SXin Chen 			    STATE_SENT_CMD |
199358bc78c7SXin Chen 			    STATE_XFERRED_DATA;
199458bc78c7SXin Chen 			arqstat->sts_rqpkt_statistics = 0;
199558bc78c7SXin Chen 
199658bc78c7SXin Chen 			sense_data_size = ddi_get32(acc,
199758bc78c7SXin Chen 			    &resp->sense_data_size);
199858bc78c7SXin Chen 			ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
199958bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE,
200058bc78c7SXin Chen 			    "CHECK CONDITION: sense len=%d, xfer len=%d",
200158bc78c7SXin Chen 			    sense_data_size, data_xfer_length);
200258bc78c7SXin Chen 
200358bc78c7SXin Chen 			if (sense_data_size > SENSE_LENGTH)
200458bc78c7SXin Chen 				sense_data_size = SENSE_LENGTH;
200558bc78c7SXin Chen 			ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
200658bc78c7SXin Chen 			    (uint8_t *)resp->sense_data, sense_data_size,
200758bc78c7SXin Chen 			    DDI_DEV_AUTOINCR);
200858bc78c7SXin Chen 		} else {
200958bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
201058bc78c7SXin Chen 			    "scsi_status=%d, srb_status=%d",
201158bc78c7SXin Chen 			    scsi_status, srb_status);
201258bc78c7SXin Chen 			aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
201358bc78c7SXin Chen 		}
201458bc78c7SXin Chen 	} else {
201558bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
201658bc78c7SXin Chen 		    resp_status);
201758bc78c7SXin Chen 		aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
201858bc78c7SXin Chen 	}
201958bc78c7SXin Chen }
202058bc78c7SXin Chen 
202158bc78c7SXin Chen /*
2022942c5e3cSpl196000  * Handle completed IOCTL command
2023942c5e3cSpl196000  */
2024942c5e3cSpl196000 /*ARGSUSED*/
2025942c5e3cSpl196000 void
aac_ioctl_complete(struct aac_softstate * softs,struct aac_cmd * acp)2026942c5e3cSpl196000 aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2027942c5e3cSpl196000 {
2028942c5e3cSpl196000 	struct aac_slot *slotp = acp->slotp;
2029942c5e3cSpl196000 
2030942c5e3cSpl196000 	/*
2031942c5e3cSpl196000 	 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
2032942c5e3cSpl196000 	 * may wait on softs->event, so use cv_broadcast() instead
2033942c5e3cSpl196000 	 * of cv_signal().
2034942c5e3cSpl196000 	 */
2035942c5e3cSpl196000 	ASSERT(acp->flags & AAC_CMD_SYNC);
2036942c5e3cSpl196000 	ASSERT(acp->flags & AAC_CMD_NO_CB);
2037942c5e3cSpl196000 
2038942c5e3cSpl196000 	/* Get the size of the response FIB from its FIB.Header.Size field */
2039942c5e3cSpl196000 	acp->fib_size = ddi_get16(slotp->fib_acc_handle,
2040942c5e3cSpl196000 	    &slotp->fibp->Header.Size);
2041942c5e3cSpl196000 
2042942c5e3cSpl196000 	ASSERT(acp->fib_size <= softs->aac_max_fib_size);
2043942c5e3cSpl196000 	ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
2044942c5e3cSpl196000 	    (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
2045942c5e3cSpl196000 }
2046942c5e3cSpl196000 
2047942c5e3cSpl196000 /*
2048f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Handle completed sync fib command
2049f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
2050f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*ARGSUSED*/
2051f42c2f53Szhongyan gu - Sun Microsystems - Beijing China void
aac_sync_complete(struct aac_softstate * softs,struct aac_cmd * acp)2052f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2053f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2054f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2055f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2056f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
2057942c5e3cSpl196000  * Handle completed Flush command
2058942c5e3cSpl196000  */
2059942c5e3cSpl196000 /*ARGSUSED*/
2060942c5e3cSpl196000 static void
aac_synccache_complete(struct aac_softstate * softs,struct aac_cmd * acp)2061942c5e3cSpl196000 aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2062942c5e3cSpl196000 {
2063942c5e3cSpl196000 	struct aac_slot *slotp = acp->slotp;
2064942c5e3cSpl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2065942c5e3cSpl196000 	struct aac_synchronize_reply *resp;
2066942c5e3cSpl196000 	uint32_t status;
2067942c5e3cSpl196000 
2068942c5e3cSpl196000 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2069942c5e3cSpl196000 
207058bc78c7SXin Chen 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
207158bc78c7SXin Chen 
2072942c5e3cSpl196000 	resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
2073942c5e3cSpl196000 	status = ddi_get32(acc, &resp->Status);
2074942c5e3cSpl196000 	if (status != CT_OK)
2075942c5e3cSpl196000 		aac_set_arq_data_hwerr(acp);
2076942c5e3cSpl196000 }
2077942c5e3cSpl196000 
20781ee13a44SXinChen /*ARGSUSED*/
2079b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void
aac_startstop_complete(struct aac_softstate * softs,struct aac_cmd * acp)2080b40e8a89Szhongyan gu - Sun Microsystems - Beijing China aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
2081b40e8a89Szhongyan gu - Sun Microsystems - Beijing China {
2082b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp = acp->slotp;
2083b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
2084b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_Container_resp *resp;
2085b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t status;
2086b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2087b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
2088b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2089b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
2090b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2091b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
2092b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	status = ddi_get32(acc, &resp->Status);
2093b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	if (status != 0) {
2094b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
2095b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		aac_set_arq_data_hwerr(acp);
2096b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	}
2097b40e8a89Szhongyan gu - Sun Microsystems - Beijing China }
2098b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
2099942c5e3cSpl196000 /*
2100942c5e3cSpl196000  * Access PCI space to see if the driver can support the card
2101942c5e3cSpl196000  */
2102942c5e3cSpl196000 static int
aac_check_card_type(struct aac_softstate * softs)2103942c5e3cSpl196000 aac_check_card_type(struct aac_softstate *softs)
2104942c5e3cSpl196000 {
2105942c5e3cSpl196000 	ddi_acc_handle_t pci_config_handle;
2106942c5e3cSpl196000 	int card_index;
2107942c5e3cSpl196000 	uint32_t pci_cmd;
2108942c5e3cSpl196000 
2109942c5e3cSpl196000 	/* Map pci configuration space */
2110942c5e3cSpl196000 	if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
2111942c5e3cSpl196000 	    DDI_SUCCESS) {
2112942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
2113942c5e3cSpl196000 		return (AACERR);
2114942c5e3cSpl196000 	}
2115942c5e3cSpl196000 
2116942c5e3cSpl196000 	softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
2117942c5e3cSpl196000 	softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
2118942c5e3cSpl196000 	softs->subvendid = pci_config_get16(pci_config_handle,
2119942c5e3cSpl196000 	    PCI_CONF_SUBVENID);
2120942c5e3cSpl196000 	softs->subsysid = pci_config_get16(pci_config_handle,
2121942c5e3cSpl196000 	    PCI_CONF_SUBSYSID);
2122942c5e3cSpl196000 
2123942c5e3cSpl196000 	card_index = 0;
2124942c5e3cSpl196000 	while (!CARD_IS_UNKNOWN(card_index)) {
2125942c5e3cSpl196000 		if ((aac_cards[card_index].vendor == softs->vendid) &&
2126942c5e3cSpl196000 		    (aac_cards[card_index].device == softs->devid) &&
2127942c5e3cSpl196000 		    (aac_cards[card_index].subvendor == softs->subvendid) &&
2128942c5e3cSpl196000 		    (aac_cards[card_index].subsys == softs->subsysid)) {
2129942c5e3cSpl196000 			break;
2130942c5e3cSpl196000 		}
2131942c5e3cSpl196000 		card_index++;
2132942c5e3cSpl196000 	}
2133942c5e3cSpl196000 
2134942c5e3cSpl196000 	softs->card = card_index;
2135942c5e3cSpl196000 	softs->hwif = aac_cards[card_index].hwif;
2136942c5e3cSpl196000 
2137942c5e3cSpl196000 	/*
2138942c5e3cSpl196000 	 * Unknown aac card
2139942c5e3cSpl196000 	 * do a generic match based on the VendorID and DeviceID to
2140942c5e3cSpl196000 	 * support the new cards in the aac family
2141942c5e3cSpl196000 	 */
2142942c5e3cSpl196000 	if (CARD_IS_UNKNOWN(card_index)) {
2143942c5e3cSpl196000 		if (softs->vendid != 0x9005) {
2144942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
2145942c5e3cSpl196000 			    "Unknown vendor 0x%x", softs->vendid);
2146942c5e3cSpl196000 			goto error;
2147942c5e3cSpl196000 		}
2148942c5e3cSpl196000 		switch (softs->devid) {
2149942c5e3cSpl196000 		case 0x285:
2150942c5e3cSpl196000 			softs->hwif = AAC_HWIF_I960RX;
2151942c5e3cSpl196000 			break;
2152942c5e3cSpl196000 		case 0x286:
2153942c5e3cSpl196000 			softs->hwif = AAC_HWIF_RKT;
2154942c5e3cSpl196000 			break;
2155942c5e3cSpl196000 		default:
2156942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
2157942c5e3cSpl196000 			    "Unknown device \"pci9005,%x\"", softs->devid);
2158942c5e3cSpl196000 			goto error;
2159942c5e3cSpl196000 		}
2160942c5e3cSpl196000 	}
2161942c5e3cSpl196000 
2162942c5e3cSpl196000 	/* Set hardware dependent interface */
2163942c5e3cSpl196000 	switch (softs->hwif) {
2164942c5e3cSpl196000 	case AAC_HWIF_I960RX:
2165942c5e3cSpl196000 		softs->aac_if = aac_rx_interface;
2166942c5e3cSpl196000 		softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
2167942c5e3cSpl196000 		break;
2168942c5e3cSpl196000 	case AAC_HWIF_RKT:
2169942c5e3cSpl196000 		softs->aac_if = aac_rkt_interface;
2170942c5e3cSpl196000 		softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
2171942c5e3cSpl196000 		break;
2172942c5e3cSpl196000 	default:
2173942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
2174942c5e3cSpl196000 		    "Unknown hardware interface %d", softs->hwif);
2175942c5e3cSpl196000 		goto error;
2176942c5e3cSpl196000 	}
2177942c5e3cSpl196000 
2178942c5e3cSpl196000 	/* Set card names */
2179942c5e3cSpl196000 	(void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
2180942c5e3cSpl196000 	    AAC_VENDOR_LEN);
2181942c5e3cSpl196000 	(void *)strncpy(softs->product_name, aac_cards[card_index].desc,
2182942c5e3cSpl196000 	    AAC_PRODUCT_LEN);
2183942c5e3cSpl196000 
2184942c5e3cSpl196000 	/* Set up quirks */
2185942c5e3cSpl196000 	softs->flags = aac_cards[card_index].quirks;
2186942c5e3cSpl196000 
2187942c5e3cSpl196000 	/* Force the busmaster enable bit on */
2188942c5e3cSpl196000 	pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2189942c5e3cSpl196000 	if ((pci_cmd & PCI_COMM_ME) == 0) {
2190942c5e3cSpl196000 		pci_cmd |= PCI_COMM_ME;
2191942c5e3cSpl196000 		pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
2192942c5e3cSpl196000 		pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
2193942c5e3cSpl196000 		if ((pci_cmd & PCI_COMM_ME) == 0) {
2194942c5e3cSpl196000 			cmn_err(CE_CONT, "?Cannot enable busmaster bit");
2195942c5e3cSpl196000 			goto error;
2196942c5e3cSpl196000 		}
2197942c5e3cSpl196000 	}
2198942c5e3cSpl196000 
2199942c5e3cSpl196000 	/* Set memory base to map */
2200942c5e3cSpl196000 	softs->pci_mem_base_paddr = 0xfffffff0UL & \
2201942c5e3cSpl196000 	    pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
2202942c5e3cSpl196000 
2203942c5e3cSpl196000 	pci_config_teardown(&pci_config_handle);
2204942c5e3cSpl196000 
2205942c5e3cSpl196000 	return (AACOK); /* card type detected */
2206942c5e3cSpl196000 error:
2207942c5e3cSpl196000 	pci_config_teardown(&pci_config_handle);
2208942c5e3cSpl196000 	return (AACERR); /* no matched card found */
2209942c5e3cSpl196000 }
2210942c5e3cSpl196000 
2211942c5e3cSpl196000 /*
2212f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Do the usual interrupt handler setup stuff.
2213f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
2214f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_register_intrs(struct aac_softstate * softs)2215f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_register_intrs(struct aac_softstate *softs)
2216f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2217f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	dev_info_t *dip;
2218f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int intr_types;
2219f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2220f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(softs->devinfo_p);
2221f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	dip = softs->devinfo_p;
2222f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2223f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get the type of device intrrupts */
2224f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
2225f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2226f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "ddi_intr_get_supported_types() failed");
2227f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2228f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2229f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AACDB_PRINT(softs, CE_NOTE,
2230f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
2231f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2232f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Query interrupt, and alloc/init all needed struct */
2233f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (intr_types & DDI_INTR_TYPE_MSI) {
2234f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
2235f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    != DDI_SUCCESS) {
2236f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_WARN,
2237f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			    "MSI interrupt query failed");
2238f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			return (AACERR);
2239f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
2240f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		softs->intr_type = DDI_INTR_TYPE_MSI;
2241f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
2242f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
2243f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    != DDI_SUCCESS) {
2244f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_WARN,
2245f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			    "FIXED interrupt query failed");
2246f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			return (AACERR);
2247f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		}
2248f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		softs->intr_type = DDI_INTR_TYPE_FIXED;
2249f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	} else {
2250f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2251f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Device cannot suppport both FIXED and MSI interrupts");
2252f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2253f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2254f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2255f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Connect interrupt handlers */
2256f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_add_intrs(softs) != DDI_SUCCESS) {
2257f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2258f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Interrupt registration failed, intr type: %s",
2259f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
2260f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2261f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2262f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_enable_intrs(softs);
2263f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2264f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
2265f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
2266f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_WARN,
2267f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "Can not setup soft interrupt handler!");
2268f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		aac_remove_intrs(softs);
2269f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
2270f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2271f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2272f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (AACOK);
2273f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2274f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2275f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void
aac_unregister_intrs(struct aac_softstate * softs)2276f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_unregister_intrs(struct aac_softstate *softs)
2277f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
2278f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_remove_intrs(softs);
2279f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_remove_softintr(softs->softint_id);
2280f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
2281f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2282f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
2283942c5e3cSpl196000  * Check the firmware to determine the features to support and the FIB
2284942c5e3cSpl196000  * parameters to use.
2285942c5e3cSpl196000  */
2286942c5e3cSpl196000 static int
aac_check_firmware(struct aac_softstate * softs)2287942c5e3cSpl196000 aac_check_firmware(struct aac_softstate *softs)
2288942c5e3cSpl196000 {
2289942c5e3cSpl196000 	uint32_t options;
2290942c5e3cSpl196000 	uint32_t atu_size;
2291942c5e3cSpl196000 	ddi_acc_handle_t pci_handle;
229258bc78c7SXin Chen 	uint8_t *data;
2293942c5e3cSpl196000 	uint32_t max_fibs;
2294942c5e3cSpl196000 	uint32_t max_fib_size;
2295942c5e3cSpl196000 	uint32_t sg_tablesize;
2296942c5e3cSpl196000 	uint32_t max_sectors;
2297942c5e3cSpl196000 	uint32_t status;
2298942c5e3cSpl196000 
2299942c5e3cSpl196000 	/* Get supported options */
2300942c5e3cSpl196000 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
2301942c5e3cSpl196000 	    &status)) != AACOK) {
2302942c5e3cSpl196000 		if (status != SRB_STATUS_INVALID_REQUEST) {
2303942c5e3cSpl196000 			cmn_err(CE_CONT,
2304942c5e3cSpl196000 			    "?Fatal error: request adapter info error");
2305942c5e3cSpl196000 			return (AACERR);
2306942c5e3cSpl196000 		}
2307942c5e3cSpl196000 		options = 0;
2308942c5e3cSpl196000 		atu_size = 0;
2309942c5e3cSpl196000 	} else {
2310942c5e3cSpl196000 		options = AAC_MAILBOX_GET(softs, 1);
2311942c5e3cSpl196000 		atu_size = AAC_MAILBOX_GET(softs, 2);
2312942c5e3cSpl196000 	}
2313942c5e3cSpl196000 
2314942c5e3cSpl196000 	if (softs->state & AAC_STATE_RESET) {
2315942c5e3cSpl196000 		if ((softs->support_opt == options) &&
2316942c5e3cSpl196000 		    (softs->atu_size == atu_size))
2317942c5e3cSpl196000 			return (AACOK);
2318942c5e3cSpl196000 
2319942c5e3cSpl196000 		cmn_err(CE_WARN,
2320942c5e3cSpl196000 		    "?Fatal error: firmware changed, system needs reboot");
2321942c5e3cSpl196000 		return (AACERR);
2322942c5e3cSpl196000 	}
2323942c5e3cSpl196000 
2324942c5e3cSpl196000 	/*
2325942c5e3cSpl196000 	 * The following critical settings are initialized only once during
2326942c5e3cSpl196000 	 * driver attachment.
2327942c5e3cSpl196000 	 */
2328942c5e3cSpl196000 	softs->support_opt = options;
2329942c5e3cSpl196000 	softs->atu_size = atu_size;
2330942c5e3cSpl196000 
2331942c5e3cSpl196000 	/* Process supported options */
2332942c5e3cSpl196000 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
2333942c5e3cSpl196000 	    (softs->flags & AAC_FLAGS_NO4GB) == 0) {
2334942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
2335942c5e3cSpl196000 		softs->flags |= AAC_FLAGS_4GB_WINDOW;
2336942c5e3cSpl196000 	} else {
2337942c5e3cSpl196000 		/*
2338942c5e3cSpl196000 		 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
2339942c5e3cSpl196000 		 * only. IO is handled by the DMA engine which does not suffer
2340942c5e3cSpl196000 		 * from the ATU window programming workarounds necessary for
2341942c5e3cSpl196000 		 * CPU copy operations.
2342942c5e3cSpl196000 		 */
2343942c5e3cSpl196000 		softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
2344942c5e3cSpl196000 		softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
2345942c5e3cSpl196000 	}
2346942c5e3cSpl196000 
2347942c5e3cSpl196000 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
2348942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
2349942c5e3cSpl196000 		softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
2350942c5e3cSpl196000 		softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
2351942c5e3cSpl196000 		softs->flags |= AAC_FLAGS_SG_64BIT;
2352942c5e3cSpl196000 	}
2353942c5e3cSpl196000 
2354942c5e3cSpl196000 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
2355942c5e3cSpl196000 		softs->flags |= AAC_FLAGS_ARRAY_64BIT;
2356942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
2357942c5e3cSpl196000 	}
2358942c5e3cSpl196000 
235958bc78c7SXin Chen 	if (options & AAC_SUPPORTED_NONDASD) {
236058bc78c7SXin Chen 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
236158bc78c7SXin Chen 		    "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
236258bc78c7SXin Chen 			if (strcmp((char *)data, "yes") == 0) {
236358bc78c7SXin Chen 				AACDB_PRINT(softs, CE_NOTE,
236458bc78c7SXin Chen 				    "!Enable Non-DASD access");
236558bc78c7SXin Chen 				softs->flags |= AAC_FLAGS_NONDASD;
236658bc78c7SXin Chen 			}
236758bc78c7SXin Chen 			ddi_prop_free(data);
236858bc78c7SXin Chen 		}
236958bc78c7SXin Chen 	}
237058bc78c7SXin Chen 
2371942c5e3cSpl196000 	/* Read preferred settings */
2372942c5e3cSpl196000 	max_fib_size = 0;
2373942c5e3cSpl196000 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
2374942c5e3cSpl196000 	    0, 0, 0, 0, NULL)) == AACOK) {
2375942c5e3cSpl196000 		options = AAC_MAILBOX_GET(softs, 1);
2376942c5e3cSpl196000 		max_fib_size = (options & 0xffff);
2377942c5e3cSpl196000 		max_sectors = (options >> 16) << 1;
2378942c5e3cSpl196000 		options = AAC_MAILBOX_GET(softs, 2);
2379942c5e3cSpl196000 		sg_tablesize = (options >> 16);
2380942c5e3cSpl196000 		options = AAC_MAILBOX_GET(softs, 3);
2381942c5e3cSpl196000 		max_fibs = (options & 0xffff);
2382942c5e3cSpl196000 	}
2383942c5e3cSpl196000 
2384942c5e3cSpl196000 	/* Enable new comm. and rawio at the same time */
2385942c5e3cSpl196000 	if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
2386942c5e3cSpl196000 	    (max_fib_size != 0)) {
238758bc78c7SXin Chen 		/* read out and save PCI MBR */
2388942c5e3cSpl196000 		if ((atu_size > softs->map_size) &&
2389942c5e3cSpl196000 		    (ddi_regs_map_setup(softs->devinfo_p, 1,
2390837c1ac4SStephen Hanson 		    (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
2391942c5e3cSpl196000 		    &pci_handle) == DDI_SUCCESS)) {
2392942c5e3cSpl196000 			ddi_regs_map_free(&softs->pci_mem_handle);
2393942c5e3cSpl196000 			softs->pci_mem_handle = pci_handle;
239458bc78c7SXin Chen 			softs->pci_mem_base_vaddr = data;
2395942c5e3cSpl196000 			softs->map_size = atu_size;
2396942c5e3cSpl196000 		}
2397942c5e3cSpl196000 		if (atu_size == softs->map_size) {
2398942c5e3cSpl196000 			softs->flags |= AAC_FLAGS_NEW_COMM;
2399942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE,
2400942c5e3cSpl196000 			    "!Enable New Comm. interface");
2401942c5e3cSpl196000 		}
2402942c5e3cSpl196000 	}
2403942c5e3cSpl196000 
2404942c5e3cSpl196000 	/* Set FIB parameters */
2405942c5e3cSpl196000 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
2406942c5e3cSpl196000 		softs->aac_max_fibs = max_fibs;
2407942c5e3cSpl196000 		softs->aac_max_fib_size = max_fib_size;
2408942c5e3cSpl196000 		softs->aac_max_sectors = max_sectors;
2409942c5e3cSpl196000 		softs->aac_sg_tablesize = sg_tablesize;
2410942c5e3cSpl196000 
2411942c5e3cSpl196000 		softs->flags |= AAC_FLAGS_RAW_IO;
2412942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
2413942c5e3cSpl196000 	} else {
2414942c5e3cSpl196000 		softs->aac_max_fibs =
2415942c5e3cSpl196000 		    (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
2416942c5e3cSpl196000 		softs->aac_max_fib_size = AAC_FIB_SIZE;
2417942c5e3cSpl196000 		softs->aac_max_sectors = 128;	/* 64K */
2418942c5e3cSpl196000 		if (softs->flags & AAC_FLAGS_17SG)
2419942c5e3cSpl196000 			softs->aac_sg_tablesize = 17;
2420942c5e3cSpl196000 		else if (softs->flags & AAC_FLAGS_34SG)
2421942c5e3cSpl196000 			softs->aac_sg_tablesize = 34;
2422942c5e3cSpl196000 		else if (softs->flags & AAC_FLAGS_SG_64BIT)
2423942c5e3cSpl196000 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2424942c5e3cSpl196000 			    sizeof (struct aac_blockwrite64) +
2425942c5e3cSpl196000 			    sizeof (struct aac_sg_entry64)) /
2426942c5e3cSpl196000 			    sizeof (struct aac_sg_entry64);
2427942c5e3cSpl196000 		else
2428942c5e3cSpl196000 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
2429942c5e3cSpl196000 			    sizeof (struct aac_blockwrite) +
2430942c5e3cSpl196000 			    sizeof (struct aac_sg_entry)) /
2431942c5e3cSpl196000 			    sizeof (struct aac_sg_entry);
2432942c5e3cSpl196000 	}
2433942c5e3cSpl196000 
2434942c5e3cSpl196000 	if ((softs->flags & AAC_FLAGS_RAW_IO) &&
2435942c5e3cSpl196000 	    (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
2436942c5e3cSpl196000 		softs->flags |= AAC_FLAGS_LBA_64BIT;
2437942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
2438942c5e3cSpl196000 	}
2439942c5e3cSpl196000 	softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
2440942c5e3cSpl196000 	softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
2441942c5e3cSpl196000 	/*
2442942c5e3cSpl196000 	 * 64K maximum segment size in scatter gather list is controlled by
2443942c5e3cSpl196000 	 * the NEW_COMM bit in the adapter information. If not set, the card
2444942c5e3cSpl196000 	 * can only accept a maximum of 64K. It is not recommended to permit
2445942c5e3cSpl196000 	 * more than 128KB of total transfer size to the adapters because
2446942c5e3cSpl196000 	 * performance is negatively impacted.
2447942c5e3cSpl196000 	 *
2448942c5e3cSpl196000 	 * For new comm, segment size equals max xfer size. For old comm,
2449942c5e3cSpl196000 	 * we use 64K for both.
2450942c5e3cSpl196000 	 */
2451942c5e3cSpl196000 	softs->buf_dma_attr.dma_attr_count_max =
2452942c5e3cSpl196000 	    softs->buf_dma_attr.dma_attr_maxxfer - 1;
2453942c5e3cSpl196000 
245458bc78c7SXin Chen 	/* Setup FIB operations */
2455942c5e3cSpl196000 	if (softs->flags & AAC_FLAGS_RAW_IO)
2456942c5e3cSpl196000 		softs->aac_cmd_fib = aac_cmd_fib_rawio;
2457942c5e3cSpl196000 	else if (softs->flags & AAC_FLAGS_SG_64BIT)
2458942c5e3cSpl196000 		softs->aac_cmd_fib = aac_cmd_fib_brw64;
2459942c5e3cSpl196000 	else
2460942c5e3cSpl196000 		softs->aac_cmd_fib = aac_cmd_fib_brw;
2461942c5e3cSpl196000 	softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
2462942c5e3cSpl196000 	    aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
2463942c5e3cSpl196000 
2464942c5e3cSpl196000 	/* 64-bit LBA needs descriptor format sense data */
2465942c5e3cSpl196000 	softs->slen = sizeof (struct scsi_arq_status);
2466942c5e3cSpl196000 	if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
2467942c5e3cSpl196000 	    softs->slen < AAC_ARQ64_LENGTH)
2468942c5e3cSpl196000 		softs->slen = AAC_ARQ64_LENGTH;
2469942c5e3cSpl196000 
2470942c5e3cSpl196000 	AACDB_PRINT(softs, CE_NOTE,
2471942c5e3cSpl196000 	    "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
2472942c5e3cSpl196000 	    softs->aac_max_fibs, softs->aac_max_fib_size,
2473942c5e3cSpl196000 	    softs->aac_max_sectors, softs->aac_sg_tablesize);
2474942c5e3cSpl196000 
2475942c5e3cSpl196000 	return (AACOK);
2476942c5e3cSpl196000 }
2477942c5e3cSpl196000 
2478942c5e3cSpl196000 static void
aac_fsa_rev(struct aac_softstate * softs,struct FsaRev * fsarev0,struct FsaRev * fsarev1)2479942c5e3cSpl196000 aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
2480942c5e3cSpl196000     struct FsaRev *fsarev1)
2481942c5e3cSpl196000 {
2482f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
2483942c5e3cSpl196000 
2484942c5e3cSpl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
2485942c5e3cSpl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
2486942c5e3cSpl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
2487942c5e3cSpl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
2488942c5e3cSpl196000 	AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
2489942c5e3cSpl196000 }
2490942c5e3cSpl196000 
2491942c5e3cSpl196000 /*
2492942c5e3cSpl196000  * The following function comes from Adaptec:
2493942c5e3cSpl196000  *
2494942c5e3cSpl196000  * Query adapter information and supplement adapter information
2495942c5e3cSpl196000  */
2496942c5e3cSpl196000 static int
aac_get_adapter_info(struct aac_softstate * softs,struct aac_adapter_info * ainfr,struct aac_supplement_adapter_info * sinfr)2497942c5e3cSpl196000 aac_get_adapter_info(struct aac_softstate *softs,
2498942c5e3cSpl196000     struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
2499942c5e3cSpl196000 {
2500f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2501f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2502f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
2503942c5e3cSpl196000 	struct aac_adapter_info *ainfp;
2504942c5e3cSpl196000 	struct aac_supplement_adapter_info *sinfp;
2505f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
2506f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2507f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2508f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2509f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2510942c5e3cSpl196000 
2511942c5e3cSpl196000 	ddi_put8(acc, &fibp->data[0], 0);
2512942c5e3cSpl196000 	if (aac_sync_fib(softs, RequestAdapterInfo,
25133fced439Szhongyan gu - Sun Microsystems - Beijing China 	    AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
2514942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
2515f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2516f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
2517942c5e3cSpl196000 	}
2518942c5e3cSpl196000 	ainfp = (struct aac_adapter_info *)fibp->data;
2519942c5e3cSpl196000 	if (ainfr) {
2520942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2521942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
2522942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
2523942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
2524942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
2525942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
2526942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
2527942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
2528942c5e3cSpl196000 		aac_fsa_rev(softs, &ainfp->KernelRevision,
2529942c5e3cSpl196000 		    &ainfr->KernelRevision);
2530942c5e3cSpl196000 		aac_fsa_rev(softs, &ainfp->MonitorRevision,
2531942c5e3cSpl196000 		    &ainfr->MonitorRevision);
2532942c5e3cSpl196000 		aac_fsa_rev(softs, &ainfp->HardwareRevision,
2533942c5e3cSpl196000 		    &ainfr->HardwareRevision);
2534942c5e3cSpl196000 		aac_fsa_rev(softs, &ainfp->BIOSRevision,
2535942c5e3cSpl196000 		    &ainfr->BIOSRevision);
2536942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
2537942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
2538942c5e3cSpl196000 		AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
2539942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
2540942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
2541942c5e3cSpl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
2542942c5e3cSpl196000 	}
2543942c5e3cSpl196000 	if (sinfr) {
2544942c5e3cSpl196000 		if (!(softs->support_opt &
2545942c5e3cSpl196000 		    AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
2546942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
2547942c5e3cSpl196000 			    "SupplementAdapterInfo not supported");
2548f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
2549f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			goto finish;
2550942c5e3cSpl196000 		}
2551942c5e3cSpl196000 		ddi_put8(acc, &fibp->data[0], 0);
2552942c5e3cSpl196000 		if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
25533fced439Szhongyan gu - Sun Microsystems - Beijing China 		    AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
25543fced439Szhongyan gu - Sun Microsystems - Beijing China 		    != AACOK) {
2555942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
2556942c5e3cSpl196000 			    "RequestSupplementAdapterInfo failed");
2557f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			rval = AACERR;
2558f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			goto finish;
2559942c5e3cSpl196000 		}
2560942c5e3cSpl196000 		sinfp = (struct aac_supplement_adapter_info *)fibp->data;
2561942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
2562942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
2563942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
2564942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
2565942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
2566942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
2567942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
2568942c5e3cSpl196000 		AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
2569942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
2570942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
2571942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
2572942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
2573942c5e3cSpl196000 		    sizeof (struct vpd_info));
2574942c5e3cSpl196000 		aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
2575942c5e3cSpl196000 		    &sinfr->FlashFirmwareRevision);
2576942c5e3cSpl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
2577942c5e3cSpl196000 		aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
2578942c5e3cSpl196000 		    &sinfr->FlashFirmwareBootRevision);
2579942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
2580942c5e3cSpl196000 		    MFG_PCBA_SERIAL_NUMBER_WIDTH);
2581942c5e3cSpl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
2582942c5e3cSpl196000 		    MFG_WWN_WIDTH);
2583b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
2584b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
2585b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (sinfr->ExpansionFlag == 1) {
2586b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
2587b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_GET_FIELD32(acc, sinfr, sinfp,
2588b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			    SupportedPerformanceMode);
2589b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
2590b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			    ReservedGrowth[0], 80);
2591b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		}
2592942c5e3cSpl196000 	}
2593f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = AACOK;
2594f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
2595f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
2596f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
2597942c5e3cSpl196000 }
2598942c5e3cSpl196000 
259958bc78c7SXin Chen static int
aac_get_bus_info(struct aac_softstate * softs,uint32_t * bus_max,uint32_t * tgt_max)260058bc78c7SXin Chen aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
260158bc78c7SXin Chen     uint32_t *tgt_max)
260258bc78c7SXin Chen {
2603f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2604f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2605f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
260658bc78c7SXin Chen 	struct aac_ctcfg *c_cmd;
260758bc78c7SXin Chen 	struct aac_ctcfg_resp *c_resp;
260858bc78c7SXin Chen 	uint32_t scsi_method_id;
260958bc78c7SXin Chen 	struct aac_bus_info *cmd;
261058bc78c7SXin Chen 	struct aac_bus_info_response *resp;
261158bc78c7SXin Chen 	int rval;
261258bc78c7SXin Chen 
2613f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2614f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2615f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2616f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
261758bc78c7SXin Chen 	/* Detect MethodId */
261858bc78c7SXin Chen 	c_cmd = (struct aac_ctcfg *)&fibp->data[0];
261958bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
262058bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
262158bc78c7SXin Chen 	ddi_put32(acc, &c_cmd->param, 0);
262258bc78c7SXin Chen 	rval = aac_sync_fib(softs, ContainerCommand,
262358bc78c7SXin Chen 	    AAC_FIB_SIZEOF(struct aac_ctcfg));
262458bc78c7SXin Chen 	c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
262558bc78c7SXin Chen 	if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
262658bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN,
262758bc78c7SXin Chen 		    "VM_ContainerConfig command fail");
2628f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2629f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
263058bc78c7SXin Chen 	}
263158bc78c7SXin Chen 	scsi_method_id = ddi_get32(acc, &c_resp->param);
263258bc78c7SXin Chen 
263358bc78c7SXin Chen 	/* Detect phys. bus count and max. target id first */
263458bc78c7SXin Chen 	cmd = (struct aac_bus_info *)&fibp->data[0];
263558bc78c7SXin Chen 	ddi_put32(acc, &cmd->Command, VM_Ioctl);
263658bc78c7SXin Chen 	ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
263758bc78c7SXin Chen 	ddi_put32(acc, &cmd->MethodId, scsi_method_id);
263858bc78c7SXin Chen 	ddi_put32(acc, &cmd->ObjectId, 0);
263958bc78c7SXin Chen 	ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
264058bc78c7SXin Chen 	/*
264158bc78c7SXin Chen 	 * For VM_Ioctl, the firmware uses the Header.Size filled from the
264258bc78c7SXin Chen 	 * driver as the size to be returned. Therefore the driver has to use
264358bc78c7SXin Chen 	 * sizeof (struct aac_bus_info_response) because it is greater than
264458bc78c7SXin Chen 	 * sizeof (struct aac_bus_info).
264558bc78c7SXin Chen 	 */
264658bc78c7SXin Chen 	rval = aac_sync_fib(softs, ContainerCommand,
264758bc78c7SXin Chen 	    AAC_FIB_SIZEOF(struct aac_bus_info_response));
264858bc78c7SXin Chen 	resp = (struct aac_bus_info_response *)cmd;
264958bc78c7SXin Chen 
265058bc78c7SXin Chen 	/* Scan all coordinates with INQUIRY */
265158bc78c7SXin Chen 	if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
265258bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
2653f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
2654f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
265558bc78c7SXin Chen 	}
265658bc78c7SXin Chen 	*bus_max = ddi_get32(acc, &resp->BusCount);
265758bc78c7SXin Chen 	*tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
2658f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2659f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
2660f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
266158bc78c7SXin Chen 	return (AACOK);
266258bc78c7SXin Chen }
266358bc78c7SXin Chen 
2664942c5e3cSpl196000 /*
2665942c5e3cSpl196000  * The following function comes from Adaptec:
2666942c5e3cSpl196000  *
2667942c5e3cSpl196000  * Routine to be called during initialization of communications with
2668942c5e3cSpl196000  * the adapter to handle possible adapter configuration issues. When
2669942c5e3cSpl196000  * the adapter first boots up, it examines attached drives, etc, and
2670942c5e3cSpl196000  * potentially comes up with a new or revised configuration (relative to
2671942c5e3cSpl196000  * what's stored in it's NVRAM). Additionally it may discover problems
2672942c5e3cSpl196000  * that make the current physical configuration unworkable (currently
2673942c5e3cSpl196000  * applicable only to cluster configuration issues).
2674942c5e3cSpl196000  *
2675942c5e3cSpl196000  * If there are no configuration issues or the issues are considered
2676942c5e3cSpl196000  * trival by the adapter, it will set it's configuration status to
2677942c5e3cSpl196000  * "FSACT_CONTINUE" and execute the "commit confiuguration" action
2678942c5e3cSpl196000  * automatically on it's own.
2679942c5e3cSpl196000  *
2680942c5e3cSpl196000  * However, if there are non-trivial issues, the adapter will set it's
2681942c5e3cSpl196000  * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
2682942c5e3cSpl196000  * and wait for some agent on the host to issue the "\ContainerCommand
2683942c5e3cSpl196000  * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
2684942c5e3cSpl196000  * adapter to commit the new/updated configuration and enable
2685942c5e3cSpl196000  * un-inhibited operation.  The host agent should first issue the
2686942c5e3cSpl196000  * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
2687942c5e3cSpl196000  * command to obtain information about config issues detected by
2688942c5e3cSpl196000  * the adapter.
2689942c5e3cSpl196000  *
2690942c5e3cSpl196000  * Normally the adapter's PC BIOS will execute on the host following
2691942c5e3cSpl196000  * adapter poweron and reset and will be responsible for querring the
2692942c5e3cSpl196000  * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
2693942c5e3cSpl196000  * command if appropriate.
2694942c5e3cSpl196000  *
2695942c5e3cSpl196000  * However, with the introduction of IOP reset support, the adapter may
2696942c5e3cSpl196000  * boot up without the benefit of the adapter's PC BIOS host agent.
2697942c5e3cSpl196000  * This routine is intended to take care of these issues in situations
2698942c5e3cSpl196000  * where BIOS doesn't execute following adapter poweron or reset.  The
2699942c5e3cSpl196000  * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
2700942c5e3cSpl196000  * there is no harm in doing this when it's already been done.
2701942c5e3cSpl196000  */
2702942c5e3cSpl196000 static int
aac_handle_adapter_config_issues(struct aac_softstate * softs)2703942c5e3cSpl196000 aac_handle_adapter_config_issues(struct aac_softstate *softs)
2704942c5e3cSpl196000 {
2705f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
2706f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
2707f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
2708942c5e3cSpl196000 	struct aac_Container *cmd;
2709942c5e3cSpl196000 	struct aac_Container_resp *resp;
2710942c5e3cSpl196000 	struct aac_cf_status_header *cfg_sts_hdr;
2711942c5e3cSpl196000 	uint32_t resp_status;
2712942c5e3cSpl196000 	uint32_t ct_status;
2713942c5e3cSpl196000 	uint32_t cfg_stat_action;
2714942c5e3cSpl196000 	int rval;
2715942c5e3cSpl196000 
2716f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, acp);
2717f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = acp->slotp->fib_acc_handle;
2718f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	fibp = acp->slotp->fibp;
2719f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2720942c5e3cSpl196000 	/* Get adapter config status */
2721942c5e3cSpl196000 	cmd = (struct aac_Container *)&fibp->data[0];
2722942c5e3cSpl196000 
2723942c5e3cSpl196000 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2724942c5e3cSpl196000 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2725942c5e3cSpl196000 	ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
2726942c5e3cSpl196000 	ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
2727942c5e3cSpl196000 	    sizeof (struct aac_cf_status_header));
2728942c5e3cSpl196000 	rval = aac_sync_fib(softs, ContainerCommand,
2729942c5e3cSpl196000 	    AAC_FIB_SIZEOF(struct aac_Container));
2730942c5e3cSpl196000 	resp = (struct aac_Container_resp *)cmd;
2731942c5e3cSpl196000 	cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
2732942c5e3cSpl196000 
2733942c5e3cSpl196000 	resp_status = ddi_get32(acc, &resp->Status);
2734942c5e3cSpl196000 	ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2735942c5e3cSpl196000 	if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
2736942c5e3cSpl196000 		cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
2737942c5e3cSpl196000 
2738942c5e3cSpl196000 		/* Commit configuration if it's reasonable to do so. */
2739942c5e3cSpl196000 		if (cfg_stat_action <= CFACT_PAUSE) {
2740942c5e3cSpl196000 			bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
2741942c5e3cSpl196000 			ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
2742942c5e3cSpl196000 			ddi_put32(acc, &cmd->CTCommand.command,
2743942c5e3cSpl196000 			    CT_COMMIT_CONFIG);
2744942c5e3cSpl196000 			rval = aac_sync_fib(softs, ContainerCommand,
2745942c5e3cSpl196000 			    AAC_FIB_SIZEOF(struct aac_Container));
2746942c5e3cSpl196000 
2747942c5e3cSpl196000 			resp_status = ddi_get32(acc, &resp->Status);
2748942c5e3cSpl196000 			ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
2749942c5e3cSpl196000 			if ((rval == AACOK) && (resp_status == 0) &&
2750942c5e3cSpl196000 			    (ct_status == CT_OK))
2751942c5e3cSpl196000 				/* Successful completion */
2752942c5e3cSpl196000 				rval = AACMPE_OK;
2753942c5e3cSpl196000 			else
2754942c5e3cSpl196000 				/* Auto-commit aborted due to error(s). */
2755942c5e3cSpl196000 				rval = AACMPE_COMMIT_CONFIG;
2756942c5e3cSpl196000 		} else {
2757942c5e3cSpl196000 			/*
2758942c5e3cSpl196000 			 * Auto-commit aborted due to adapter indicating
2759942c5e3cSpl196000 			 * configuration issue(s) too dangerous to auto-commit.
2760942c5e3cSpl196000 			 */
2761942c5e3cSpl196000 			rval = AACMPE_CONFIG_STATUS;
2762942c5e3cSpl196000 		}
2763942c5e3cSpl196000 	} else {
2764942c5e3cSpl196000 		cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
2765942c5e3cSpl196000 		rval = AACMPE_CONFIG_STATUS;
2766942c5e3cSpl196000 	}
2767f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
2768f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, acp);
2769942c5e3cSpl196000 	return (rval);
2770942c5e3cSpl196000 }
2771942c5e3cSpl196000 
2772942c5e3cSpl196000 /*
2773942c5e3cSpl196000  * Hardware initialization and resource allocation
2774942c5e3cSpl196000  */
2775942c5e3cSpl196000 static int
aac_common_attach(struct aac_softstate * softs)2776942c5e3cSpl196000 aac_common_attach(struct aac_softstate *softs)
2777942c5e3cSpl196000 {
2778942c5e3cSpl196000 	uint32_t status;
2779942c5e3cSpl196000 	int i;
27800749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_supplement_adapter_info sinf;
2781942c5e3cSpl196000 
2782942c5e3cSpl196000 	DBCALLED(softs, 1);
2783942c5e3cSpl196000 
2784942c5e3cSpl196000 	/*
2785942c5e3cSpl196000 	 * Do a little check here to make sure there aren't any outstanding
2786942c5e3cSpl196000 	 * FIBs in the message queue. At this point there should not be and
2787942c5e3cSpl196000 	 * if there are they are probably left over from another instance of
2788942c5e3cSpl196000 	 * the driver like when the system crashes and the crash dump driver
2789942c5e3cSpl196000 	 * gets loaded.
2790942c5e3cSpl196000 	 */
2791942c5e3cSpl196000 	while (AAC_OUTB_GET(softs) != 0xfffffffful)
2792942c5e3cSpl196000 		;
2793942c5e3cSpl196000 
2794942c5e3cSpl196000 	/*
2795942c5e3cSpl196000 	 * Wait the card to complete booting up before do anything that
2796942c5e3cSpl196000 	 * attempts to communicate with it.
2797942c5e3cSpl196000 	 */
2798942c5e3cSpl196000 	status = AAC_FWSTATUS_GET(softs);
2799942c5e3cSpl196000 	if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
2800942c5e3cSpl196000 		goto error;
2801942c5e3cSpl196000 	i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
2802942c5e3cSpl196000 	AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
2803942c5e3cSpl196000 	if (i == 0) {
2804942c5e3cSpl196000 		cmn_err(CE_CONT, "?Fatal error: controller not ready");
2805942c5e3cSpl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2806942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2807942c5e3cSpl196000 		goto error;
2808942c5e3cSpl196000 	}
2809942c5e3cSpl196000 
2810942c5e3cSpl196000 	/* Read and set card supported options and settings */
2811942c5e3cSpl196000 	if (aac_check_firmware(softs) == AACERR) {
2812942c5e3cSpl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2813942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2814942c5e3cSpl196000 		goto error;
2815942c5e3cSpl196000 	}
2816942c5e3cSpl196000 
2817f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Add interrupt handlers */
2818f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (aac_register_intrs(softs) == AACERR) {
2819f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		cmn_err(CE_CONT,
2820f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "?Fatal error: interrupts register failed");
2821f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto error;
2822f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
2823942c5e3cSpl196000 
2824942c5e3cSpl196000 	/* Setup communication space with the card */
2825942c5e3cSpl196000 	if (softs->comm_space_dma_handle == NULL) {
2826942c5e3cSpl196000 		if (aac_alloc_comm_space(softs) != AACOK)
2827942c5e3cSpl196000 			goto error;
2828942c5e3cSpl196000 	}
2829942c5e3cSpl196000 	if (aac_setup_comm_space(softs) != AACOK) {
2830942c5e3cSpl196000 		cmn_err(CE_CONT, "?Setup communication space failed");
2831942c5e3cSpl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2832942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2833942c5e3cSpl196000 		goto error;
2834942c5e3cSpl196000 	}
2835942c5e3cSpl196000 
2836942c5e3cSpl196000 #ifdef DEBUG
2837942c5e3cSpl196000 	if (aac_get_fw_debug_buffer(softs) != AACOK)
2838942c5e3cSpl196000 		cmn_err(CE_CONT, "?firmware UART trace not supported");
2839942c5e3cSpl196000 #endif
2840942c5e3cSpl196000 
2841942c5e3cSpl196000 	/* Allocate slots */
2842942c5e3cSpl196000 	if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
2843942c5e3cSpl196000 		cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
2844942c5e3cSpl196000 		goto error;
2845942c5e3cSpl196000 	}
2846942c5e3cSpl196000 	AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
2847942c5e3cSpl196000 
2848942c5e3cSpl196000 	/* Allocate FIBs */
2849942c5e3cSpl196000 	if (softs->total_fibs < softs->total_slots) {
2850942c5e3cSpl196000 		aac_alloc_fibs(softs);
2851942c5e3cSpl196000 		if (softs->total_fibs == 0)
2852942c5e3cSpl196000 			goto error;
2853942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
2854942c5e3cSpl196000 		    softs->total_fibs);
2855942c5e3cSpl196000 	}
2856942c5e3cSpl196000 
2857f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
2858f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
2859f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
28600749e8deSXin Chen - Sun Microsystems - Beijing China 	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
2861b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		softs->feature_bits = sinf.FeatureBits;
2862b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		softs->support_opt2 = sinf.SupportedOptions2;
2863b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
28643fced439Szhongyan gu - Sun Microsystems - Beijing China 		/* Get adapter names */
28653fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (CARD_IS_UNKNOWN(softs->card)) {
2866942c5e3cSpl196000 			char *p, *p0, *p1;
2867942c5e3cSpl196000 
2868942c5e3cSpl196000 			/*
2869942c5e3cSpl196000 			 * Now find the controller name in supp_adapter_info->
2870942c5e3cSpl196000 			 * AdapterTypeText. Use the first word as the vendor
2871942c5e3cSpl196000 			 * and the other words as the product name.
2872942c5e3cSpl196000 			 */
2873942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
2874942c5e3cSpl196000 			    "\"%s\"", sinf.AdapterTypeText);
2875942c5e3cSpl196000 			p = sinf.AdapterTypeText;
2876942c5e3cSpl196000 			p0 = p1 = NULL;
2877942c5e3cSpl196000 			/* Skip heading spaces */
2878942c5e3cSpl196000 			while (*p && (*p == ' ' || *p == '\t'))
2879942c5e3cSpl196000 				p++;
2880942c5e3cSpl196000 			p0 = p;
2881942c5e3cSpl196000 			while (*p && (*p != ' ' && *p != '\t'))
2882942c5e3cSpl196000 				p++;
2883942c5e3cSpl196000 			/* Remove middle spaces */
2884942c5e3cSpl196000 			while (*p && (*p == ' ' || *p == '\t'))
2885942c5e3cSpl196000 				*p++ = 0;
2886942c5e3cSpl196000 			p1 = p;
2887942c5e3cSpl196000 			/* Remove trailing spaces */
2888942c5e3cSpl196000 			p = p1 + strlen(p1) - 1;
2889942c5e3cSpl196000 			while (p > p1 && (*p == ' ' || *p == '\t'))
2890942c5e3cSpl196000 				*p-- = 0;
2891942c5e3cSpl196000 			if (*p0 && *p1) {
2892942c5e3cSpl196000 				(void *)strncpy(softs->vendor_name, p0,
2893942c5e3cSpl196000 				    AAC_VENDOR_LEN);
2894942c5e3cSpl196000 				(void *)strncpy(softs->product_name, p1,
2895942c5e3cSpl196000 				    AAC_PRODUCT_LEN);
2896942c5e3cSpl196000 			} else {
2897942c5e3cSpl196000 				cmn_err(CE_WARN,
2898942c5e3cSpl196000 				    "?adapter name mis-formatted\n");
2899942c5e3cSpl196000 				if (*p0)
2900942c5e3cSpl196000 					(void *)strncpy(softs->product_name,
2901942c5e3cSpl196000 					    p0, AAC_PRODUCT_LEN);
2902942c5e3cSpl196000 			}
2903942c5e3cSpl196000 		}
29040749e8deSXin Chen - Sun Microsystems - Beijing China 	} else {
29050749e8deSXin Chen - Sun Microsystems - Beijing China 		cmn_err(CE_CONT, "?Query adapter information failed");
2906942c5e3cSpl196000 	}
2907942c5e3cSpl196000 
29080749e8deSXin Chen - Sun Microsystems - Beijing China 
2909942c5e3cSpl196000 	cmn_err(CE_NOTE,
2910942c5e3cSpl196000 	    "!aac driver %d.%02d.%02d-%d, found card: " \
2911942c5e3cSpl196000 	    "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
2912942c5e3cSpl196000 	    AAC_DRIVER_MAJOR_VERSION,
2913942c5e3cSpl196000 	    AAC_DRIVER_MINOR_VERSION,
2914942c5e3cSpl196000 	    AAC_DRIVER_BUGFIX_LEVEL,
2915942c5e3cSpl196000 	    AAC_DRIVER_BUILD,
2916942c5e3cSpl196000 	    softs->vendor_name, softs->product_name,
2917942c5e3cSpl196000 	    softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
2918942c5e3cSpl196000 	    softs->pci_mem_base_paddr);
2919942c5e3cSpl196000 
2920942c5e3cSpl196000 	/* Perform acceptance of adapter-detected config changes if possible */
2921942c5e3cSpl196000 	if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
2922942c5e3cSpl196000 		cmn_err(CE_CONT, "?Handle adapter config issues failed");
2923942c5e3cSpl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
2924942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2925942c5e3cSpl196000 		goto error;
2926942c5e3cSpl196000 	}
2927942c5e3cSpl196000 
292858bc78c7SXin Chen 	/* Setup containers (logical devices) */
2929942c5e3cSpl196000 	if (aac_probe_containers(softs) != AACOK) {
2930942c5e3cSpl196000 		cmn_err(CE_CONT, "?Fatal error: get container info error");
2931942c5e3cSpl196000 		goto error;
2932942c5e3cSpl196000 	}
2933942c5e3cSpl196000 
29343fced439Szhongyan gu - Sun Microsystems - Beijing China 	/* Check for JBOD support. Default disable */
29353fced439Szhongyan gu - Sun Microsystems - Beijing China 	char *data;
29363fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
29373fced439Szhongyan gu - Sun Microsystems - Beijing China 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
29383fced439Szhongyan gu - Sun Microsystems - Beijing China 		    0, "jbod-enable", &data) == DDI_SUCCESS)) {
29393fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (strcmp(data, "yes") == 0) {
29403fced439Szhongyan gu - Sun Microsystems - Beijing China 				AACDB_PRINT(softs, CE_NOTE,
29413fced439Szhongyan gu - Sun Microsystems - Beijing China 				    "Enable JBOD access");
29423fced439Szhongyan gu - Sun Microsystems - Beijing China 				softs->flags |= AAC_FLAGS_JBOD;
29433fced439Szhongyan gu - Sun Microsystems - Beijing China 			}
29443fced439Szhongyan gu - Sun Microsystems - Beijing China 			ddi_prop_free(data);
29453fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
29463fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
29473fced439Szhongyan gu - Sun Microsystems - Beijing China 
294858bc78c7SXin Chen 	/* Setup phys. devices */
29493fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
295058bc78c7SXin Chen 		uint32_t bus_max, tgt_max;
295158bc78c7SXin Chen 		uint32_t bus, tgt;
295258bc78c7SXin Chen 		int index;
295358bc78c7SXin Chen 
295458bc78c7SXin Chen 		if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
295558bc78c7SXin Chen 			cmn_err(CE_CONT, "?Fatal error: get bus info error");
295658bc78c7SXin Chen 			goto error;
295758bc78c7SXin Chen 		}
295858bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
295958bc78c7SXin Chen 		    bus_max, tgt_max);
296058bc78c7SXin Chen 		if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
296158bc78c7SXin Chen 			if (softs->state & AAC_STATE_RESET) {
296258bc78c7SXin Chen 				cmn_err(CE_WARN,
296358bc78c7SXin Chen 				    "?Fatal error: bus map changed");
296458bc78c7SXin Chen 				goto error;
296558bc78c7SXin Chen 			}
296658bc78c7SXin Chen 			softs->bus_max = bus_max;
296758bc78c7SXin Chen 			softs->tgt_max = tgt_max;
296858bc78c7SXin Chen 			if (softs->nondasds) {
296958bc78c7SXin Chen 				kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
297058bc78c7SXin Chen 				    sizeof (struct aac_nondasd));
297158bc78c7SXin Chen 			}
297258bc78c7SXin Chen 			softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
297358bc78c7SXin Chen 			    sizeof (struct aac_nondasd), KM_SLEEP);
297458bc78c7SXin Chen 
297558bc78c7SXin Chen 			index = 0;
297658bc78c7SXin Chen 			for (bus = 0; bus < softs->bus_max; bus++) {
297758bc78c7SXin Chen 				for (tgt = 0; tgt < softs->tgt_max; tgt++) {
297858bc78c7SXin Chen 					struct aac_nondasd *dvp =
297958bc78c7SXin Chen 					    &softs->nondasds[index++];
298058bc78c7SXin Chen 					dvp->dev.type = AAC_DEV_PD;
298158bc78c7SXin Chen 					dvp->bus = bus;
298258bc78c7SXin Chen 					dvp->tid = tgt;
298358bc78c7SXin Chen 				}
298458bc78c7SXin Chen 			}
298558bc78c7SXin Chen 		}
298658bc78c7SXin Chen 	}
298758bc78c7SXin Chen 
2988942c5e3cSpl196000 	/* Check dma & acc handles allocated in attach */
2989942c5e3cSpl196000 	if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
2990942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2991942c5e3cSpl196000 		goto error;
2992942c5e3cSpl196000 	}
2993942c5e3cSpl196000 
2994942c5e3cSpl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
2995942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
2996942c5e3cSpl196000 		goto error;
2997942c5e3cSpl196000 	}
2998942c5e3cSpl196000 
2999942c5e3cSpl196000 	for (i = 0; i < softs->total_slots; i++) {
3000942c5e3cSpl196000 		if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
3001942c5e3cSpl196000 		    DDI_SUCCESS) {
3002942c5e3cSpl196000 			ddi_fm_service_impact(softs->devinfo_p,
3003942c5e3cSpl196000 			    DDI_SERVICE_LOST);
3004942c5e3cSpl196000 			goto error;
3005942c5e3cSpl196000 		}
3006942c5e3cSpl196000 	}
3007942c5e3cSpl196000 
3008942c5e3cSpl196000 	return (AACOK);
3009942c5e3cSpl196000 error:
3010942c5e3cSpl196000 	if (softs->state & AAC_STATE_RESET)
3011942c5e3cSpl196000 		return (AACERR);
301258bc78c7SXin Chen 	if (softs->nondasds) {
301358bc78c7SXin Chen 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
301458bc78c7SXin Chen 		    sizeof (struct aac_nondasd));
301558bc78c7SXin Chen 		softs->nondasds = NULL;
301658bc78c7SXin Chen 	}
3017942c5e3cSpl196000 	if (softs->total_fibs > 0)
3018942c5e3cSpl196000 		aac_destroy_fibs(softs);
3019942c5e3cSpl196000 	if (softs->total_slots > 0)
3020942c5e3cSpl196000 		aac_destroy_slots(softs);
3021942c5e3cSpl196000 	if (softs->comm_space_dma_handle)
3022942c5e3cSpl196000 		aac_free_comm_space(softs);
3023942c5e3cSpl196000 	return (AACERR);
3024942c5e3cSpl196000 }
3025942c5e3cSpl196000 
3026942c5e3cSpl196000 /*
3027942c5e3cSpl196000  * Hardware shutdown and resource release
3028942c5e3cSpl196000  */
3029942c5e3cSpl196000 static void
aac_common_detach(struct aac_softstate * softs)3030942c5e3cSpl196000 aac_common_detach(struct aac_softstate *softs)
3031942c5e3cSpl196000 {
3032942c5e3cSpl196000 	DBCALLED(softs, 1);
3033942c5e3cSpl196000 
3034f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_unregister_intrs(softs);
3035f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3036f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
3037942c5e3cSpl196000 	(void) aac_shutdown(softs);
3038942c5e3cSpl196000 
303958bc78c7SXin Chen 	if (softs->nondasds) {
304058bc78c7SXin Chen 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
304158bc78c7SXin Chen 		    sizeof (struct aac_nondasd));
304258bc78c7SXin Chen 		softs->nondasds = NULL;
304358bc78c7SXin Chen 	}
3044942c5e3cSpl196000 	aac_destroy_fibs(softs);
3045942c5e3cSpl196000 	aac_destroy_slots(softs);
3046942c5e3cSpl196000 	aac_free_comm_space(softs);
3047f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	mutex_exit(&softs->io_lock);
3048942c5e3cSpl196000 }
3049942c5e3cSpl196000 
3050942c5e3cSpl196000 /*
3051942c5e3cSpl196000  * Send a synchronous command to the controller and wait for a result.
3052942c5e3cSpl196000  * Indicate if the controller completed the command with an error status.
3053942c5e3cSpl196000  */
3054942c5e3cSpl196000 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)3055942c5e3cSpl196000 aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
3056942c5e3cSpl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
3057942c5e3cSpl196000     uint32_t *statusp)
3058942c5e3cSpl196000 {
3059942c5e3cSpl196000 	int timeout;
3060942c5e3cSpl196000 	uint32_t status;
3061942c5e3cSpl196000 
3062942c5e3cSpl196000 	if (statusp != NULL)
3063942c5e3cSpl196000 		*statusp = SRB_STATUS_SUCCESS;
3064942c5e3cSpl196000 
3065942c5e3cSpl196000 	/* Fill in mailbox */
3066942c5e3cSpl196000 	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
3067942c5e3cSpl196000 
3068942c5e3cSpl196000 	/* Ensure the sync command doorbell flag is cleared */
3069942c5e3cSpl196000 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3070942c5e3cSpl196000 
3071942c5e3cSpl196000 	/* Then set it to signal the adapter */
3072942c5e3cSpl196000 	AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
3073942c5e3cSpl196000 
3074942c5e3cSpl196000 	/* Spin waiting for the command to complete */
3075942c5e3cSpl196000 	timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
3076942c5e3cSpl196000 	AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
3077942c5e3cSpl196000 	if (!timeout) {
3078942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3079942c5e3cSpl196000 		    "Sync command timed out after %d seconds (0x%x)!",
3080942c5e3cSpl196000 		    AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
3081942c5e3cSpl196000 		return (AACERR);
3082942c5e3cSpl196000 	}
3083942c5e3cSpl196000 
3084942c5e3cSpl196000 	/* Clear the completion flag */
3085942c5e3cSpl196000 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
3086942c5e3cSpl196000 
3087942c5e3cSpl196000 	/* Get the command status */
3088942c5e3cSpl196000 	status = AAC_MAILBOX_GET(softs, 0);
3089942c5e3cSpl196000 	if (statusp != NULL)
3090942c5e3cSpl196000 		*statusp = status;
3091942c5e3cSpl196000 	if (status != SRB_STATUS_SUCCESS) {
3092942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3093942c5e3cSpl196000 		    "Sync command fail: status = 0x%x", status);
3094942c5e3cSpl196000 		return (AACERR);
3095942c5e3cSpl196000 	}
3096942c5e3cSpl196000 
3097942c5e3cSpl196000 	return (AACOK);
3098942c5e3cSpl196000 }
3099942c5e3cSpl196000 
3100942c5e3cSpl196000 /*
3101942c5e3cSpl196000  * Send a synchronous FIB to the adapter and wait for its completion
3102942c5e3cSpl196000  */
3103942c5e3cSpl196000 static int
aac_sync_fib(struct aac_softstate * softs,uint16_t cmd,uint16_t fibsize)3104942c5e3cSpl196000 aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
3105942c5e3cSpl196000 {
3106f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_cmd *acp = &softs->sync_ac;
3107942c5e3cSpl196000 
31081ee13a44SXinChen 	acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
31091ee13a44SXinChen 	if (softs->state & AAC_STATE_INTR)
31101ee13a44SXinChen 		acp->flags |= AAC_CMD_NO_CB;
31111ee13a44SXinChen 	else
31121ee13a44SXinChen 		acp->flags |= AAC_CMD_NO_INTR;
31131ee13a44SXinChen 
3114f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->ac_comp = aac_sync_complete;
3115f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->timeout = AAC_SYNC_TIMEOUT;
3116f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = fibsize;
31171ee13a44SXinChen 
3118942c5e3cSpl196000 	/*
3119f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	 * Only need to setup sync fib header, caller should have init
3120f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	 * fib data
3121942c5e3cSpl196000 	 */
3122f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, cmd);
3123942c5e3cSpl196000 
31241ee13a44SXinChen 	(void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
31251ee13a44SXinChen 	    DDI_DMA_SYNC_FORDEV);
31261ee13a44SXinChen 
3127f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_start_io(softs, acp);
312858bc78c7SXin Chen 
31291ee13a44SXinChen 	if (softs->state & AAC_STATE_INTR)
31301ee13a44SXinChen 		return (aac_do_sync_io(softs, acp));
31311ee13a44SXinChen 	else
31321ee13a44SXinChen 		return (aac_do_poll_io(softs, acp));
3133942c5e3cSpl196000 }
3134942c5e3cSpl196000 
3135942c5e3cSpl196000 static void
aac_cmd_initq(struct aac_cmd_queue * q)3136942c5e3cSpl196000 aac_cmd_initq(struct aac_cmd_queue *q)
3137942c5e3cSpl196000 {
3138942c5e3cSpl196000 	q->q_head = NULL;
3139942c5e3cSpl196000 	q->q_tail = (struct aac_cmd *)&q->q_head;
3140942c5e3cSpl196000 }
3141942c5e3cSpl196000 
3142942c5e3cSpl196000 /*
3143942c5e3cSpl196000  * Remove a cmd from the head of q
3144942c5e3cSpl196000  */
3145942c5e3cSpl196000 static struct aac_cmd *
aac_cmd_dequeue(struct aac_cmd_queue * q)3146942c5e3cSpl196000 aac_cmd_dequeue(struct aac_cmd_queue *q)
3147942c5e3cSpl196000 {
3148942c5e3cSpl196000 	struct aac_cmd *acp;
3149942c5e3cSpl196000 
3150942c5e3cSpl196000 	_NOTE(ASSUMING_PROTECTED(*q))
3151942c5e3cSpl196000 
3152942c5e3cSpl196000 	if ((acp = q->q_head) != NULL) {
3153942c5e3cSpl196000 		if ((q->q_head = acp->next) != NULL)
3154942c5e3cSpl196000 			acp->next = NULL;
3155942c5e3cSpl196000 		else
3156942c5e3cSpl196000 			q->q_tail = (struct aac_cmd *)&q->q_head;
3157942c5e3cSpl196000 		acp->prev = NULL;
3158942c5e3cSpl196000 	}
3159942c5e3cSpl196000 	return (acp);
3160942c5e3cSpl196000 }
3161942c5e3cSpl196000 
3162942c5e3cSpl196000 /*
3163942c5e3cSpl196000  * Add a cmd to the tail of q
3164942c5e3cSpl196000  */
3165942c5e3cSpl196000 static void
aac_cmd_enqueue(struct aac_cmd_queue * q,struct aac_cmd * acp)3166942c5e3cSpl196000 aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
3167942c5e3cSpl196000 {
3168942c5e3cSpl196000 	ASSERT(acp->next == NULL);
3169942c5e3cSpl196000 	acp->prev = q->q_tail;
3170942c5e3cSpl196000 	q->q_tail->next = acp;
3171942c5e3cSpl196000 	q->q_tail = acp;
3172942c5e3cSpl196000 }
3173942c5e3cSpl196000 
3174942c5e3cSpl196000 /*
3175942c5e3cSpl196000  * Remove the cmd ac from q
3176942c5e3cSpl196000  */
3177942c5e3cSpl196000 static void
aac_cmd_delete(struct aac_cmd_queue * q,struct aac_cmd * acp)3178942c5e3cSpl196000 aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
3179942c5e3cSpl196000 {
3180942c5e3cSpl196000 	if (acp->prev) {
3181942c5e3cSpl196000 		if ((acp->prev->next = acp->next) != NULL) {
3182942c5e3cSpl196000 			acp->next->prev = acp->prev;
3183942c5e3cSpl196000 			acp->next = NULL;
3184942c5e3cSpl196000 		} else {
3185942c5e3cSpl196000 			q->q_tail = acp->prev;
3186942c5e3cSpl196000 		}
3187942c5e3cSpl196000 		acp->prev = NULL;
3188942c5e3cSpl196000 	}
3189942c5e3cSpl196000 	/* ac is not in the queue */
3190942c5e3cSpl196000 }
3191942c5e3cSpl196000 
3192942c5e3cSpl196000 /*
3193942c5e3cSpl196000  * Atomically insert an entry into the nominated queue, returns 0 on success or
3194942c5e3cSpl196000  * AACERR if the queue is full.
3195942c5e3cSpl196000  *
3196942c5e3cSpl196000  * Note: it would be more efficient to defer notifying the controller in
3197942c5e3cSpl196000  *	 the case where we may be inserting several entries in rapid succession,
3198942c5e3cSpl196000  *	 but implementing this usefully may be difficult (it would involve a
3199942c5e3cSpl196000  *	 separate queue/notify interface).
3200942c5e3cSpl196000  */
3201942c5e3cSpl196000 static int
aac_fib_enqueue(struct aac_softstate * softs,int queue,uint32_t fib_addr,uint32_t fib_size)3202942c5e3cSpl196000 aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
3203942c5e3cSpl196000     uint32_t fib_size)
3204942c5e3cSpl196000 {
3205942c5e3cSpl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3206942c5e3cSpl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3207942c5e3cSpl196000 	uint32_t pi, ci;
3208942c5e3cSpl196000 
3209942c5e3cSpl196000 	DBCALLED(softs, 2);
3210942c5e3cSpl196000 
3211942c5e3cSpl196000 	ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
3212942c5e3cSpl196000 
3213942c5e3cSpl196000 	/* Get the producer/consumer indices */
3214a74f7440Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3215a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3216942c5e3cSpl196000 	    DDI_DMA_SYNC_FORCPU);
3217942c5e3cSpl196000 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3218942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3219942c5e3cSpl196000 		return (AACERR);
3220942c5e3cSpl196000 	}
3221942c5e3cSpl196000 
3222942c5e3cSpl196000 	pi = ddi_get32(acc,
3223942c5e3cSpl196000 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3224942c5e3cSpl196000 	ci = ddi_get32(acc,
3225942c5e3cSpl196000 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3226942c5e3cSpl196000 
3227942c5e3cSpl196000 	/*
3228942c5e3cSpl196000 	 * Wrap the queue first before we check the queue to see
3229942c5e3cSpl196000 	 * if it is full
3230942c5e3cSpl196000 	 */
3231942c5e3cSpl196000 	if (pi >= aac_qinfo[queue].size)
3232942c5e3cSpl196000 		pi = 0;
3233942c5e3cSpl196000 
3234942c5e3cSpl196000 	/* XXX queue full */
3235942c5e3cSpl196000 	if ((pi + 1) == ci)
3236942c5e3cSpl196000 		return (AACERR);
3237942c5e3cSpl196000 
3238942c5e3cSpl196000 	/* Fill in queue entry */
3239942c5e3cSpl196000 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
3240942c5e3cSpl196000 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
3241a74f7440Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3242a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3243942c5e3cSpl196000 	    DDI_DMA_SYNC_FORDEV);
3244942c5e3cSpl196000 
3245942c5e3cSpl196000 	/* Update producer index */
3246942c5e3cSpl196000 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
3247942c5e3cSpl196000 	    pi + 1);
3248942c5e3cSpl196000 	(void) ddi_dma_sync(dma,
3249a74f7440Spl196000 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
3250a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3251942c5e3cSpl196000 	    DDI_DMA_SYNC_FORDEV);
3252942c5e3cSpl196000 
3253942c5e3cSpl196000 	if (aac_qinfo[queue].notify != 0)
3254942c5e3cSpl196000 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3255942c5e3cSpl196000 	return (AACOK);
3256942c5e3cSpl196000 }
3257942c5e3cSpl196000 
3258942c5e3cSpl196000 /*
3259942c5e3cSpl196000  * Atomically remove one entry from the nominated queue, returns 0 on
3260942c5e3cSpl196000  * success or AACERR if the queue is empty.
3261942c5e3cSpl196000  */
3262942c5e3cSpl196000 static int
aac_fib_dequeue(struct aac_softstate * softs,int queue,int * idxp)3263942c5e3cSpl196000 aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
3264942c5e3cSpl196000 {
3265942c5e3cSpl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3266942c5e3cSpl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3267942c5e3cSpl196000 	uint32_t pi, ci;
3268942c5e3cSpl196000 	int unfull = 0;
3269942c5e3cSpl196000 
3270942c5e3cSpl196000 	DBCALLED(softs, 2);
3271942c5e3cSpl196000 
3272942c5e3cSpl196000 	ASSERT(idxp);
3273942c5e3cSpl196000 
3274942c5e3cSpl196000 	/* Get the producer/consumer indices */
3275a74f7440Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
3276a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
3277942c5e3cSpl196000 	    DDI_DMA_SYNC_FORCPU);
3278942c5e3cSpl196000 	pi = ddi_get32(acc,
3279942c5e3cSpl196000 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
3280942c5e3cSpl196000 	ci = ddi_get32(acc,
3281942c5e3cSpl196000 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
3282942c5e3cSpl196000 
3283942c5e3cSpl196000 	/* Check for queue empty */
3284942c5e3cSpl196000 	if (ci == pi)
3285942c5e3cSpl196000 		return (AACERR);
3286942c5e3cSpl196000 
3287942c5e3cSpl196000 	if (pi >= aac_qinfo[queue].size)
3288942c5e3cSpl196000 		pi = 0;
3289942c5e3cSpl196000 
3290942c5e3cSpl196000 	/* Check for queue full */
3291942c5e3cSpl196000 	if (ci == pi + 1)
3292942c5e3cSpl196000 		unfull = 1;
3293942c5e3cSpl196000 
3294942c5e3cSpl196000 	/*
3295942c5e3cSpl196000 	 * The controller does not wrap the queue,
3296942c5e3cSpl196000 	 * so we have to do it by ourselves
3297942c5e3cSpl196000 	 */
3298942c5e3cSpl196000 	if (ci >= aac_qinfo[queue].size)
3299942c5e3cSpl196000 		ci = 0;
3300942c5e3cSpl196000 
3301942c5e3cSpl196000 	/* Fetch the entry */
3302a74f7440Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
3303a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
3304942c5e3cSpl196000 	    DDI_DMA_SYNC_FORCPU);
3305942c5e3cSpl196000 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
3306942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
3307942c5e3cSpl196000 		return (AACERR);
3308942c5e3cSpl196000 	}
3309942c5e3cSpl196000 
3310942c5e3cSpl196000 	switch (queue) {
3311942c5e3cSpl196000 	case AAC_HOST_NORM_RESP_Q:
3312942c5e3cSpl196000 	case AAC_HOST_HIGH_RESP_Q:
3313942c5e3cSpl196000 		*idxp = ddi_get32(acc,
3314942c5e3cSpl196000 		    &(softs->qentries[queue] + ci)->aq_fib_addr);
3315942c5e3cSpl196000 		break;
3316942c5e3cSpl196000 
3317942c5e3cSpl196000 	case AAC_HOST_NORM_CMD_Q:
3318942c5e3cSpl196000 	case AAC_HOST_HIGH_CMD_Q:
3319942c5e3cSpl196000 		*idxp = ddi_get32(acc,
3320942c5e3cSpl196000 		    &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
3321942c5e3cSpl196000 		break;
3322942c5e3cSpl196000 
3323942c5e3cSpl196000 	default:
3324942c5e3cSpl196000 		cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
3325942c5e3cSpl196000 		return (AACERR);
3326942c5e3cSpl196000 	}
3327942c5e3cSpl196000 
3328942c5e3cSpl196000 	/* Update consumer index */
3329942c5e3cSpl196000 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
3330942c5e3cSpl196000 	    ci + 1);
3331942c5e3cSpl196000 	(void) ddi_dma_sync(dma,
3332a74f7440Spl196000 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
3333a74f7440Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
3334942c5e3cSpl196000 	    DDI_DMA_SYNC_FORDEV);
3335942c5e3cSpl196000 
3336942c5e3cSpl196000 	if (unfull && aac_qinfo[queue].notify != 0)
3337942c5e3cSpl196000 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
3338942c5e3cSpl196000 	return (AACOK);
3339942c5e3cSpl196000 }
3340942c5e3cSpl196000 
3341942c5e3cSpl196000 static struct aac_mntinforesp *
aac_get_mntinfo(struct aac_softstate * softs,int cid)3342f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_get_mntinfo(struct aac_softstate *softs, int cid)
3343942c5e3cSpl196000 {
3344f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3345f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
3346942c5e3cSpl196000 	struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
3347942c5e3cSpl196000 	struct aac_mntinforesp *mir;
3348942c5e3cSpl196000 
3349942c5e3cSpl196000 	ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
3350942c5e3cSpl196000 	    (softs->flags & AAC_FLAGS_LBA_64BIT) ?
3351942c5e3cSpl196000 	    VM_NameServe64 : VM_NameServe);
3352942c5e3cSpl196000 	ddi_put32(acc, &mi->MntType, FT_FILESYS);
3353942c5e3cSpl196000 	ddi_put32(acc, &mi->MntCount, cid);
3354942c5e3cSpl196000 
3355942c5e3cSpl196000 	if (aac_sync_fib(softs, ContainerCommand,
3356942c5e3cSpl196000 	    AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
3357942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
3358942c5e3cSpl196000 		return (NULL);
3359942c5e3cSpl196000 	}
3360942c5e3cSpl196000 
3361942c5e3cSpl196000 	mir = (struct aac_mntinforesp *)&fibp->data[0];
3362942c5e3cSpl196000 	if (ddi_get32(acc, &mir->Status) == ST_OK)
3363942c5e3cSpl196000 		return (mir);
3364942c5e3cSpl196000 	return (NULL);
3365942c5e3cSpl196000 }
3366942c5e3cSpl196000 
3367942c5e3cSpl196000 static int
aac_get_container_count(struct aac_softstate * softs,int * count)3368942c5e3cSpl196000 aac_get_container_count(struct aac_softstate *softs, int *count)
3369942c5e3cSpl196000 {
3370f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
3371942c5e3cSpl196000 	struct aac_mntinforesp *mir;
3372f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
3373942c5e3cSpl196000 
3374f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3375f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
3376f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3377f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
3378f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
3379f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3380f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3381942c5e3cSpl196000 	*count = ddi_get32(acc, &mir->MntRespCount);
3382942c5e3cSpl196000 	if (*count > AAC_MAX_LD) {
3383942c5e3cSpl196000 		AACDB_PRINT(softs, CE_CONT,
3384942c5e3cSpl196000 		    "container count(%d) > AAC_MAX_LD", *count);
3385f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		rval = AACERR;
3386f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3387942c5e3cSpl196000 	}
3388f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = AACOK;
3389f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3390f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
3391f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
3392f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (rval);
3393942c5e3cSpl196000 }
3394942c5e3cSpl196000 
3395942c5e3cSpl196000 static int
aac_get_container_uid(struct aac_softstate * softs,uint32_t cid,uint32_t * uid)3396942c5e3cSpl196000 aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
3397942c5e3cSpl196000 {
3398f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3399942c5e3cSpl196000 	struct aac_Container *ct = (struct aac_Container *) \
3400f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    &softs->sync_ac.slotp->fibp->data[0];
3401942c5e3cSpl196000 
3402942c5e3cSpl196000 	bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
3403942c5e3cSpl196000 	ddi_put32(acc, &ct->Command, VM_ContainerConfig);
3404942c5e3cSpl196000 	ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
3405942c5e3cSpl196000 	ddi_put32(acc, &ct->CTCommand.param[0], cid);
3406942c5e3cSpl196000 
3407942c5e3cSpl196000 	if (aac_sync_fib(softs, ContainerCommand,
3408942c5e3cSpl196000 	    AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
3409942c5e3cSpl196000 		return (AACERR);
3410942c5e3cSpl196000 	if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
3411942c5e3cSpl196000 		return (AACERR);
3412942c5e3cSpl196000 
3413942c5e3cSpl196000 	*uid = ddi_get32(acc, &ct->CTCommand.param[1]);
3414942c5e3cSpl196000 	return (AACOK);
3415942c5e3cSpl196000 }
3416942c5e3cSpl196000 
3417f42c2f53Szhongyan gu - Sun Microsystems - Beijing China /*
3418f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  * Request information of the container cid
3419f42c2f53Szhongyan gu - Sun Microsystems - Beijing China  */
3420f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static struct aac_mntinforesp *
aac_get_container_info(struct aac_softstate * softs,int cid)3421f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_get_container_info(struct aac_softstate *softs, int cid)
3422f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
3423f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
3424f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_mntinforesp *mir;
3425f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval_uid;
3426f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t uid;
3427f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3428f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get container UID first so that it will not overwrite mntinfo */
3429f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval_uid = aac_get_container_uid(softs, cid, &uid);
3430f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3431f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Get container basic info */
3432f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
3433f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_CONT,
3434f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "query container %d info failed", cid);
3435f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (NULL);
3436f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3437f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
3438f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (mir);
3439f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (rval_uid != AACOK) {
3440f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_CONT,
3441f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		    "query container %d uid failed", cid);
3442f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (NULL);
3443f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3444f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3445f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &mir->Status, uid);
3446f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (mir);
3447f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
3448f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
34490749e8deSXin Chen - Sun Microsystems - Beijing China static enum aac_cfg_event
aac_probe_container(struct aac_softstate * softs,uint32_t cid)3450942c5e3cSpl196000 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
3451942c5e3cSpl196000 {
34520749e8deSXin Chen - Sun Microsystems - Beijing China 	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
3453942c5e3cSpl196000 	struct aac_container *dvp = &softs->containers[cid];
3454942c5e3cSpl196000 	struct aac_mntinforesp *mir;
34550749e8deSXin Chen - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
3456f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3457f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
3458f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
3459942c5e3cSpl196000 
3460942c5e3cSpl196000 	/* Get container basic info */
3461f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
34620749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AAC_CFG_NULL_NOEXIST */
3463f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		goto finish;
3464f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
3465942c5e3cSpl196000 
3466942c5e3cSpl196000 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
346758bc78c7SXin Chen 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3468942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE,
3469942c5e3cSpl196000 			    ">>> Container %d deleted", cid);
347058bc78c7SXin Chen 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
34710749e8deSXin Chen - Sun Microsystems - Beijing China 			event = AAC_CFG_DELETE;
3472942c5e3cSpl196000 		}
34730749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AAC_CFG_NULL_NOEXIST */
3474942c5e3cSpl196000 	} else {
34750749e8deSXin Chen - Sun Microsystems - Beijing China 		uint64_t size;
34760749e8deSXin Chen - Sun Microsystems - Beijing China 		uint32_t uid;
34770749e8deSXin Chen - Sun Microsystems - Beijing China 
34780749e8deSXin Chen - Sun Microsystems - Beijing China 		event = AAC_CFG_NULL_EXIST;
34790749e8deSXin Chen - Sun Microsystems - Beijing China 
3480942c5e3cSpl196000 		size = AAC_MIR_SIZE(softs, acc, mir);
3481f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		uid = ddi_get32(acc, &mir->Status);
348258bc78c7SXin Chen 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
3483942c5e3cSpl196000 			if (dvp->uid != uid) {
3484942c5e3cSpl196000 				AACDB_PRINT(softs, CE_WARN,
3485942c5e3cSpl196000 				    ">>> Container %u uid changed to %d",
3486942c5e3cSpl196000 				    cid, uid);
3487942c5e3cSpl196000 				dvp->uid = uid;
34880749e8deSXin Chen - Sun Microsystems - Beijing China 				event = AAC_CFG_CHANGE;
3489942c5e3cSpl196000 			}
3490942c5e3cSpl196000 			if (dvp->size != size) {
3491942c5e3cSpl196000 				AACDB_PRINT(softs, CE_NOTE,
3492942c5e3cSpl196000 				    ">>> Container %u size changed to %"PRIu64,
3493942c5e3cSpl196000 				    cid, size);
3494942c5e3cSpl196000 				dvp->size = size;
34950749e8deSXin Chen - Sun Microsystems - Beijing China 				event = AAC_CFG_CHANGE;
3496942c5e3cSpl196000 			}
3497942c5e3cSpl196000 		} else { /* Init new container */
3498942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE,
349958bc78c7SXin Chen 			    ">>> Container %d added: " \
350058bc78c7SXin Chen 			    "size=0x%x.%08x, type=%d, name=%s",
350158bc78c7SXin Chen 			    cid,
350258bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.CapacityHigh),
350358bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.Capacity),
350458bc78c7SXin Chen 			    ddi_get32(acc, &mir->MntObj.VolType),
350558bc78c7SXin Chen 			    mir->MntObj.FileSystemName);
350658bc78c7SXin Chen 			dvp->dev.flags |= AAC_DFLAG_VALID;
350758bc78c7SXin Chen 			dvp->dev.type = AAC_DEV_LD;
3508942c5e3cSpl196000 
3509942c5e3cSpl196000 			dvp->cid = cid;
3510942c5e3cSpl196000 			dvp->uid = uid;
3511942c5e3cSpl196000 			dvp->size = size;
3512942c5e3cSpl196000 			dvp->locked = 0;
3513942c5e3cSpl196000 			dvp->deleted = 0;
35140749e8deSXin Chen - Sun Microsystems - Beijing China 
35150749e8deSXin Chen - Sun Microsystems - Beijing China 			event = AAC_CFG_ADD;
3516942c5e3cSpl196000 		}
3517942c5e3cSpl196000 	}
3518f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
3519f42c2f53Szhongyan gu - Sun Microsystems - Beijing China finish:
3520f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
35210749e8deSXin Chen - Sun Microsystems - Beijing China 	return (event);
3522942c5e3cSpl196000 }
3523942c5e3cSpl196000 
3524942c5e3cSpl196000 /*
3525942c5e3cSpl196000  * Do a rescan of all the possible containers and update the container list
352658bc78c7SXin Chen  * with newly online/offline containers, and prepare for autoconfiguration.
3527942c5e3cSpl196000  */
3528942c5e3cSpl196000 static int
aac_probe_containers(struct aac_softstate * softs)3529942c5e3cSpl196000 aac_probe_containers(struct aac_softstate *softs)
3530942c5e3cSpl196000 {
3531942c5e3cSpl196000 	int i, count, total;
3532942c5e3cSpl196000 
3533942c5e3cSpl196000 	/* Loop over possible containers */
3534942c5e3cSpl196000 	count = softs->container_count;
3535942c5e3cSpl196000 	if (aac_get_container_count(softs, &count) == AACERR)
3536942c5e3cSpl196000 		return (AACERR);
35370749e8deSXin Chen - Sun Microsystems - Beijing China 
3538942c5e3cSpl196000 	for (i = total = 0; i < count; i++) {
35390749e8deSXin Chen - Sun Microsystems - Beijing China 		enum aac_cfg_event event = aac_probe_container(softs, i);
35400749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((event != AAC_CFG_NULL_NOEXIST) &&
35410749e8deSXin Chen - Sun Microsystems - Beijing China 		    (event != AAC_CFG_NULL_EXIST)) {
35420749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_dr(softs, i, -1, event);
3543942c5e3cSpl196000 			total++;
3544942c5e3cSpl196000 		}
35450749e8deSXin Chen - Sun Microsystems - Beijing China 	}
35460749e8deSXin Chen - Sun Microsystems - Beijing China 
3547942c5e3cSpl196000 	if (count < softs->container_count) {
3548942c5e3cSpl196000 		struct aac_container *dvp;
3549942c5e3cSpl196000 
3550942c5e3cSpl196000 		for (dvp = &softs->containers[count];
3551942c5e3cSpl196000 		    dvp < &softs->containers[softs->container_count]; dvp++) {
355258bc78c7SXin Chen 			if (!AAC_DEV_IS_VALID(&dvp->dev))
3553942c5e3cSpl196000 				continue;
3554942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
3555942c5e3cSpl196000 			    dvp->cid);
355658bc78c7SXin Chen 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
35570749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_dr(softs, dvp->cid, -1,
35580749e8deSXin Chen - Sun Microsystems - Beijing China 			    AAC_CFG_DELETE);
3559942c5e3cSpl196000 		}
3560942c5e3cSpl196000 	}
35610749e8deSXin Chen - Sun Microsystems - Beijing China 
3562942c5e3cSpl196000 	softs->container_count = count;
3563942c5e3cSpl196000 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
3564942c5e3cSpl196000 	return (AACOK);
3565942c5e3cSpl196000 }
3566942c5e3cSpl196000 
3567942c5e3cSpl196000 static int
aac_probe_jbod(struct aac_softstate * softs,int tgt,int event)35683fced439Szhongyan gu - Sun Microsystems - Beijing China aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
35693fced439Szhongyan gu - Sun Microsystems - Beijing China {
3570*3ce33fb0SHengqing Hu 	ASSERT(AAC_MAX_LD <= tgt);
3571*3ce33fb0SHengqing Hu 	ASSERT(tgt < AAC_MAX_DEV(softs));
35723fced439Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_device *dvp;
35733fced439Szhongyan gu - Sun Microsystems - Beijing China 	dvp = AAC_DEV(softs, tgt);
35743fced439Szhongyan gu - Sun Microsystems - Beijing China 
35753fced439Szhongyan gu - Sun Microsystems - Beijing China 	switch (event) {
35763fced439Szhongyan gu - Sun Microsystems - Beijing China 	case AAC_CFG_ADD:
35773fced439Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE,
35783fced439Szhongyan gu - Sun Microsystems - Beijing China 		    ">>> Jbod %d added", tgt - AAC_MAX_LD);
35793fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->flags |= AAC_DFLAG_VALID;
35803fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->type = AAC_DEV_PD;
35813fced439Szhongyan gu - Sun Microsystems - Beijing China 		break;
35823fced439Szhongyan gu - Sun Microsystems - Beijing China 	case AAC_CFG_DELETE:
35833fced439Szhongyan gu - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE,
35843fced439Szhongyan gu - Sun Microsystems - Beijing China 		    ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
35853fced439Szhongyan gu - Sun Microsystems - Beijing China 		dvp->flags &= ~AAC_DFLAG_VALID;
35863fced439Szhongyan gu - Sun Microsystems - Beijing China 		break;
35873fced439Szhongyan gu - Sun Microsystems - Beijing China 	default:
35883fced439Szhongyan gu - Sun Microsystems - Beijing China 		return (AACERR);
35893fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
35903fced439Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_handle_dr(softs, tgt, 0, event);
35913fced439Szhongyan gu - Sun Microsystems - Beijing China 	return (AACOK);
35923fced439Szhongyan gu - Sun Microsystems - Beijing China }
35933fced439Szhongyan gu - Sun Microsystems - Beijing China 
35943fced439Szhongyan gu - Sun Microsystems - Beijing China static int
aac_alloc_comm_space(struct aac_softstate * softs)3595942c5e3cSpl196000 aac_alloc_comm_space(struct aac_softstate *softs)
3596942c5e3cSpl196000 {
3597942c5e3cSpl196000 	size_t rlen;
3598942c5e3cSpl196000 	ddi_dma_cookie_t cookie;
3599942c5e3cSpl196000 	uint_t cookien;
3600942c5e3cSpl196000 
3601942c5e3cSpl196000 	/* Allocate DMA for comm. space */
3602942c5e3cSpl196000 	if (ddi_dma_alloc_handle(
3603942c5e3cSpl196000 	    softs->devinfo_p,
3604942c5e3cSpl196000 	    &softs->addr_dma_attr,
3605942c5e3cSpl196000 	    DDI_DMA_SLEEP,
3606942c5e3cSpl196000 	    NULL,
3607942c5e3cSpl196000 	    &softs->comm_space_dma_handle) != DDI_SUCCESS) {
3608942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3609942c5e3cSpl196000 		    "Cannot alloc dma handle for communication area");
3610942c5e3cSpl196000 		goto error;
3611942c5e3cSpl196000 	}
3612942c5e3cSpl196000 	if (ddi_dma_mem_alloc(
3613942c5e3cSpl196000 	    softs->comm_space_dma_handle,
3614942c5e3cSpl196000 	    sizeof (struct aac_comm_space),
361558bc78c7SXin Chen 	    &softs->acc_attr,
3616942c5e3cSpl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3617942c5e3cSpl196000 	    DDI_DMA_SLEEP,
3618942c5e3cSpl196000 	    NULL,
3619942c5e3cSpl196000 	    (caddr_t *)&softs->comm_space,
3620942c5e3cSpl196000 	    &rlen,
3621942c5e3cSpl196000 	    &softs->comm_space_acc_handle) != DDI_SUCCESS) {
3622942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3623942c5e3cSpl196000 		    "Cannot alloc mem for communication area");
3624942c5e3cSpl196000 		goto error;
3625942c5e3cSpl196000 	}
3626942c5e3cSpl196000 	if (ddi_dma_addr_bind_handle(
3627942c5e3cSpl196000 	    softs->comm_space_dma_handle,
3628942c5e3cSpl196000 	    NULL,
3629942c5e3cSpl196000 	    (caddr_t)softs->comm_space,
3630942c5e3cSpl196000 	    sizeof (struct aac_comm_space),
3631942c5e3cSpl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3632942c5e3cSpl196000 	    DDI_DMA_SLEEP,
3633942c5e3cSpl196000 	    NULL,
3634942c5e3cSpl196000 	    &cookie,
3635942c5e3cSpl196000 	    &cookien) != DDI_DMA_MAPPED) {
3636942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3637942c5e3cSpl196000 		    "DMA bind failed for communication area");
3638942c5e3cSpl196000 		goto error;
3639942c5e3cSpl196000 	}
3640942c5e3cSpl196000 	softs->comm_space_phyaddr = cookie.dmac_address;
3641942c5e3cSpl196000 
3642942c5e3cSpl196000 	return (AACOK);
3643942c5e3cSpl196000 error:
3644942c5e3cSpl196000 	if (softs->comm_space_acc_handle) {
3645942c5e3cSpl196000 		ddi_dma_mem_free(&softs->comm_space_acc_handle);
3646942c5e3cSpl196000 		softs->comm_space_acc_handle = NULL;
3647942c5e3cSpl196000 	}
3648942c5e3cSpl196000 	if (softs->comm_space_dma_handle) {
3649942c5e3cSpl196000 		ddi_dma_free_handle(&softs->comm_space_dma_handle);
3650942c5e3cSpl196000 		softs->comm_space_dma_handle = NULL;
3651942c5e3cSpl196000 	}
3652942c5e3cSpl196000 	return (AACERR);
3653942c5e3cSpl196000 }
3654942c5e3cSpl196000 
3655942c5e3cSpl196000 static void
aac_free_comm_space(struct aac_softstate * softs)3656942c5e3cSpl196000 aac_free_comm_space(struct aac_softstate *softs)
3657942c5e3cSpl196000 {
3658942c5e3cSpl196000 
3659942c5e3cSpl196000 	(void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
3660942c5e3cSpl196000 	ddi_dma_mem_free(&softs->comm_space_acc_handle);
3661942c5e3cSpl196000 	softs->comm_space_acc_handle = NULL;
3662942c5e3cSpl196000 	ddi_dma_free_handle(&softs->comm_space_dma_handle);
3663942c5e3cSpl196000 	softs->comm_space_dma_handle = NULL;
3664942c5e3cSpl196000 	softs->comm_space_phyaddr = NULL;
3665942c5e3cSpl196000 }
3666942c5e3cSpl196000 
3667942c5e3cSpl196000 /*
3668942c5e3cSpl196000  * Initialize the data structures that are required for the communication
3669942c5e3cSpl196000  * interface to operate
3670942c5e3cSpl196000  */
3671942c5e3cSpl196000 static int
aac_setup_comm_space(struct aac_softstate * softs)3672942c5e3cSpl196000 aac_setup_comm_space(struct aac_softstate *softs)
3673942c5e3cSpl196000 {
3674942c5e3cSpl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
3675942c5e3cSpl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
3676942c5e3cSpl196000 	uint32_t comm_space_phyaddr;
3677942c5e3cSpl196000 	struct aac_adapter_init *initp;
3678942c5e3cSpl196000 	int qoffset;
3679942c5e3cSpl196000 
3680942c5e3cSpl196000 	comm_space_phyaddr = softs->comm_space_phyaddr;
3681942c5e3cSpl196000 
3682942c5e3cSpl196000 	/* Setup adapter init struct */
3683942c5e3cSpl196000 	initp = &softs->comm_space->init_data;
3684942c5e3cSpl196000 	bzero(initp, sizeof (struct aac_adapter_init));
3685942c5e3cSpl196000 
3686942c5e3cSpl196000 	ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
3687942c5e3cSpl196000 	ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
3688942c5e3cSpl196000 
3689942c5e3cSpl196000 	/* Setup new/old comm. specific data */
3690942c5e3cSpl196000 	if (softs->flags & AAC_FLAGS_RAW_IO) {
3691b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		uint32_t init_flags = 0;
3692b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
3693b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->flags & AAC_FLAGS_NEW_COMM)
3694b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
3695b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		/* AAC_SUPPORTED_POWER_MANAGEMENT */
3696b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
3697b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
3698b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
3699942c5e3cSpl196000 		ddi_put32(acc, &initp->InitStructRevision,
3700942c5e3cSpl196000 		    AAC_INIT_STRUCT_REVISION_4);
3701b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		ddi_put32(acc, &initp->InitFlags, init_flags);
3702942c5e3cSpl196000 		/* Setup the preferred settings */
3703942c5e3cSpl196000 		ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
3704942c5e3cSpl196000 		ddi_put32(acc, &initp->MaxIoSize,
3705942c5e3cSpl196000 		    (softs->aac_max_sectors << 9));
3706942c5e3cSpl196000 		ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
3707942c5e3cSpl196000 	} else {
3708942c5e3cSpl196000 		/*
3709942c5e3cSpl196000 		 * Tells the adapter about the physical location of various
3710942c5e3cSpl196000 		 * important shared data structures
3711942c5e3cSpl196000 		 */
3712942c5e3cSpl196000 		ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
3713942c5e3cSpl196000 		    comm_space_phyaddr + \
3714942c5e3cSpl196000 		    offsetof(struct aac_comm_space, adapter_fibs));
3715942c5e3cSpl196000 		ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
3716942c5e3cSpl196000 		ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
3717942c5e3cSpl196000 		ddi_put32(acc, &initp->AdapterFibsSize,
3718942c5e3cSpl196000 		    AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
3719942c5e3cSpl196000 		ddi_put32(acc, &initp->PrintfBufferAddress,
3720942c5e3cSpl196000 		    comm_space_phyaddr + \
3721942c5e3cSpl196000 		    offsetof(struct aac_comm_space, adapter_print_buf));
3722942c5e3cSpl196000 		ddi_put32(acc, &initp->PrintfBufferSize,
3723942c5e3cSpl196000 		    AAC_ADAPTER_PRINT_BUFSIZE);
3724942c5e3cSpl196000 		ddi_put32(acc, &initp->MiniPortRevision,
3725942c5e3cSpl196000 		    AAC_INIT_STRUCT_MINIPORT_REVISION);
3726942c5e3cSpl196000 		ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
3727942c5e3cSpl196000 
3728942c5e3cSpl196000 		qoffset = (comm_space_phyaddr + \
3729942c5e3cSpl196000 		    offsetof(struct aac_comm_space, qtable)) % \
3730942c5e3cSpl196000 		    AAC_QUEUE_ALIGN;
3731942c5e3cSpl196000 		if (qoffset)
3732942c5e3cSpl196000 			qoffset = AAC_QUEUE_ALIGN - qoffset;
3733942c5e3cSpl196000 		softs->qtablep = (struct aac_queue_table *) \
3734942c5e3cSpl196000 		    ((char *)&softs->comm_space->qtable + qoffset);
3735942c5e3cSpl196000 		ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
3736942c5e3cSpl196000 		    offsetof(struct aac_comm_space, qtable) + qoffset);
3737942c5e3cSpl196000 
3738942c5e3cSpl196000 		/* Init queue table */
3739942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3740942c5e3cSpl196000 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3741942c5e3cSpl196000 		    AAC_HOST_NORM_CMD_ENTRIES);
3742942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3743942c5e3cSpl196000 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3744942c5e3cSpl196000 		    AAC_HOST_NORM_CMD_ENTRIES);
3745942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3746942c5e3cSpl196000 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3747942c5e3cSpl196000 		    AAC_HOST_HIGH_CMD_ENTRIES);
3748942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3749942c5e3cSpl196000 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3750942c5e3cSpl196000 		    AAC_HOST_HIGH_CMD_ENTRIES);
3751942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3752942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
3753942c5e3cSpl196000 		    AAC_ADAP_NORM_CMD_ENTRIES);
3754942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3755942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
3756942c5e3cSpl196000 		    AAC_ADAP_NORM_CMD_ENTRIES);
3757942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3758942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
3759942c5e3cSpl196000 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3760942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3761942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
3762942c5e3cSpl196000 		    AAC_ADAP_HIGH_CMD_ENTRIES);
3763942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3764942c5e3cSpl196000 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3765942c5e3cSpl196000 		    AAC_HOST_NORM_RESP_ENTRIES);
3766942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3767942c5e3cSpl196000 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3768942c5e3cSpl196000 		    AAC_HOST_NORM_RESP_ENTRIES);
3769942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3770942c5e3cSpl196000 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3771942c5e3cSpl196000 		    AAC_HOST_HIGH_RESP_ENTRIES);
3772942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3773942c5e3cSpl196000 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3774942c5e3cSpl196000 		    AAC_HOST_HIGH_RESP_ENTRIES);
3775942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3776942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
3777942c5e3cSpl196000 		    AAC_ADAP_NORM_RESP_ENTRIES);
3778942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3779942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
3780942c5e3cSpl196000 		    AAC_ADAP_NORM_RESP_ENTRIES);
3781942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3782942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
3783942c5e3cSpl196000 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3784942c5e3cSpl196000 		ddi_put32(acc, &softs->qtablep-> \
3785942c5e3cSpl196000 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
3786942c5e3cSpl196000 		    AAC_ADAP_HIGH_RESP_ENTRIES);
3787942c5e3cSpl196000 
3788942c5e3cSpl196000 		/* Init queue entries */
3789942c5e3cSpl196000 		softs->qentries[AAC_HOST_NORM_CMD_Q] =
3790942c5e3cSpl196000 		    &softs->qtablep->qt_HostNormCmdQueue[0];
3791942c5e3cSpl196000 		softs->qentries[AAC_HOST_HIGH_CMD_Q] =
3792942c5e3cSpl196000 		    &softs->qtablep->qt_HostHighCmdQueue[0];
3793942c5e3cSpl196000 		softs->qentries[AAC_ADAP_NORM_CMD_Q] =
3794942c5e3cSpl196000 		    &softs->qtablep->qt_AdapNormCmdQueue[0];
3795942c5e3cSpl196000 		softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
3796942c5e3cSpl196000 		    &softs->qtablep->qt_AdapHighCmdQueue[0];
3797942c5e3cSpl196000 		softs->qentries[AAC_HOST_NORM_RESP_Q] =
3798942c5e3cSpl196000 		    &softs->qtablep->qt_HostNormRespQueue[0];
3799942c5e3cSpl196000 		softs->qentries[AAC_HOST_HIGH_RESP_Q] =
3800942c5e3cSpl196000 		    &softs->qtablep->qt_HostHighRespQueue[0];
3801942c5e3cSpl196000 		softs->qentries[AAC_ADAP_NORM_RESP_Q] =
3802942c5e3cSpl196000 		    &softs->qtablep->qt_AdapNormRespQueue[0];
3803942c5e3cSpl196000 		softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
3804942c5e3cSpl196000 		    &softs->qtablep->qt_AdapHighRespQueue[0];
3805942c5e3cSpl196000 	}
3806942c5e3cSpl196000 	(void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
3807942c5e3cSpl196000 
3808942c5e3cSpl196000 	/* Send init structure to the card */
3809942c5e3cSpl196000 	if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
3810942c5e3cSpl196000 	    comm_space_phyaddr + \
3811942c5e3cSpl196000 	    offsetof(struct aac_comm_space, init_data),
3812942c5e3cSpl196000 	    0, 0, 0, NULL) == AACERR) {
3813942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
3814942c5e3cSpl196000 		    "Cannot send init structure to adapter");
3815942c5e3cSpl196000 		return (AACERR);
3816942c5e3cSpl196000 	}
3817942c5e3cSpl196000 
3818942c5e3cSpl196000 	return (AACOK);
3819942c5e3cSpl196000 }
3820942c5e3cSpl196000 
3821942c5e3cSpl196000 static uchar_t *
aac_vendor_id(struct aac_softstate * softs,uchar_t * buf)3822942c5e3cSpl196000 aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
3823942c5e3cSpl196000 {
3824942c5e3cSpl196000 	(void) memset(buf, ' ', AAC_VENDOR_LEN);
3825942c5e3cSpl196000 	bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
3826942c5e3cSpl196000 	return (buf + AAC_VENDOR_LEN);
3827942c5e3cSpl196000 }
3828942c5e3cSpl196000 
3829942c5e3cSpl196000 static uchar_t *
aac_product_id(struct aac_softstate * softs,uchar_t * buf)3830942c5e3cSpl196000 aac_product_id(struct aac_softstate *softs, uchar_t *buf)
3831942c5e3cSpl196000 {
3832942c5e3cSpl196000 	(void) memset(buf, ' ', AAC_PRODUCT_LEN);
3833942c5e3cSpl196000 	bcopy(softs->product_name, buf, strlen(softs->product_name));
3834942c5e3cSpl196000 	return (buf + AAC_PRODUCT_LEN);
3835942c5e3cSpl196000 }
3836942c5e3cSpl196000 
3837942c5e3cSpl196000 /*
3838942c5e3cSpl196000  * Construct unit serial number from container uid
3839942c5e3cSpl196000  */
3840942c5e3cSpl196000 static uchar_t *
aac_lun_serialno(struct aac_softstate * softs,int tgt,uchar_t * buf)3841942c5e3cSpl196000 aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
3842942c5e3cSpl196000 {
3843942c5e3cSpl196000 	int i, d;
384458bc78c7SXin Chen 	uint32_t uid;
3845942c5e3cSpl196000 
384658bc78c7SXin Chen 	ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
384758bc78c7SXin Chen 
384858bc78c7SXin Chen 	uid = softs->containers[tgt].uid;
3849942c5e3cSpl196000 	for (i = 7; i >= 0; i--) {
3850942c5e3cSpl196000 		d = uid & 0xf;
3851942c5e3cSpl196000 		buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
3852942c5e3cSpl196000 		uid >>= 4;
3853942c5e3cSpl196000 	}
3854942c5e3cSpl196000 	return (buf + 8);
3855942c5e3cSpl196000 }
3856942c5e3cSpl196000 
3857942c5e3cSpl196000 /*
3858942c5e3cSpl196000  * SPC-3 7.5 INQUIRY command implementation
3859942c5e3cSpl196000  */
3860942c5e3cSpl196000 static void
aac_inquiry(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp)3861942c5e3cSpl196000 aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
3862942c5e3cSpl196000     union scsi_cdb *cdbp, struct buf *bp)
3863942c5e3cSpl196000 {
3864942c5e3cSpl196000 	int tgt = pkt->pkt_address.a_target;
3865942c5e3cSpl196000 	char *b_addr = NULL;
3866942c5e3cSpl196000 	uchar_t page = cdbp->cdb_opaque[2];
3867942c5e3cSpl196000 
3868942c5e3cSpl196000 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
3869942c5e3cSpl196000 		/* Command Support Data is not supported */
3870942c5e3cSpl196000 		aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
3871942c5e3cSpl196000 		return;
3872942c5e3cSpl196000 	}
3873942c5e3cSpl196000 
3874942c5e3cSpl196000 	if (bp && bp->b_un.b_addr && bp->b_bcount) {
3875942c5e3cSpl196000 		if (bp->b_flags & (B_PHYS | B_PAGEIO))
3876942c5e3cSpl196000 			bp_mapin(bp);
3877942c5e3cSpl196000 		b_addr = bp->b_un.b_addr;
3878942c5e3cSpl196000 	}
3879942c5e3cSpl196000 
3880942c5e3cSpl196000 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
3881942c5e3cSpl196000 		uchar_t *vpdp = (uchar_t *)b_addr;
3882942c5e3cSpl196000 		uchar_t *idp, *sp;
3883942c5e3cSpl196000 
3884942c5e3cSpl196000 		/* SPC-3 8.4 Vital product data parameters */
3885942c5e3cSpl196000 		switch (page) {
3886942c5e3cSpl196000 		case 0x00:
3887942c5e3cSpl196000 			/* Supported VPD pages */
388851ccf66eSjd218194 			if (vpdp == NULL ||
388951ccf66eSjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
3890942c5e3cSpl196000 				return;
3891942c5e3cSpl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3892942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x00;
3893942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = 3;
3894942c5e3cSpl196000 
3895942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_DATA] = 0x00;
3896942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
3897942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
3898942c5e3cSpl196000 
3899942c5e3cSpl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
3900942c5e3cSpl196000 			break;
3901942c5e3cSpl196000 
3902942c5e3cSpl196000 		case 0x80:
3903942c5e3cSpl196000 			/* Unit serial number page */
390451ccf66eSjd218194 			if (vpdp == NULL ||
390551ccf66eSjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
3906942c5e3cSpl196000 				return;
3907942c5e3cSpl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3908942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x80;
3909942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = 8;
3910942c5e3cSpl196000 
3911942c5e3cSpl196000 			sp = &vpdp[AAC_VPD_PAGE_DATA];
3912942c5e3cSpl196000 			(void) aac_lun_serialno(softs, tgt, sp);
3913942c5e3cSpl196000 
3914942c5e3cSpl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
3915942c5e3cSpl196000 			break;
3916942c5e3cSpl196000 
3917942c5e3cSpl196000 		case 0x83:
3918942c5e3cSpl196000 			/* Device identification page */
391951ccf66eSjd218194 			if (vpdp == NULL ||
392051ccf66eSjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
3921942c5e3cSpl196000 				return;
3922942c5e3cSpl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
3923942c5e3cSpl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x83;
3924942c5e3cSpl196000 
3925942c5e3cSpl196000 			idp = &vpdp[AAC_VPD_PAGE_DATA];
3926942c5e3cSpl196000 			bzero(idp, AAC_VPD_ID_LENGTH);
3927942c5e3cSpl196000 			idp[AAC_VPD_ID_CODESET] = 0x02;
3928942c5e3cSpl196000 			idp[AAC_VPD_ID_TYPE] = 0x01;
3929942c5e3cSpl196000 
3930942c5e3cSpl196000 			/*
3931942c5e3cSpl196000 			 * SPC-3 Table 111 - Identifier type
3932942c5e3cSpl196000 			 * One recommanded method of constructing the remainder
3933942c5e3cSpl196000 			 * of identifier field is to concatenate the product
3934942c5e3cSpl196000 			 * identification field from the standard INQUIRY data
3935942c5e3cSpl196000 			 * field and the product serial number field from the
3936942c5e3cSpl196000 			 * unit serial number page.
3937942c5e3cSpl196000 			 */
3938942c5e3cSpl196000 			sp = &idp[AAC_VPD_ID_DATA];
3939942c5e3cSpl196000 			sp = aac_vendor_id(softs, sp);
3940942c5e3cSpl196000 			sp = aac_product_id(softs, sp);
3941942c5e3cSpl196000 			sp = aac_lun_serialno(softs, tgt, sp);
3942a74f7440Spl196000 			idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
3943a74f7440Spl196000 			    (uintptr_t)&idp[AAC_VPD_ID_DATA];
3944942c5e3cSpl196000 
3945a74f7440Spl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
3946a74f7440Spl196000 			    (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
3947942c5e3cSpl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
3948942c5e3cSpl196000 			break;
3949942c5e3cSpl196000 
3950942c5e3cSpl196000 		default:
3951942c5e3cSpl196000 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3952942c5e3cSpl196000 			    0x24, 0x00, 0);
3953942c5e3cSpl196000 			break;
3954942c5e3cSpl196000 		}
3955942c5e3cSpl196000 	} else {
3956942c5e3cSpl196000 		struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
3957942c5e3cSpl196000 		size_t len = sizeof (struct scsi_inquiry);
3958942c5e3cSpl196000 
3959942c5e3cSpl196000 		if (page != 0) {
3960942c5e3cSpl196000 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
3961942c5e3cSpl196000 			    0x24, 0x00, 0);
3962942c5e3cSpl196000 			return;
3963942c5e3cSpl196000 		}
396451ccf66eSjd218194 		if (inqp == NULL || bp->b_bcount < len)
3965942c5e3cSpl196000 			return;
3966942c5e3cSpl196000 
3967942c5e3cSpl196000 		bzero(inqp, len);
3968942c5e3cSpl196000 		inqp->inq_len = AAC_ADDITIONAL_LEN;
3969942c5e3cSpl196000 		inqp->inq_ansi = AAC_ANSI_VER;
3970942c5e3cSpl196000 		inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
3971942c5e3cSpl196000 		(void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
3972942c5e3cSpl196000 		(void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
3973942c5e3cSpl196000 		bcopy("V1.0", inqp->inq_revision, 4);
3974942c5e3cSpl196000 		inqp->inq_cmdque = 1; /* enable tagged-queuing */
3975942c5e3cSpl196000 		/*
3976942c5e3cSpl196000 		 * For "sd-max-xfer-size" property which may impact performance
3977942c5e3cSpl196000 		 * when IO threads increase.
3978942c5e3cSpl196000 		 */
3979942c5e3cSpl196000 		inqp->inq_wbus32 = 1;
3980942c5e3cSpl196000 
3981942c5e3cSpl196000 		pkt->pkt_state |= STATE_XFERRED_DATA;
3982942c5e3cSpl196000 	}
3983942c5e3cSpl196000 }
3984942c5e3cSpl196000 
3985942c5e3cSpl196000 /*
3986942c5e3cSpl196000  * SPC-3 7.10 MODE SENSE command implementation
3987942c5e3cSpl196000  */
3988942c5e3cSpl196000 static void
aac_mode_sense(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp,int capacity)3989942c5e3cSpl196000 aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
3990942c5e3cSpl196000     union scsi_cdb *cdbp, struct buf *bp, int capacity)
3991942c5e3cSpl196000 {
3992942c5e3cSpl196000 	uchar_t pagecode;
3993942c5e3cSpl196000 	struct mode_header *headerp;
399451ccf66eSjd218194 	struct mode_header_g1 *g1_headerp;
3995942c5e3cSpl196000 	unsigned int ncyl;
399651ccf66eSjd218194 	caddr_t sense_data;
399751ccf66eSjd218194 	caddr_t next_page;
399851ccf66eSjd218194 	size_t sdata_size;
399951ccf66eSjd218194 	size_t pages_size;
400051ccf66eSjd218194 	int unsupport_page = 0;
400151ccf66eSjd218194 
400251ccf66eSjd218194 	ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
400351ccf66eSjd218194 	    cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
4004942c5e3cSpl196000 
4005942c5e3cSpl196000 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
4006942c5e3cSpl196000 		return;
4007942c5e3cSpl196000 
4008942c5e3cSpl196000 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
4009942c5e3cSpl196000 		bp_mapin(bp);
4010942c5e3cSpl196000 	pkt->pkt_state |= STATE_XFERRED_DATA;
401151ccf66eSjd218194 	pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
4012942c5e3cSpl196000 
401351ccf66eSjd218194 	/* calculate the size of needed buffer */
401451ccf66eSjd218194 	if (cdbp->scc_cmd == SCMD_MODE_SENSE)
401551ccf66eSjd218194 		sdata_size = MODE_HEADER_LENGTH;
401651ccf66eSjd218194 	else /* must be SCMD_MODE_SENSE_G1 */
401751ccf66eSjd218194 		sdata_size = MODE_HEADER_LENGTH_G1;
401851ccf66eSjd218194 
401951ccf66eSjd218194 	pages_size = 0;
4020942c5e3cSpl196000 	switch (pagecode) {
4021942c5e3cSpl196000 	case SD_MODE_SENSE_PAGE3_CODE:
402251ccf66eSjd218194 		pages_size += sizeof (struct mode_format);
402351ccf66eSjd218194 		break;
402451ccf66eSjd218194 
402551ccf66eSjd218194 	case SD_MODE_SENSE_PAGE4_CODE:
402651ccf66eSjd218194 		pages_size += sizeof (struct mode_geometry);
402751ccf66eSjd218194 		break;
402851ccf66eSjd218194 
402951ccf66eSjd218194 	case MODEPAGE_CTRL_MODE:
403051ccf66eSjd218194 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
403151ccf66eSjd218194 			pages_size += sizeof (struct mode_control_scsi3);
403251ccf66eSjd218194 		} else {
403351ccf66eSjd218194 			unsupport_page = 1;
403451ccf66eSjd218194 		}
403551ccf66eSjd218194 		break;
403651ccf66eSjd218194 
403751ccf66eSjd218194 	case MODEPAGE_ALLPAGES:
403851ccf66eSjd218194 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
403951ccf66eSjd218194 			pages_size += sizeof (struct mode_format) +
404051ccf66eSjd218194 			    sizeof (struct mode_geometry) +
404151ccf66eSjd218194 			    sizeof (struct mode_control_scsi3);
404251ccf66eSjd218194 		} else {
404351ccf66eSjd218194 			pages_size += sizeof (struct mode_format) +
404451ccf66eSjd218194 			    sizeof (struct mode_geometry);
404551ccf66eSjd218194 		}
404651ccf66eSjd218194 		break;
404751ccf66eSjd218194 
404851ccf66eSjd218194 	default:
404951ccf66eSjd218194 		/* unsupported pages */
405051ccf66eSjd218194 		unsupport_page = 1;
405151ccf66eSjd218194 	}
405251ccf66eSjd218194 
405351ccf66eSjd218194 	/* allocate buffer to fill the send data */
405451ccf66eSjd218194 	sdata_size += pages_size;
405551ccf66eSjd218194 	sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
405651ccf66eSjd218194 
405751ccf66eSjd218194 	if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
405851ccf66eSjd218194 		headerp = (struct mode_header *)sense_data;
405951ccf66eSjd218194 		headerp->length = MODE_HEADER_LENGTH + pages_size -
406051ccf66eSjd218194 		    sizeof (headerp->length);
406151ccf66eSjd218194 		headerp->bdesc_length = 0;
406251ccf66eSjd218194 		next_page = sense_data + sizeof (struct mode_header);
406351ccf66eSjd218194 	} else {
4064a74f7440Spl196000 		g1_headerp = (void *)sense_data;
4065b6094a86Sjd218194 		g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
4066b6094a86Sjd218194 		    sizeof (g1_headerp->length));
406751ccf66eSjd218194 		g1_headerp->bdesc_length = 0;
406851ccf66eSjd218194 		next_page = sense_data + sizeof (struct mode_header_g1);
406951ccf66eSjd218194 	}
407051ccf66eSjd218194 
407151ccf66eSjd218194 	if (unsupport_page)
407251ccf66eSjd218194 		goto finish;
407351ccf66eSjd218194 
407451ccf66eSjd218194 	if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
407551ccf66eSjd218194 	    pagecode == MODEPAGE_ALLPAGES) {
407651ccf66eSjd218194 		/* SBC-3 7.1.3.3 Format device page */
407751ccf66eSjd218194 		struct mode_format *page3p;
407851ccf66eSjd218194 
4079a74f7440Spl196000 		page3p = (void *)next_page;
4080942c5e3cSpl196000 		page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
4081942c5e3cSpl196000 		page3p->mode_page.length = sizeof (struct mode_format);
4082942c5e3cSpl196000 		page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
4083942c5e3cSpl196000 		page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
4084942c5e3cSpl196000 
408551ccf66eSjd218194 		next_page += sizeof (struct mode_format);
408651ccf66eSjd218194 	}
408751ccf66eSjd218194 
408851ccf66eSjd218194 	if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
408951ccf66eSjd218194 	    pagecode == MODEPAGE_ALLPAGES) {
4090942c5e3cSpl196000 		/* SBC-3 7.1.3.8 Rigid disk device geometry page */
409151ccf66eSjd218194 		struct mode_geometry *page4p;
409251ccf66eSjd218194 
4093a74f7440Spl196000 		page4p = (void *)next_page;
4094942c5e3cSpl196000 		page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
4095942c5e3cSpl196000 		page4p->mode_page.length = sizeof (struct mode_geometry);
4096942c5e3cSpl196000 		page4p->heads = AAC_NUMBER_OF_HEADS;
4097942c5e3cSpl196000 		page4p->rpm = BE_16(AAC_ROTATION_SPEED);
4098942c5e3cSpl196000 		ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
4099942c5e3cSpl196000 		page4p->cyl_lb = ncyl & 0xff;
4100942c5e3cSpl196000 		page4p->cyl_mb = (ncyl >> 8) & 0xff;
4101942c5e3cSpl196000 		page4p->cyl_ub = (ncyl >> 16) & 0xff;
4102942c5e3cSpl196000 
410351ccf66eSjd218194 		next_page += sizeof (struct mode_geometry);
410451ccf66eSjd218194 	}
410551ccf66eSjd218194 
410651ccf66eSjd218194 	if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
410751ccf66eSjd218194 	    softs->flags & AAC_FLAGS_LBA_64BIT) {
410851ccf66eSjd218194 		/* 64-bit LBA need large sense data */
4109942c5e3cSpl196000 		struct mode_control_scsi3 *mctl;
4110942c5e3cSpl196000 
4111a74f7440Spl196000 		mctl = (void *)next_page;
4112942c5e3cSpl196000 		mctl->mode_page.code = MODEPAGE_CTRL_MODE;
4113942c5e3cSpl196000 		mctl->mode_page.length =
4114942c5e3cSpl196000 		    sizeof (struct mode_control_scsi3) -
4115942c5e3cSpl196000 		    sizeof (struct mode_page);
4116942c5e3cSpl196000 		mctl->d_sense = 1;
4117942c5e3cSpl196000 	}
4118942c5e3cSpl196000 
411951ccf66eSjd218194 finish:
412051ccf66eSjd218194 	/* copyout the valid data. */
412151ccf66eSjd218194 	bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
412251ccf66eSjd218194 	kmem_free(sense_data, sdata_size);
4123942c5e3cSpl196000 }
4124942c5e3cSpl196000 
412558bc78c7SXin Chen static int
aac_name_node(dev_info_t * dip,char * name,int len)412658bc78c7SXin Chen aac_name_node(dev_info_t *dip, char *name, int len)
412758bc78c7SXin Chen {
412858bc78c7SXin Chen 	int tgt, lun;
412958bc78c7SXin Chen 
413058bc78c7SXin Chen 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
413158bc78c7SXin Chen 	    DDI_PROP_DONTPASS, "target", -1);
413258bc78c7SXin Chen 	if (tgt == -1)
413358bc78c7SXin Chen 		return (DDI_FAILURE);
413458bc78c7SXin Chen 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
413558bc78c7SXin Chen 	    DDI_PROP_DONTPASS, "lun", -1);
413658bc78c7SXin Chen 	if (lun == -1)
413758bc78c7SXin Chen 		return (DDI_FAILURE);
413858bc78c7SXin Chen 
413958bc78c7SXin Chen 	(void) snprintf(name, len, "%x,%x", tgt, lun);
414058bc78c7SXin Chen 	return (DDI_SUCCESS);
414158bc78c7SXin Chen }
414258bc78c7SXin Chen 
4143942c5e3cSpl196000 /*ARGSUSED*/
4144942c5e3cSpl196000 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)4145942c5e3cSpl196000 aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4146942c5e3cSpl196000     scsi_hba_tran_t *tran, struct scsi_device *sd)
4147942c5e3cSpl196000 {
4148942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
4149942c5e3cSpl196000 #if defined(DEBUG) || defined(__lock_lint)
4150942c5e3cSpl196000 	int ctl = ddi_get_instance(softs->devinfo_p);
4151942c5e3cSpl196000 #endif
415258bc78c7SXin Chen 	uint16_t tgt = sd->sd_address.a_target;
415358bc78c7SXin Chen 	uint8_t lun = sd->sd_address.a_lun;
415458bc78c7SXin Chen 	struct aac_device *dvp;
4155942c5e3cSpl196000 
4156942c5e3cSpl196000 	DBCALLED(softs, 2);
4157942c5e3cSpl196000 
415858bc78c7SXin Chen 	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
415958bc78c7SXin Chen 		/*
416058bc78c7SXin Chen 		 * If no persistent node exist, we don't allow .conf node
416158bc78c7SXin Chen 		 * to be created.
416258bc78c7SXin Chen 		 */
416358bc78c7SXin Chen 		if (aac_find_child(softs, tgt, lun) != NULL) {
416458bc78c7SXin Chen 			if (ndi_merge_node(tgt_dip, aac_name_node) !=
416558bc78c7SXin Chen 			    DDI_SUCCESS)
416658bc78c7SXin Chen 				/* Create this .conf node */
416758bc78c7SXin Chen 				return (DDI_SUCCESS);
416858bc78c7SXin Chen 		}
4169942c5e3cSpl196000 		return (DDI_FAILURE);
4170942c5e3cSpl196000 	}
4171942c5e3cSpl196000 
4172942c5e3cSpl196000 	/*
417358bc78c7SXin Chen 	 * Only support container/phys. device that has been
417458bc78c7SXin Chen 	 * detected and valid
4175942c5e3cSpl196000 	 */
4176942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
417758bc78c7SXin Chen 	if (tgt >= AAC_MAX_DEV(softs)) {
417858bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs,
417958bc78c7SXin Chen 		    "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
4180942c5e3cSpl196000 		mutex_exit(&softs->io_lock);
418158bc78c7SXin Chen 		return (DDI_FAILURE);
418258bc78c7SXin Chen 	}
418358bc78c7SXin Chen 
418458bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
418558bc78c7SXin Chen 		dvp = (struct aac_device *)&softs->containers[tgt];
418658bc78c7SXin Chen 		if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
418758bc78c7SXin Chen 			AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
4188942c5e3cSpl196000 			    ctl, tgt, lun);
4189942c5e3cSpl196000 			mutex_exit(&softs->io_lock);
4190942c5e3cSpl196000 			return (DDI_FAILURE);
4191942c5e3cSpl196000 		}
419258bc78c7SXin Chen 		/*
419358bc78c7SXin Chen 		 * Save the tgt_dip for the given target if one doesn't exist
419458bc78c7SXin Chen 		 * already. Dip's for non-existance tgt's will be cleared in
419558bc78c7SXin Chen 		 * tgt_free.
419658bc78c7SXin Chen 		 */
419758bc78c7SXin Chen 		if (softs->containers[tgt].dev.dip == NULL &&
419858bc78c7SXin Chen 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
419958bc78c7SXin Chen 			softs->containers[tgt].dev.dip = tgt_dip;
420058bc78c7SXin Chen 	} else {
420158bc78c7SXin Chen 		dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
42023fced439Szhongyan gu - Sun Microsystems - Beijing China 		/*
42033fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * Save the tgt_dip for the given target if one doesn't exist
42043fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * already. Dip's for non-existance tgt's will be cleared in
42053fced439Szhongyan gu - Sun Microsystems - Beijing China 		 * tgt_free.
42063fced439Szhongyan gu - Sun Microsystems - Beijing China 		 */
42073fced439Szhongyan gu - Sun Microsystems - Beijing China 
42083fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->nondasds[AAC_PD(tgt)].dev.dip  == NULL &&
42093fced439Szhongyan gu - Sun Microsystems - Beijing China 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
42103fced439Szhongyan gu - Sun Microsystems - Beijing China 			softs->nondasds[AAC_PD(tgt)].dev.dip  = tgt_dip;
421158bc78c7SXin Chen 	}
421258bc78c7SXin Chen 
421372888e72Speng liu - Sun Microsystems - Beijing China 	if (softs->flags & AAC_FLAGS_BRKUP) {
421472888e72Speng liu - Sun Microsystems - Beijing China 		if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
421572888e72Speng liu - Sun Microsystems - Beijing China 		    "buf_break", 1) != DDI_PROP_SUCCESS) {
421672888e72Speng liu - Sun Microsystems - Beijing China 			cmn_err(CE_CONT, "unable to create "
421772888e72Speng liu - Sun Microsystems - Beijing China 			    "property for t%dL%d (buf_break)", tgt, lun);
421872888e72Speng liu - Sun Microsystems - Beijing China 		}
421972888e72Speng liu - Sun Microsystems - Beijing China 	}
422072888e72Speng liu - Sun Microsystems - Beijing China 
422158bc78c7SXin Chen 	AACDB_PRINT(softs, CE_NOTE,
422258bc78c7SXin Chen 	    "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
422358bc78c7SXin Chen 	    (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
422458bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
422558bc78c7SXin Chen 	return (DDI_SUCCESS);
422658bc78c7SXin Chen }
422758bc78c7SXin Chen 
422858bc78c7SXin 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)422958bc78c7SXin Chen aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
423058bc78c7SXin Chen     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
423158bc78c7SXin Chen {
423258bc78c7SXin Chen #ifndef __lock_lint
423358bc78c7SXin Chen 	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
423458bc78c7SXin Chen #endif
423558bc78c7SXin Chen 
423658bc78c7SXin Chen 	struct aac_softstate *softs = SD2AAC(sd);
423758bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
423858bc78c7SXin Chen 
423958bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
424058bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
424158bc78c7SXin Chen 		if (softs->containers[tgt].dev.dip == tgt_dip)
424258bc78c7SXin Chen 			softs->containers[tgt].dev.dip = NULL;
424358bc78c7SXin Chen 	} else {
42443fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
42453fced439Szhongyan gu - Sun Microsystems - Beijing China 			softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
424658bc78c7SXin Chen 		softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
424758bc78c7SXin Chen 	}
424858bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
4249942c5e3cSpl196000 }
4250942c5e3cSpl196000 
4251942c5e3cSpl196000 /*
4252942c5e3cSpl196000  * Check if the firmware is Up And Running. If it is in the Kernel Panic
4253942c5e3cSpl196000  * state, (BlinkLED code + 1) is returned.
4254942c5e3cSpl196000  *    0 -- firmware up and running
4255942c5e3cSpl196000  *   -1 -- firmware dead
4256942c5e3cSpl196000  *   >0 -- firmware kernel panic
4257942c5e3cSpl196000  */
4258942c5e3cSpl196000 static int
aac_check_adapter_health(struct aac_softstate * softs)4259942c5e3cSpl196000 aac_check_adapter_health(struct aac_softstate *softs)
4260942c5e3cSpl196000 {
4261942c5e3cSpl196000 	int rval;
4262942c5e3cSpl196000 
4263942c5e3cSpl196000 	rval = PCI_MEM_GET32(softs, AAC_OMR0);
4264942c5e3cSpl196000 
4265942c5e3cSpl196000 	if (rval & AAC_KERNEL_UP_AND_RUNNING) {
4266942c5e3cSpl196000 		rval = 0;
4267942c5e3cSpl196000 	} else if (rval & AAC_KERNEL_PANIC) {
4268942c5e3cSpl196000 		cmn_err(CE_WARN, "firmware panic");
4269942c5e3cSpl196000 		rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
4270942c5e3cSpl196000 	} else {
4271942c5e3cSpl196000 		cmn_err(CE_WARN, "firmware dead");
4272942c5e3cSpl196000 		rval = -1;
4273942c5e3cSpl196000 	}
4274942c5e3cSpl196000 	return (rval);
4275942c5e3cSpl196000 }
4276942c5e3cSpl196000 
4277942c5e3cSpl196000 static void
aac_abort_iocmd(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason)4278942c5e3cSpl196000 aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
4279942c5e3cSpl196000     uchar_t reason)
4280942c5e3cSpl196000 {
4281942c5e3cSpl196000 	acp->flags |= AAC_CMD_ABORT;
4282942c5e3cSpl196000 
4283942c5e3cSpl196000 	if (acp->pkt) {
428458bc78c7SXin Chen 		if (acp->slotp) { /* outstanding cmd */
428558bc78c7SXin Chen 			acp->pkt->pkt_state |= STATE_GOT_STATUS;
428658bc78c7SXin Chen 		}
4287942c5e3cSpl196000 
4288942c5e3cSpl196000 		switch (reason) {
4289942c5e3cSpl196000 		case CMD_TIMEOUT:
429058bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
429158bc78c7SXin Chen 			    acp);
4292942c5e3cSpl196000 			aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
4293942c5e3cSpl196000 			    STAT_TIMEOUT | STAT_BUS_RESET);
4294942c5e3cSpl196000 			break;
4295942c5e3cSpl196000 		case CMD_RESET:
4296942c5e3cSpl196000 			/* aac support only RESET_ALL */
429758bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
4298942c5e3cSpl196000 			aac_set_pkt_reason(softs, acp, CMD_RESET,
4299942c5e3cSpl196000 			    STAT_BUS_RESET);
4300942c5e3cSpl196000 			break;
4301942c5e3cSpl196000 		case CMD_ABORTED:
430258bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
430358bc78c7SXin Chen 			    acp);
4304942c5e3cSpl196000 			aac_set_pkt_reason(softs, acp, CMD_ABORTED,
4305942c5e3cSpl196000 			    STAT_ABORTED);
4306942c5e3cSpl196000 			break;
4307942c5e3cSpl196000 		}
4308942c5e3cSpl196000 	}
4309942c5e3cSpl196000 	aac_end_io(softs, acp);
4310942c5e3cSpl196000 }
4311942c5e3cSpl196000 
4312942c5e3cSpl196000 /*
4313942c5e3cSpl196000  * Abort all the pending commands of type iocmd or just the command pkt
4314942c5e3cSpl196000  * corresponding to pkt
4315942c5e3cSpl196000  */
4316942c5e3cSpl196000 static void
aac_abort_iocmds(struct aac_softstate * softs,int iocmd,struct scsi_pkt * pkt,int reason)4317942c5e3cSpl196000 aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
4318942c5e3cSpl196000     int reason)
4319942c5e3cSpl196000 {
4320942c5e3cSpl196000 	struct aac_cmd *ac_arg, *acp;
4321942c5e3cSpl196000 	int i;
4322942c5e3cSpl196000 
4323942c5e3cSpl196000 	if (pkt == NULL) {
4324942c5e3cSpl196000 		ac_arg = NULL;
4325942c5e3cSpl196000 	} else {
4326942c5e3cSpl196000 		ac_arg = PKT2AC(pkt);
4327942c5e3cSpl196000 		iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
4328942c5e3cSpl196000 		    AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
4329942c5e3cSpl196000 	}
4330942c5e3cSpl196000 
4331942c5e3cSpl196000 	/*
4332942c5e3cSpl196000 	 * a) outstanding commands on the controller
4333942c5e3cSpl196000 	 * Note: should abort outstanding commands only after one
4334942c5e3cSpl196000 	 * IOP reset has been done.
4335942c5e3cSpl196000 	 */
4336942c5e3cSpl196000 	if (iocmd & AAC_IOCMD_OUTSTANDING) {
4337942c5e3cSpl196000 		struct aac_cmd *acp;
4338942c5e3cSpl196000 
4339942c5e3cSpl196000 		for (i = 0; i < AAC_MAX_LD; i++) {
434058bc78c7SXin Chen 			if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
4341942c5e3cSpl196000 				softs->containers[i].reset = 1;
4342942c5e3cSpl196000 		}
4343942c5e3cSpl196000 		while ((acp = softs->q_busy.q_head) != NULL)
4344942c5e3cSpl196000 			aac_abort_iocmd(softs, acp, reason);
4345942c5e3cSpl196000 	}
4346942c5e3cSpl196000 
4347942c5e3cSpl196000 	/* b) commands in the waiting queues */
4348942c5e3cSpl196000 	for (i = 0; i < AAC_CMDQ_NUM; i++) {
4349942c5e3cSpl196000 		if (iocmd & (1 << i)) {
4350942c5e3cSpl196000 			if (ac_arg) {
4351942c5e3cSpl196000 				aac_abort_iocmd(softs, ac_arg, reason);
4352942c5e3cSpl196000 			} else {
4353942c5e3cSpl196000 				while ((acp = softs->q_wait[i].q_head) != NULL)
4354942c5e3cSpl196000 					aac_abort_iocmd(softs, acp, reason);
4355942c5e3cSpl196000 			}
4356942c5e3cSpl196000 		}
4357942c5e3cSpl196000 	}
4358942c5e3cSpl196000 }
4359942c5e3cSpl196000 
4360942c5e3cSpl196000 /*
4361942c5e3cSpl196000  * The draining thread is shared among quiesce threads. It terminates
4362942c5e3cSpl196000  * when the adapter is quiesced or stopped by aac_stop_drain().
4363942c5e3cSpl196000  */
4364942c5e3cSpl196000 static void
aac_check_drain(void * arg)4365942c5e3cSpl196000 aac_check_drain(void *arg)
4366942c5e3cSpl196000 {
4367942c5e3cSpl196000 	struct aac_softstate *softs = arg;
4368942c5e3cSpl196000 
4369942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
4370942c5e3cSpl196000 	if (softs->ndrains) {
437158bc78c7SXin Chen 		softs->drain_timeid = 0;
4372942c5e3cSpl196000 		/*
4373942c5e3cSpl196000 		 * If both ASYNC and SYNC bus throttle are held,
4374942c5e3cSpl196000 		 * wake up threads only when both are drained out.
4375942c5e3cSpl196000 		 */
4376942c5e3cSpl196000 		if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
4377942c5e3cSpl196000 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
4378942c5e3cSpl196000 		    (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
4379942c5e3cSpl196000 		    softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
4380942c5e3cSpl196000 			cv_broadcast(&softs->drain_cv);
4381942c5e3cSpl196000 		else
4382942c5e3cSpl196000 			softs->drain_timeid = timeout(aac_check_drain, softs,
4383942c5e3cSpl196000 			    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4384942c5e3cSpl196000 	}
4385942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
4386942c5e3cSpl196000 }
4387942c5e3cSpl196000 
4388942c5e3cSpl196000 /*
4389942c5e3cSpl196000  * If not draining the outstanding cmds, drain them. Otherwise,
4390942c5e3cSpl196000  * only update ndrains.
4391942c5e3cSpl196000  */
4392942c5e3cSpl196000 static void
aac_start_drain(struct aac_softstate * softs)4393942c5e3cSpl196000 aac_start_drain(struct aac_softstate *softs)
4394942c5e3cSpl196000 {
4395942c5e3cSpl196000 	if (softs->ndrains == 0) {
439658bc78c7SXin Chen 		ASSERT(softs->drain_timeid == 0);
4397942c5e3cSpl196000 		softs->drain_timeid = timeout(aac_check_drain, softs,
4398942c5e3cSpl196000 		    AAC_QUIESCE_TICK * drv_usectohz(1000000));
4399942c5e3cSpl196000 	}
4400942c5e3cSpl196000 	softs->ndrains++;
4401942c5e3cSpl196000 }
4402942c5e3cSpl196000 
4403942c5e3cSpl196000 /*
4404942c5e3cSpl196000  * Stop the draining thread when no other threads use it any longer.
4405942c5e3cSpl196000  * Side effect: io_lock may be released in the middle.
4406942c5e3cSpl196000  */
4407942c5e3cSpl196000 static void
aac_stop_drain(struct aac_softstate * softs)4408942c5e3cSpl196000 aac_stop_drain(struct aac_softstate *softs)
4409942c5e3cSpl196000 {
4410942c5e3cSpl196000 	softs->ndrains--;
4411942c5e3cSpl196000 	if (softs->ndrains == 0) {
4412942c5e3cSpl196000 		if (softs->drain_timeid != 0) {
4413942c5e3cSpl196000 			timeout_id_t tid = softs->drain_timeid;
4414942c5e3cSpl196000 
4415942c5e3cSpl196000 			softs->drain_timeid = 0;
4416942c5e3cSpl196000 			mutex_exit(&softs->io_lock);
4417942c5e3cSpl196000 			(void) untimeout(tid);
4418942c5e3cSpl196000 			mutex_enter(&softs->io_lock);
4419942c5e3cSpl196000 		}
4420942c5e3cSpl196000 	}
4421942c5e3cSpl196000 }
4422942c5e3cSpl196000 
4423942c5e3cSpl196000 /*
4424942c5e3cSpl196000  * The following function comes from Adaptec:
4425942c5e3cSpl196000  *
4426942c5e3cSpl196000  * Once do an IOP reset, basically the driver have to re-initialize the card
4427942c5e3cSpl196000  * as if up from a cold boot, and the driver is responsible for any IO that
4428942c5e3cSpl196000  * is outstanding to the adapter at the time of the IOP RESET. And prepare
4429942c5e3cSpl196000  * for IOP RESET by making the init code modular with the ability to call it
4430942c5e3cSpl196000  * from multiple places.
4431942c5e3cSpl196000  */
4432942c5e3cSpl196000 static int
aac_reset_adapter(struct aac_softstate * softs)4433942c5e3cSpl196000 aac_reset_adapter(struct aac_softstate *softs)
4434942c5e3cSpl196000 {
4435942c5e3cSpl196000 	int health;
4436942c5e3cSpl196000 	uint32_t status;
443758bc78c7SXin Chen 	int rval = AAC_IOP_RESET_FAILED;
4438942c5e3cSpl196000 
4439942c5e3cSpl196000 	DBCALLED(softs, 1);
4440942c5e3cSpl196000 
4441942c5e3cSpl196000 	ASSERT(softs->state & AAC_STATE_RESET);
4442942c5e3cSpl196000 
4443942c5e3cSpl196000 	ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
4444942c5e3cSpl196000 	/* Disable interrupt */
4445942c5e3cSpl196000 	AAC_DISABLE_INTR(softs);
4446942c5e3cSpl196000 
4447942c5e3cSpl196000 	health = aac_check_adapter_health(softs);
4448942c5e3cSpl196000 	if (health == -1) {
4449942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
4450942c5e3cSpl196000 		goto finish;
4451942c5e3cSpl196000 	}
4452942c5e3cSpl196000 	if (health == 0) /* flush drives if possible */
4453942c5e3cSpl196000 		(void) aac_shutdown(softs);
4454942c5e3cSpl196000 
4455942c5e3cSpl196000 	/* Execute IOP reset */
4456942c5e3cSpl196000 	if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
4457942c5e3cSpl196000 	    &status)) != AACOK) {
4458f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		ddi_acc_handle_t acc;
4459942c5e3cSpl196000 		struct aac_fib *fibp;
4460942c5e3cSpl196000 		struct aac_pause_command *pc;
4461942c5e3cSpl196000 
4462942c5e3cSpl196000 		if ((status & 0xf) == 0xf) {
4463942c5e3cSpl196000 			uint32_t wait_count;
4464942c5e3cSpl196000 
4465942c5e3cSpl196000 			/*
4466942c5e3cSpl196000 			 * Sunrise Lake has dual cores and we must drag the
4467942c5e3cSpl196000 			 * other core with us to reset simultaneously. There
4468942c5e3cSpl196000 			 * are 2 bits in the Inbound Reset Control and Status
4469942c5e3cSpl196000 			 * Register (offset 0x38) of the Sunrise Lake to reset
4470942c5e3cSpl196000 			 * the chip without clearing out the PCI configuration
4471942c5e3cSpl196000 			 * info (COMMAND & BARS).
4472942c5e3cSpl196000 			 */
4473942c5e3cSpl196000 			PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
4474942c5e3cSpl196000 
4475942c5e3cSpl196000 			/*
4476942c5e3cSpl196000 			 * We need to wait for 5 seconds before accessing the MU
4477942c5e3cSpl196000 			 * again 10000 * 100us = 1000,000us = 1000ms = 1s
4478942c5e3cSpl196000 			 */
4479942c5e3cSpl196000 			wait_count = 5 * 10000;
4480942c5e3cSpl196000 			while (wait_count) {
4481942c5e3cSpl196000 				drv_usecwait(100); /* delay 100 microseconds */
4482942c5e3cSpl196000 				wait_count--;
4483942c5e3cSpl196000 			}
4484942c5e3cSpl196000 		} else {
4485942c5e3cSpl196000 			if (status == SRB_STATUS_INVALID_REQUEST)
4486942c5e3cSpl196000 				cmn_err(CE_WARN, "!IOP_RESET not supported");
4487942c5e3cSpl196000 			else /* probably timeout */
4488942c5e3cSpl196000 				cmn_err(CE_WARN, "!IOP_RESET failed");
4489942c5e3cSpl196000 
4490942c5e3cSpl196000 			/* Unwind aac_shutdown() */
4491f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
4492f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			acc = softs->sync_ac.slotp->fib_acc_handle;
4493f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
4494f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			fibp = softs->sync_ac.slotp->fibp;
4495942c5e3cSpl196000 			pc = (struct aac_pause_command *)&fibp->data[0];
4496942c5e3cSpl196000 
4497942c5e3cSpl196000 			bzero(pc, sizeof (*pc));
4498942c5e3cSpl196000 			ddi_put32(acc, &pc->Command, VM_ContainerConfig);
4499942c5e3cSpl196000 			ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
4500942c5e3cSpl196000 			ddi_put32(acc, &pc->Timeout, 1);
4501942c5e3cSpl196000 			ddi_put32(acc, &pc->Min, 1);
4502942c5e3cSpl196000 			ddi_put32(acc, &pc->NoRescan, 1);
4503942c5e3cSpl196000 
4504942c5e3cSpl196000 			(void) aac_sync_fib(softs, ContainerCommand,
4505942c5e3cSpl196000 			    AAC_FIB_SIZEOF(struct aac_pause_command));
4506f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			aac_sync_fib_slot_release(softs, &softs->sync_ac);
4507942c5e3cSpl196000 
450858bc78c7SXin Chen 			if (aac_check_adapter_health(softs) != 0)
4509942c5e3cSpl196000 				ddi_fm_service_impact(softs->devinfo_p,
4510942c5e3cSpl196000 				    DDI_SERVICE_LOST);
451158bc78c7SXin Chen 			else
451258bc78c7SXin Chen 				/*
451358bc78c7SXin Chen 				 * IOP reset not supported or IOP not reseted
451458bc78c7SXin Chen 				 */
451558bc78c7SXin Chen 				rval = AAC_IOP_RESET_ABNORMAL;
4516942c5e3cSpl196000 			goto finish;
4517942c5e3cSpl196000 		}
4518942c5e3cSpl196000 	}
4519942c5e3cSpl196000 
4520942c5e3cSpl196000 	/*
4521942c5e3cSpl196000 	 * Re-read and renegotiate the FIB parameters, as one of the actions
4522942c5e3cSpl196000 	 * that can result from an IOP reset is the running of a new firmware
4523942c5e3cSpl196000 	 * image.
4524942c5e3cSpl196000 	 */
4525942c5e3cSpl196000 	if (aac_common_attach(softs) != AACOK)
4526942c5e3cSpl196000 		goto finish;
4527942c5e3cSpl196000 
452858bc78c7SXin Chen 	rval = AAC_IOP_RESET_SUCCEED;
4529942c5e3cSpl196000 
4530942c5e3cSpl196000 finish:
4531942c5e3cSpl196000 	AAC_ENABLE_INTR(softs);
4532942c5e3cSpl196000 	return (rval);
4533942c5e3cSpl196000 }
4534942c5e3cSpl196000 
4535942c5e3cSpl196000 static void
aac_set_throttle(struct aac_softstate * softs,struct aac_device * dvp,int q,int throttle)453658bc78c7SXin Chen aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
4537942c5e3cSpl196000     int throttle)
4538942c5e3cSpl196000 {
4539942c5e3cSpl196000 	/*
4540942c5e3cSpl196000 	 * If the bus is draining/quiesced, no changes to the throttles
4541942c5e3cSpl196000 	 * are allowed. All throttles should have been set to 0.
4542942c5e3cSpl196000 	 */
4543942c5e3cSpl196000 	if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
4544942c5e3cSpl196000 		return;
4545942c5e3cSpl196000 	dvp->throttle[q] = throttle;
4546942c5e3cSpl196000 }
4547942c5e3cSpl196000 
4548942c5e3cSpl196000 static void
aac_hold_bus(struct aac_softstate * softs,int iocmds)4549942c5e3cSpl196000 aac_hold_bus(struct aac_softstate *softs, int iocmds)
4550942c5e3cSpl196000 {
4551942c5e3cSpl196000 	int i, q;
4552942c5e3cSpl196000 
4553942c5e3cSpl196000 	/* Hold bus by holding every device on the bus */
4554942c5e3cSpl196000 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4555942c5e3cSpl196000 		if (iocmds & (1 << q)) {
4556942c5e3cSpl196000 			softs->bus_throttle[q] = 0;
4557942c5e3cSpl196000 			for (i = 0; i < AAC_MAX_LD; i++)
455858bc78c7SXin Chen 				aac_set_throttle(softs,
455958bc78c7SXin Chen 				    &softs->containers[i].dev, q, 0);
456058bc78c7SXin Chen 			for (i = 0; i < AAC_MAX_PD(softs); i++)
456158bc78c7SXin Chen 				aac_set_throttle(softs,
456258bc78c7SXin Chen 				    &softs->nondasds[i].dev, q, 0);
4563942c5e3cSpl196000 		}
4564942c5e3cSpl196000 	}
4565942c5e3cSpl196000 }
4566942c5e3cSpl196000 
4567942c5e3cSpl196000 static void
aac_unhold_bus(struct aac_softstate * softs,int iocmds)4568942c5e3cSpl196000 aac_unhold_bus(struct aac_softstate *softs, int iocmds)
4569942c5e3cSpl196000 {
4570f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int i, q, max_throttle;
4571942c5e3cSpl196000 
4572942c5e3cSpl196000 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
4573942c5e3cSpl196000 		if (iocmds & (1 << q)) {
4574942c5e3cSpl196000 			/*
4575942c5e3cSpl196000 			 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
4576942c5e3cSpl196000 			 * quiesced or being drained by possibly some quiesce
4577942c5e3cSpl196000 			 * threads.
4578942c5e3cSpl196000 			 */
4579942c5e3cSpl196000 			if (q == AAC_CMDQ_ASYNC && ((softs->state &
4580942c5e3cSpl196000 			    AAC_STATE_QUIESCED) || softs->ndrains))
4581942c5e3cSpl196000 				continue;
4582f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			if (q == AAC_CMDQ_ASYNC)
4583f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				max_throttle = softs->total_slots -
4584f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    AAC_MGT_SLOT_NUM;
4585f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			else
4586f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				max_throttle = softs->total_slots - 1;
4587f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 			softs->bus_throttle[q] = max_throttle;
4588942c5e3cSpl196000 			for (i = 0; i < AAC_MAX_LD; i++)
458958bc78c7SXin Chen 				aac_set_throttle(softs,
459058bc78c7SXin Chen 				    &softs->containers[i].dev,
4591f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    q, max_throttle);
459258bc78c7SXin Chen 			for (i = 0; i < AAC_MAX_PD(softs); i++)
459358bc78c7SXin Chen 				aac_set_throttle(softs, &softs->nondasds[i].dev,
4594f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 				    q, max_throttle);
4595942c5e3cSpl196000 		}
4596942c5e3cSpl196000 	}
4597942c5e3cSpl196000 }
4598942c5e3cSpl196000 
4599942c5e3cSpl196000 static int
aac_do_reset(struct aac_softstate * softs)4600942c5e3cSpl196000 aac_do_reset(struct aac_softstate *softs)
4601942c5e3cSpl196000 {
4602942c5e3cSpl196000 	int health;
4603942c5e3cSpl196000 	int rval;
4604942c5e3cSpl196000 
4605942c5e3cSpl196000 	softs->state |= AAC_STATE_RESET;
4606942c5e3cSpl196000 	health = aac_check_adapter_health(softs);
4607942c5e3cSpl196000 
4608942c5e3cSpl196000 	/*
4609942c5e3cSpl196000 	 * Hold off new io commands and wait all outstanding io
4610942c5e3cSpl196000 	 * commands to complete.
4611942c5e3cSpl196000 	 */
461258bc78c7SXin Chen 	if (health == 0) {
461358bc78c7SXin Chen 		int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
461458bc78c7SXin Chen 		int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
461558bc78c7SXin Chen 
461658bc78c7SXin Chen 		if (sync_cmds == 0 && async_cmds == 0) {
461758bc78c7SXin Chen 			rval = AAC_IOP_RESET_SUCCEED;
461858bc78c7SXin Chen 			goto finish;
461958bc78c7SXin Chen 		}
4620942c5e3cSpl196000 		/*
4621942c5e3cSpl196000 		 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
4622942c5e3cSpl196000 		 * to complete the outstanding io commands
4623942c5e3cSpl196000 		 */
4624942c5e3cSpl196000 		int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
4625942c5e3cSpl196000 		int (*intr_handler)(struct aac_softstate *);
4626942c5e3cSpl196000 
4627942c5e3cSpl196000 		aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
4628942c5e3cSpl196000 		/*
4629942c5e3cSpl196000 		 * Poll the adapter by ourselves in case interrupt is disabled
4630942c5e3cSpl196000 		 * and to avoid releasing the io_lock.
4631942c5e3cSpl196000 		 */
4632942c5e3cSpl196000 		intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
4633942c5e3cSpl196000 		    aac_process_intr_new : aac_process_intr_old;
4634942c5e3cSpl196000 		while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
4635942c5e3cSpl196000 		    softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
4636942c5e3cSpl196000 			drv_usecwait(100);
4637942c5e3cSpl196000 			(void) intr_handler(softs);
4638942c5e3cSpl196000 			timeout--;
4639942c5e3cSpl196000 		}
4640942c5e3cSpl196000 		aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
464158bc78c7SXin Chen 
464258bc78c7SXin Chen 		if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
464358bc78c7SXin Chen 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
464458bc78c7SXin Chen 			/* Cmds drained out */
464558bc78c7SXin Chen 			rval = AAC_IOP_RESET_SUCCEED;
464658bc78c7SXin Chen 			goto finish;
464758bc78c7SXin Chen 		} else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
464858bc78c7SXin Chen 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
464958bc78c7SXin Chen 			/* Cmds not drained out, adapter overloaded */
465058bc78c7SXin Chen 			rval = AAC_IOP_RESET_ABNORMAL;
465158bc78c7SXin Chen 			goto finish;
465258bc78c7SXin Chen 		}
4653942c5e3cSpl196000 	}
4654942c5e3cSpl196000 
4655942c5e3cSpl196000 	/*
465658bc78c7SXin Chen 	 * If a longer waiting time still can't drain any outstanding io
4657942c5e3cSpl196000 	 * commands, do IOP reset.
4658942c5e3cSpl196000 	 */
465958bc78c7SXin Chen 	if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
4660942c5e3cSpl196000 		softs->state |= AAC_STATE_DEAD;
4661942c5e3cSpl196000 
466258bc78c7SXin Chen finish:
4663942c5e3cSpl196000 	softs->state &= ~AAC_STATE_RESET;
4664942c5e3cSpl196000 	return (rval);
4665942c5e3cSpl196000 }
4666942c5e3cSpl196000 
4667942c5e3cSpl196000 static int
aac_tran_reset(struct scsi_address * ap,int level)4668942c5e3cSpl196000 aac_tran_reset(struct scsi_address *ap, int level)
4669942c5e3cSpl196000 {
4670942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4671942c5e3cSpl196000 	int rval;
4672942c5e3cSpl196000 
4673942c5e3cSpl196000 	DBCALLED(softs, 1);
4674942c5e3cSpl196000 
4675942c5e3cSpl196000 	if (level != RESET_ALL) {
4676942c5e3cSpl196000 		cmn_err(CE_NOTE, "!reset target/lun not supported");
4677942c5e3cSpl196000 		return (0);
4678942c5e3cSpl196000 	}
4679942c5e3cSpl196000 
4680942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
468158bc78c7SXin Chen 	switch (rval = aac_do_reset(softs)) {
468258bc78c7SXin Chen 	case AAC_IOP_RESET_SUCCEED:
4683942c5e3cSpl196000 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
4684942c5e3cSpl196000 		    NULL, CMD_RESET);
4685942c5e3cSpl196000 		aac_start_waiting_io(softs);
468658bc78c7SXin Chen 		break;
468758bc78c7SXin Chen 	case AAC_IOP_RESET_FAILED:
468858bc78c7SXin Chen 		/* Abort IOCTL cmds when adapter is dead */
4689942c5e3cSpl196000 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
469058bc78c7SXin Chen 		break;
469158bc78c7SXin Chen 	case AAC_IOP_RESET_ABNORMAL:
469258bc78c7SXin Chen 		aac_start_waiting_io(softs);
4693942c5e3cSpl196000 	}
4694942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
4695942c5e3cSpl196000 
4696942c5e3cSpl196000 	aac_drain_comp_q(softs);
469758bc78c7SXin Chen 	return (rval == 0);
4698942c5e3cSpl196000 }
4699942c5e3cSpl196000 
4700942c5e3cSpl196000 static int
aac_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)4701942c5e3cSpl196000 aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
4702942c5e3cSpl196000 {
4703942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4704942c5e3cSpl196000 
4705942c5e3cSpl196000 	DBCALLED(softs, 1);
4706942c5e3cSpl196000 
4707942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
4708942c5e3cSpl196000 	aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
4709942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
4710942c5e3cSpl196000 
4711942c5e3cSpl196000 	aac_drain_comp_q(softs);
4712942c5e3cSpl196000 	return (1);
4713942c5e3cSpl196000 }
4714942c5e3cSpl196000 
4715942c5e3cSpl196000 void
aac_free_dmamap(struct aac_cmd * acp)4716942c5e3cSpl196000 aac_free_dmamap(struct aac_cmd *acp)
4717942c5e3cSpl196000 {
4718942c5e3cSpl196000 	/* Free dma mapping */
4719942c5e3cSpl196000 	if (acp->flags & AAC_CMD_DMA_VALID) {
4720942c5e3cSpl196000 		ASSERT(acp->buf_dma_handle);
4721942c5e3cSpl196000 		(void) ddi_dma_unbind_handle(acp->buf_dma_handle);
4722942c5e3cSpl196000 		acp->flags &= ~AAC_CMD_DMA_VALID;
4723942c5e3cSpl196000 	}
4724942c5e3cSpl196000 
4725942c5e3cSpl196000 	if (acp->abp != NULL) { /* free non-aligned buf DMA */
4726942c5e3cSpl196000 		ASSERT(acp->buf_dma_handle);
4727942c5e3cSpl196000 		if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
4728942c5e3cSpl196000 			ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
4729942c5e3cSpl196000 			    (uint8_t *)acp->abp, acp->bp->b_bcount,
4730942c5e3cSpl196000 			    DDI_DEV_AUTOINCR);
4731942c5e3cSpl196000 		ddi_dma_mem_free(&acp->abh);
4732942c5e3cSpl196000 		acp->abp = NULL;
4733942c5e3cSpl196000 	}
4734942c5e3cSpl196000 
4735942c5e3cSpl196000 	if (acp->buf_dma_handle) {
4736942c5e3cSpl196000 		ddi_dma_free_handle(&acp->buf_dma_handle);
4737942c5e3cSpl196000 		acp->buf_dma_handle = NULL;
4738942c5e3cSpl196000 	}
4739942c5e3cSpl196000 }
4740942c5e3cSpl196000 
4741942c5e3cSpl196000 static void
aac_unknown_scmd(struct aac_softstate * softs,struct aac_cmd * acp)4742942c5e3cSpl196000 aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
4743942c5e3cSpl196000 {
4744942c5e3cSpl196000 	AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
4745a74f7440Spl196000 	    ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
4746942c5e3cSpl196000 	aac_free_dmamap(acp);
4747942c5e3cSpl196000 	aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
4748942c5e3cSpl196000 	aac_soft_callback(softs, acp);
4749942c5e3cSpl196000 }
4750942c5e3cSpl196000 
4751942c5e3cSpl196000 /*
4752942c5e3cSpl196000  * Handle command to logical device
4753942c5e3cSpl196000  */
4754942c5e3cSpl196000 static int
aac_tran_start_ld(struct aac_softstate * softs,struct aac_cmd * acp)4755942c5e3cSpl196000 aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
4756942c5e3cSpl196000 {
4757942c5e3cSpl196000 	struct aac_container *dvp;
4758942c5e3cSpl196000 	struct scsi_pkt *pkt;
4759942c5e3cSpl196000 	union scsi_cdb *cdbp;
4760942c5e3cSpl196000 	struct buf *bp;
4761942c5e3cSpl196000 	int rval;
4762942c5e3cSpl196000 
476358bc78c7SXin Chen 	dvp = (struct aac_container *)acp->dvp;
4764942c5e3cSpl196000 	pkt = acp->pkt;
4765a74f7440Spl196000 	cdbp = (void *)pkt->pkt_cdbp;
4766942c5e3cSpl196000 	bp = acp->bp;
4767942c5e3cSpl196000 
4768942c5e3cSpl196000 	switch (cdbp->scc_cmd) {
4769942c5e3cSpl196000 	case SCMD_INQUIRY: /* inquiry */
4770942c5e3cSpl196000 		aac_free_dmamap(acp);
4771942c5e3cSpl196000 		aac_inquiry(softs, pkt, cdbp, bp);
4772942c5e3cSpl196000 		aac_soft_callback(softs, acp);
4773942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4774942c5e3cSpl196000 		break;
4775942c5e3cSpl196000 
4776942c5e3cSpl196000 	case SCMD_READ_CAPACITY: /* read capacity */
4777942c5e3cSpl196000 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4778942c5e3cSpl196000 			struct scsi_capacity cap;
4779942c5e3cSpl196000 			uint64_t last_lba;
4780942c5e3cSpl196000 
4781942c5e3cSpl196000 			/* check 64-bit LBA */
4782942c5e3cSpl196000 			last_lba = dvp->size - 1;
4783942c5e3cSpl196000 			if (last_lba > 0xffffffffull) {
4784942c5e3cSpl196000 				cap.capacity = 0xfffffffful;
4785942c5e3cSpl196000 			} else {
4786942c5e3cSpl196000 				cap.capacity = BE_32(last_lba);
4787942c5e3cSpl196000 			}
4788942c5e3cSpl196000 			cap.lbasize = BE_32(AAC_SECTOR_SIZE);
4789942c5e3cSpl196000 
4790942c5e3cSpl196000 			aac_free_dmamap(acp);
4791942c5e3cSpl196000 			if (bp->b_flags & (B_PHYS|B_PAGEIO))
4792942c5e3cSpl196000 				bp_mapin(bp);
479351ccf66eSjd218194 			bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
4794942c5e3cSpl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
4795942c5e3cSpl196000 		}
4796942c5e3cSpl196000 		aac_soft_callback(softs, acp);
4797942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4798942c5e3cSpl196000 		break;
4799942c5e3cSpl196000 
4800942c5e3cSpl196000 	case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
4801942c5e3cSpl196000 		/* Check if containers need 64-bit LBA support */
4802942c5e3cSpl196000 		if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
4803942c5e3cSpl196000 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
4804942c5e3cSpl196000 				struct scsi_capacity_16 cap16;
4805942c5e3cSpl196000 				int cap_len = sizeof (struct scsi_capacity_16);
4806942c5e3cSpl196000 
4807942c5e3cSpl196000 				bzero(&cap16, cap_len);
4808b6094a86Sjd218194 				cap16.sc_capacity = BE_64(dvp->size - 1);
4809942c5e3cSpl196000 				cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
4810942c5e3cSpl196000 
4811942c5e3cSpl196000 				aac_free_dmamap(acp);
4812942c5e3cSpl196000 				if (bp->b_flags & (B_PHYS | B_PAGEIO))
4813942c5e3cSpl196000 					bp_mapin(bp);
481451ccf66eSjd218194 				bcopy(&cap16, bp->b_un.b_addr,
481551ccf66eSjd218194 				    min(bp->b_bcount, cap_len));
4816942c5e3cSpl196000 				pkt->pkt_state |= STATE_XFERRED_DATA;
4817942c5e3cSpl196000 			}
4818942c5e3cSpl196000 			aac_soft_callback(softs, acp);
4819942c5e3cSpl196000 		} else {
4820942c5e3cSpl196000 			aac_unknown_scmd(softs, acp);
4821942c5e3cSpl196000 		}
4822942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4823942c5e3cSpl196000 		break;
4824942c5e3cSpl196000 
4825942c5e3cSpl196000 	case SCMD_READ_G4: /* read_16 */
4826942c5e3cSpl196000 	case SCMD_WRITE_G4: /* write_16 */
4827942c5e3cSpl196000 		if (softs->flags & AAC_FLAGS_RAW_IO) {
4828942c5e3cSpl196000 			/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
4829942c5e3cSpl196000 			acp->blkno = ((uint64_t) \
4830942c5e3cSpl196000 			    GETG4ADDR(cdbp) << 32) | \
4831942c5e3cSpl196000 			    (uint32_t)GETG4ADDRTL(cdbp);
4832942c5e3cSpl196000 			goto do_io;
4833942c5e3cSpl196000 		}
4834942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
4835942c5e3cSpl196000 		aac_unknown_scmd(softs, acp);
4836942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4837942c5e3cSpl196000 		break;
4838942c5e3cSpl196000 
4839942c5e3cSpl196000 	case SCMD_READ: /* read_6 */
4840942c5e3cSpl196000 	case SCMD_WRITE: /* write_6 */
4841942c5e3cSpl196000 		acp->blkno = GETG0ADDR(cdbp);
4842942c5e3cSpl196000 		goto do_io;
4843942c5e3cSpl196000 
484458bc78c7SXin Chen 	case SCMD_READ_G5: /* read_12 */
484558bc78c7SXin Chen 	case SCMD_WRITE_G5: /* write_12 */
484658bc78c7SXin Chen 		acp->blkno = GETG5ADDR(cdbp);
484758bc78c7SXin Chen 		goto do_io;
484858bc78c7SXin Chen 
4849942c5e3cSpl196000 	case SCMD_READ_G1: /* read_10 */
4850942c5e3cSpl196000 	case SCMD_WRITE_G1: /* write_10 */
4851942c5e3cSpl196000 		acp->blkno = (uint32_t)GETG1ADDR(cdbp);
4852942c5e3cSpl196000 do_io:
4853942c5e3cSpl196000 		if (acp->flags & AAC_CMD_DMA_VALID) {
4854942c5e3cSpl196000 			uint64_t cnt_size = dvp->size;
4855942c5e3cSpl196000 
4856942c5e3cSpl196000 			/*
4857942c5e3cSpl196000 			 * If LBA > array size AND rawio, the
4858942c5e3cSpl196000 			 * adapter may hang. So check it before
4859942c5e3cSpl196000 			 * sending.
4860942c5e3cSpl196000 			 * NOTE: (blkno + blkcnt) may overflow
4861942c5e3cSpl196000 			 */
4862942c5e3cSpl196000 			if ((acp->blkno < cnt_size) &&
4863942c5e3cSpl196000 			    ((acp->blkno + acp->bcount /
4864942c5e3cSpl196000 			    AAC_BLK_SIZE) <= cnt_size)) {
4865942c5e3cSpl196000 				rval = aac_do_io(softs, acp);
4866942c5e3cSpl196000 			} else {
4867942c5e3cSpl196000 			/*
4868942c5e3cSpl196000 			 * Request exceeds the capacity of disk,
4869942c5e3cSpl196000 			 * set error block number to last LBA
4870942c5e3cSpl196000 			 * + 1.
4871942c5e3cSpl196000 			 */
4872942c5e3cSpl196000 				aac_set_arq_data(pkt,
4873942c5e3cSpl196000 				    KEY_ILLEGAL_REQUEST, 0x21,
4874942c5e3cSpl196000 				    0x00, cnt_size);
4875942c5e3cSpl196000 				aac_soft_callback(softs, acp);
4876942c5e3cSpl196000 				rval = TRAN_ACCEPT;
4877942c5e3cSpl196000 			}
4878942c5e3cSpl196000 		} else if (acp->bcount == 0) {
4879942c5e3cSpl196000 			/* For 0 length IO, just return ok */
4880942c5e3cSpl196000 			aac_soft_callback(softs, acp);
4881942c5e3cSpl196000 			rval = TRAN_ACCEPT;
4882942c5e3cSpl196000 		} else {
4883942c5e3cSpl196000 			rval = TRAN_BADPKT;
4884942c5e3cSpl196000 		}
4885942c5e3cSpl196000 		break;
4886942c5e3cSpl196000 
4887942c5e3cSpl196000 	case SCMD_MODE_SENSE: /* mode_sense_6 */
4888942c5e3cSpl196000 	case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
4889942c5e3cSpl196000 		int capacity;
4890942c5e3cSpl196000 
4891942c5e3cSpl196000 		aac_free_dmamap(acp);
4892942c5e3cSpl196000 		if (dvp->size > 0xffffffffull)
4893942c5e3cSpl196000 			capacity = 0xfffffffful; /* 64-bit LBA */
4894942c5e3cSpl196000 		else
4895942c5e3cSpl196000 			capacity = dvp->size;
4896942c5e3cSpl196000 		aac_mode_sense(softs, pkt, cdbp, bp, capacity);
4897942c5e3cSpl196000 		aac_soft_callback(softs, acp);
4898942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4899942c5e3cSpl196000 		break;
4900942c5e3cSpl196000 	}
4901942c5e3cSpl196000 
4902b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	case SCMD_START_STOP:
4903b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
4904b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			acp->aac_cmd_fib = aac_cmd_fib_startstop;
4905b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			acp->ac_comp = aac_startstop_complete;
4906b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			rval = aac_do_io(softs, acp);
4907b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 			break;
4908b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 		}
4909b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	/* FALLTHRU */
4910942c5e3cSpl196000 	case SCMD_TEST_UNIT_READY:
4911942c5e3cSpl196000 	case SCMD_REQUEST_SENSE:
4912942c5e3cSpl196000 	case SCMD_FORMAT:
4913942c5e3cSpl196000 		aac_free_dmamap(acp);
4914942c5e3cSpl196000 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
4915942c5e3cSpl196000 			if (acp->flags & AAC_CMD_BUF_READ) {
4916942c5e3cSpl196000 				if (bp->b_flags & (B_PHYS|B_PAGEIO))
4917942c5e3cSpl196000 					bp_mapin(bp);
4918942c5e3cSpl196000 				bzero(bp->b_un.b_addr, bp->b_bcount);
4919942c5e3cSpl196000 			}
4920942c5e3cSpl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
4921942c5e3cSpl196000 		}
4922942c5e3cSpl196000 		aac_soft_callback(softs, acp);
4923942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4924942c5e3cSpl196000 		break;
4925942c5e3cSpl196000 
4926942c5e3cSpl196000 	case SCMD_SYNCHRONIZE_CACHE:
4927942c5e3cSpl196000 		acp->flags |= AAC_CMD_NTAG;
4928942c5e3cSpl196000 		acp->aac_cmd_fib = aac_cmd_fib_sync;
4929942c5e3cSpl196000 		acp->ac_comp = aac_synccache_complete;
4930942c5e3cSpl196000 		rval = aac_do_io(softs, acp);
4931942c5e3cSpl196000 		break;
4932942c5e3cSpl196000 
4933942c5e3cSpl196000 	case SCMD_DOORLOCK:
4934942c5e3cSpl196000 		aac_free_dmamap(acp);
4935942c5e3cSpl196000 		dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
4936942c5e3cSpl196000 		aac_soft_callback(softs, acp);
4937942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4938942c5e3cSpl196000 		break;
4939942c5e3cSpl196000 
4940942c5e3cSpl196000 	default: /* unknown command */
4941942c5e3cSpl196000 		aac_unknown_scmd(softs, acp);
4942942c5e3cSpl196000 		rval = TRAN_ACCEPT;
4943942c5e3cSpl196000 		break;
4944942c5e3cSpl196000 	}
4945942c5e3cSpl196000 
4946942c5e3cSpl196000 	return (rval);
4947942c5e3cSpl196000 }
4948942c5e3cSpl196000 
4949942c5e3cSpl196000 static int
aac_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)4950942c5e3cSpl196000 aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
4951942c5e3cSpl196000 {
4952942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
4953942c5e3cSpl196000 	struct aac_cmd *acp = PKT2AC(pkt);
495458bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
4955942c5e3cSpl196000 	int rval;
4956942c5e3cSpl196000 
4957942c5e3cSpl196000 	DBCALLED(softs, 2);
4958942c5e3cSpl196000 
4959942c5e3cSpl196000 	/*
4960942c5e3cSpl196000 	 * Reinitialize some fields of ac and pkt; the packet may
4961942c5e3cSpl196000 	 * have been resubmitted
4962942c5e3cSpl196000 	 */
4963942c5e3cSpl196000 	acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
4964942c5e3cSpl196000 	    AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
4965942c5e3cSpl196000 	acp->timeout = acp->pkt->pkt_time;
4966942c5e3cSpl196000 	if (pkt->pkt_flags & FLAG_NOINTR)
4967942c5e3cSpl196000 		acp->flags |= AAC_CMD_NO_INTR;
496858bc78c7SXin Chen #ifdef DEBUG
496958bc78c7SXin Chen 	acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
497058bc78c7SXin Chen #endif
4971942c5e3cSpl196000 	pkt->pkt_reason = CMD_CMPLT;
4972942c5e3cSpl196000 	pkt->pkt_state = 0;
4973942c5e3cSpl196000 	pkt->pkt_statistics = 0;
497458bc78c7SXin Chen 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
4975942c5e3cSpl196000 
4976942c5e3cSpl196000 	if (acp->flags & AAC_CMD_DMA_VALID) {
4977942c5e3cSpl196000 		pkt->pkt_resid = acp->bcount;
4978942c5e3cSpl196000 		/* Consistent packets need to be sync'ed first */
4979942c5e3cSpl196000 		if ((acp->flags & AAC_CMD_CONSISTENT) &&
4980942c5e3cSpl196000 		    (acp->flags & AAC_CMD_BUF_WRITE))
4981942c5e3cSpl196000 			if (aac_dma_sync_ac(acp) != AACOK) {
4982942c5e3cSpl196000 				ddi_fm_service_impact(softs->devinfo_p,
4983942c5e3cSpl196000 				    DDI_SERVICE_UNAFFECTED);
4984942c5e3cSpl196000 				return (TRAN_BADPKT);
4985942c5e3cSpl196000 			}
4986942c5e3cSpl196000 	} else {
4987942c5e3cSpl196000 		pkt->pkt_resid = 0;
4988942c5e3cSpl196000 	}
4989942c5e3cSpl196000 
4990942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
4991942c5e3cSpl196000 	AACDB_PRINT_SCMD(softs, acp);
499258bc78c7SXin Chen 	if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
499358bc78c7SXin Chen 	    !(softs->state & AAC_STATE_DEAD)) {
499458bc78c7SXin Chen 		if (dvp->type == AAC_DEV_LD) {
499558bc78c7SXin Chen 			if (ap->a_lun == 0)
4996942c5e3cSpl196000 				rval = aac_tran_start_ld(softs, acp);
499758bc78c7SXin Chen 			else
499858bc78c7SXin Chen 				goto error;
499958bc78c7SXin Chen 		} else {
500058bc78c7SXin Chen 			rval = aac_do_io(softs, acp);
500158bc78c7SXin Chen 		}
500258bc78c7SXin Chen 	} else {
500358bc78c7SXin Chen error:
500458bc78c7SXin Chen #ifdef DEBUG
500558bc78c7SXin Chen 		if (!(softs->state & AAC_STATE_DEAD)) {
500658bc78c7SXin Chen 			AACDB_PRINT_TRAN(softs,
500758bc78c7SXin Chen 			    "Cannot send cmd to target t%dL%d: %s",
500858bc78c7SXin Chen 			    ap->a_target, ap->a_lun,
500958bc78c7SXin Chen 			    "target invalid");
5010942c5e3cSpl196000 		} else {
5011942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5012942c5e3cSpl196000 			    "Cannot send cmd to target t%dL%d: %s",
5013942c5e3cSpl196000 			    ap->a_target, ap->a_lun,
501458bc78c7SXin Chen 			    "adapter dead");
501558bc78c7SXin Chen 		}
501658bc78c7SXin Chen #endif
5017942c5e3cSpl196000 		rval = TRAN_FATAL_ERROR;
5018942c5e3cSpl196000 	}
5019942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
5020942c5e3cSpl196000 	return (rval);
5021942c5e3cSpl196000 }
5022942c5e3cSpl196000 
5023942c5e3cSpl196000 static int
aac_tran_getcap(struct scsi_address * ap,char * cap,int whom)5024942c5e3cSpl196000 aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
5025942c5e3cSpl196000 {
5026942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
502758bc78c7SXin Chen 	struct aac_device *dvp;
5028942c5e3cSpl196000 	int rval;
5029942c5e3cSpl196000 
5030942c5e3cSpl196000 	DBCALLED(softs, 2);
5031942c5e3cSpl196000 
5032942c5e3cSpl196000 	/* We don't allow inquiring about capabilities for other targets */
5033942c5e3cSpl196000 	if (cap == NULL || whom == 0) {
5034942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
5035942c5e3cSpl196000 		    "GetCap> %s not supported: whom=%d", cap, whom);
5036942c5e3cSpl196000 		return (-1);
5037942c5e3cSpl196000 	}
5038942c5e3cSpl196000 
5039942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
504058bc78c7SXin Chen 	dvp = AAC_DEV(softs, ap->a_target);
504158bc78c7SXin Chen 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5042942c5e3cSpl196000 		mutex_exit(&softs->io_lock);
504358bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
5044942c5e3cSpl196000 		    ap->a_target, ap->a_lun);
5045942c5e3cSpl196000 		return (-1);
5046942c5e3cSpl196000 	}
5047942c5e3cSpl196000 
5048942c5e3cSpl196000 	switch (scsi_hba_lookup_capstr(cap)) {
5049942c5e3cSpl196000 	case SCSI_CAP_ARQ: /* auto request sense */
5050942c5e3cSpl196000 		rval = 1;
5051942c5e3cSpl196000 		break;
5052942c5e3cSpl196000 	case SCSI_CAP_UNTAGGED_QING:
5053942c5e3cSpl196000 	case SCSI_CAP_TAGGED_QING:
5054942c5e3cSpl196000 		rval = 1;
5055942c5e3cSpl196000 		break;
5056942c5e3cSpl196000 	case SCSI_CAP_DMA_MAX:
505772888e72Speng liu - Sun Microsystems - Beijing China 		rval = softs->dma_max;
5058942c5e3cSpl196000 		break;
5059942c5e3cSpl196000 	default:
5060942c5e3cSpl196000 		rval = -1;
5061942c5e3cSpl196000 		break;
5062942c5e3cSpl196000 	}
5063942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
5064942c5e3cSpl196000 
5065942c5e3cSpl196000 	AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
5066942c5e3cSpl196000 	    cap, ap->a_target, ap->a_lun, rval);
5067942c5e3cSpl196000 	return (rval);
5068942c5e3cSpl196000 }
5069942c5e3cSpl196000 
5070942c5e3cSpl196000 /*ARGSUSED*/
5071942c5e3cSpl196000 static int
aac_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)5072942c5e3cSpl196000 aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
5073942c5e3cSpl196000 {
5074942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
507558bc78c7SXin Chen 	struct aac_device *dvp;
5076942c5e3cSpl196000 	int rval;
5077942c5e3cSpl196000 
5078942c5e3cSpl196000 	DBCALLED(softs, 2);
5079942c5e3cSpl196000 
5080942c5e3cSpl196000 	/* We don't allow inquiring about capabilities for other targets */
5081942c5e3cSpl196000 	if (cap == NULL || whom == 0) {
5082942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
5083942c5e3cSpl196000 		    "SetCap> %s not supported: whom=%d", cap, whom);
5084942c5e3cSpl196000 		return (-1);
5085942c5e3cSpl196000 	}
5086942c5e3cSpl196000 
5087942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
508858bc78c7SXin Chen 	dvp = AAC_DEV(softs, ap->a_target);
508958bc78c7SXin Chen 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
5090942c5e3cSpl196000 		mutex_exit(&softs->io_lock);
509158bc78c7SXin Chen 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
5092942c5e3cSpl196000 		    ap->a_target, ap->a_lun);
5093942c5e3cSpl196000 		return (-1);
5094942c5e3cSpl196000 	}
5095942c5e3cSpl196000 
5096942c5e3cSpl196000 	switch (scsi_hba_lookup_capstr(cap)) {
5097942c5e3cSpl196000 	case SCSI_CAP_ARQ:
5098942c5e3cSpl196000 		/* Force auto request sense */
5099942c5e3cSpl196000 		rval = (value == 1) ? 1 : 0;
5100942c5e3cSpl196000 		break;
5101942c5e3cSpl196000 	case SCSI_CAP_UNTAGGED_QING:
5102942c5e3cSpl196000 	case SCSI_CAP_TAGGED_QING:
5103942c5e3cSpl196000 		rval = (value == 1) ? 1 : 0;
5104942c5e3cSpl196000 		break;
5105942c5e3cSpl196000 	default:
5106942c5e3cSpl196000 		rval = -1;
5107942c5e3cSpl196000 		break;
5108942c5e3cSpl196000 	}
5109942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
5110942c5e3cSpl196000 
5111942c5e3cSpl196000 	AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
5112942c5e3cSpl196000 	    cap, ap->a_target, ap->a_lun, value, rval);
5113942c5e3cSpl196000 	return (rval);
5114942c5e3cSpl196000 }
5115942c5e3cSpl196000 
5116942c5e3cSpl196000 static void
aac_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)5117942c5e3cSpl196000 aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5118942c5e3cSpl196000 {
5119942c5e3cSpl196000 	struct aac_cmd *acp = PKT2AC(pkt);
5120942c5e3cSpl196000 
5121942c5e3cSpl196000 	DBCALLED(NULL, 2);
5122942c5e3cSpl196000 
5123942c5e3cSpl196000 	if (acp->sgt) {
5124942c5e3cSpl196000 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5125942c5e3cSpl196000 		    acp->left_cookien);
5126942c5e3cSpl196000 	}
5127942c5e3cSpl196000 	aac_free_dmamap(acp);
5128942c5e3cSpl196000 	ASSERT(acp->slotp == NULL);
5129942c5e3cSpl196000 	scsi_hba_pkt_free(ap, pkt);
5130942c5e3cSpl196000 }
5131942c5e3cSpl196000 
5132942c5e3cSpl196000 int
aac_cmd_dma_alloc(struct aac_softstate * softs,struct aac_cmd * acp,struct buf * bp,int flags,int (* cb)(),caddr_t arg)5133942c5e3cSpl196000 aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
5134942c5e3cSpl196000     struct buf *bp, int flags, int (*cb)(), caddr_t arg)
5135942c5e3cSpl196000 {
5136942c5e3cSpl196000 	int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
5137942c5e3cSpl196000 	uint_t oldcookiec;
5138942c5e3cSpl196000 	int bioerr;
5139942c5e3cSpl196000 	int rval;
5140942c5e3cSpl196000 
5141942c5e3cSpl196000 	oldcookiec = acp->left_cookien;
5142942c5e3cSpl196000 
5143942c5e3cSpl196000 	/* Move window to build s/g map */
5144942c5e3cSpl196000 	if (acp->total_nwin > 0) {
5145942c5e3cSpl196000 		if (++acp->cur_win < acp->total_nwin) {
5146942c5e3cSpl196000 			off_t off;
5147942c5e3cSpl196000 			size_t len;
5148942c5e3cSpl196000 
5149942c5e3cSpl196000 			rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
5150942c5e3cSpl196000 			    &off, &len, &acp->cookie, &acp->left_cookien);
5151942c5e3cSpl196000 			if (rval == DDI_SUCCESS)
5152942c5e3cSpl196000 				goto get_dma_cookies;
5153942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5154942c5e3cSpl196000 			    "ddi_dma_getwin() fail %d", rval);
515558bc78c7SXin Chen 			return (AACERR);
5156942c5e3cSpl196000 		}
5157942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
515858bc78c7SXin Chen 		return (AACERR);
5159942c5e3cSpl196000 	}
5160942c5e3cSpl196000 
5161942c5e3cSpl196000 	/* We need to transfer data, so we alloc DMA resources for this pkt */
5162942c5e3cSpl196000 	if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
5163942c5e3cSpl196000 		uint_t dma_flags = 0;
5164942c5e3cSpl196000 		struct aac_sge *sge;
5165942c5e3cSpl196000 
5166942c5e3cSpl196000 		/*
5167942c5e3cSpl196000 		 * We will still use this point to fake some
5168942c5e3cSpl196000 		 * infomation in tran_start
5169942c5e3cSpl196000 		 */
5170942c5e3cSpl196000 		acp->bp = bp;
5171942c5e3cSpl196000 
5172942c5e3cSpl196000 		/* Set dma flags */
5173942c5e3cSpl196000 		if (BUF_IS_READ(bp)) {
5174942c5e3cSpl196000 			dma_flags |= DDI_DMA_READ;
5175942c5e3cSpl196000 			acp->flags |= AAC_CMD_BUF_READ;
5176942c5e3cSpl196000 		} else {
5177942c5e3cSpl196000 			dma_flags |= DDI_DMA_WRITE;
5178942c5e3cSpl196000 			acp->flags |= AAC_CMD_BUF_WRITE;
5179942c5e3cSpl196000 		}
5180942c5e3cSpl196000 		if (flags & PKT_CONSISTENT)
5181942c5e3cSpl196000 			dma_flags |= DDI_DMA_CONSISTENT;
5182942c5e3cSpl196000 		if (flags & PKT_DMA_PARTIAL)
5183942c5e3cSpl196000 			dma_flags |= DDI_DMA_PARTIAL;
5184942c5e3cSpl196000 
5185942c5e3cSpl196000 		/* Alloc buf dma handle */
5186942c5e3cSpl196000 		if (!acp->buf_dma_handle) {
5187942c5e3cSpl196000 			rval = ddi_dma_alloc_handle(softs->devinfo_p,
5188942c5e3cSpl196000 			    &softs->buf_dma_attr, cb, arg,
5189942c5e3cSpl196000 			    &acp->buf_dma_handle);
5190942c5e3cSpl196000 			if (rval != DDI_SUCCESS) {
5191942c5e3cSpl196000 				AACDB_PRINT(softs, CE_WARN,
5192942c5e3cSpl196000 				    "Can't allocate DMA handle, errno=%d",
5193942c5e3cSpl196000 				    rval);
5194942c5e3cSpl196000 				goto error_out;
5195942c5e3cSpl196000 			}
5196942c5e3cSpl196000 		}
5197942c5e3cSpl196000 
5198942c5e3cSpl196000 		/* Bind buf */
5199942c5e3cSpl196000 		if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
5200942c5e3cSpl196000 			rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
5201942c5e3cSpl196000 			    bp, dma_flags, cb, arg, &acp->cookie,
5202942c5e3cSpl196000 			    &acp->left_cookien);
5203942c5e3cSpl196000 		} else {
5204942c5e3cSpl196000 			size_t bufsz;
5205942c5e3cSpl196000 
5206942c5e3cSpl196000 			AACDB_PRINT_TRAN(softs,
5207942c5e3cSpl196000 			    "non-aligned buffer: addr=0x%p, cnt=%lu",
5208942c5e3cSpl196000 			    (void *)bp->b_un.b_addr, bp->b_bcount);
5209942c5e3cSpl196000 			if (bp->b_flags & (B_PAGEIO|B_PHYS))
5210942c5e3cSpl196000 				bp_mapin(bp);
5211942c5e3cSpl196000 
5212942c5e3cSpl196000 			rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
5213942c5e3cSpl196000 			    AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
521458bc78c7SXin Chen 			    &softs->acc_attr, DDI_DMA_STREAMING,
5215942c5e3cSpl196000 			    cb, arg, &acp->abp, &bufsz, &acp->abh);
5216942c5e3cSpl196000 
5217942c5e3cSpl196000 			if (rval != DDI_SUCCESS) {
5218942c5e3cSpl196000 				AACDB_PRINT(softs, CE_NOTE,
5219942c5e3cSpl196000 				    "Cannot alloc DMA to non-aligned buf");
5220942c5e3cSpl196000 				bioerr = 0;
5221942c5e3cSpl196000 				goto error_out;
5222942c5e3cSpl196000 			}
5223942c5e3cSpl196000 
5224942c5e3cSpl196000 			if (acp->flags & AAC_CMD_BUF_WRITE)
5225942c5e3cSpl196000 				ddi_rep_put8(acp->abh,
5226942c5e3cSpl196000 				    (uint8_t *)bp->b_un.b_addr,
5227942c5e3cSpl196000 				    (uint8_t *)acp->abp, bp->b_bcount,
5228942c5e3cSpl196000 				    DDI_DEV_AUTOINCR);
5229942c5e3cSpl196000 
5230942c5e3cSpl196000 			rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
5231942c5e3cSpl196000 			    NULL, acp->abp, bufsz, dma_flags, cb, arg,
5232942c5e3cSpl196000 			    &acp->cookie, &acp->left_cookien);
5233942c5e3cSpl196000 		}
5234942c5e3cSpl196000 
5235942c5e3cSpl196000 		switch (rval) {
5236942c5e3cSpl196000 		case DDI_DMA_PARTIAL_MAP:
5237942c5e3cSpl196000 			if (ddi_dma_numwin(acp->buf_dma_handle,
5238942c5e3cSpl196000 			    &acp->total_nwin) == DDI_FAILURE) {
5239942c5e3cSpl196000 				AACDB_PRINT(softs, CE_WARN,
5240942c5e3cSpl196000 				    "Cannot get number of DMA windows");
5241942c5e3cSpl196000 				bioerr = 0;
5242942c5e3cSpl196000 				goto error_out;
5243942c5e3cSpl196000 			}
5244942c5e3cSpl196000 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5245942c5e3cSpl196000 			    acp->left_cookien);
5246942c5e3cSpl196000 			acp->cur_win = 0;
5247942c5e3cSpl196000 			break;
5248942c5e3cSpl196000 
5249942c5e3cSpl196000 		case DDI_DMA_MAPPED:
5250942c5e3cSpl196000 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
5251942c5e3cSpl196000 			    acp->left_cookien);
5252942c5e3cSpl196000 			acp->cur_win = 0;
5253942c5e3cSpl196000 			acp->total_nwin = 1;
5254942c5e3cSpl196000 			break;
5255942c5e3cSpl196000 
5256942c5e3cSpl196000 		case DDI_DMA_NORESOURCES:
5257942c5e3cSpl196000 			bioerr = 0;
5258942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5259942c5e3cSpl196000 			    "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
5260942c5e3cSpl196000 			goto error_out;
5261942c5e3cSpl196000 		case DDI_DMA_BADATTR:
5262942c5e3cSpl196000 		case DDI_DMA_NOMAPPING:
5263942c5e3cSpl196000 			bioerr = EFAULT;
5264942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5265942c5e3cSpl196000 			    "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
5266942c5e3cSpl196000 			goto error_out;
5267942c5e3cSpl196000 		case DDI_DMA_TOOBIG:
5268942c5e3cSpl196000 			bioerr = EINVAL;
5269942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5270942c5e3cSpl196000 			    "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
5271942c5e3cSpl196000 			    bp->b_bcount);
5272942c5e3cSpl196000 			goto error_out;
5273942c5e3cSpl196000 		default:
5274942c5e3cSpl196000 			bioerr = EINVAL;
5275942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN,
5276942c5e3cSpl196000 			    "Cannot bind buf for DMA: %d", rval);
5277942c5e3cSpl196000 			goto error_out;
5278942c5e3cSpl196000 		}
5279942c5e3cSpl196000 		acp->flags |= AAC_CMD_DMA_VALID;
5280942c5e3cSpl196000 
5281942c5e3cSpl196000 get_dma_cookies:
5282942c5e3cSpl196000 		ASSERT(acp->left_cookien > 0);
5283942c5e3cSpl196000 		if (acp->left_cookien > softs->aac_sg_tablesize) {
5284942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
5285942c5e3cSpl196000 			    acp->left_cookien);
5286942c5e3cSpl196000 			bioerr = EINVAL;
5287942c5e3cSpl196000 			goto error_out;
5288942c5e3cSpl196000 		}
5289942c5e3cSpl196000 		if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
5290942c5e3cSpl196000 			kmem_free(acp->sgt, sizeof (struct aac_sge) * \
5291942c5e3cSpl196000 			    oldcookiec);
5292942c5e3cSpl196000 			acp->sgt = NULL;
5293942c5e3cSpl196000 		}
5294942c5e3cSpl196000 		if (acp->sgt == NULL) {
5295942c5e3cSpl196000 			acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
5296942c5e3cSpl196000 			    acp->left_cookien, kf);
5297942c5e3cSpl196000 			if (acp->sgt == NULL) {
5298942c5e3cSpl196000 				AACDB_PRINT(softs, CE_WARN,
5299942c5e3cSpl196000 				    "sgt kmem_alloc fail");
5300942c5e3cSpl196000 				bioerr = ENOMEM;
5301942c5e3cSpl196000 				goto error_out;
5302942c5e3cSpl196000 			}
5303942c5e3cSpl196000 		}
5304942c5e3cSpl196000 
5305942c5e3cSpl196000 		sge = &acp->sgt[0];
5306942c5e3cSpl196000 		sge->bcount = acp->cookie.dmac_size;
5307942c5e3cSpl196000 		sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5308942c5e3cSpl196000 		sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5309942c5e3cSpl196000 		acp->bcount = acp->cookie.dmac_size;
5310942c5e3cSpl196000 		for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
5311942c5e3cSpl196000 			ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
5312942c5e3cSpl196000 			sge->bcount = acp->cookie.dmac_size;
5313942c5e3cSpl196000 			sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
5314942c5e3cSpl196000 			sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
5315942c5e3cSpl196000 			acp->bcount += acp->cookie.dmac_size;
5316942c5e3cSpl196000 		}
5317942c5e3cSpl196000 
5318942c5e3cSpl196000 		/*
5319942c5e3cSpl196000 		 * Note: The old DMA engine do not correctly handle
5320942c5e3cSpl196000 		 * dma_attr_maxxfer attribute. So we have to ensure
5321942c5e3cSpl196000 		 * it by ourself.
5322942c5e3cSpl196000 		 */
5323942c5e3cSpl196000 		if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
5324942c5e3cSpl196000 			AACDB_PRINT(softs, CE_NOTE,
5325942c5e3cSpl196000 			    "large xfer size received %d\n", acp->bcount);
5326942c5e3cSpl196000 			bioerr = EINVAL;
5327942c5e3cSpl196000 			goto error_out;
5328942c5e3cSpl196000 		}
5329942c5e3cSpl196000 
5330942c5e3cSpl196000 		acp->total_xfer += acp->bcount;
5331942c5e3cSpl196000 
5332942c5e3cSpl196000 		if (acp->pkt) {
5333942c5e3cSpl196000 			/* Return remaining byte count */
533458bc78c7SXin Chen 			if (acp->total_xfer <= bp->b_bcount) {
533558bc78c7SXin Chen 				acp->pkt->pkt_resid = bp->b_bcount - \
533658bc78c7SXin Chen 				    acp->total_xfer;
533758bc78c7SXin Chen 			} else {
533858bc78c7SXin Chen 				/*
533958bc78c7SXin Chen 				 * Allocated DMA size is greater than the buf
534058bc78c7SXin Chen 				 * size of bp. This is caused by devices like
534158bc78c7SXin Chen 				 * tape. we have extra bytes allocated, but
534258bc78c7SXin Chen 				 * the packet residual has to stay correct.
534358bc78c7SXin Chen 				 */
534458bc78c7SXin Chen 				acp->pkt->pkt_resid = 0;
534558bc78c7SXin Chen 			}
5346942c5e3cSpl196000 			AACDB_PRINT_TRAN(softs,
5347942c5e3cSpl196000 			    "bp=0x%p, xfered=%d/%d, resid=%d",
5348942c5e3cSpl196000 			    (void *)bp->b_un.b_addr, (int)acp->total_xfer,
5349942c5e3cSpl196000 			    (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
5350942c5e3cSpl196000 		}
5351942c5e3cSpl196000 	}
5352942c5e3cSpl196000 	return (AACOK);
5353942c5e3cSpl196000 
5354942c5e3cSpl196000 error_out:
5355942c5e3cSpl196000 	bioerror(bp, bioerr);
5356942c5e3cSpl196000 	return (AACERR);
5357942c5e3cSpl196000 }
5358942c5e3cSpl196000 
5359942c5e3cSpl196000 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)5360942c5e3cSpl196000 aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
5361942c5e3cSpl196000     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
5362942c5e3cSpl196000     int (*callback)(), caddr_t arg)
5363942c5e3cSpl196000 {
5364942c5e3cSpl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
5365942c5e3cSpl196000 	struct aac_cmd *acp, *new_acp;
5366942c5e3cSpl196000 
5367942c5e3cSpl196000 	DBCALLED(softs, 2);
5368942c5e3cSpl196000 
5369942c5e3cSpl196000 	/* Allocate pkt */
5370942c5e3cSpl196000 	if (pkt == NULL) {
5371942c5e3cSpl196000 		int slen;
5372942c5e3cSpl196000 
5373942c5e3cSpl196000 		/* Force auto request sense */
5374942c5e3cSpl196000 		slen = (statuslen > softs->slen) ? statuslen : softs->slen;
5375942c5e3cSpl196000 		pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
5376942c5e3cSpl196000 		    slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
5377942c5e3cSpl196000 		if (pkt == NULL) {
5378942c5e3cSpl196000 			AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
5379942c5e3cSpl196000 			return (NULL);
5380942c5e3cSpl196000 		}
5381942c5e3cSpl196000 		acp = new_acp = PKT2AC(pkt);
5382942c5e3cSpl196000 		acp->pkt = pkt;
5383942c5e3cSpl196000 		acp->cmdlen = cmdlen;
5384942c5e3cSpl196000 
538558bc78c7SXin Chen 		if (ap->a_target < AAC_MAX_LD) {
538658bc78c7SXin Chen 			acp->dvp = &softs->containers[ap->a_target].dev;
5387942c5e3cSpl196000 			acp->aac_cmd_fib = softs->aac_cmd_fib;
5388942c5e3cSpl196000 			acp->ac_comp = aac_ld_complete;
5389942c5e3cSpl196000 		} else {
539058bc78c7SXin Chen 			_NOTE(ASSUMING_PROTECTED(softs->nondasds))
539158bc78c7SXin Chen 
539258bc78c7SXin Chen 			acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
539358bc78c7SXin Chen 			acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
539458bc78c7SXin Chen 			acp->ac_comp = aac_pd_complete;
539558bc78c7SXin Chen 		}
539658bc78c7SXin Chen 	} else {
5397942c5e3cSpl196000 		acp = PKT2AC(pkt);
5398942c5e3cSpl196000 		new_acp = NULL;
5399942c5e3cSpl196000 	}
5400942c5e3cSpl196000 
5401942c5e3cSpl196000 	if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
5402942c5e3cSpl196000 		return (pkt);
5403942c5e3cSpl196000 
5404942c5e3cSpl196000 	if (new_acp)
5405942c5e3cSpl196000 		aac_tran_destroy_pkt(ap, pkt);
5406942c5e3cSpl196000 	return (NULL);
5407942c5e3cSpl196000 }
5408942c5e3cSpl196000 
5409942c5e3cSpl196000 /*
5410942c5e3cSpl196000  * tran_sync_pkt(9E) - explicit DMA synchronization
5411942c5e3cSpl196000  */
5412942c5e3cSpl196000 /*ARGSUSED*/
5413942c5e3cSpl196000 static void
aac_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)5414942c5e3cSpl196000 aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
5415942c5e3cSpl196000 {
5416942c5e3cSpl196000 	struct aac_cmd *acp = PKT2AC(pkt);
5417942c5e3cSpl196000 
5418942c5e3cSpl196000 	DBCALLED(NULL, 2);
5419942c5e3cSpl196000 
5420942c5e3cSpl196000 	if (aac_dma_sync_ac(acp) != AACOK)
5421942c5e3cSpl196000 		ddi_fm_service_impact(
5422942c5e3cSpl196000 		    (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
5423942c5e3cSpl196000 		    DDI_SERVICE_UNAFFECTED);
5424942c5e3cSpl196000 }
5425942c5e3cSpl196000 
5426942c5e3cSpl196000 /*
5427942c5e3cSpl196000  * tran_dmafree(9E) - deallocate DMA resources allocated for command
5428942c5e3cSpl196000  */
5429942c5e3cSpl196000 /*ARGSUSED*/
5430942c5e3cSpl196000 static void
aac_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)5431942c5e3cSpl196000 aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
5432942c5e3cSpl196000 {
5433942c5e3cSpl196000 	struct aac_cmd *acp = PKT2AC(pkt);
5434942c5e3cSpl196000 
5435942c5e3cSpl196000 	DBCALLED(NULL, 2);
5436942c5e3cSpl196000 
5437942c5e3cSpl196000 	aac_free_dmamap(acp);
5438942c5e3cSpl196000 }
5439942c5e3cSpl196000 
5440942c5e3cSpl196000 static int
aac_do_quiesce(struct aac_softstate * softs)5441942c5e3cSpl196000 aac_do_quiesce(struct aac_softstate *softs)
5442942c5e3cSpl196000 {
5443942c5e3cSpl196000 	aac_hold_bus(softs, AAC_IOCMD_ASYNC);
5444942c5e3cSpl196000 	if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
5445942c5e3cSpl196000 		aac_start_drain(softs);
5446942c5e3cSpl196000 		do {
5447942c5e3cSpl196000 			if (cv_wait_sig(&softs->drain_cv,
5448942c5e3cSpl196000 			    &softs->io_lock) == 0) {
5449942c5e3cSpl196000 				/* Quiesce has been interrupted */
5450942c5e3cSpl196000 				aac_stop_drain(softs);
5451942c5e3cSpl196000 				aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5452942c5e3cSpl196000 				aac_start_waiting_io(softs);
5453942c5e3cSpl196000 				return (AACERR);
5454942c5e3cSpl196000 			}
5455942c5e3cSpl196000 		} while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
5456942c5e3cSpl196000 		aac_stop_drain(softs);
5457942c5e3cSpl196000 	}
5458942c5e3cSpl196000 
5459942c5e3cSpl196000 	softs->state |= AAC_STATE_QUIESCED;
5460942c5e3cSpl196000 	return (AACOK);
5461942c5e3cSpl196000 }
5462942c5e3cSpl196000 
5463942c5e3cSpl196000 static int
aac_tran_quiesce(dev_info_t * dip)5464942c5e3cSpl196000 aac_tran_quiesce(dev_info_t *dip)
5465942c5e3cSpl196000 {
5466942c5e3cSpl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5467942c5e3cSpl196000 	int rval;
5468942c5e3cSpl196000 
5469942c5e3cSpl196000 	DBCALLED(softs, 1);
5470942c5e3cSpl196000 
5471942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
5472942c5e3cSpl196000 	if (aac_do_quiesce(softs) == AACOK)
5473942c5e3cSpl196000 		rval = 0;
5474942c5e3cSpl196000 	else
5475942c5e3cSpl196000 		rval = 1;
5476942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
5477942c5e3cSpl196000 	return (rval);
5478942c5e3cSpl196000 }
5479942c5e3cSpl196000 
5480942c5e3cSpl196000 static int
aac_do_unquiesce(struct aac_softstate * softs)5481942c5e3cSpl196000 aac_do_unquiesce(struct aac_softstate *softs)
5482942c5e3cSpl196000 {
5483942c5e3cSpl196000 	softs->state &= ~AAC_STATE_QUIESCED;
5484942c5e3cSpl196000 	aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
5485942c5e3cSpl196000 
5486942c5e3cSpl196000 	aac_start_waiting_io(softs);
5487942c5e3cSpl196000 	return (AACOK);
5488942c5e3cSpl196000 }
5489942c5e3cSpl196000 
5490942c5e3cSpl196000 static int
aac_tran_unquiesce(dev_info_t * dip)5491942c5e3cSpl196000 aac_tran_unquiesce(dev_info_t *dip)
5492942c5e3cSpl196000 {
5493942c5e3cSpl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
5494942c5e3cSpl196000 	int rval;
5495942c5e3cSpl196000 
5496942c5e3cSpl196000 	DBCALLED(softs, 1);
5497942c5e3cSpl196000 
5498942c5e3cSpl196000 	mutex_enter(&softs->io_lock);
5499942c5e3cSpl196000 	if (aac_do_unquiesce(softs) == AACOK)
5500942c5e3cSpl196000 		rval = 0;
5501942c5e3cSpl196000 	else
5502942c5e3cSpl196000 		rval = 1;
5503942c5e3cSpl196000 	mutex_exit(&softs->io_lock);
5504942c5e3cSpl196000 	return (rval);
5505942c5e3cSpl196000 }
5506942c5e3cSpl196000 
5507942c5e3cSpl196000 static int
aac_hba_setup(struct aac_softstate * softs)5508942c5e3cSpl196000 aac_hba_setup(struct aac_softstate *softs)
5509942c5e3cSpl196000 {
5510942c5e3cSpl196000 	scsi_hba_tran_t *hba_tran;
5511942c5e3cSpl196000 	int rval;
5512942c5e3cSpl196000 
5513942c5e3cSpl196000 	hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
5514942c5e3cSpl196000 	if (hba_tran == NULL)
5515942c5e3cSpl196000 		return (AACERR);
5516942c5e3cSpl196000 	hba_tran->tran_hba_private = softs;
5517942c5e3cSpl196000 	hba_tran->tran_tgt_init = aac_tran_tgt_init;
551858bc78c7SXin Chen 	hba_tran->tran_tgt_free = aac_tran_tgt_free;
5519942c5e3cSpl196000 	hba_tran->tran_tgt_probe = scsi_hba_probe;
5520942c5e3cSpl196000 	hba_tran->tran_start = aac_tran_start;
5521942c5e3cSpl196000 	hba_tran->tran_getcap = aac_tran_getcap;
5522942c5e3cSpl196000 	hba_tran->tran_setcap = aac_tran_setcap;
5523942c5e3cSpl196000 	hba_tran->tran_init_pkt = aac_tran_init_pkt;
5524942c5e3cSpl196000 	hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
5525942c5e3cSpl196000 	hba_tran->tran_reset = aac_tran_reset;
5526942c5e3cSpl196000 	hba_tran->tran_abort = aac_tran_abort;
5527942c5e3cSpl196000 	hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
5528942c5e3cSpl196000 	hba_tran->tran_dmafree = aac_tran_dmafree;
5529942c5e3cSpl196000 	hba_tran->tran_quiesce = aac_tran_quiesce;
5530942c5e3cSpl196000 	hba_tran->tran_unquiesce = aac_tran_unquiesce;
553158bc78c7SXin Chen 	hba_tran->tran_bus_config = aac_tran_bus_config;
5532942c5e3cSpl196000 	rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
5533942c5e3cSpl196000 	    hba_tran, 0);
5534942c5e3cSpl196000 	if (rval != DDI_SUCCESS) {
5535942c5e3cSpl196000 		scsi_hba_tran_free(hba_tran);
5536942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
5537942c5e3cSpl196000 		return (AACERR);
5538942c5e3cSpl196000 	}
5539942c5e3cSpl196000 
554058bc78c7SXin Chen 	softs->hba_tran = hba_tran;
5541942c5e3cSpl196000 	return (AACOK);
5542942c5e3cSpl196000 }
5543942c5e3cSpl196000 
5544942c5e3cSpl196000 /*
5545942c5e3cSpl196000  * FIB setup operations
5546942c5e3cSpl196000  */
5547942c5e3cSpl196000 
5548942c5e3cSpl196000 /*
5549942c5e3cSpl196000  * Init FIB header
5550942c5e3cSpl196000  */
5551942c5e3cSpl196000 static void
aac_cmd_fib_header(struct aac_softstate * softs,struct aac_cmd * acp,uint16_t cmd)5552f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
5553f42c2f53Szhongyan gu - Sun Microsystems - Beijing China     uint16_t cmd)
5554942c5e3cSpl196000 {
5555f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp = acp->slotp;
5556942c5e3cSpl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5557942c5e3cSpl196000 	struct aac_fib *fibp = slotp->fibp;
5558942c5e3cSpl196000 	uint32_t xfer_state;
5559942c5e3cSpl196000 
5560942c5e3cSpl196000 	xfer_state =
5561942c5e3cSpl196000 	    AAC_FIBSTATE_HOSTOWNED |
5562942c5e3cSpl196000 	    AAC_FIBSTATE_INITIALISED |
5563942c5e3cSpl196000 	    AAC_FIBSTATE_EMPTY |
55640749e8deSXin Chen - Sun Microsystems - Beijing China 	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
5565942c5e3cSpl196000 	    AAC_FIBSTATE_FROMHOST |
5566942c5e3cSpl196000 	    AAC_FIBSTATE_REXPECTED |
5567942c5e3cSpl196000 	    AAC_FIBSTATE_NORM;
5568f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
55690749e8deSXin Chen - Sun Microsystems - Beijing China 	if (!(acp->flags & AAC_CMD_SYNC))
55700749e8deSXin Chen - Sun Microsystems - Beijing China 		xfer_state |= AAC_FIBSTATE_ASYNC;
5571942c5e3cSpl196000 
5572942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
5573942c5e3cSpl196000 	ddi_put16(acc, &fibp->Header.Command, cmd);
5574942c5e3cSpl196000 	ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
5575942c5e3cSpl196000 	ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
5576f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
5577f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
5578942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
5579942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5580942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
5581942c5e3cSpl196000 }
5582942c5e3cSpl196000 
5583942c5e3cSpl196000 /*
5584942c5e3cSpl196000  * Init FIB for raw IO command
5585942c5e3cSpl196000  */
5586942c5e3cSpl196000 static void
aac_cmd_fib_rawio(struct aac_softstate * softs,struct aac_cmd * acp)5587942c5e3cSpl196000 aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
5588942c5e3cSpl196000 {
5589942c5e3cSpl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5590942c5e3cSpl196000 	struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
5591942c5e3cSpl196000 	struct aac_sg_entryraw *sgp;
5592942c5e3cSpl196000 	struct aac_sge *sge;
5593942c5e3cSpl196000 
5594942c5e3cSpl196000 	/* Calculate FIB size */
5595942c5e3cSpl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
5596942c5e3cSpl196000 	    sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
5597942c5e3cSpl196000 	    sizeof (struct aac_sg_entryraw);
5598942c5e3cSpl196000 
5599f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, RawIo);
5600942c5e3cSpl196000 
5601942c5e3cSpl196000 	ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
5602942c5e3cSpl196000 	ddi_put16(acc, &io->BpTotal, 0);
5603942c5e3cSpl196000 	ddi_put16(acc, &io->BpComplete, 0);
5604942c5e3cSpl196000 
5605942c5e3cSpl196000 	ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
5606942c5e3cSpl196000 	ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
5607942c5e3cSpl196000 	ddi_put16(acc, &io->ContainerId,
5608942c5e3cSpl196000 	    ((struct aac_container *)acp->dvp)->cid);
5609942c5e3cSpl196000 
5610942c5e3cSpl196000 	/* Fill SG table */
5611942c5e3cSpl196000 	ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
5612942c5e3cSpl196000 	ddi_put32(acc, &io->ByteCount, acp->bcount);
5613942c5e3cSpl196000 
5614942c5e3cSpl196000 	for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
5615942c5e3cSpl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5616942c5e3cSpl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5617942c5e3cSpl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5618942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5619942c5e3cSpl196000 		sgp->Next = 0;
5620942c5e3cSpl196000 		sgp->Prev = 0;
5621942c5e3cSpl196000 		sgp->Flags = 0;
5622942c5e3cSpl196000 	}
5623942c5e3cSpl196000 }
5624942c5e3cSpl196000 
5625942c5e3cSpl196000 /* Init FIB for 64-bit block IO command */
5626942c5e3cSpl196000 static void
aac_cmd_fib_brw64(struct aac_softstate * softs,struct aac_cmd * acp)5627942c5e3cSpl196000 aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
5628942c5e3cSpl196000 {
5629942c5e3cSpl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5630942c5e3cSpl196000 	struct aac_blockread64 *br = (struct aac_blockread64 *) \
5631942c5e3cSpl196000 	    &acp->slotp->fibp->data[0];
5632942c5e3cSpl196000 	struct aac_sg_entry64 *sgp;
5633942c5e3cSpl196000 	struct aac_sge *sge;
5634942c5e3cSpl196000 
5635942c5e3cSpl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
5636942c5e3cSpl196000 	    sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
5637942c5e3cSpl196000 	    sizeof (struct aac_sg_entry64);
5638942c5e3cSpl196000 
5639f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand64);
5640942c5e3cSpl196000 
5641942c5e3cSpl196000 	/*
5642942c5e3cSpl196000 	 * The definitions for aac_blockread64 and aac_blockwrite64
5643942c5e3cSpl196000 	 * are the same.
5644942c5e3cSpl196000 	 */
5645942c5e3cSpl196000 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5646942c5e3cSpl196000 	ddi_put16(acc, &br->ContainerId,
5647942c5e3cSpl196000 	    ((struct aac_container *)acp->dvp)->cid);
5648942c5e3cSpl196000 	ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
5649942c5e3cSpl196000 	    VM_CtHostRead64 : VM_CtHostWrite64);
5650942c5e3cSpl196000 	ddi_put16(acc, &br->Pad, 0);
5651942c5e3cSpl196000 	ddi_put16(acc, &br->Flags, 0);
5652942c5e3cSpl196000 
5653942c5e3cSpl196000 	/* Fill SG table */
5654942c5e3cSpl196000 	ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
5655942c5e3cSpl196000 	ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
5656942c5e3cSpl196000 
5657942c5e3cSpl196000 	for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
5658942c5e3cSpl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5659942c5e3cSpl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5660942c5e3cSpl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5661942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5662942c5e3cSpl196000 	}
5663942c5e3cSpl196000 }
5664942c5e3cSpl196000 
5665942c5e3cSpl196000 /* Init FIB for block IO command */
5666942c5e3cSpl196000 static void
aac_cmd_fib_brw(struct aac_softstate * softs,struct aac_cmd * acp)5667942c5e3cSpl196000 aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
5668942c5e3cSpl196000 {
5669942c5e3cSpl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5670942c5e3cSpl196000 	struct aac_blockread *br = (struct aac_blockread *) \
5671942c5e3cSpl196000 	    &acp->slotp->fibp->data[0];
5672942c5e3cSpl196000 	struct aac_sg_entry *sgp;
5673942c5e3cSpl196000 	struct aac_sge *sge = &acp->sgt[0];
5674942c5e3cSpl196000 
5675942c5e3cSpl196000 	if (acp->flags & AAC_CMD_BUF_READ) {
5676942c5e3cSpl196000 		acp->fib_size = sizeof (struct aac_fib_header) + \
5677942c5e3cSpl196000 		    sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
5678942c5e3cSpl196000 		    sizeof (struct aac_sg_entry);
5679942c5e3cSpl196000 
5680942c5e3cSpl196000 		ddi_put32(acc, &br->Command, VM_CtBlockRead);
5681942c5e3cSpl196000 		ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
5682942c5e3cSpl196000 		sgp = &br->SgMap.SgEntry[0];
5683942c5e3cSpl196000 	} else {
5684942c5e3cSpl196000 		struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
5685942c5e3cSpl196000 
5686942c5e3cSpl196000 		acp->fib_size = sizeof (struct aac_fib_header) + \
5687942c5e3cSpl196000 		    sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
5688942c5e3cSpl196000 		    sizeof (struct aac_sg_entry);
5689942c5e3cSpl196000 
5690942c5e3cSpl196000 		ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
5691942c5e3cSpl196000 		ddi_put32(acc, &bw->Stable, CUNSTABLE);
5692942c5e3cSpl196000 		ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
5693942c5e3cSpl196000 		sgp = &bw->SgMap.SgEntry[0];
5694942c5e3cSpl196000 	}
5695f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5696942c5e3cSpl196000 
5697942c5e3cSpl196000 	/*
5698942c5e3cSpl196000 	 * aac_blockread and aac_blockwrite have the similar
5699942c5e3cSpl196000 	 * structure head, so use br for bw here
5700942c5e3cSpl196000 	 */
5701942c5e3cSpl196000 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
5702942c5e3cSpl196000 	ddi_put32(acc, &br->ContainerId,
5703942c5e3cSpl196000 	    ((struct aac_container *)acp->dvp)->cid);
5704942c5e3cSpl196000 	ddi_put32(acc, &br->ByteCount, acp->bcount);
5705942c5e3cSpl196000 
5706942c5e3cSpl196000 	/* Fill SG table */
5707942c5e3cSpl196000 	for (sge = &acp->sgt[0];
5708942c5e3cSpl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5709942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5710942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5711942c5e3cSpl196000 	}
5712942c5e3cSpl196000 }
5713942c5e3cSpl196000 
5714942c5e3cSpl196000 /*ARGSUSED*/
5715942c5e3cSpl196000 void
aac_cmd_fib_copy(struct aac_softstate * softs,struct aac_cmd * acp)5716942c5e3cSpl196000 aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
5717942c5e3cSpl196000 {
5718942c5e3cSpl196000 	struct aac_slot *slotp = acp->slotp;
5719942c5e3cSpl196000 	struct aac_fib *fibp = slotp->fibp;
5720942c5e3cSpl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
5721942c5e3cSpl196000 
5722942c5e3cSpl196000 	ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
5723942c5e3cSpl196000 	    acp->fib_size,   /* only copy data of needed length */
5724942c5e3cSpl196000 	    DDI_DEV_AUTOINCR);
5725942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
5726942c5e3cSpl196000 	ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
5727942c5e3cSpl196000 }
5728942c5e3cSpl196000 
5729942c5e3cSpl196000 static void
aac_cmd_fib_sync(struct aac_softstate * softs,struct aac_cmd * acp)5730942c5e3cSpl196000 aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
5731942c5e3cSpl196000 {
5732f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5733942c5e3cSpl196000 	struct aac_synchronize_command *sync =
5734f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
5735942c5e3cSpl196000 
5736f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
5737942c5e3cSpl196000 
5738f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5739942c5e3cSpl196000 	ddi_put32(acc, &sync->Command, VM_ContainerConfig);
5740942c5e3cSpl196000 	ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
5741942c5e3cSpl196000 	ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
5742942c5e3cSpl196000 	ddi_put32(acc, &sync->Count,
5743942c5e3cSpl196000 	    sizeof (((struct aac_synchronize_reply *)0)->Data));
5744942c5e3cSpl196000 }
5745942c5e3cSpl196000 
5746942c5e3cSpl196000 /*
5747b40e8a89Szhongyan gu - Sun Microsystems - Beijing China  * Start/Stop unit (Power Management)
5748b40e8a89Szhongyan gu - Sun Microsystems - Beijing China  */
5749b40e8a89Szhongyan gu - Sun Microsystems - Beijing China static void
aac_cmd_fib_startstop(struct aac_softstate * softs,struct aac_cmd * acp)5750b40e8a89Szhongyan gu - Sun Microsystems - Beijing China aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
5751b40e8a89Szhongyan gu - Sun Microsystems - Beijing China {
5752f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5753b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_Container *cmd =
5754f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    (struct aac_Container *)&acp->slotp->fibp->data[0];
5755b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
5756b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5757b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
5758b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5759f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ContainerCommand);
5760b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
5761b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
5762b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
5763b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
5764b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	    AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
5765b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[1],
5766b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	    ((struct aac_container *)acp->dvp)->cid);
5767b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
5768b40e8a89Szhongyan gu - Sun Microsystems - Beijing China }
5769b40e8a89Szhongyan gu - Sun Microsystems - Beijing China 
5770b40e8a89Szhongyan gu - Sun Microsystems - Beijing China /*
5771942c5e3cSpl196000  * Init FIB for pass-through SCMD
5772942c5e3cSpl196000  */
5773942c5e3cSpl196000 static void
aac_cmd_fib_srb(struct aac_cmd * acp)5774942c5e3cSpl196000 aac_cmd_fib_srb(struct aac_cmd *acp)
5775942c5e3cSpl196000 {
5776f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5777f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
577858bc78c7SXin Chen 	uint8_t *cdb;
5779942c5e3cSpl196000 
5780942c5e3cSpl196000 	ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
5781942c5e3cSpl196000 	ddi_put32(acc, &srb->retry_limit, 0);
5782942c5e3cSpl196000 	ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
5783942c5e3cSpl196000 	ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
578458bc78c7SXin Chen 	if (acp->fibp == NULL) {
578558bc78c7SXin Chen 		if (acp->flags & AAC_CMD_BUF_READ)
578658bc78c7SXin Chen 			ddi_put32(acc, &srb->flags, SRB_DataIn);
578758bc78c7SXin Chen 		else if (acp->flags & AAC_CMD_BUF_WRITE)
578858bc78c7SXin Chen 			ddi_put32(acc, &srb->flags, SRB_DataOut);
578958bc78c7SXin Chen 		ddi_put32(acc, &srb->channel,
579058bc78c7SXin Chen 		    ((struct aac_nondasd *)acp->dvp)->bus);
579158bc78c7SXin Chen 		ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
579258bc78c7SXin Chen 		ddi_put32(acc, &srb->lun, 0);
579358bc78c7SXin Chen 		cdb = acp->pkt->pkt_cdbp;
579458bc78c7SXin Chen 	} else {
579558bc78c7SXin Chen 		struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
5796942c5e3cSpl196000 
5797942c5e3cSpl196000 		ddi_put32(acc, &srb->flags, srb0->flags);
5798942c5e3cSpl196000 		ddi_put32(acc, &srb->channel, srb0->channel);
5799942c5e3cSpl196000 		ddi_put32(acc, &srb->id, srb0->id);
5800942c5e3cSpl196000 		ddi_put32(acc, &srb->lun, srb0->lun);
580158bc78c7SXin Chen 		cdb = srb0->cdb;
580258bc78c7SXin Chen 	}
580358bc78c7SXin Chen 	ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
5804942c5e3cSpl196000 }
5805942c5e3cSpl196000 
5806942c5e3cSpl196000 static void
aac_cmd_fib_scsi32(struct aac_softstate * softs,struct aac_cmd * acp)5807942c5e3cSpl196000 aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
5808942c5e3cSpl196000 {
5809942c5e3cSpl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5810942c5e3cSpl196000 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5811942c5e3cSpl196000 	struct aac_sg_entry *sgp;
5812942c5e3cSpl196000 	struct aac_sge *sge;
5813942c5e3cSpl196000 
5814942c5e3cSpl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
5815942c5e3cSpl196000 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5816942c5e3cSpl196000 	    acp->left_cookien * sizeof (struct aac_sg_entry);
5817942c5e3cSpl196000 
5818942c5e3cSpl196000 	/* Fill FIB and SRB headers, and copy cdb */
5819f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ScsiPortCommand);
5820942c5e3cSpl196000 	aac_cmd_fib_srb(acp);
5821942c5e3cSpl196000 
5822942c5e3cSpl196000 	/* Fill SG table */
5823942c5e3cSpl196000 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5824942c5e3cSpl196000 	ddi_put32(acc, &srb->count, acp->bcount);
5825942c5e3cSpl196000 
5826942c5e3cSpl196000 	for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
5827942c5e3cSpl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5828942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
5829942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5830942c5e3cSpl196000 	}
5831942c5e3cSpl196000 }
5832942c5e3cSpl196000 
5833942c5e3cSpl196000 static void
aac_cmd_fib_scsi64(struct aac_softstate * softs,struct aac_cmd * acp)5834942c5e3cSpl196000 aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
5835942c5e3cSpl196000 {
5836942c5e3cSpl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
5837942c5e3cSpl196000 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
5838942c5e3cSpl196000 	struct aac_sg_entry64 *sgp;
5839942c5e3cSpl196000 	struct aac_sge *sge;
5840942c5e3cSpl196000 
5841942c5e3cSpl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
5842942c5e3cSpl196000 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
5843942c5e3cSpl196000 	    acp->left_cookien * sizeof (struct aac_sg_entry64);
5844942c5e3cSpl196000 
5845942c5e3cSpl196000 	/* Fill FIB and SRB headers, and copy cdb */
5846f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
5847942c5e3cSpl196000 	aac_cmd_fib_srb(acp);
5848942c5e3cSpl196000 
5849942c5e3cSpl196000 	/* Fill SG table */
5850942c5e3cSpl196000 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
5851942c5e3cSpl196000 	ddi_put32(acc, &srb->count, acp->bcount);
5852942c5e3cSpl196000 
5853942c5e3cSpl196000 	for (sge = &acp->sgt[0],
5854942c5e3cSpl196000 	    sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
5855942c5e3cSpl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
5856942c5e3cSpl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
5857942c5e3cSpl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
5858942c5e3cSpl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
5859942c5e3cSpl196000 	}
5860942c5e3cSpl196000 }
5861942c5e3cSpl196000 
5862942c5e3cSpl196000 static int
aac_cmd_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5863942c5e3cSpl196000 aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5864942c5e3cSpl196000 {
5865942c5e3cSpl196000 	struct aac_slot *slotp;
5866942c5e3cSpl196000 
5867942c5e3cSpl196000 	if (slotp = aac_get_slot(softs)) {
5868942c5e3cSpl196000 		acp->slotp = slotp;
5869942c5e3cSpl196000 		slotp->acp = acp;
5870942c5e3cSpl196000 		acp->aac_cmd_fib(softs, acp);
5871942c5e3cSpl196000 		(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
5872942c5e3cSpl196000 		    DDI_DMA_SYNC_FORDEV);
5873942c5e3cSpl196000 		return (AACOK);
5874942c5e3cSpl196000 	}
5875942c5e3cSpl196000 	return (AACERR);
5876942c5e3cSpl196000 }
5877942c5e3cSpl196000 
5878942c5e3cSpl196000 static int
aac_bind_io(struct aac_softstate * softs,struct aac_cmd * acp)5879942c5e3cSpl196000 aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
5880942c5e3cSpl196000 {
588158bc78c7SXin Chen 	struct aac_device *dvp = acp->dvp;
5882942c5e3cSpl196000 	int q = AAC_CMDQ(acp);
5883942c5e3cSpl196000 
58841ee13a44SXinChen 	if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
5885942c5e3cSpl196000 		if (dvp) {
5886942c5e3cSpl196000 			if (dvp->ncmds[q] < dvp->throttle[q]) {
5887942c5e3cSpl196000 				if (!(acp->flags & AAC_CMD_NTAG) ||
5888942c5e3cSpl196000 				    dvp->ncmds[q] == 0) {
5889942c5e3cSpl196000 					return (aac_cmd_slot_bind(softs, acp));
5890942c5e3cSpl196000 				}
5891942c5e3cSpl196000 				ASSERT(q == AAC_CMDQ_ASYNC);
5892942c5e3cSpl196000 				aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
5893942c5e3cSpl196000 				    AAC_THROTTLE_DRAIN);
5894942c5e3cSpl196000 			}
5895942c5e3cSpl196000 		} else {
58961ee13a44SXinChen 			return (aac_cmd_slot_bind(softs, acp));
58971ee13a44SXinChen 		}
5898942c5e3cSpl196000 	}
5899942c5e3cSpl196000 	return (AACERR);
5900942c5e3cSpl196000 }
5901942c5e3cSpl196000 
5902f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static int
aac_sync_fib_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)5903f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
5904f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
5905f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	struct aac_slot *slotp;
5906f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
59071ee13a44SXinChen 	while (softs->sync_ac.slotp)
59081ee13a44SXinChen 		cv_wait(&softs->sync_fib_cv, &softs->io_lock);
59091ee13a44SXinChen 
5910f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (slotp = aac_get_slot(softs)) {
5911f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		ASSERT(acp->slotp == NULL);
5912f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5913f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		acp->slotp = slotp;
5914f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		slotp->acp = acp;
5915f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		return (AACOK);
5916f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
5917f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	return (AACERR);
5918f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
5919f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5920f42c2f53Szhongyan gu - Sun Microsystems - Beijing China static void
aac_sync_fib_slot_release(struct aac_softstate * softs,struct aac_cmd * acp)5921f42c2f53Szhongyan gu - Sun Microsystems - Beijing China aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
5922f42c2f53Szhongyan gu - Sun Microsystems - Beijing China {
5923f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ASSERT(acp->slotp);
5924f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5925f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_release_slot(softs, acp->slotp);
5926f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->slotp->acp = NULL;
5927f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acp->slotp = NULL;
59281ee13a44SXinChen 
59291ee13a44SXinChen 	cv_signal(&softs->sync_fib_cv);
5930f42c2f53Szhongyan gu - Sun Microsystems - Beijing China }
5931f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
5932942c5e3cSpl196000 static void
aac_start_io(struct aac_softstate * softs,struct aac_cmd * acp)5933942c5e3cSpl196000 aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
5934942c5e3cSpl196000 {
5935942c5e3cSpl196000 	struct aac_slot *slotp = acp->slotp;
5936942c5e3cSpl196000 	int q = AAC_CMDQ(acp);
5937942c5e3cSpl196000 	int rval;
5938942c5e3cSpl196000 
5939942c5e3cSpl196000 	/* Set ac and pkt */
5940942c5e3cSpl196000 	if (acp->pkt) { /* ac from ioctl has no pkt */
5941942c5e3cSpl196000 		acp->pkt->pkt_state |=
5942942c5e3cSpl196000 		    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
5943942c5e3cSpl196000 	}
5944942c5e3cSpl196000 	if (acp->timeout) /* 0 indicates no timeout */
5945942c5e3cSpl196000 		acp->timeout += aac_timebase + aac_tick;
5946942c5e3cSpl196000 
5947942c5e3cSpl196000 	if (acp->dvp)
5948942c5e3cSpl196000 		acp->dvp->ncmds[q]++;
5949942c5e3cSpl196000 	softs->bus_ncmds[q]++;
5950942c5e3cSpl196000 	aac_cmd_enqueue(&softs->q_busy, acp);
5951942c5e3cSpl196000 
595258bc78c7SXin Chen 	AACDB_PRINT_FIB(softs, slotp);
595358bc78c7SXin Chen 
5954942c5e3cSpl196000 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
5955942c5e3cSpl196000 		rval = aac_send_command(softs, slotp);
5956942c5e3cSpl196000 	} else {
5957942c5e3cSpl196000 		/*
5958942c5e3cSpl196000 		 * If fib can not be enqueued, the adapter is in an abnormal
5959942c5e3cSpl196000 		 * state, there will be no interrupt to us.
5960942c5e3cSpl196000 		 */
5961942c5e3cSpl196000 		rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
5962942c5e3cSpl196000 		    slotp->fib_phyaddr, acp->fib_size);
5963942c5e3cSpl196000 	}
5964942c5e3cSpl196000 
5965942c5e3cSpl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
5966942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
5967942c5e3cSpl196000 
5968942c5e3cSpl196000 	/*
5969942c5e3cSpl196000 	 * NOTE: We send command only when slots availabe, so should never
5970942c5e3cSpl196000 	 * reach here.
5971942c5e3cSpl196000 	 */
5972942c5e3cSpl196000 	if (rval != AACOK) {
5973942c5e3cSpl196000 		AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
5974942c5e3cSpl196000 		if (acp->pkt) {
5975942c5e3cSpl196000 			acp->pkt->pkt_state &= ~STATE_SENT_CMD;
5976942c5e3cSpl196000 			aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
5977942c5e3cSpl196000 		}
5978942c5e3cSpl196000 		aac_end_io(softs, acp);
5979942c5e3cSpl196000 		if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
5980942c5e3cSpl196000 			ddi_trigger_softintr(softs->softint_id);
5981942c5e3cSpl196000 	}
5982942c5e3cSpl196000 }
5983942c5e3cSpl196000 
5984942c5e3cSpl196000 static void
aac_start_waitq(struct aac_softstate * softs,struct aac_cmd_queue * q)5985942c5e3cSpl196000 aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
5986942c5e3cSpl196000 {
5987942c5e3cSpl196000 	struct aac_cmd *acp, *next_acp;
5988942c5e3cSpl196000 
5989942c5e3cSpl196000 	/* Serve as many waiting io's as possible */
5990942c5e3cSpl196000 	for (acp = q->q_head; acp; acp = next_acp) {
5991942c5e3cSpl196000 		next_acp = acp->next;
5992942c5e3cSpl196000 		if (aac_bind_io(softs, acp) == AACOK) {
5993942c5e3cSpl196000 			aac_cmd_delete(q, acp);
5994942c5e3cSpl196000 			aac_start_io(softs, acp);
5995942c5e3cSpl196000 		}
5996942c5e3cSpl196000 		if (softs->free_io_slot_head == NULL)
5997942c5e3cSpl196000 			break;
5998942c5e3cSpl196000 	}
5999942c5e3cSpl196000 }
6000942c5e3cSpl196000 
6001942c5e3cSpl196000 static void
aac_start_waiting_io(struct aac_softstate * softs)6002942c5e3cSpl196000 aac_start_waiting_io(struct aac_softstate *softs)
6003942c5e3cSpl196000 {
6004942c5e3cSpl196000 	/*
6005942c5e3cSpl196000 	 * Sync FIB io is served before async FIB io so that io requests
6006942c5e3cSpl196000 	 * sent by interactive userland commands get responded asap.
6007942c5e3cSpl196000 	 */
6008942c5e3cSpl196000 	if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
6009942c5e3cSpl196000 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
6010942c5e3cSpl196000 	if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
6011942c5e3cSpl196000 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
6012942c5e3cSpl196000 }
6013942c5e3cSpl196000 
6014942c5e3cSpl196000 static void
aac_drain_comp_q(struct aac_softstate * softs)6015942c5e3cSpl196000 aac_drain_comp_q(struct aac_softstate *softs)
6016942c5e3cSpl196000 {
6017942c5e3cSpl196000 	struct aac_cmd *acp;
6018942c5e3cSpl196000 	struct scsi_pkt *pkt;
6019942c5e3cSpl196000 
6020942c5e3cSpl196000 	/*CONSTCOND*/
6021942c5e3cSpl196000 	while (1) {
6022942c5e3cSpl196000 		mutex_enter(&softs->q_comp_mutex);
6023942c5e3cSpl196000 		acp = aac_cmd_dequeue(&softs->q_comp);
6024942c5e3cSpl196000 		mutex_exit(&softs->q_comp_mutex);
6025942c5e3cSpl196000 		if (acp != NULL) {
6026942c5e3cSpl196000 			ASSERT(acp->pkt != NULL);
6027942c5e3cSpl196000 			pkt = acp->pkt;
6028942c5e3cSpl196000 
6029942c5e3cSpl196000 			if (pkt->pkt_reason == CMD_CMPLT) {
6030942c5e3cSpl196000 				/*
6031942c5e3cSpl196000 				 * Consistent packets need to be sync'ed first
6032942c5e3cSpl196000 				 */
6033942c5e3cSpl196000 				if ((acp->flags & AAC_CMD_CONSISTENT) &&
6034942c5e3cSpl196000 				    (acp->flags & AAC_CMD_BUF_READ)) {
6035942c5e3cSpl196000 					if (aac_dma_sync_ac(acp) != AACOK) {
6036942c5e3cSpl196000 						ddi_fm_service_impact(
6037942c5e3cSpl196000 						    softs->devinfo_p,
6038942c5e3cSpl196000 						    DDI_SERVICE_UNAFFECTED);
6039942c5e3cSpl196000 						pkt->pkt_reason = CMD_TRAN_ERR;
6040942c5e3cSpl196000 						pkt->pkt_statistics = 0;
6041942c5e3cSpl196000 					}
6042942c5e3cSpl196000 				}
6043942c5e3cSpl196000 				if ((aac_check_acc_handle(softs-> \
6044942c5e3cSpl196000 				    comm_space_acc_handle) != DDI_SUCCESS) ||
6045942c5e3cSpl196000 				    (aac_check_acc_handle(softs-> \
6046942c5e3cSpl196000 				    pci_mem_handle) != DDI_SUCCESS)) {
6047942c5e3cSpl196000 					ddi_fm_service_impact(softs->devinfo_p,
6048942c5e3cSpl196000 					    DDI_SERVICE_UNAFFECTED);
6049942c5e3cSpl196000 					ddi_fm_acc_err_clear(softs-> \
6050942c5e3cSpl196000 					    pci_mem_handle, DDI_FME_VER0);
6051942c5e3cSpl196000 					pkt->pkt_reason = CMD_TRAN_ERR;
6052942c5e3cSpl196000 					pkt->pkt_statistics = 0;
6053942c5e3cSpl196000 				}
6054942c5e3cSpl196000 				if (aac_check_dma_handle(softs-> \
6055942c5e3cSpl196000 				    comm_space_dma_handle) != DDI_SUCCESS) {
6056942c5e3cSpl196000 					ddi_fm_service_impact(softs->devinfo_p,
6057942c5e3cSpl196000 					    DDI_SERVICE_UNAFFECTED);
6058942c5e3cSpl196000 					pkt->pkt_reason = CMD_TRAN_ERR;
6059942c5e3cSpl196000 					pkt->pkt_statistics = 0;
6060942c5e3cSpl196000 				}
6061942c5e3cSpl196000 			}
60629c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
6063942c5e3cSpl196000 		} else {
6064942c5e3cSpl196000 			break;
6065942c5e3cSpl196000 		}
6066942c5e3cSpl196000 	}
6067942c5e3cSpl196000 }
6068942c5e3cSpl196000 
6069942c5e3cSpl196000 static int
aac_alloc_fib(struct aac_softstate * softs,struct aac_slot * slotp)6070942c5e3cSpl196000 aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
6071942c5e3cSpl196000 {
6072942c5e3cSpl196000 	size_t rlen;
6073942c5e3cSpl196000 	ddi_dma_cookie_t cookie;
6074942c5e3cSpl196000 	uint_t cookien;
6075942c5e3cSpl196000 
6076942c5e3cSpl196000 	/* Allocate FIB dma resource */
6077942c5e3cSpl196000 	if (ddi_dma_alloc_handle(
6078942c5e3cSpl196000 	    softs->devinfo_p,
6079942c5e3cSpl196000 	    &softs->addr_dma_attr,
6080942c5e3cSpl196000 	    DDI_DMA_SLEEP,
6081942c5e3cSpl196000 	    NULL,
6082942c5e3cSpl196000 	    &slotp->fib_dma_handle) != DDI_SUCCESS) {
6083942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
6084942c5e3cSpl196000 		    "Cannot alloc dma handle for slot fib area");
6085942c5e3cSpl196000 		goto error;
6086942c5e3cSpl196000 	}
6087942c5e3cSpl196000 	if (ddi_dma_mem_alloc(
6088942c5e3cSpl196000 	    slotp->fib_dma_handle,
6089942c5e3cSpl196000 	    softs->aac_max_fib_size,
609058bc78c7SXin Chen 	    &softs->acc_attr,
6091942c5e3cSpl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6092942c5e3cSpl196000 	    DDI_DMA_SLEEP,
6093942c5e3cSpl196000 	    NULL,
6094942c5e3cSpl196000 	    (caddr_t *)&slotp->fibp,
6095942c5e3cSpl196000 	    &rlen,
6096942c5e3cSpl196000 	    &slotp->fib_acc_handle) != DDI_SUCCESS) {
6097942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
6098942c5e3cSpl196000 		    "Cannot alloc mem for slot fib area");
6099942c5e3cSpl196000 		goto error;
6100942c5e3cSpl196000 	}
6101942c5e3cSpl196000 	if (ddi_dma_addr_bind_handle(
6102942c5e3cSpl196000 	    slotp->fib_dma_handle,
6103942c5e3cSpl196000 	    NULL,
6104942c5e3cSpl196000 	    (caddr_t)slotp->fibp,
6105942c5e3cSpl196000 	    softs->aac_max_fib_size,
6106942c5e3cSpl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6107942c5e3cSpl196000 	    DDI_DMA_SLEEP,
6108942c5e3cSpl196000 	    NULL,
6109942c5e3cSpl196000 	    &cookie,
6110942c5e3cSpl196000 	    &cookien) != DDI_DMA_MAPPED) {
6111942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN,
6112942c5e3cSpl196000 		    "dma bind failed for slot fib area");
6113942c5e3cSpl196000 		goto error;
6114942c5e3cSpl196000 	}
6115942c5e3cSpl196000 
6116942c5e3cSpl196000 	/* Check dma handles allocated in fib attach */
6117942c5e3cSpl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
6118942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6119942c5e3cSpl196000 		goto error;
6120942c5e3cSpl196000 	}
6121942c5e3cSpl196000 
6122942c5e3cSpl196000 	/* Check acc handles allocated in fib attach */
6123942c5e3cSpl196000 	if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
6124942c5e3cSpl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
6125942c5e3cSpl196000 		goto error;
6126942c5e3cSpl196000 	}
6127942c5e3cSpl196000 
6128942c5e3cSpl196000 	slotp->fib_phyaddr = cookie.dmac_laddress;
6129942c5e3cSpl196000 	return (AACOK);
6130942c5e3cSpl196000 
6131942c5e3cSpl196000 error:
6132942c5e3cSpl196000 	if (slotp->fib_acc_handle) {
6133942c5e3cSpl196000 		ddi_dma_mem_free(&slotp->fib_acc_handle);
6134942c5e3cSpl196000 		slotp->fib_acc_handle = NULL;
6135942c5e3cSpl196000 	}
6136942c5e3cSpl196000 	if (slotp->fib_dma_handle) {
6137942c5e3cSpl196000 		ddi_dma_free_handle(&slotp->fib_dma_handle);
6138942c5e3cSpl196000 		slotp->fib_dma_handle = NULL;
6139942c5e3cSpl196000 	}
6140942c5e3cSpl196000 	return (AACERR);
6141942c5e3cSpl196000 }
6142942c5e3cSpl196000 
6143942c5e3cSpl196000 static void
aac_free_fib(struct aac_slot * slotp)6144942c5e3cSpl196000 aac_free_fib(struct aac_slot *slotp)
6145942c5e3cSpl196000 {
6146942c5e3cSpl196000 	(void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
6147942c5e3cSpl196000 	ddi_dma_mem_free(&slotp->fib_acc_handle);
6148942c5e3cSpl196000 	slotp->fib_acc_handle = NULL;
6149942c5e3cSpl196000 	ddi_dma_free_handle(&slotp->fib_dma_handle);
6150942c5e3cSpl196000 	slotp->fib_dma_handle = NULL;
6151942c5e3cSpl196000 	slotp->fib_phyaddr = 0;
6152942c5e3cSpl196000 }
6153942c5e3cSpl196000 
6154942c5e3cSpl196000 static void
aac_alloc_fibs(struct aac_softstate * softs)6155942c5e3cSpl196000 aac_alloc_fibs(struct aac_softstate *softs)
6156942c5e3cSpl196000 {
6157942c5e3cSpl196000 	int i;
6158942c5e3cSpl196000 	struct aac_slot *slotp;
6159942c5e3cSpl196000 
6160942c5e3cSpl196000 	for (i = 0; i < softs->total_slots &&
6161942c5e3cSpl196000 	    softs->total_fibs < softs->total_slots; i++) {
6162942c5e3cSpl196000 		slotp = &(softs->io_slot[i]);
6163942c5e3cSpl196000 		if (slotp->fib_phyaddr)
6164942c5e3cSpl196000 			continue;
6165942c5e3cSpl196000 		if (aac_alloc_fib(softs, slotp) != AACOK)
6166942c5e3cSpl196000 			break;
6167942c5e3cSpl196000 
6168942c5e3cSpl196000 		/* Insert the slot to the free slot list */
6169942c5e3cSpl196000 		aac_release_slot(softs, slotp);
6170942c5e3cSpl196000 		softs->total_fibs++;
6171942c5e3cSpl196000 	}
6172942c5e3cSpl196000 }
6173942c5e3cSpl196000 
6174942c5e3cSpl196000 static void
aac_destroy_fibs(struct aac_softstate * softs)6175942c5e3cSpl196000 aac_destroy_fibs(struct aac_softstate *softs)
6176942c5e3cSpl196000 {
6177942c5e3cSpl196000 	struct aac_slot *slotp;
6178942c5e3cSpl196000 
6179942c5e3cSpl196000 	while ((slotp = softs->free_io_slot_head) != NULL) {
6180942c5e3cSpl196000 		ASSERT(slotp->fib_phyaddr);
6181942c5e3cSpl196000 		softs->free_io_slot_head = slotp->next;
6182942c5e3cSpl196000 		aac_free_fib(slotp);
6183942c5e3cSpl196000 		ASSERT(slotp->index == (slotp - softs->io_slot));
6184942c5e3cSpl196000 		softs->total_fibs--;
6185942c5e3cSpl196000 	}
6186942c5e3cSpl196000 	ASSERT(softs->total_fibs == 0);
6187942c5e3cSpl196000 }
6188942c5e3cSpl196000 
6189942c5e3cSpl196000 static int
aac_create_slots(struct aac_softstate * softs)6190942c5e3cSpl196000 aac_create_slots(struct aac_softstate *softs)
6191942c5e3cSpl196000 {
6192942c5e3cSpl196000 	int i;
6193942c5e3cSpl196000 
6194942c5e3cSpl196000 	softs->total_slots = softs->aac_max_fibs;
6195942c5e3cSpl196000 	softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
6196942c5e3cSpl196000 	    softs->total_slots, KM_SLEEP);
6197942c5e3cSpl196000 	if (softs->io_slot == NULL) {
6198942c5e3cSpl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
6199942c5e3cSpl196000 		return (AACERR);
6200942c5e3cSpl196000 	}
6201942c5e3cSpl196000 	for (i = 0; i < softs->total_slots; i++)
6202942c5e3cSpl196000 		softs->io_slot[i].index = i;
6203942c5e3cSpl196000 	softs->free_io_slot_head = NULL;
6204942c5e3cSpl196000 	softs->total_fibs = 0;
6205942c5e3cSpl196000 	return (AACOK);
6206942c5e3cSpl196000 }
6207942c5e3cSpl196000 
6208942c5e3cSpl196000 static void
aac_destroy_slots(struct aac_softstate * softs)6209942c5e3cSpl196000 aac_destroy_slots(struct aac_softstate *softs)
6210942c5e3cSpl196000 {
6211942c5e3cSpl196000 	ASSERT(softs->free_io_slot_head == NULL);
6212942c5e3cSpl196000 
6213942c5e3cSpl196000 	kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
6214942c5e3cSpl196000 	    softs->total_slots);
6215942c5e3cSpl196000 	softs->io_slot = NULL;
6216942c5e3cSpl196000 	softs->total_slots = 0;
6217942c5e3cSpl196000 }
6218942c5e3cSpl196000 
6219942c5e3cSpl196000 struct aac_slot *
aac_get_slot(struct aac_softstate * softs)6220942c5e3cSpl196000 aac_get_slot(struct aac_softstate *softs)
6221942c5e3cSpl196000 {
6222942c5e3cSpl196000 	struct aac_slot *slotp;
6223942c5e3cSpl196000 
6224942c5e3cSpl196000 	if ((slotp = softs->free_io_slot_head) != NULL) {
6225942c5e3cSpl196000 		softs->free_io_slot_head = slotp->next;
6226942c5e3cSpl196000 		slotp->next = NULL;
6227942c5e3cSpl196000 	}
6228942c5e3cSpl196000 	return (slotp);
6229942c5e3cSpl196000 }
6230942c5e3cSpl196000 
6231942c5e3cSpl196000 static void
aac_release_slot(struct aac_softstate * softs,struct aac_slot * slotp)6232942c5e3cSpl196000 aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
6233942c5e3cSpl196000 {
6234942c5e3cSpl196000 	ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
6235942c5e3cSpl196000 	ASSERT(slotp == &softs->io_slot[slotp->index]);
6236942c5e3cSpl196000 
6237942c5e3cSpl196000 	slotp->acp = NULL;
6238942c5e3cSpl196000 	slotp->next = softs->free_io_slot_head;
6239942c5e3cSpl196000 	softs->free_io_slot_head = slotp;
6240942c5e3cSpl196000 }
6241942c5e3cSpl196000 
6242942c5e3cSpl196000 int
aac_do_io(struct aac_softstate * softs,struct aac_cmd * acp)6243942c5e3cSpl196000 aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
6244942c5e3cSpl196000 {
6245942c5e3cSpl196000 	if (aac_bind_io(softs, acp) == AACOK)
6246942c5e3cSpl196000 		aac_start_io(softs, acp);
6247942c5e3cSpl196000 	else
6248942c5e3cSpl196000 		aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
6249942c5e3cSpl196000 
6250942c5e3cSpl196000 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
6251942c5e3cSpl196000 		return (TRAN_ACCEPT);
6252942c5e3cSpl196000 	/*
6253942c5e3cSpl196000 	 * Because sync FIB is always 512 bytes and used for critical
6254942c5e3cSpl196000 	 * functions, async FIB is used for poll IO.
6255942c5e3cSpl196000 	 */
6256942c5e3cSpl196000 	if (acp->flags & AAC_CMD_NO_INTR) {
6257942c5e3cSpl196000 		if (aac_do_poll_io(softs, acp) == AACOK)
6258942c5e3cSpl196000 			return (TRAN_ACCEPT);
6259942c5e3cSpl196000 	} else {
6260942c5e3cSpl196000 		if (aac_do_sync_io(softs, acp) == AACOK)
6261942c5e3cSpl196000 			return (TRAN_ACCEPT);
6262942c5e3cSpl196000 	}
6263942c5e3cSpl196000 	return (TRAN_BADPKT);
6264942c5e3cSpl196000 }
6265942c5e3cSpl196000 
6266942c5e3cSpl196000 static int
aac_do_poll_io(struct aac_softstate * softs,struct aac_cmd * acp)6267942c5e3cSpl196000 aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
6268942c5e3cSpl196000 {
6269942c5e3cSpl196000 	int (*intr_handler)(struct aac_softstate *);
6270942c5e3cSpl196000 
6271942c5e3cSpl196000 	/*
6272942c5e3cSpl196000 	 * Interrupt is disabled, we have to poll the adapter by ourselves.
6273942c5e3cSpl196000 	 */
6274942c5e3cSpl196000 	intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
6275942c5e3cSpl196000 	    aac_process_intr_new : aac_process_intr_old;
6276942c5e3cSpl196000 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
6277942c5e3cSpl196000 		int i = AAC_POLL_TIME * 1000;
6278942c5e3cSpl196000 
6279942c5e3cSpl196000 		AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
6280942c5e3cSpl196000 		if (i == 0)
628158bc78c7SXin Chen 			aac_cmd_timeout(softs, acp);
6282942c5e3cSpl196000 	}
6283942c5e3cSpl196000 
6284942c5e3cSpl196000 	ddi_trigger_softintr(softs->softint_id);
6285942c5e3cSpl196000 
6286942c5e3cSpl196000 	if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
6287942c5e3cSpl196000 		return (AACOK);
6288942c5e3cSpl196000 	return (AACERR);
6289942c5e3cSpl196000 }
6290942c5e3cSpl196000 
6291942c5e3cSpl196000 static int
aac_do_sync_io(struct aac_softstate * softs,struct aac_cmd * acp)6292942c5e3cSpl196000 aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
6293942c5e3cSpl196000 {
6294942c5e3cSpl196000 	ASSERT(softs && acp);
6295942c5e3cSpl196000 
6296942c5e3cSpl196000 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
6297942c5e3cSpl196000 		cv_wait(&softs->event, &softs->io_lock);
6298942c5e3cSpl196000 
6299942c5e3cSpl196000 	if (acp->flags & AAC_CMD_CMPLT)
6300942c5e3cSpl196000 		return (AACOK);
6301942c5e3cSpl196000 	return (AACERR);
6302942c5e3cSpl196000 }
6303942c5e3cSpl196000 
6304942c5e3cSpl196000 static int
aac_dma_sync_ac(struct aac_cmd * acp)6305942c5e3cSpl196000 aac_dma_sync_ac(struct aac_cmd *acp)
6306942c5e3cSpl196000 {
6307942c5e3cSpl196000 	if (acp->buf_dma_handle) {
6308942c5e3cSpl196000 		if (acp->flags & AAC_CMD_BUF_WRITE) {
6309942c5e3cSpl196000 			if (acp->abp != NULL)
6310942c5e3cSpl196000 				ddi_rep_put8(acp->abh,
6311942c5e3cSpl196000 				    (uint8_t *)acp->bp->b_un.b_addr,
6312942c5e3cSpl196000 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6313942c5e3cSpl196000 				    DDI_DEV_AUTOINCR);
6314942c5e3cSpl196000 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6315942c5e3cSpl196000 			    DDI_DMA_SYNC_FORDEV);
6316942c5e3cSpl196000 		} else {
6317942c5e3cSpl196000 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
6318942c5e3cSpl196000 			    DDI_DMA_SYNC_FORCPU);
6319942c5e3cSpl196000 			if (aac_check_dma_handle(acp->buf_dma_handle) !=
6320942c5e3cSpl196000 			    DDI_SUCCESS)
6321942c5e3cSpl196000 				return (AACERR);
6322942c5e3cSpl196000 			if (acp->abp != NULL)
6323942c5e3cSpl196000 				ddi_rep_get8(acp->abh,
6324942c5e3cSpl196000 				    (uint8_t *)acp->bp->b_un.b_addr,
6325942c5e3cSpl196000 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
6326942c5e3cSpl196000 				    DDI_DEV_AUTOINCR);
6327942c5e3cSpl196000 		}
6328942c5e3cSpl196000 	}
6329942c5e3cSpl196000 	return (AACOK);
6330942c5e3cSpl196000 }
6331942c5e3cSpl196000 
6332942c5e3cSpl196000 /*
63330749e8deSXin Chen - Sun Microsystems - Beijing China  * Copy AIF from adapter to the empty AIF slot and inform AIF threads
63340749e8deSXin Chen - Sun Microsystems - Beijing China  */
63350749e8deSXin 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)63360749e8deSXin Chen - Sun Microsystems - Beijing China aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
63370749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib *fibp0, int fib_size0)
63380749e8deSXin Chen - Sun Microsystems - Beijing China {
63390749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib *fibp;	/* FIB in AIF queue */
63400749e8deSXin Chen - Sun Microsystems - Beijing China 	int fib_size;
63410749e8deSXin Chen - Sun Microsystems - Beijing China 	uint16_t fib_command;
63420749e8deSXin Chen - Sun Microsystems - Beijing China 	int current, next;
63430749e8deSXin Chen - Sun Microsystems - Beijing China 
63440749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Ignore non AIF messages */
63450749e8deSXin Chen - Sun Microsystems - Beijing China 	fib_command = ddi_get16(acc, &fibp0->Header.Command);
63460749e8deSXin Chen - Sun Microsystems - Beijing China 	if (fib_command != AifRequest) {
63470749e8deSXin Chen - Sun Microsystems - Beijing China 		cmn_err(CE_WARN, "!Unknown command from controller");
63480749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
63490749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63500749e8deSXin Chen - Sun Microsystems - Beijing China 
63510749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
63520749e8deSXin Chen - Sun Microsystems - Beijing China 
63530749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Save AIF */
63540749e8deSXin Chen - Sun Microsystems - Beijing China 	fibp = &softs->aifq[softs->aifq_idx].d;
63550749e8deSXin Chen - Sun Microsystems - Beijing China 	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
63560749e8deSXin Chen - Sun Microsystems - Beijing China 	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
63570749e8deSXin Chen - Sun Microsystems - Beijing China 	    DDI_DEV_AUTOINCR);
63580749e8deSXin Chen - Sun Microsystems - Beijing China 
63590749e8deSXin Chen - Sun Microsystems - Beijing China 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
63600749e8deSXin Chen - Sun Microsystems - Beijing China 		ddi_fm_service_impact(softs->devinfo_p,
63610749e8deSXin Chen - Sun Microsystems - Beijing China 		    DDI_SERVICE_UNAFFECTED);
63620749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->aifq_mutex);
63630749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
63640749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63650749e8deSXin Chen - Sun Microsystems - Beijing China 
63660749e8deSXin Chen - Sun Microsystems - Beijing China 	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
63670749e8deSXin Chen - Sun Microsystems - Beijing China 
63680749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Modify AIF contexts */
63690749e8deSXin Chen - Sun Microsystems - Beijing China 	current = softs->aifq_idx;
63700749e8deSXin Chen - Sun Microsystems - Beijing China 	next = (current + 1) % AAC_AIFQ_LENGTH;
63710749e8deSXin Chen - Sun Microsystems - Beijing China 	if (next == 0) {
63720749e8deSXin Chen - Sun Microsystems - Beijing China 		struct aac_fib_context *ctx_p;
63730749e8deSXin Chen - Sun Microsystems - Beijing China 
63740749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->aifq_wrap = 1;
63750749e8deSXin Chen - Sun Microsystems - Beijing China 		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
63760749e8deSXin Chen - Sun Microsystems - Beijing China 			if (next == ctx_p->ctx_idx) {
63770749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
63780749e8deSXin Chen - Sun Microsystems - Beijing China 			} else if (current == ctx_p->ctx_idx &&
63790749e8deSXin Chen - Sun Microsystems - Beijing China 			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
63800749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_idx = next;
63810749e8deSXin Chen - Sun Microsystems - Beijing China 				ctx_p->ctx_overrun++;
63820749e8deSXin Chen - Sun Microsystems - Beijing China 			}
63830749e8deSXin Chen - Sun Microsystems - Beijing China 		}
63840749e8deSXin Chen - Sun Microsystems - Beijing China 	}
63850749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->aifq_idx = next;
63860749e8deSXin Chen - Sun Microsystems - Beijing China 
63870749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Wakeup AIF threads */
63880749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_broadcast(&softs->aifq_cv);
63890749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
63900749e8deSXin Chen - Sun Microsystems - Beijing China 
63910749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Wakeup event thread to handle aif */
63920749e8deSXin Chen - Sun Microsystems - Beijing China 	aac_event_disp(softs, AAC_EVENT_AIF);
63930749e8deSXin Chen - Sun Microsystems - Beijing China }
63940749e8deSXin Chen - Sun Microsystems - Beijing China 
63950749e8deSXin Chen - Sun Microsystems - Beijing China static int
aac_return_aif_common(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)63960749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
63970749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
63980749e8deSXin Chen - Sun Microsystems - Beijing China {
63990749e8deSXin Chen - Sun Microsystems - Beijing China 	int current;
64000749e8deSXin Chen - Sun Microsystems - Beijing China 
64010749e8deSXin Chen - Sun Microsystems - Beijing China 	current = ctx->ctx_idx;
64020749e8deSXin Chen - Sun Microsystems - Beijing China 	if (current == softs->aifq_idx &&
64030749e8deSXin Chen - Sun Microsystems - Beijing China 	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
64040749e8deSXin Chen - Sun Microsystems - Beijing China 		return (EAGAIN); /* Empty */
64050749e8deSXin Chen - Sun Microsystems - Beijing China 
64060749e8deSXin Chen - Sun Microsystems - Beijing China 	*fibpp = &softs->aifq[current].d;
64070749e8deSXin Chen - Sun Microsystems - Beijing China 
64080749e8deSXin Chen - Sun Microsystems - Beijing China 	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
64090749e8deSXin Chen - Sun Microsystems - Beijing China 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
64100749e8deSXin Chen - Sun Microsystems - Beijing China 	return (0);
64110749e8deSXin Chen - Sun Microsystems - Beijing China }
64120749e8deSXin Chen - Sun Microsystems - Beijing China 
64130749e8deSXin Chen - Sun Microsystems - Beijing China int
aac_return_aif(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)64140749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
64150749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
64160749e8deSXin Chen - Sun Microsystems - Beijing China {
64170749e8deSXin Chen - Sun Microsystems - Beijing China 	int rval;
64180749e8deSXin Chen - Sun Microsystems - Beijing China 
64190749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
64200749e8deSXin Chen - Sun Microsystems - Beijing China 	rval = aac_return_aif_common(softs, ctx, fibpp);
64210749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
64220749e8deSXin Chen - Sun Microsystems - Beijing China 	return (rval);
64230749e8deSXin Chen - Sun Microsystems - Beijing China }
64240749e8deSXin Chen - Sun Microsystems - Beijing China 
64250749e8deSXin Chen - Sun Microsystems - Beijing China int
aac_return_aif_wait(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)64260749e8deSXin Chen - Sun Microsystems - Beijing China aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
64270749e8deSXin Chen - Sun Microsystems - Beijing China     struct aac_fib **fibpp)
64280749e8deSXin Chen - Sun Microsystems - Beijing China {
64290749e8deSXin Chen - Sun Microsystems - Beijing China 	int rval;
64300749e8deSXin Chen - Sun Microsystems - Beijing China 
64310749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->aifq_mutex);
64320749e8deSXin Chen - Sun Microsystems - Beijing China 	rval = aac_return_aif_common(softs, ctx, fibpp);
64330749e8deSXin Chen - Sun Microsystems - Beijing China 	if (rval == EAGAIN) {
64340749e8deSXin Chen - Sun Microsystems - Beijing China 		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
64350749e8deSXin Chen - Sun Microsystems - Beijing China 		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
64360749e8deSXin Chen - Sun Microsystems - Beijing China 	}
64370749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->aifq_mutex);
64380749e8deSXin Chen - Sun Microsystems - Beijing China 	return ((rval > 0) ? 0 : EINTR);
64390749e8deSXin Chen - Sun Microsystems - Beijing China }
64400749e8deSXin Chen - Sun Microsystems - Beijing China 
64410749e8deSXin Chen - Sun Microsystems - Beijing China /*
6442942c5e3cSpl196000  * The following function comes from Adaptec:
6443942c5e3cSpl196000  *
6444942c5e3cSpl196000  * When driver sees a particular event that means containers are changed, it
6445942c5e3cSpl196000  * will rescan containers. However a change may not be complete until some
6446942c5e3cSpl196000  * other event is received. For example, creating or deleting an array will
6447942c5e3cSpl196000  * incur as many as six AifEnConfigChange events which would generate six
6448942c5e3cSpl196000  * container rescans. To diminish rescans, driver set a flag to wait for
6449942c5e3cSpl196000  * another particular event. When sees that events come in, it will do rescan.
6450942c5e3cSpl196000  */
6451942c5e3cSpl196000 static int
aac_handle_aif(struct aac_softstate * softs,struct aac_aif_command * aif)64520749e8deSXin Chen - Sun Microsystems - Beijing China aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
6453942c5e3cSpl196000 {
6454942c5e3cSpl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
6455942c5e3cSpl196000 	int en_type;
6456942c5e3cSpl196000 	int devcfg_needed;
64573fced439Szhongyan gu - Sun Microsystems - Beijing China 	int cid;
64583fced439Szhongyan gu - Sun Microsystems - Beijing China 	uint32_t bus_id, tgt_id;
64593fced439Szhongyan gu - Sun Microsystems - Beijing China 	enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
6460942c5e3cSpl196000 
6461942c5e3cSpl196000 	devcfg_needed = 0;
6462942c5e3cSpl196000 	en_type = LE_32((uint32_t)aif->data.EN.type);
6463942c5e3cSpl196000 
6464942c5e3cSpl196000 	switch (LE_32((uint32_t)aif->command)) {
6465942c5e3cSpl196000 	case AifCmdDriverNotify: {
64663fced439Szhongyan gu - Sun Microsystems - Beijing China 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6467942c5e3cSpl196000 
6468942c5e3cSpl196000 		switch (en_type) {
6469942c5e3cSpl196000 		case AifDenMorphComplete:
6470942c5e3cSpl196000 		case AifDenVolumeExtendComplete:
647158bc78c7SXin Chen 			if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
6472942c5e3cSpl196000 				softs->devcfg_wait_on = AifEnConfigChange;
6473942c5e3cSpl196000 			break;
6474942c5e3cSpl196000 		}
6475942c5e3cSpl196000 		if (softs->devcfg_wait_on == en_type)
6476942c5e3cSpl196000 			devcfg_needed = 1;
6477942c5e3cSpl196000 		break;
6478942c5e3cSpl196000 	}
6479942c5e3cSpl196000 
6480942c5e3cSpl196000 	case AifCmdEventNotify:
64813fced439Szhongyan gu - Sun Microsystems - Beijing China 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
6482942c5e3cSpl196000 		switch (en_type) {
6483942c5e3cSpl196000 		case AifEnAddContainer:
6484942c5e3cSpl196000 		case AifEnDeleteContainer:
6485942c5e3cSpl196000 			softs->devcfg_wait_on = AifEnConfigChange;
6486942c5e3cSpl196000 			break;
6487942c5e3cSpl196000 		case AifEnContainerChange:
6488942c5e3cSpl196000 			if (!softs->devcfg_wait_on)
6489942c5e3cSpl196000 				softs->devcfg_wait_on = AifEnConfigChange;
6490942c5e3cSpl196000 			break;
6491942c5e3cSpl196000 		case AifEnContainerEvent:
6492942c5e3cSpl196000 			if (ddi_get32(acc, &aif-> \
6493942c5e3cSpl196000 			    data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
6494942c5e3cSpl196000 				devcfg_needed = 1;
6495942c5e3cSpl196000 			break;
64963fced439Szhongyan gu - Sun Microsystems - Beijing China 		case AifEnAddJBOD:
64973fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD))
64983fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (AACERR);
64993fced439Szhongyan gu - Sun Microsystems - Beijing China 			event = AAC_CFG_ADD;
65003fced439Szhongyan gu - Sun Microsystems - Beijing China 			bus_id = (cid >> 24) & 0xf;
65013fced439Szhongyan gu - Sun Microsystems - Beijing China 			tgt_id = cid & 0xffff;
65023fced439Szhongyan gu - Sun Microsystems - Beijing China 			break;
65033fced439Szhongyan gu - Sun Microsystems - Beijing China 		case AifEnDeleteJBOD:
65043fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD))
65053fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (AACERR);
65063fced439Szhongyan gu - Sun Microsystems - Beijing China 			event = AAC_CFG_DELETE;
65073fced439Szhongyan gu - Sun Microsystems - Beijing China 			bus_id = (cid >> 24) & 0xf;
65083fced439Szhongyan gu - Sun Microsystems - Beijing China 			tgt_id = cid & 0xffff;
65093fced439Szhongyan gu - Sun Microsystems - Beijing China 			break;
6510942c5e3cSpl196000 		}
6511942c5e3cSpl196000 		if (softs->devcfg_wait_on == en_type)
6512942c5e3cSpl196000 			devcfg_needed = 1;
6513942c5e3cSpl196000 		break;
6514942c5e3cSpl196000 
6515942c5e3cSpl196000 	case AifCmdJobProgress:
6516942c5e3cSpl196000 		if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
6517942c5e3cSpl196000 			int pr_status;
6518942c5e3cSpl196000 			uint32_t pr_ftick, pr_ctick;
6519942c5e3cSpl196000 
6520942c5e3cSpl196000 			pr_status = LE_32((uint32_t)aif->data.PR[0].status);
6521942c5e3cSpl196000 			pr_ctick = LE_32(aif->data.PR[0].currentTick);
6522942c5e3cSpl196000 			pr_ftick = LE_32(aif->data.PR[0].finalTick);
6523942c5e3cSpl196000 
6524942c5e3cSpl196000 			if ((pr_ctick == pr_ftick) ||
6525942c5e3cSpl196000 			    (pr_status == AifJobStsSuccess))
6526942c5e3cSpl196000 				softs->devcfg_wait_on = AifEnContainerChange;
6527942c5e3cSpl196000 			else if ((pr_ctick == 0) &&
6528942c5e3cSpl196000 			    (pr_status == AifJobStsRunning))
6529942c5e3cSpl196000 				softs->devcfg_wait_on = AifEnContainerChange;
6530942c5e3cSpl196000 		}
6531942c5e3cSpl196000 		break;
6532942c5e3cSpl196000 	}
6533942c5e3cSpl196000 
653458bc78c7SXin Chen 	if (devcfg_needed) {
653558bc78c7SXin Chen 		softs->devcfg_wait_on = 0;
6536942c5e3cSpl196000 		(void) aac_probe_containers(softs);
653758bc78c7SXin Chen 	}
6538942c5e3cSpl196000 
65393fced439Szhongyan gu - Sun Microsystems - Beijing China 	if (event != AAC_CFG_NULL_EXIST) {
65403fced439Szhongyan gu - Sun Microsystems - Beijing China 		ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
65413fced439Szhongyan gu - Sun Microsystems - Beijing China 		(void) aac_probe_jbod(softs,
65423fced439Szhongyan gu - Sun Microsystems - Beijing China 		    AAC_P2VTGT(softs, bus_id, tgt_id), event);
65433fced439Szhongyan gu - Sun Microsystems - Beijing China 	}
6544942c5e3cSpl196000 	return (AACOK);
6545942c5e3cSpl196000 }
6546942c5e3cSpl196000 
65470749e8deSXin Chen - Sun Microsystems - Beijing China 
65480749e8deSXin Chen - Sun Microsystems - Beijing China /*
65490749e8deSXin Chen - Sun Microsystems - Beijing China  * Check and handle AIF events
65500749e8deSXin Chen - Sun Microsystems - Beijing China  */
65510749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_aif_event(struct aac_softstate * softs)65520749e8deSXin Chen - Sun Microsystems - Beijing China aac_aif_event(struct aac_softstate *softs)
65530749e8deSXin Chen - Sun Microsystems - Beijing China {
65540749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_fib *fibp;
65550749e8deSXin Chen - Sun Microsystems - Beijing China 
65560749e8deSXin Chen - Sun Microsystems - Beijing China 	/*CONSTCOND*/
65570749e8deSXin Chen - Sun Microsystems - Beijing China 	while (1) {
65580749e8deSXin Chen - Sun Microsystems - Beijing China 		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
65590749e8deSXin Chen - Sun Microsystems - Beijing China 			break; /* No more AIFs to handle, end loop */
65600749e8deSXin Chen - Sun Microsystems - Beijing China 
65610749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AIF overrun, array create/delete may missed. */
65620749e8deSXin Chen - Sun Microsystems - Beijing China 		if (softs->aifctx.ctx_overrun) {
65630749e8deSXin Chen - Sun Microsystems - Beijing China 			softs->aifctx.ctx_overrun = 0;
65640749e8deSXin Chen - Sun Microsystems - Beijing China 		}
65650749e8deSXin Chen - Sun Microsystems - Beijing China 
65660749e8deSXin Chen - Sun Microsystems - Beijing China 		/* AIF received, handle it */
65670749e8deSXin Chen - Sun Microsystems - Beijing China 		struct aac_aif_command *aifp =
65680749e8deSXin Chen - Sun Microsystems - Beijing China 		    (struct aac_aif_command *)&fibp->data[0];
65690749e8deSXin Chen - Sun Microsystems - Beijing China 		uint32_t aif_command = LE_32((uint32_t)aifp->command);
65700749e8deSXin Chen - Sun Microsystems - Beijing China 
65710749e8deSXin Chen - Sun Microsystems - Beijing China 		if (aif_command == AifCmdDriverNotify ||
65720749e8deSXin Chen - Sun Microsystems - Beijing China 		    aif_command == AifCmdEventNotify ||
65730749e8deSXin Chen - Sun Microsystems - Beijing China 		    aif_command == AifCmdJobProgress)
65740749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_handle_aif(softs, aifp);
65750749e8deSXin Chen - Sun Microsystems - Beijing China 	}
65760749e8deSXin Chen - Sun Microsystems - Beijing China }
65770749e8deSXin Chen - Sun Microsystems - Beijing China 
6578942c5e3cSpl196000 /*
6579942c5e3cSpl196000  * Timeout recovery
6580942c5e3cSpl196000  */
658158bc78c7SXin Chen /*ARGSUSED*/
6582942c5e3cSpl196000 static void
aac_cmd_timeout(struct aac_softstate * softs,struct aac_cmd * acp)658358bc78c7SXin Chen aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
6584942c5e3cSpl196000 {
658558bc78c7SXin Chen #ifdef DEBUG
658658bc78c7SXin Chen 	acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
658758bc78c7SXin Chen 	AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
658858bc78c7SXin Chen 	AACDB_PRINT_FIB(softs, acp->slotp);
658958bc78c7SXin Chen #endif
659058bc78c7SXin Chen 
6591942c5e3cSpl196000 	/*
6592942c5e3cSpl196000 	 * Besides the firmware in unhealthy state, an overloaded
6593942c5e3cSpl196000 	 * adapter may also incur pkt timeout.
6594942c5e3cSpl196000 	 * There is a chance for an adapter with a slower IOP to take
6595942c5e3cSpl196000 	 * longer than 60 seconds to process the commands, such as when
6596942c5e3cSpl196000 	 * to perform IOs. So the adapter is doing a build on a RAID-5
6597942c5e3cSpl196000 	 * while being required longer completion times should be
6598942c5e3cSpl196000 	 * tolerated.
6599942c5e3cSpl196000 	 */
660058bc78c7SXin Chen 	switch (aac_do_reset(softs)) {
660158bc78c7SXin Chen 	case AAC_IOP_RESET_SUCCEED:
660258bc78c7SXin Chen 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
6603942c5e3cSpl196000 		aac_start_waiting_io(softs);
660458bc78c7SXin Chen 		break;
660558bc78c7SXin Chen 	case AAC_IOP_RESET_FAILED:
6606942c5e3cSpl196000 		/* Abort all waiting cmds when adapter is dead */
660758bc78c7SXin Chen 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
660858bc78c7SXin Chen 		break;
660958bc78c7SXin Chen 	case AAC_IOP_RESET_ABNORMAL:
661058bc78c7SXin Chen 		aac_start_waiting_io(softs);
6611942c5e3cSpl196000 	}
6612942c5e3cSpl196000 }
6613942c5e3cSpl196000 
6614942c5e3cSpl196000 /*
6615942c5e3cSpl196000  * The following function comes from Adaptec:
6616942c5e3cSpl196000  *
6617942c5e3cSpl196000  * Time sync. command added to synchronize time with firmware every 30
6618942c5e3cSpl196000  * minutes (required for correct AIF timestamps etc.)
6619942c5e3cSpl196000  */
66200749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_sync_tick(struct aac_softstate * softs)6621942c5e3cSpl196000 aac_sync_tick(struct aac_softstate *softs)
6622942c5e3cSpl196000 {
6623f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_acc_handle_t acc;
6624f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	int rval;
6625942c5e3cSpl196000 
66260749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66270749e8deSXin Chen - Sun Microsystems - Beijing China 	ASSERT(softs->time_sync <= softs->timebase);
66280749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_sync = 0;
66290749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
66300749e8deSXin Chen - Sun Microsystems - Beijing China 
6631f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* Time sync. with firmware every AAC_SYNC_TICK */
6632f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
6633f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	acc = softs->sync_ac.slotp->fib_acc_handle;
6634f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 
6635f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
6636f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	    ddi_get_time());
6637f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
6638f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
66390749e8deSXin Chen - Sun Microsystems - Beijing China 
66400749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66410749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_sync = softs->timebase;
66420749e8deSXin Chen - Sun Microsystems - Beijing China 	if (rval != AACOK)
66430749e8deSXin Chen - Sun Microsystems - Beijing China 		/* retry shortly */
66440749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->time_sync += aac_tick << 1;
66450749e8deSXin Chen - Sun Microsystems - Beijing China 	else
66460749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->time_sync += AAC_SYNC_TICK;
66470749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
6648942c5e3cSpl196000 }
6649942c5e3cSpl196000 
66500749e8deSXin Chen - Sun Microsystems - Beijing China /*
66510749e8deSXin Chen - Sun Microsystems - Beijing China  * Timeout checking and handling
66520749e8deSXin Chen - Sun Microsystems - Beijing China  */
6653942c5e3cSpl196000 static void
aac_daemon(struct aac_softstate * softs)66540749e8deSXin Chen - Sun Microsystems - Beijing China aac_daemon(struct aac_softstate *softs)
6655942c5e3cSpl196000 {
66560749e8deSXin Chen - Sun Microsystems - Beijing China 	int time_out; /* set if timeout happened */
66570749e8deSXin Chen - Sun Microsystems - Beijing China 	int time_adjust;
66580749e8deSXin Chen - Sun Microsystems - Beijing China 	uint32_t softs_timebase;
66590749e8deSXin Chen - Sun Microsystems - Beijing China 
66600749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66610749e8deSXin Chen - Sun Microsystems - Beijing China 	ASSERT(softs->time_out <= softs->timebase);
66620749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_out = 0;
66630749e8deSXin Chen - Sun Microsystems - Beijing China 	softs_timebase = softs->timebase;
66640749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
66650749e8deSXin Chen - Sun Microsystems - Beijing China 
66660749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Check slots for timeout pkts */
66670749e8deSXin Chen - Sun Microsystems - Beijing China 	time_adjust = 0;
66680749e8deSXin Chen - Sun Microsystems - Beijing China 	do {
6669942c5e3cSpl196000 		struct aac_cmd *acp;
6670942c5e3cSpl196000 
66710749e8deSXin Chen - Sun Microsystems - Beijing China 		time_out = 0;
66720749e8deSXin Chen - Sun Microsystems - Beijing China 		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
66730749e8deSXin Chen - Sun Microsystems - Beijing China 			if (acp->timeout == 0)
66740749e8deSXin Chen - Sun Microsystems - Beijing China 				continue;
66750749e8deSXin Chen - Sun Microsystems - Beijing China 
66760749e8deSXin Chen - Sun Microsystems - Beijing China 			/*
66770749e8deSXin Chen - Sun Microsystems - Beijing China 			 * If timeout happened, update outstanding cmds
66780749e8deSXin Chen - Sun Microsystems - Beijing China 			 * to be checked later again.
66790749e8deSXin Chen - Sun Microsystems - Beijing China 			 */
66800749e8deSXin Chen - Sun Microsystems - Beijing China 			if (time_adjust) {
66810749e8deSXin Chen - Sun Microsystems - Beijing China 				acp->timeout += time_adjust;
66820749e8deSXin Chen - Sun Microsystems - Beijing China 				continue;
66830749e8deSXin Chen - Sun Microsystems - Beijing China 			}
66840749e8deSXin Chen - Sun Microsystems - Beijing China 
66850749e8deSXin Chen - Sun Microsystems - Beijing China 			if (acp->timeout <= softs_timebase) {
66860749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_cmd_timeout(softs, acp);
66870749e8deSXin Chen - Sun Microsystems - Beijing China 				time_out = 1;
66880749e8deSXin Chen - Sun Microsystems - Beijing China 				time_adjust = aac_tick * drv_usectohz(1000000);
66890749e8deSXin Chen - Sun Microsystems - Beijing China 				break; /* timeout happened */
66900749e8deSXin Chen - Sun Microsystems - Beijing China 			} else {
66910749e8deSXin Chen - Sun Microsystems - Beijing China 				break; /* no timeout */
66920749e8deSXin Chen - Sun Microsystems - Beijing China 			}
66930749e8deSXin Chen - Sun Microsystems - Beijing China 		}
66940749e8deSXin Chen - Sun Microsystems - Beijing China 	} while (time_out);
66950749e8deSXin Chen - Sun Microsystems - Beijing China 
66960749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
66970749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->time_out = softs->timebase + aac_tick;
66980749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
66990749e8deSXin Chen - Sun Microsystems - Beijing China }
67000749e8deSXin Chen - Sun Microsystems - Beijing China 
67010749e8deSXin Chen - Sun Microsystems - Beijing China /*
67020749e8deSXin Chen - Sun Microsystems - Beijing China  * The event thread handles various tasks serially for the other parts of
67030749e8deSXin Chen - Sun Microsystems - Beijing China  * the driver, so that they can run fast.
67040749e8deSXin Chen - Sun Microsystems - Beijing China  */
67050749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_event_thread(struct aac_softstate * softs)67060749e8deSXin Chen - Sun Microsystems - Beijing China aac_event_thread(struct aac_softstate *softs)
67070749e8deSXin Chen - Sun Microsystems - Beijing China {
67080749e8deSXin Chen - Sun Microsystems - Beijing China 	int run = 1;
67090749e8deSXin Chen - Sun Microsystems - Beijing China 
67100749e8deSXin Chen - Sun Microsystems - Beijing China 	DBCALLED(softs, 1);
67110749e8deSXin Chen - Sun Microsystems - Beijing China 
67120749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
67130749e8deSXin Chen - Sun Microsystems - Beijing China 	while (run) {
67140749e8deSXin Chen - Sun Microsystems - Beijing China 		int events;
67150749e8deSXin Chen - Sun Microsystems - Beijing China 
67160749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((events = softs->events) == 0) {
67170749e8deSXin Chen - Sun Microsystems - Beijing China 			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
67180749e8deSXin Chen - Sun Microsystems - Beijing China 			events = softs->events;
67190749e8deSXin Chen - Sun Microsystems - Beijing China 		}
67200749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->events = 0;
67210749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->ev_lock);
6722942c5e3cSpl196000 
6723942c5e3cSpl196000 		mutex_enter(&softs->io_lock);
67240749e8deSXin Chen - Sun Microsystems - Beijing China 		if ((softs->state & AAC_STATE_RUN) &&
67250749e8deSXin Chen - Sun Microsystems - Beijing China 		    (softs->state & AAC_STATE_DEAD) == 0) {
67260749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_TIMEOUT)
67270749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_daemon(softs);
67280749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_SYNCTICK)
67290749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_sync_tick(softs);
67300749e8deSXin Chen - Sun Microsystems - Beijing China 			if (events & AAC_EVENT_AIF)
67310749e8deSXin Chen - Sun Microsystems - Beijing China 				aac_aif_event(softs);
67320749e8deSXin Chen - Sun Microsystems - Beijing China 		} else {
67330749e8deSXin Chen - Sun Microsystems - Beijing China 			run = 0;
6734942c5e3cSpl196000 		}
6735942c5e3cSpl196000 		mutex_exit(&softs->io_lock);
67360749e8deSXin Chen - Sun Microsystems - Beijing China 
67370749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_enter(&softs->ev_lock);
67380749e8deSXin Chen - Sun Microsystems - Beijing China 	}
67390749e8deSXin Chen - Sun Microsystems - Beijing China 
67400749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_signal(&softs->event_wait_cv);
67410749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
67420749e8deSXin Chen - Sun Microsystems - Beijing China }
67430749e8deSXin Chen - Sun Microsystems - Beijing China 
67440749e8deSXin Chen - Sun Microsystems - Beijing China /*
67450749e8deSXin Chen - Sun Microsystems - Beijing China  * Internal timer. It is only responsbile for time counting and report time
67460749e8deSXin Chen - Sun Microsystems - Beijing China  * related events. Events handling is done by aac_event_thread(), so that
67470749e8deSXin Chen - Sun Microsystems - Beijing China  * the timer itself could be as precise as possible.
67480749e8deSXin Chen - Sun Microsystems - Beijing China  */
67490749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_timer(void * arg)67500749e8deSXin Chen - Sun Microsystems - Beijing China aac_timer(void *arg)
67510749e8deSXin Chen - Sun Microsystems - Beijing China {
67520749e8deSXin Chen - Sun Microsystems - Beijing China 	struct aac_softstate *softs = arg;
67530749e8deSXin Chen - Sun Microsystems - Beijing China 	int events = 0;
67540749e8deSXin Chen - Sun Microsystems - Beijing China 
67550749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->time_mutex);
67560749e8deSXin Chen - Sun Microsystems - Beijing China 
67570749e8deSXin Chen - Sun Microsystems - Beijing China 	/* If timer is being stopped, exit */
67580749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->timeout_id) {
67590749e8deSXin Chen - Sun Microsystems - Beijing China 		softs->timeout_id = timeout(aac_timer, (void *)softs,
67600749e8deSXin Chen - Sun Microsystems - Beijing China 		    (aac_tick * drv_usectohz(1000000)));
67610749e8deSXin Chen - Sun Microsystems - Beijing China 	} else {
67620749e8deSXin Chen - Sun Microsystems - Beijing China 		mutex_exit(&softs->time_mutex);
67630749e8deSXin Chen - Sun Microsystems - Beijing China 		return;
67640749e8deSXin Chen - Sun Microsystems - Beijing China 	}
67650749e8deSXin Chen - Sun Microsystems - Beijing China 
67660749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Time counting */
67670749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->timebase += aac_tick;
67680749e8deSXin Chen - Sun Microsystems - Beijing China 
67690749e8deSXin Chen - Sun Microsystems - Beijing China 	/* Check time related events */
67700749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->time_out && softs->time_out <= softs->timebase)
67710749e8deSXin Chen - Sun Microsystems - Beijing China 		events |= AAC_EVENT_TIMEOUT;
67720749e8deSXin Chen - Sun Microsystems - Beijing China 	if (softs->time_sync && softs->time_sync <= softs->timebase)
67730749e8deSXin Chen - Sun Microsystems - Beijing China 		events |= AAC_EVENT_SYNCTICK;
67740749e8deSXin Chen - Sun Microsystems - Beijing China 
67750749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->time_mutex);
67760749e8deSXin Chen - Sun Microsystems - Beijing China 
67770749e8deSXin Chen - Sun Microsystems - Beijing China 	if (events)
67780749e8deSXin Chen - Sun Microsystems - Beijing China 		aac_event_disp(softs, events);
67790749e8deSXin Chen - Sun Microsystems - Beijing China }
67800749e8deSXin Chen - Sun Microsystems - Beijing China 
67810749e8deSXin Chen - Sun Microsystems - Beijing China /*
67820749e8deSXin Chen - Sun Microsystems - Beijing China  * Dispatch events to daemon thread for handling
67830749e8deSXin Chen - Sun Microsystems - Beijing China  */
67840749e8deSXin Chen - Sun Microsystems - Beijing China static void
aac_event_disp(struct aac_softstate * softs,int events)67850749e8deSXin Chen - Sun Microsystems - Beijing China aac_event_disp(struct aac_softstate *softs, int events)
67860749e8deSXin Chen - Sun Microsystems - Beijing China {
67870749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->ev_lock);
67880749e8deSXin Chen - Sun Microsystems - Beijing China 	softs->events |= events;
67890749e8deSXin Chen - Sun Microsystems - Beijing China 	cv_broadcast(&softs->event_disp_cv);
67900749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_exit(&softs->ev_lock);
6791942c5e3cSpl196000 }
6792942c5e3cSpl196000 
6793942c5e3cSpl196000 /*
6794942c5e3cSpl196000  * Architecture dependent functions
6795942c5e3cSpl196000  */
6796942c5e3cSpl196000 static int
aac_rx_get_fwstatus(struct aac_softstate * softs)6797942c5e3cSpl196000 aac_rx_get_fwstatus(struct aac_softstate *softs)
6798942c5e3cSpl196000 {
6799942c5e3cSpl196000 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6800942c5e3cSpl196000 }
6801942c5e3cSpl196000 
6802942c5e3cSpl196000 static int
aac_rx_get_mailbox(struct aac_softstate * softs,int mb)6803942c5e3cSpl196000 aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
6804942c5e3cSpl196000 {
6805942c5e3cSpl196000 	return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
6806942c5e3cSpl196000 }
6807942c5e3cSpl196000 
6808942c5e3cSpl196000 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)6809942c5e3cSpl196000 aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6810942c5e3cSpl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6811942c5e3cSpl196000 {
6812942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
6813942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
6814942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
6815942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
6816942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
6817942c5e3cSpl196000 }
6818942c5e3cSpl196000 
6819942c5e3cSpl196000 static int
aac_rkt_get_fwstatus(struct aac_softstate * softs)6820942c5e3cSpl196000 aac_rkt_get_fwstatus(struct aac_softstate *softs)
6821942c5e3cSpl196000 {
6822942c5e3cSpl196000 	return (PCI_MEM_GET32(softs, AAC_OMR0));
6823942c5e3cSpl196000 }
6824942c5e3cSpl196000 
6825942c5e3cSpl196000 static int
aac_rkt_get_mailbox(struct aac_softstate * softs,int mb)6826942c5e3cSpl196000 aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
6827942c5e3cSpl196000 {
6828942c5e3cSpl196000 	return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
6829942c5e3cSpl196000 }
6830942c5e3cSpl196000 
6831942c5e3cSpl196000 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)6832942c5e3cSpl196000 aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
6833942c5e3cSpl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
6834942c5e3cSpl196000 {
6835942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
6836942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
6837942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
6838942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
6839942c5e3cSpl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
6840942c5e3cSpl196000 }
6841942c5e3cSpl196000 
6842942c5e3cSpl196000 /*
6843942c5e3cSpl196000  * cb_ops functions
6844942c5e3cSpl196000  */
6845942c5e3cSpl196000 static int
aac_open(dev_t * devp,int flag,int otyp,cred_t * cred)6846942c5e3cSpl196000 aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
6847942c5e3cSpl196000 {
6848942c5e3cSpl196000 	struct aac_softstate *softs;
6849942c5e3cSpl196000 	int minor0, minor;
6850942c5e3cSpl196000 	int instance;
6851942c5e3cSpl196000 
6852942c5e3cSpl196000 	DBCALLED(NULL, 2);
6853942c5e3cSpl196000 
6854942c5e3cSpl196000 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6855942c5e3cSpl196000 		return (EINVAL);
6856942c5e3cSpl196000 
6857942c5e3cSpl196000 	minor0 = getminor(*devp);
6858942c5e3cSpl196000 	minor = AAC_SCSA_MINOR(minor0);
6859942c5e3cSpl196000 
6860942c5e3cSpl196000 	if (AAC_IS_SCSA_NODE(minor))
6861942c5e3cSpl196000 		return (scsi_hba_open(devp, flag, otyp, cred));
6862942c5e3cSpl196000 
6863942c5e3cSpl196000 	instance = MINOR2INST(minor0);
6864942c5e3cSpl196000 	if (instance >= AAC_MAX_ADAPTERS)
6865942c5e3cSpl196000 		return (ENXIO);
6866942c5e3cSpl196000 
6867942c5e3cSpl196000 	softs = ddi_get_soft_state(aac_softstatep, instance);
6868942c5e3cSpl196000 	if (softs == NULL)
6869942c5e3cSpl196000 		return (ENXIO);
6870942c5e3cSpl196000 
6871942c5e3cSpl196000 	return (0);
6872942c5e3cSpl196000 }
6873942c5e3cSpl196000 
6874942c5e3cSpl196000 /*ARGSUSED*/
6875942c5e3cSpl196000 static int
aac_close(dev_t dev,int flag,int otyp,cred_t * cred)6876942c5e3cSpl196000 aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
6877942c5e3cSpl196000 {
6878942c5e3cSpl196000 	int minor0, minor;
6879942c5e3cSpl196000 	int instance;
6880942c5e3cSpl196000 
6881942c5e3cSpl196000 	DBCALLED(NULL, 2);
6882942c5e3cSpl196000 
6883942c5e3cSpl196000 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
6884942c5e3cSpl196000 		return (EINVAL);
6885942c5e3cSpl196000 
6886942c5e3cSpl196000 	minor0 = getminor(dev);
6887942c5e3cSpl196000 	minor = AAC_SCSA_MINOR(minor0);
6888942c5e3cSpl196000 
6889942c5e3cSpl196000 	if (AAC_IS_SCSA_NODE(minor))
6890942c5e3cSpl196000 		return (scsi_hba_close(dev, flag, otyp, cred));
6891942c5e3cSpl196000 
6892942c5e3cSpl196000 	instance = MINOR2INST(minor0);
6893942c5e3cSpl196000 	if (instance >= AAC_MAX_ADAPTERS)
6894942c5e3cSpl196000 		return (ENXIO);
6895942c5e3cSpl196000 
6896942c5e3cSpl196000 	return (0);
6897942c5e3cSpl196000 }
6898942c5e3cSpl196000 
6899942c5e3cSpl196000 static int
aac_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)6900942c5e3cSpl196000 aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
6901942c5e3cSpl196000     int *rval_p)
6902942c5e3cSpl196000 {
6903942c5e3cSpl196000 	struct aac_softstate *softs;
6904942c5e3cSpl196000 	int minor0, minor;
6905942c5e3cSpl196000 	int instance;
6906942c5e3cSpl196000 
6907942c5e3cSpl196000 	DBCALLED(NULL, 2);
6908942c5e3cSpl196000 
6909942c5e3cSpl196000 	if (drv_priv(cred_p) != 0)
6910942c5e3cSpl196000 		return (EPERM);
6911942c5e3cSpl196000 
6912942c5e3cSpl196000 	minor0 = getminor(dev);
6913942c5e3cSpl196000 	minor = AAC_SCSA_MINOR(minor0);
6914942c5e3cSpl196000 
6915942c5e3cSpl196000 	if (AAC_IS_SCSA_NODE(minor))
6916942c5e3cSpl196000 		return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
6917942c5e3cSpl196000 
6918942c5e3cSpl196000 	instance = MINOR2INST(minor0);
6919942c5e3cSpl196000 	if (instance < AAC_MAX_ADAPTERS) {
6920942c5e3cSpl196000 		softs = ddi_get_soft_state(aac_softstatep, instance);
6921942c5e3cSpl196000 		return (aac_do_ioctl(softs, dev, cmd, arg, flag));
6922942c5e3cSpl196000 	}
6923942c5e3cSpl196000 	return (ENXIO);
6924942c5e3cSpl196000 }
6925942c5e3cSpl196000 
6926942c5e3cSpl196000 /*
6927942c5e3cSpl196000  * The IO fault service error handling callback function
6928942c5e3cSpl196000  */
6929942c5e3cSpl196000 /*ARGSUSED*/
6930942c5e3cSpl196000 static int
aac_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)6931942c5e3cSpl196000 aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
6932942c5e3cSpl196000 {
6933942c5e3cSpl196000 	/*
6934942c5e3cSpl196000 	 * as the driver can always deal with an error in any dma or
6935942c5e3cSpl196000 	 * access handle, we can just return the fme_status value.
6936942c5e3cSpl196000 	 */
6937942c5e3cSpl196000 	pci_ereport_post(dip, err, NULL);
6938942c5e3cSpl196000 	return (err->fme_status);
6939942c5e3cSpl196000 }
6940942c5e3cSpl196000 
6941942c5e3cSpl196000 /*
6942942c5e3cSpl196000  * aac_fm_init - initialize fma capabilities and register with IO
6943942c5e3cSpl196000  *               fault services.
6944942c5e3cSpl196000  */
6945942c5e3cSpl196000 static void
aac_fm_init(struct aac_softstate * softs)6946942c5e3cSpl196000 aac_fm_init(struct aac_softstate *softs)
6947942c5e3cSpl196000 {
6948942c5e3cSpl196000 	/*
6949942c5e3cSpl196000 	 * Need to change iblock to priority for new MSI intr
6950942c5e3cSpl196000 	 */
6951942c5e3cSpl196000 	ddi_iblock_cookie_t fm_ibc;
6952942c5e3cSpl196000 
695358bc78c7SXin Chen 	softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
695458bc78c7SXin Chen 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
695558bc78c7SXin Chen 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
695658bc78c7SXin Chen 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
695758bc78c7SXin Chen 
6958942c5e3cSpl196000 	/* Only register with IO Fault Services if we have some capability */
6959942c5e3cSpl196000 	if (softs->fm_capabilities) {
6960942c5e3cSpl196000 		/* Adjust access and dma attributes for FMA */
6961837c1ac4SStephen Hanson 		softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
696258bc78c7SXin Chen 		softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
696358bc78c7SXin Chen 		softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
6964942c5e3cSpl196000 
6965942c5e3cSpl196000 		/*
6966942c5e3cSpl196000 		 * Register capabilities with IO Fault Services.
6967942c5e3cSpl196000 		 * fm_capabilities will be updated to indicate
6968942c5e3cSpl196000 		 * capabilities actually supported (not requested.)
6969942c5e3cSpl196000 		 */
6970942c5e3cSpl196000 		ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
6971942c5e3cSpl196000 
6972942c5e3cSpl196000 		/*
6973942c5e3cSpl196000 		 * Initialize pci ereport capabilities if ereport
6974942c5e3cSpl196000 		 * capable (should always be.)
6975942c5e3cSpl196000 		 */
6976942c5e3cSpl196000 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
6977942c5e3cSpl196000 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6978942c5e3cSpl196000 			pci_ereport_setup(softs->devinfo_p);
6979942c5e3cSpl196000 		}
6980942c5e3cSpl196000 
6981942c5e3cSpl196000 		/*
6982942c5e3cSpl196000 		 * Register error callback if error callback capable.
6983942c5e3cSpl196000 		 */
6984942c5e3cSpl196000 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
6985942c5e3cSpl196000 			ddi_fm_handler_register(softs->devinfo_p,
6986942c5e3cSpl196000 			    aac_fm_error_cb, (void *) softs);
6987942c5e3cSpl196000 		}
6988942c5e3cSpl196000 	}
6989942c5e3cSpl196000 }
6990942c5e3cSpl196000 
6991942c5e3cSpl196000 /*
6992942c5e3cSpl196000  * aac_fm_fini - Releases fma capabilities and un-registers with IO
6993942c5e3cSpl196000  *               fault services.
6994942c5e3cSpl196000  */
6995942c5e3cSpl196000 static void
aac_fm_fini(struct aac_softstate * softs)6996942c5e3cSpl196000 aac_fm_fini(struct aac_softstate *softs)
6997942c5e3cSpl196000 {
6998942c5e3cSpl196000 	/* Only unregister FMA capabilities if registered */
6999942c5e3cSpl196000 	if (softs->fm_capabilities) {
7000942c5e3cSpl196000 		/*
7001942c5e3cSpl196000 		 * Un-register error callback if error callback capable.
7002942c5e3cSpl196000 		 */
7003942c5e3cSpl196000 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7004942c5e3cSpl196000 			ddi_fm_handler_unregister(softs->devinfo_p);
7005942c5e3cSpl196000 		}
7006942c5e3cSpl196000 
7007942c5e3cSpl196000 		/*
7008942c5e3cSpl196000 		 * Release any resources allocated by pci_ereport_setup()
7009942c5e3cSpl196000 		 */
7010942c5e3cSpl196000 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
7011942c5e3cSpl196000 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
7012942c5e3cSpl196000 			pci_ereport_teardown(softs->devinfo_p);
7013942c5e3cSpl196000 		}
7014942c5e3cSpl196000 
7015942c5e3cSpl196000 		/* Unregister from IO Fault Services */
7016942c5e3cSpl196000 		ddi_fm_fini(softs->devinfo_p);
701758bc78c7SXin Chen 
701858bc78c7SXin Chen 		/* Adjust access and dma attributes for FMA */
7019837c1ac4SStephen Hanson 		softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
702058bc78c7SXin Chen 		softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
702158bc78c7SXin Chen 		softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
7022942c5e3cSpl196000 	}
7023942c5e3cSpl196000 }
7024942c5e3cSpl196000 
7025942c5e3cSpl196000 int
aac_check_acc_handle(ddi_acc_handle_t handle)7026942c5e3cSpl196000 aac_check_acc_handle(ddi_acc_handle_t handle)
7027942c5e3cSpl196000 {
7028942c5e3cSpl196000 	ddi_fm_error_t de;
7029942c5e3cSpl196000 
7030942c5e3cSpl196000 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
7031942c5e3cSpl196000 	return (de.fme_status);
7032942c5e3cSpl196000 }
7033942c5e3cSpl196000 
7034942c5e3cSpl196000 int
aac_check_dma_handle(ddi_dma_handle_t handle)7035942c5e3cSpl196000 aac_check_dma_handle(ddi_dma_handle_t handle)
7036942c5e3cSpl196000 {
7037942c5e3cSpl196000 	ddi_fm_error_t de;
7038942c5e3cSpl196000 
7039942c5e3cSpl196000 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
7040942c5e3cSpl196000 	return (de.fme_status);
7041942c5e3cSpl196000 }
7042942c5e3cSpl196000 
7043942c5e3cSpl196000 void
aac_fm_ereport(struct aac_softstate * softs,char * detail)7044942c5e3cSpl196000 aac_fm_ereport(struct aac_softstate *softs, char *detail)
7045942c5e3cSpl196000 {
7046942c5e3cSpl196000 	uint64_t ena;
7047942c5e3cSpl196000 	char buf[FM_MAX_CLASS];
7048942c5e3cSpl196000 
7049942c5e3cSpl196000 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
7050942c5e3cSpl196000 	ena = fm_ena_generate(0, FM_ENA_FMT1);
7051942c5e3cSpl196000 	if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
7052942c5e3cSpl196000 		ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
7053942c5e3cSpl196000 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
7054942c5e3cSpl196000 	}
7055942c5e3cSpl196000 }
7056942c5e3cSpl196000 
705758bc78c7SXin Chen /*
705858bc78c7SXin Chen  * Autoconfiguration support
705958bc78c7SXin Chen  */
706058bc78c7SXin Chen static int
aac_parse_devname(char * devnm,int * tgt,int * lun)706158bc78c7SXin Chen aac_parse_devname(char *devnm, int *tgt, int *lun)
706258bc78c7SXin Chen {
706358bc78c7SXin Chen 	char devbuf[SCSI_MAXNAMELEN];
706458bc78c7SXin Chen 	char *addr;
706558bc78c7SXin Chen 	char *p,  *tp, *lp;
706658bc78c7SXin Chen 	long num;
706758bc78c7SXin Chen 
706858bc78c7SXin Chen 	/* Parse dev name and address */
706958bc78c7SXin Chen 	(void) strcpy(devbuf, devnm);
707058bc78c7SXin Chen 	addr = "";
707158bc78c7SXin Chen 	for (p = devbuf; *p != '\0'; p++) {
707258bc78c7SXin Chen 		if (*p == '@') {
707358bc78c7SXin Chen 			addr = p + 1;
707458bc78c7SXin Chen 			*p = '\0';
707558bc78c7SXin Chen 		} else if (*p == ':') {
707658bc78c7SXin Chen 			*p = '\0';
707758bc78c7SXin Chen 			break;
707858bc78c7SXin Chen 		}
707958bc78c7SXin Chen 	}
708058bc78c7SXin Chen 
708158bc78c7SXin Chen 	/* Parse taget and lun */
708258bc78c7SXin Chen 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
708358bc78c7SXin Chen 		if (*p == ',') {
708458bc78c7SXin Chen 			lp = p + 1;
708558bc78c7SXin Chen 			*p = '\0';
708658bc78c7SXin Chen 			break;
708758bc78c7SXin Chen 		}
708858bc78c7SXin Chen 	}
708958bc78c7SXin Chen 	if (tgt && tp) {
709058bc78c7SXin Chen 		if (ddi_strtol(tp, NULL, 0x10, &num))
709158bc78c7SXin Chen 			return (AACERR);
709258bc78c7SXin Chen 		*tgt = (int)num;
709358bc78c7SXin Chen 	}
709458bc78c7SXin Chen 	if (lun && lp) {
709558bc78c7SXin Chen 		if (ddi_strtol(lp, NULL, 0x10, &num))
709658bc78c7SXin Chen 			return (AACERR);
709758bc78c7SXin Chen 		*lun = (int)num;
709858bc78c7SXin Chen 	}
709958bc78c7SXin Chen 	return (AACOK);
710058bc78c7SXin Chen }
710158bc78c7SXin Chen 
710258bc78c7SXin Chen static dev_info_t *
aac_find_child(struct aac_softstate * softs,uint16_t tgt,uint8_t lun)710358bc78c7SXin Chen aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
710458bc78c7SXin Chen {
710558bc78c7SXin Chen 	dev_info_t *child = NULL;
710658bc78c7SXin Chen 	char addr[SCSI_MAXNAMELEN];
710758bc78c7SXin Chen 	char tmp[MAXNAMELEN];
710858bc78c7SXin Chen 
710958bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
711058bc78c7SXin Chen 		if (lun == 0) {
711158bc78c7SXin Chen 			struct aac_device *dvp = &softs->containers[tgt].dev;
711258bc78c7SXin Chen 
711358bc78c7SXin Chen 			child = dvp->dip;
711458bc78c7SXin Chen 		}
711558bc78c7SXin Chen 	} else {
711658bc78c7SXin Chen 		(void) sprintf(addr, "%x,%x", tgt, lun);
711758bc78c7SXin Chen 		for (child = ddi_get_child(softs->devinfo_p);
711858bc78c7SXin Chen 		    child; child = ddi_get_next_sibling(child)) {
711958bc78c7SXin Chen 			/* We don't care about non-persistent node */
712058bc78c7SXin Chen 			if (ndi_dev_is_persistent_node(child) == 0)
712158bc78c7SXin Chen 				continue;
712258bc78c7SXin Chen 
712358bc78c7SXin Chen 			if (aac_name_node(child, tmp, MAXNAMELEN) !=
712458bc78c7SXin Chen 			    DDI_SUCCESS)
712558bc78c7SXin Chen 				continue;
712658bc78c7SXin Chen 			if (strcmp(addr, tmp) == 0)
712758bc78c7SXin Chen 				break;
712858bc78c7SXin Chen 		}
712958bc78c7SXin Chen 	}
713058bc78c7SXin Chen 	return (child);
713158bc78c7SXin Chen }
713258bc78c7SXin Chen 
713358bc78c7SXin Chen static int
aac_config_child(struct aac_softstate * softs,struct scsi_device * sd,dev_info_t ** dipp)713458bc78c7SXin Chen aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
713558bc78c7SXin Chen     dev_info_t **dipp)
713658bc78c7SXin Chen {
713758bc78c7SXin Chen 	char *nodename = NULL;
713858bc78c7SXin Chen 	char **compatible = NULL;
713958bc78c7SXin Chen 	int ncompatible = 0;
714058bc78c7SXin Chen 	char *childname;
714158bc78c7SXin Chen 	dev_info_t *ldip = NULL;
714258bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
714358bc78c7SXin Chen 	int lun = sd->sd_address.a_lun;
714458bc78c7SXin Chen 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
714558bc78c7SXin Chen 	int rval;
714658bc78c7SXin Chen 
714758bc78c7SXin Chen 	DBCALLED(softs, 2);
714858bc78c7SXin Chen 
714958bc78c7SXin Chen 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
715058bc78c7SXin Chen 	    NULL, &nodename, &compatible, &ncompatible);
715158bc78c7SXin Chen 	if (nodename == NULL) {
715258bc78c7SXin Chen 		AACDB_PRINT(softs, CE_WARN,
715358bc78c7SXin Chen 		    "found no comptible driver for t%dL%d", tgt, lun);
715458bc78c7SXin Chen 		rval = NDI_FAILURE;
715558bc78c7SXin Chen 		goto finish;
715658bc78c7SXin Chen 	}
715758bc78c7SXin Chen 	childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
715858bc78c7SXin Chen 
715958bc78c7SXin Chen 	/* Create dev node */
716058bc78c7SXin Chen 	rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
716158bc78c7SXin Chen 	    &ldip);
716258bc78c7SXin Chen 	if (rval == NDI_SUCCESS) {
716358bc78c7SXin Chen 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
716458bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
716558bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
716658bc78c7SXin Chen 			    "property for t%dL%d (target)", tgt, lun);
716758bc78c7SXin Chen 			rval = NDI_FAILURE;
716858bc78c7SXin Chen 			goto finish;
716958bc78c7SXin Chen 		}
717058bc78c7SXin Chen 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
717158bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
717258bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
717358bc78c7SXin Chen 			    "property for t%dL%d (lun)", tgt, lun);
717458bc78c7SXin Chen 			rval = NDI_FAILURE;
717558bc78c7SXin Chen 			goto finish;
717658bc78c7SXin Chen 		}
717758bc78c7SXin Chen 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
717858bc78c7SXin Chen 		    "compatible", compatible, ncompatible)
717958bc78c7SXin Chen 		    != DDI_PROP_SUCCESS) {
718058bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to create "
718158bc78c7SXin Chen 			    "property for t%dL%d (compatible)", tgt, lun);
718258bc78c7SXin Chen 			rval = NDI_FAILURE;
718358bc78c7SXin Chen 			goto finish;
718458bc78c7SXin Chen 		}
718558bc78c7SXin Chen 
718658bc78c7SXin Chen 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
718758bc78c7SXin Chen 		if (rval != NDI_SUCCESS) {
718858bc78c7SXin Chen 			AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
718958bc78c7SXin Chen 			    tgt, lun);
719058bc78c7SXin Chen 			ndi_prop_remove_all(ldip);
719158bc78c7SXin Chen 			(void) ndi_devi_free(ldip);
719258bc78c7SXin Chen 		}
719358bc78c7SXin Chen 	}
719458bc78c7SXin Chen finish:
719558bc78c7SXin Chen 	if (dipp)
719658bc78c7SXin Chen 		*dipp = ldip;
719758bc78c7SXin Chen 
719858bc78c7SXin Chen 	scsi_hba_nodename_compatible_free(nodename, compatible);
719958bc78c7SXin Chen 	return (rval);
720058bc78c7SXin Chen }
720158bc78c7SXin Chen 
720258bc78c7SXin Chen /*ARGSUSED*/
720358bc78c7SXin Chen static int
aac_probe_lun(struct aac_softstate * softs,struct scsi_device * sd)720458bc78c7SXin Chen aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
720558bc78c7SXin Chen {
720658bc78c7SXin Chen 	int tgt = sd->sd_address.a_target;
720758bc78c7SXin Chen 	int lun = sd->sd_address.a_lun;
720858bc78c7SXin Chen 
720958bc78c7SXin Chen 	DBCALLED(softs, 2);
721058bc78c7SXin Chen 
721158bc78c7SXin Chen 	if (tgt < AAC_MAX_LD) {
72120749e8deSXin Chen - Sun Microsystems - Beijing China 		enum aac_cfg_event event;
721358bc78c7SXin Chen 
721458bc78c7SXin Chen 		if (lun == 0) {
721558bc78c7SXin Chen 			mutex_enter(&softs->io_lock);
72160749e8deSXin Chen - Sun Microsystems - Beijing China 			event = aac_probe_container(softs, tgt);
721758bc78c7SXin Chen 			mutex_exit(&softs->io_lock);
72180749e8deSXin Chen - Sun Microsystems - Beijing China 			if ((event != AAC_CFG_NULL_NOEXIST) &&
72190749e8deSXin Chen - Sun Microsystems - Beijing China 			    (event != AAC_CFG_DELETE)) {
722058bc78c7SXin Chen 				if (scsi_hba_probe(sd, NULL) ==
722158bc78c7SXin Chen 				    SCSIPROBE_EXISTS)
722258bc78c7SXin Chen 					return (NDI_SUCCESS);
722358bc78c7SXin Chen 			}
722458bc78c7SXin Chen 		}
722558bc78c7SXin Chen 		return (NDI_FAILURE);
722658bc78c7SXin Chen 	} else {
722758bc78c7SXin Chen 		int dtype;
72283fced439Szhongyan gu - Sun Microsystems - Beijing China 		int qual; /* device qualifier */
722958bc78c7SXin Chen 
723058bc78c7SXin Chen 		if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
723158bc78c7SXin Chen 			return (NDI_FAILURE);
723258bc78c7SXin Chen 
723358bc78c7SXin Chen 		dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
72343fced439Szhongyan gu - Sun Microsystems - Beijing China 		qual = dtype >> 5;
723558bc78c7SXin Chen 
723658bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE,
723758bc78c7SXin Chen 		    "Phys. device found: tgt %d dtype %d: %s",
723858bc78c7SXin Chen 		    tgt, dtype, sd->sd_inq->inq_vid);
723958bc78c7SXin Chen 
72403fced439Szhongyan gu - Sun Microsystems - Beijing China 		/* Only non-DASD and JBOD mode DASD are allowed exposed */
72413fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (dtype == DTYPE_RODIRECT /* CDROM */ ||
72423fced439Szhongyan gu - Sun Microsystems - Beijing China 		    dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
72433fced439Szhongyan gu - Sun Microsystems - Beijing China 		    dtype == DTYPE_ESI /* SES */) {
72443fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_NONDASD))
724558bc78c7SXin Chen 				return (NDI_FAILURE);
724658bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
72473fced439Szhongyan gu - Sun Microsystems - Beijing China 
72483fced439Szhongyan gu - Sun Microsystems - Beijing China 		} else if (dtype == DTYPE_DIRECT) {
72493fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
72503fced439Szhongyan gu - Sun Microsystems - Beijing China 				return (NDI_FAILURE);
72513fced439Szhongyan gu - Sun Microsystems - Beijing China 			AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
72523fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
72533fced439Szhongyan gu - Sun Microsystems - Beijing China 
725458bc78c7SXin Chen 		mutex_enter(&softs->io_lock);
725558bc78c7SXin Chen 		softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
725658bc78c7SXin Chen 		mutex_exit(&softs->io_lock);
725758bc78c7SXin Chen 		return (NDI_SUCCESS);
725858bc78c7SXin Chen 	}
725958bc78c7SXin Chen }
726058bc78c7SXin Chen 
726158bc78c7SXin Chen static int
aac_config_lun(struct aac_softstate * softs,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)726258bc78c7SXin Chen aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
726358bc78c7SXin Chen     dev_info_t **ldip)
726458bc78c7SXin Chen {
726558bc78c7SXin Chen 	struct scsi_device sd;
726658bc78c7SXin Chen 	dev_info_t *child;
726758bc78c7SXin Chen 	int rval;
726858bc78c7SXin Chen 
726958bc78c7SXin Chen 	DBCALLED(softs, 2);
727058bc78c7SXin Chen 
727158bc78c7SXin Chen 	if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
727258bc78c7SXin Chen 		if (ldip)
727358bc78c7SXin Chen 			*ldip = child;
727458bc78c7SXin Chen 		return (NDI_SUCCESS);
727558bc78c7SXin Chen 	}
727658bc78c7SXin Chen 
727758bc78c7SXin Chen 	bzero(&sd, sizeof (struct scsi_device));
727858bc78c7SXin Chen 	sd.sd_address.a_hba_tran = softs->hba_tran;
727958bc78c7SXin Chen 	sd.sd_address.a_target = (uint16_t)tgt;
728058bc78c7SXin Chen 	sd.sd_address.a_lun = (uint8_t)lun;
728158bc78c7SXin Chen 	if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
728258bc78c7SXin Chen 		rval = aac_config_child(softs, &sd, ldip);
7283f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	/* scsi_unprobe is blank now. Free buffer manually */
7284f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	if (sd.sd_inq) {
7285f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		kmem_free(sd.sd_inq, SUN_INQSIZE);
7286f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 		sd.sd_inq = (struct scsi_inquiry *)NULL;
7287f42c2f53Szhongyan gu - Sun Microsystems - Beijing China 	}
728858bc78c7SXin Chen 	return (rval);
728958bc78c7SXin Chen }
729058bc78c7SXin Chen 
729158bc78c7SXin Chen static int
aac_config_tgt(struct aac_softstate * softs,int tgt)729258bc78c7SXin Chen aac_config_tgt(struct aac_softstate *softs, int tgt)
729358bc78c7SXin Chen {
729458bc78c7SXin Chen 	struct scsi_address ap;
729558bc78c7SXin Chen 	struct buf *bp = NULL;
729658bc78c7SXin Chen 	int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
729758bc78c7SXin Chen 	int list_len = 0;
729858bc78c7SXin Chen 	int lun_total = 0;
729958bc78c7SXin Chen 	dev_info_t *ldip;
730058bc78c7SXin Chen 	int i;
730158bc78c7SXin Chen 
730258bc78c7SXin Chen 	ap.a_hba_tran = softs->hba_tran;
730358bc78c7SXin Chen 	ap.a_target = (uint16_t)tgt;
730458bc78c7SXin Chen 	ap.a_lun = 0;
730558bc78c7SXin Chen 
730658bc78c7SXin Chen 	for (i = 0; i < 2; i++) {
730758bc78c7SXin Chen 		struct scsi_pkt *pkt;
730858bc78c7SXin Chen 		uchar_t *cdb;
730958bc78c7SXin Chen 		uchar_t *p;
731058bc78c7SXin Chen 		uint32_t data;
731158bc78c7SXin Chen 
731258bc78c7SXin Chen 		if (bp == NULL) {
731358bc78c7SXin Chen 			if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
731458bc78c7SXin Chen 			    buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
731558bc78c7SXin Chen 			return (AACERR);
731658bc78c7SXin Chen 		}
731758bc78c7SXin Chen 		if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
731858bc78c7SXin Chen 		    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
731958bc78c7SXin Chen 		    NULL, NULL)) == NULL) {
732058bc78c7SXin Chen 			scsi_free_consistent_buf(bp);
732158bc78c7SXin Chen 			return (AACERR);
732258bc78c7SXin Chen 		}
732358bc78c7SXin Chen 		cdb = pkt->pkt_cdbp;
732458bc78c7SXin Chen 		bzero(cdb, CDB_GROUP5);
732558bc78c7SXin Chen 		cdb[0] = SCMD_REPORT_LUNS;
732658bc78c7SXin Chen 
732758bc78c7SXin Chen 		/* Convert buffer len from local to LE_32 */
732858bc78c7SXin Chen 		data = buf_len;
732958bc78c7SXin Chen 		for (p = &cdb[9]; p > &cdb[5]; p--) {
733058bc78c7SXin Chen 			*p = data & 0xff;
733158bc78c7SXin Chen 			data >>= 8;
733258bc78c7SXin Chen 		}
733358bc78c7SXin Chen 
733458bc78c7SXin Chen 		if (scsi_poll(pkt) < 0 ||
733558bc78c7SXin Chen 		    ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
733658bc78c7SXin Chen 			scsi_destroy_pkt(pkt);
733758bc78c7SXin Chen 			break;
733858bc78c7SXin Chen 		}
733958bc78c7SXin Chen 
734058bc78c7SXin Chen 		/* Convert list_len from LE_32 to local */
734158bc78c7SXin Chen 		for (p = (uchar_t *)bp->b_un.b_addr;
734258bc78c7SXin Chen 		    p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
734358bc78c7SXin Chen 			data <<= 8;
734458bc78c7SXin Chen 			data |= *p;
734558bc78c7SXin Chen 		}
734658bc78c7SXin Chen 		list_len = data;
734758bc78c7SXin Chen 		if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
734858bc78c7SXin Chen 			scsi_free_consistent_buf(bp);
734958bc78c7SXin Chen 			bp = NULL;
735058bc78c7SXin Chen 			buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
735158bc78c7SXin Chen 		}
735258bc78c7SXin Chen 		scsi_destroy_pkt(pkt);
735358bc78c7SXin Chen 	}
735458bc78c7SXin Chen 	if (i >= 2) {
735558bc78c7SXin Chen 		uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
735658bc78c7SXin Chen 		    AAC_SCSI_RPTLUNS_HEAD_SIZE);
735758bc78c7SXin Chen 
735858bc78c7SXin Chen 		for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
735958bc78c7SXin Chen 			uint16_t lun;
736058bc78c7SXin Chen 
736158bc78c7SXin Chen 			/* Determine report luns addressing type */
736258bc78c7SXin Chen 			switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
736358bc78c7SXin Chen 			/*
736458bc78c7SXin Chen 			 * Vendors in the field have been found to be
736558bc78c7SXin Chen 			 * concatenating bus/target/lun to equal the
736658bc78c7SXin Chen 			 * complete lun value instead of switching to
736758bc78c7SXin Chen 			 * flat space addressing
736858bc78c7SXin Chen 			 */
736958bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
737058bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
737158bc78c7SXin Chen 			case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
737258bc78c7SXin Chen 				lun = ((buf[0] & 0x3f) << 8) | buf[1];
737358bc78c7SXin Chen 				if (lun > UINT8_MAX) {
737458bc78c7SXin Chen 					AACDB_PRINT(softs, CE_WARN,
737558bc78c7SXin Chen 					    "abnormal lun number: %d", lun);
737658bc78c7SXin Chen 					break;
737758bc78c7SXin Chen 				}
737858bc78c7SXin Chen 				if (aac_config_lun(softs, tgt, lun, &ldip) ==
737958bc78c7SXin Chen 				    NDI_SUCCESS)
738058bc78c7SXin Chen 					lun_total++;
738158bc78c7SXin Chen 				break;
738258bc78c7SXin Chen 			}
738358bc78c7SXin Chen 
738458bc78c7SXin Chen 			buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
738558bc78c7SXin Chen 		}
738658bc78c7SXin Chen 	} else {
738758bc78c7SXin Chen 		/* The target may do not support SCMD_REPORT_LUNS. */
738858bc78c7SXin Chen 		if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
738958bc78c7SXin Chen 			lun_total++;
739058bc78c7SXin Chen 	}
739158bc78c7SXin Chen 	scsi_free_consistent_buf(bp);
739258bc78c7SXin Chen 	return (lun_total);
739358bc78c7SXin Chen }
739458bc78c7SXin Chen 
739558bc78c7SXin Chen static void
aac_devcfg(struct aac_softstate * softs,int tgt,int en)739658bc78c7SXin Chen aac_devcfg(struct aac_softstate *softs, int tgt, int en)
739758bc78c7SXin Chen {
739858bc78c7SXin Chen 	struct aac_device *dvp;
739958bc78c7SXin Chen 
740058bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
740158bc78c7SXin Chen 	dvp = AAC_DEV(softs, tgt);
740258bc78c7SXin Chen 	if (en)
740358bc78c7SXin Chen 		dvp->flags |= AAC_DFLAG_CONFIGURING;
740458bc78c7SXin Chen 	else
740558bc78c7SXin Chen 		dvp->flags &= ~AAC_DFLAG_CONFIGURING;
740658bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
740758bc78c7SXin Chen }
740858bc78c7SXin Chen 
740958bc78c7SXin 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)741058bc78c7SXin Chen aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
741158bc78c7SXin Chen     void *arg, dev_info_t **childp)
741258bc78c7SXin Chen {
741358bc78c7SXin Chen 	struct aac_softstate *softs;
741458bc78c7SXin Chen 	int circ = 0;
741558bc78c7SXin Chen 	int rval;
741658bc78c7SXin Chen 
741758bc78c7SXin Chen 	if ((softs = ddi_get_soft_state(aac_softstatep,
741858bc78c7SXin Chen 	    ddi_get_instance(parent))) == NULL)
741958bc78c7SXin Chen 		return (NDI_FAILURE);
742058bc78c7SXin Chen 
742158bc78c7SXin Chen 	/* Commands for bus config should be blocked as the bus is quiesced */
742258bc78c7SXin Chen 	mutex_enter(&softs->io_lock);
742358bc78c7SXin Chen 	if (softs->state & AAC_STATE_QUIESCED) {
742458bc78c7SXin Chen 		AACDB_PRINT(softs, CE_NOTE,
742558bc78c7SXin Chen 		    "bus_config abroted because bus is quiesced");
742658bc78c7SXin Chen 		mutex_exit(&softs->io_lock);
742758bc78c7SXin Chen 		return (NDI_FAILURE);
742858bc78c7SXin Chen 	}
742958bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
743058bc78c7SXin Chen 
743158bc78c7SXin Chen 	DBCALLED(softs, 1);
743258bc78c7SXin Chen 
743358bc78c7SXin Chen 	/* Hold the nexus across the bus_config */
743458bc78c7SXin Chen 	ndi_devi_enter(parent, &circ);
743558bc78c7SXin Chen 	switch (op) {
743658bc78c7SXin Chen 	case BUS_CONFIG_ONE: {
743758bc78c7SXin Chen 		int tgt, lun;
743858bc78c7SXin Chen 
743958bc78c7SXin Chen 		if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
744058bc78c7SXin Chen 			rval = NDI_FAILURE;
744158bc78c7SXin Chen 			break;
744258bc78c7SXin Chen 		}
74433fced439Szhongyan gu - Sun Microsystems - Beijing China 		if (tgt >= AAC_MAX_LD) {
74443fced439Szhongyan gu - Sun Microsystems - Beijing China 			if (tgt >= AAC_MAX_DEV(softs)) {
74453fced439Szhongyan gu - Sun Microsystems - Beijing China 				rval = NDI_FAILURE;
74463fced439Szhongyan gu - Sun Microsystems - Beijing China 				break;
74473fced439Szhongyan gu - Sun Microsystems - Beijing China 			}
74483fced439Szhongyan gu - Sun Microsystems - Beijing China 		}
744958bc78c7SXin Chen 
745058bc78c7SXin Chen 		AAC_DEVCFG_BEGIN(softs, tgt);
745158bc78c7SXin Chen 		rval = aac_config_lun(softs, tgt, lun, childp);
745258bc78c7SXin Chen 		AAC_DEVCFG_END(softs, tgt);
745358bc78c7SXin Chen 		break;
745458bc78c7SXin Chen 	}
745558bc78c7SXin Chen 
745658bc78c7SXin Chen 	case BUS_CONFIG_DRIVER:
745758bc78c7SXin Chen 	case BUS_CONFIG_ALL: {
745858bc78c7SXin Chen 		uint32_t bus, tgt;
745958bc78c7SXin Chen 		int index, total;
746058bc78c7SXin Chen 
746158bc78c7SXin Chen 		for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
746258bc78c7SXin Chen 			AAC_DEVCFG_BEGIN(softs, tgt);
746358bc78c7SXin Chen 			(void) aac_config_lun(softs, tgt, 0, NULL);
746458bc78c7SXin Chen 			AAC_DEVCFG_END(softs, tgt);
746558bc78c7SXin Chen 		}
746658bc78c7SXin Chen 
746758bc78c7SXin Chen 		/* Config the non-DASD devices connected to the card */
746858bc78c7SXin Chen 		total = 0;
746958bc78c7SXin Chen 		index = AAC_MAX_LD;
747058bc78c7SXin Chen 		for (bus = 0; bus < softs->bus_max; bus++) {
747158bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
747258bc78c7SXin Chen 			for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
747358bc78c7SXin Chen 				AAC_DEVCFG_BEGIN(softs, index);
747458bc78c7SXin Chen 				if (aac_config_tgt(softs, index))
747558bc78c7SXin Chen 					total++;
747658bc78c7SXin Chen 				AAC_DEVCFG_END(softs, index);
747758bc78c7SXin Chen 			}
747858bc78c7SXin Chen 		}
747958bc78c7SXin Chen 		AACDB_PRINT(softs, CE_CONT,
748058bc78c7SXin Chen 		    "?Total %d phys. device(s) found", total);
748158bc78c7SXin Chen 		rval = NDI_SUCCESS;
748258bc78c7SXin Chen 		break;
748358bc78c7SXin Chen 	}
748458bc78c7SXin Chen 	}
748558bc78c7SXin Chen 
748658bc78c7SXin Chen 	if (rval == NDI_SUCCESS)
748758bc78c7SXin Chen 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
748858bc78c7SXin Chen 	ndi_devi_exit(parent, circ);
748958bc78c7SXin Chen 	return (rval);
749058bc78c7SXin Chen }
749158bc78c7SXin Chen 
74920749e8deSXin Chen - Sun Microsystems - Beijing China /*ARGSUSED*/
74930749e8deSXin Chen - Sun Microsystems - Beijing China static int
aac_handle_dr(struct aac_softstate * softs,int tgt,int lun,int event)74940749e8deSXin Chen - Sun Microsystems - Beijing China aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
749558bc78c7SXin Chen {
749658bc78c7SXin Chen 	struct aac_device *dvp;
749758bc78c7SXin Chen 	dev_info_t *dip;
749858bc78c7SXin Chen 	int valid;
749958bc78c7SXin Chen 	int circ1 = 0;
750058bc78c7SXin Chen 
750158bc78c7SXin Chen 	DBCALLED(softs, 1);
750258bc78c7SXin Chen 
750358bc78c7SXin Chen 	/* Hold the nexus across the bus_config */
75040749e8deSXin Chen - Sun Microsystems - Beijing China 	dvp = AAC_DEV(softs, tgt);
750558bc78c7SXin Chen 	valid = AAC_DEV_IS_VALID(dvp);
750658bc78c7SXin Chen 	dip = dvp->dip;
75070749e8deSXin Chen - Sun Microsystems - Beijing China 	if (!(softs->state & AAC_STATE_RUN))
75080749e8deSXin Chen - Sun Microsystems - Beijing China 		return (AACERR);
750958bc78c7SXin Chen 	mutex_exit(&softs->io_lock);
751058bc78c7SXin Chen 
75110749e8deSXin Chen - Sun Microsystems - Beijing China 	switch (event) {
75120749e8deSXin Chen - Sun Microsystems - Beijing China 	case AAC_CFG_ADD:
75130749e8deSXin Chen - Sun Microsystems - Beijing China 	case AAC_CFG_DELETE:
751458bc78c7SXin Chen 		/* Device onlined */
751558bc78c7SXin Chen 		if (dip == NULL && valid) {
751658bc78c7SXin Chen 			ndi_devi_enter(softs->devinfo_p, &circ1);
75170749e8deSXin Chen - Sun Microsystems - Beijing China 			(void) aac_config_lun(softs, tgt, 0, NULL);
751858bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
75190749e8deSXin Chen - Sun Microsystems - Beijing China 			    softs->instance, tgt, lun);
752058bc78c7SXin Chen 			ndi_devi_exit(softs->devinfo_p, circ1);
752158bc78c7SXin Chen 		}
752258bc78c7SXin Chen 		/* Device offlined */
752358bc78c7SXin Chen 		if (dip && !valid) {
752458bc78c7SXin Chen 			mutex_enter(&softs->io_lock);
752558bc78c7SXin Chen 			(void) aac_do_reset(softs);
752658bc78c7SXin Chen 			mutex_exit(&softs->io_lock);
752758bc78c7SXin Chen 
752858bc78c7SXin Chen 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
752958bc78c7SXin Chen 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
75300749e8deSXin Chen - Sun Microsystems - Beijing China 			    softs->instance, tgt, lun);
753158bc78c7SXin Chen 		}
753258bc78c7SXin Chen 		break;
753358bc78c7SXin Chen 	}
753458bc78c7SXin Chen 
75350749e8deSXin Chen - Sun Microsystems - Beijing China 	mutex_enter(&softs->io_lock);
753658bc78c7SXin Chen 	return (AACOK);
753758bc78c7SXin Chen }
753858bc78c7SXin Chen 
7539942c5e3cSpl196000 #ifdef DEBUG
7540942c5e3cSpl196000 
7541942c5e3cSpl196000 /* -------------------------debug aid functions-------------------------- */
7542942c5e3cSpl196000 
7543942c5e3cSpl196000 #define	AAC_FIB_CMD_KEY_STRINGS \
7544942c5e3cSpl196000 	TestCommandResponse, "TestCommandResponse", \
7545942c5e3cSpl196000 	TestAdapterCommand, "TestAdapterCommand", \
7546942c5e3cSpl196000 	LastTestCommand, "LastTestCommand", \
7547942c5e3cSpl196000 	ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
7548942c5e3cSpl196000 	ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
7549942c5e3cSpl196000 	ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
7550942c5e3cSpl196000 	ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
7551942c5e3cSpl196000 	ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
7552942c5e3cSpl196000 	ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
7553942c5e3cSpl196000 	ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
7554942c5e3cSpl196000 	ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
7555942c5e3cSpl196000 	InterfaceShutdown, "InterfaceShutdown", \
7556942c5e3cSpl196000 	DmaCommandFib, "DmaCommandFib", \
7557942c5e3cSpl196000 	StartProfile, "StartProfile", \
7558942c5e3cSpl196000 	TermProfile, "TermProfile", \
7559942c5e3cSpl196000 	SpeedTest, "SpeedTest", \
7560942c5e3cSpl196000 	TakeABreakPt, "TakeABreakPt", \
7561942c5e3cSpl196000 	RequestPerfData, "RequestPerfData", \
7562942c5e3cSpl196000 	SetInterruptDefTimer, "SetInterruptDefTimer", \
7563942c5e3cSpl196000 	SetInterruptDefCount, "SetInterruptDefCount", \
7564942c5e3cSpl196000 	GetInterruptDefStatus, "GetInterruptDefStatus", \
7565942c5e3cSpl196000 	LastCommCommand, "LastCommCommand", \
7566942c5e3cSpl196000 	NuFileSystem, "NuFileSystem", \
7567942c5e3cSpl196000 	UFS, "UFS", \
7568942c5e3cSpl196000 	HostFileSystem, "HostFileSystem", \
7569942c5e3cSpl196000 	LastFileSystemCommand, "LastFileSystemCommand", \
7570942c5e3cSpl196000 	ContainerCommand, "ContainerCommand", \
7571942c5e3cSpl196000 	ContainerCommand64, "ContainerCommand64", \
7572942c5e3cSpl196000 	ClusterCommand, "ClusterCommand", \
7573942c5e3cSpl196000 	ScsiPortCommand, "ScsiPortCommand", \
7574942c5e3cSpl196000 	ScsiPortCommandU64, "ScsiPortCommandU64", \
7575942c5e3cSpl196000 	AifRequest, "AifRequest", \
7576942c5e3cSpl196000 	CheckRevision, "CheckRevision", \
7577942c5e3cSpl196000 	FsaHostShutdown, "FsaHostShutdown", \
7578942c5e3cSpl196000 	RequestAdapterInfo, "RequestAdapterInfo", \
7579942c5e3cSpl196000 	IsAdapterPaused, "IsAdapterPaused", \
7580942c5e3cSpl196000 	SendHostTime, "SendHostTime", \
7581942c5e3cSpl196000 	LastMiscCommand, "LastMiscCommand"
7582942c5e3cSpl196000 
7583942c5e3cSpl196000 #define	AAC_CTVM_SUBCMD_KEY_STRINGS \
7584942c5e3cSpl196000 	VM_Null, "VM_Null", \
7585942c5e3cSpl196000 	VM_NameServe, "VM_NameServe", \
7586942c5e3cSpl196000 	VM_ContainerConfig, "VM_ContainerConfig", \
7587942c5e3cSpl196000 	VM_Ioctl, "VM_Ioctl", \
7588942c5e3cSpl196000 	VM_FilesystemIoctl, "VM_FilesystemIoctl", \
7589942c5e3cSpl196000 	VM_CloseAll, "VM_CloseAll", \
7590942c5e3cSpl196000 	VM_CtBlockRead, "VM_CtBlockRead", \
7591942c5e3cSpl196000 	VM_CtBlockWrite, "VM_CtBlockWrite", \
7592942c5e3cSpl196000 	VM_SliceBlockRead, "VM_SliceBlockRead", \
7593942c5e3cSpl196000 	VM_SliceBlockWrite, "VM_SliceBlockWrite", \
7594942c5e3cSpl196000 	VM_DriveBlockRead, "VM_DriveBlockRead", \
7595942c5e3cSpl196000 	VM_DriveBlockWrite, "VM_DriveBlockWrite", \
7596942c5e3cSpl196000 	VM_EnclosureMgt, "VM_EnclosureMgt", \
7597942c5e3cSpl196000 	VM_Unused, "VM_Unused", \
7598942c5e3cSpl196000 	VM_CtBlockVerify, "VM_CtBlockVerify", \
7599942c5e3cSpl196000 	VM_CtPerf, "VM_CtPerf", \
7600942c5e3cSpl196000 	VM_CtBlockRead64, "VM_CtBlockRead64", \
7601942c5e3cSpl196000 	VM_CtBlockWrite64, "VM_CtBlockWrite64", \
7602942c5e3cSpl196000 	VM_CtBlockVerify64, "VM_CtBlockVerify64", \
7603942c5e3cSpl196000 	VM_CtHostRead64, "VM_CtHostRead64", \
7604942c5e3cSpl196000 	VM_CtHostWrite64, "VM_CtHostWrite64", \
7605942c5e3cSpl196000 	VM_NameServe64, "VM_NameServe64"
7606942c5e3cSpl196000 
7607942c5e3cSpl196000 #define	AAC_CT_SUBCMD_KEY_STRINGS \
7608942c5e3cSpl196000 	CT_Null, "CT_Null", \
7609942c5e3cSpl196000 	CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
7610942c5e3cSpl196000 	CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
7611942c5e3cSpl196000 	CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
7612942c5e3cSpl196000 	CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
7613942c5e3cSpl196000 	CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
7614942c5e3cSpl196000 	CT_WRITE_MBR, "CT_WRITE_MBR", \
7615942c5e3cSpl196000 	CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
7616942c5e3cSpl196000 	CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
7617942c5e3cSpl196000 	CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
7618942c5e3cSpl196000 	CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
7619942c5e3cSpl196000 	CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
7620942c5e3cSpl196000 	CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
7621942c5e3cSpl196000 	CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
7622942c5e3cSpl196000 	CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
7623942c5e3cSpl196000 	CT_READ_MBR, "CT_READ_MBR", \
7624942c5e3cSpl196000 	CT_READ_PARTITION, "CT_READ_PARTITION", \
7625942c5e3cSpl196000 	CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
7626942c5e3cSpl196000 	CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
7627942c5e3cSpl196000 	CT_SLICE_SIZE, "CT_SLICE_SIZE", \
7628942c5e3cSpl196000 	CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
7629942c5e3cSpl196000 	CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
7630942c5e3cSpl196000 	CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
7631942c5e3cSpl196000 	CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
7632942c5e3cSpl196000 	CT_UNMIRROR, "CT_UNMIRROR", \
7633942c5e3cSpl196000 	CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
7634942c5e3cSpl196000 	CT_GEN_MIRROR, "CT_GEN_MIRROR", \
7635942c5e3cSpl196000 	CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
7636942c5e3cSpl196000 	CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
7637942c5e3cSpl196000 	CT_MOVE2, "CT_MOVE2", \
7638942c5e3cSpl196000 	CT_SPLIT, "CT_SPLIT", \
7639942c5e3cSpl196000 	CT_SPLIT2, "CT_SPLIT2", \
7640942c5e3cSpl196000 	CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
7641942c5e3cSpl196000 	CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
7642942c5e3cSpl196000 	CT_RECONFIG, "CT_RECONFIG", \
7643942c5e3cSpl196000 	CT_BREAK2, "CT_BREAK2", \
7644942c5e3cSpl196000 	CT_BREAK, "CT_BREAK", \
7645942c5e3cSpl196000 	CT_MERGE2, "CT_MERGE2", \
7646942c5e3cSpl196000 	CT_MERGE, "CT_MERGE", \
7647942c5e3cSpl196000 	CT_FORCE_ERROR, "CT_FORCE_ERROR", \
7648942c5e3cSpl196000 	CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
7649942c5e3cSpl196000 	CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
7650942c5e3cSpl196000 	CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
7651942c5e3cSpl196000 	CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
7652942c5e3cSpl196000 	CT_VOLUME_ADD, "CT_VOLUME_ADD", \
7653942c5e3cSpl196000 	CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
7654942c5e3cSpl196000 	CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
7655942c5e3cSpl196000 	CT_COPY_STATUS, "CT_COPY_STATUS", \
7656942c5e3cSpl196000 	CT_COPY, "CT_COPY", \
7657942c5e3cSpl196000 	CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
7658942c5e3cSpl196000 	CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
7659942c5e3cSpl196000 	CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
7660942c5e3cSpl196000 	CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
7661942c5e3cSpl196000 	CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
7662942c5e3cSpl196000 	CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
7663942c5e3cSpl196000 	CT_SET, "CT_SET", \
7664942c5e3cSpl196000 	CT_GET, "CT_GET", \
7665942c5e3cSpl196000 	CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
7666942c5e3cSpl196000 	CT_GET_DELAY, "CT_GET_DELAY", \
7667942c5e3cSpl196000 	CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
7668942c5e3cSpl196000 	CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
7669942c5e3cSpl196000 	CT_SCRUB, "CT_SCRUB", \
7670942c5e3cSpl196000 	CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
7671942c5e3cSpl196000 	CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
7672942c5e3cSpl196000 	CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
7673942c5e3cSpl196000 	CT_PAUSE_IO, "CT_PAUSE_IO", \
7674942c5e3cSpl196000 	CT_RELEASE_IO, "CT_RELEASE_IO", \
7675942c5e3cSpl196000 	CT_SCRUB2, "CT_SCRUB2", \
7676942c5e3cSpl196000 	CT_MCHECK, "CT_MCHECK", \
7677942c5e3cSpl196000 	CT_CORRUPT, "CT_CORRUPT", \
7678942c5e3cSpl196000 	CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
7679942c5e3cSpl196000 	CT_PROMOTE, "CT_PROMOTE", \
7680942c5e3cSpl196000 	CT_SET_DEAD, "CT_SET_DEAD", \
7681942c5e3cSpl196000 	CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
7682942c5e3cSpl196000 	CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
7683942c5e3cSpl196000 	CT_GET_PARAM, "CT_GET_PARAM", \
7684942c5e3cSpl196000 	CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
7685942c5e3cSpl196000 	CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
7686942c5e3cSpl196000 	CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
7687942c5e3cSpl196000 	CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
7688942c5e3cSpl196000 	CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
7689942c5e3cSpl196000 	CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
7690942c5e3cSpl196000 	CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
7691942c5e3cSpl196000 	CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
7692942c5e3cSpl196000 	CT_STOP_DATA, "CT_STOP_DATA", \
7693942c5e3cSpl196000 	CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
7694942c5e3cSpl196000 	CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
7695942c5e3cSpl196000 	CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
7696942c5e3cSpl196000 	CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
7697942c5e3cSpl196000 	CT_GET_TIME, "CT_GET_TIME", \
7698942c5e3cSpl196000 	CT_READ_DATA, "CT_READ_DATA", \
7699942c5e3cSpl196000 	CT_CTR, "CT_CTR", \
7700942c5e3cSpl196000 	CT_CTL, "CT_CTL", \
7701942c5e3cSpl196000 	CT_DRAINIO, "CT_DRAINIO", \
7702942c5e3cSpl196000 	CT_RELEASEIO, "CT_RELEASEIO", \
7703942c5e3cSpl196000 	CT_GET_NVRAM, "CT_GET_NVRAM", \
7704942c5e3cSpl196000 	CT_GET_MEMORY, "CT_GET_MEMORY", \
7705942c5e3cSpl196000 	CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
7706942c5e3cSpl196000 	CT_ADD_LEVEL, "CT_ADD_LEVEL", \
7707942c5e3cSpl196000 	CT_NV_ZERO, "CT_NV_ZERO", \
7708942c5e3cSpl196000 	CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
7709942c5e3cSpl196000 	CT_THROTTLE_ON, "CT_THROTTLE_ON", \
7710942c5e3cSpl196000 	CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
7711942c5e3cSpl196000 	CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
7712942c5e3cSpl196000 	CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
7713942c5e3cSpl196000 	CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
7714942c5e3cSpl196000 	CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
7715942c5e3cSpl196000 	CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
7716942c5e3cSpl196000 	CT_MONITOR, "CT_MONITOR", \
7717942c5e3cSpl196000 	CT_GEN_MORPH, "CT_GEN_MORPH", \
7718942c5e3cSpl196000 	CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
7719942c5e3cSpl196000 	CT_CACHE_SET, "CT_CACHE_SET", \
7720942c5e3cSpl196000 	CT_CACHE_STAT, "CT_CACHE_STAT", \
7721942c5e3cSpl196000 	CT_TRACE_START, "CT_TRACE_START", \
7722942c5e3cSpl196000 	CT_TRACE_STOP, "CT_TRACE_STOP", \
7723942c5e3cSpl196000 	CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
7724942c5e3cSpl196000 	CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
7725942c5e3cSpl196000 	CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
7726942c5e3cSpl196000 	CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
7727942c5e3cSpl196000 	CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
7728942c5e3cSpl196000 	CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
7729942c5e3cSpl196000 	CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
7730942c5e3cSpl196000 	CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
7731942c5e3cSpl196000 	CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
7732942c5e3cSpl196000 	CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
7733942c5e3cSpl196000 	CT_STOP_DUMPS, "CT_STOP_DUMPS", \
7734942c5e3cSpl196000 	CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
7735942c5e3cSpl196000 	CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
7736942c5e3cSpl196000 	CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
7737942c5e3cSpl196000 	CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
7738942c5e3cSpl196000 	CT_READ_NAME, "CT_READ_NAME", \
7739942c5e3cSpl196000 	CT_WRITE_NAME, "CT_WRITE_NAME", \
7740942c5e3cSpl196000 	CT_TOSS_CACHE, "CT_TOSS_CACHE", \
7741942c5e3cSpl196000 	CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
7742942c5e3cSpl196000 	CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
7743942c5e3cSpl196000 	CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
7744942c5e3cSpl196000 	CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
7745942c5e3cSpl196000 	CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
7746942c5e3cSpl196000 	CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
7747942c5e3cSpl196000 	CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
7748942c5e3cSpl196000 	CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
7749942c5e3cSpl196000 	CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
7750942c5e3cSpl196000 	CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
7751942c5e3cSpl196000 	CT_FLUSH, "CT_FLUSH", \
7752942c5e3cSpl196000 	CT_REBUILD, "CT_REBUILD", \
7753942c5e3cSpl196000 	CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
7754942c5e3cSpl196000 	CT_RESTART, "CT_RESTART", \
7755942c5e3cSpl196000 	CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
7756942c5e3cSpl196000 	CT_TRACE_FLAG, "CT_TRACE_FLAG", \
7757942c5e3cSpl196000 	CT_RESTART_MORPH, "CT_RESTART_MORPH", \
7758942c5e3cSpl196000 	CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
7759942c5e3cSpl196000 	CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
7760942c5e3cSpl196000 	CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
7761942c5e3cSpl196000 	CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
7762942c5e3cSpl196000 	CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
7763942c5e3cSpl196000 	CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
7764942c5e3cSpl196000 	CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
7765942c5e3cSpl196000 	CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
7766942c5e3cSpl196000 	CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
7767942c5e3cSpl196000 	CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
7768942c5e3cSpl196000 	CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
7769942c5e3cSpl196000 	CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
7770942c5e3cSpl196000 	CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
7771942c5e3cSpl196000 	CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
7772942c5e3cSpl196000 	CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
7773942c5e3cSpl196000 	CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
7774942c5e3cSpl196000 	CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
7775942c5e3cSpl196000 	CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
7776942c5e3cSpl196000 	CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
7777942c5e3cSpl196000 	CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
7778942c5e3cSpl196000 	CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
7779942c5e3cSpl196000 	CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
7780942c5e3cSpl196000 	CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
7781942c5e3cSpl196000 	CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
7782942c5e3cSpl196000 	CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
7783942c5e3cSpl196000 	CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
7784942c5e3cSpl196000 	CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
7785942c5e3cSpl196000 	CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
7786942c5e3cSpl196000 	CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
7787942c5e3cSpl196000 	CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
7788942c5e3cSpl196000 	CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
7789942c5e3cSpl196000 	CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
7790942c5e3cSpl196000 	CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
7791942c5e3cSpl196000 	CT_IS_CONTAINER_MEATADATA_STANDARD, \
7792942c5e3cSpl196000 	    "CT_IS_CONTAINER_MEATADATA_STANDARD", \
7793942c5e3cSpl196000 	CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
7794942c5e3cSpl196000 	CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
7795942c5e3cSpl196000 	CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
7796942c5e3cSpl196000 	CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
7797942c5e3cSpl196000 	CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
7798942c5e3cSpl196000 	CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
7799942c5e3cSpl196000 	CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
7800942c5e3cSpl196000 	CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
7801942c5e3cSpl196000 	CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
7802942c5e3cSpl196000 	CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
7803942c5e3cSpl196000 	CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
7804942c5e3cSpl196000 	CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
7805942c5e3cSpl196000 	CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
7806942c5e3cSpl196000 	CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
7807942c5e3cSpl196000 	CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
7808942c5e3cSpl196000 	CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
7809942c5e3cSpl196000 	CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
7810942c5e3cSpl196000 	CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
7811942c5e3cSpl196000 	CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
7812942c5e3cSpl196000 
7813942c5e3cSpl196000 #define	AAC_CL_SUBCMD_KEY_STRINGS \
7814942c5e3cSpl196000 	CL_NULL, "CL_NULL", \
7815942c5e3cSpl196000 	DS_INIT, "DS_INIT", \
7816942c5e3cSpl196000 	DS_RESCAN, "DS_RESCAN", \
7817942c5e3cSpl196000 	DS_CREATE, "DS_CREATE", \
7818942c5e3cSpl196000 	DS_DELETE, "DS_DELETE", \
7819942c5e3cSpl196000 	DS_ADD_DISK, "DS_ADD_DISK", \
7820942c5e3cSpl196000 	DS_REMOVE_DISK, "DS_REMOVE_DISK", \
7821942c5e3cSpl196000 	DS_MOVE_DISK, "DS_MOVE_DISK", \
7822942c5e3cSpl196000 	DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
7823942c5e3cSpl196000 	DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
7824942c5e3cSpl196000 	DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
7825942c5e3cSpl196000 	DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
7826942c5e3cSpl196000 	DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
7827942c5e3cSpl196000 	DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
7828942c5e3cSpl196000 	DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
7829942c5e3cSpl196000 	DS_GET_DRIVES, "DS_GET_DRIVES", \
7830942c5e3cSpl196000 	DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
7831942c5e3cSpl196000 	DS_ONLINE, "DS_ONLINE", \
7832942c5e3cSpl196000 	DS_OFFLINE, "DS_OFFLINE", \
7833942c5e3cSpl196000 	DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
7834942c5e3cSpl196000 	DS_FSAPRINT, "DS_FSAPRINT", \
7835942c5e3cSpl196000 	CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
7836942c5e3cSpl196000 	CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
7837942c5e3cSpl196000 	CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
7838942c5e3cSpl196000 	CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
7839942c5e3cSpl196000 	CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
7840942c5e3cSpl196000 	CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
7841942c5e3cSpl196000 	CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
7842942c5e3cSpl196000 	CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
7843942c5e3cSpl196000 	CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
7844942c5e3cSpl196000 	CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
7845942c5e3cSpl196000 	CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
7846942c5e3cSpl196000 	CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
7847942c5e3cSpl196000 	CC_GET_BUSINFO, "CC_GET_BUSINFO", \
7848942c5e3cSpl196000 	CC_GET_PORTINFO, "CC_GET_PORTINFO", \
7849942c5e3cSpl196000 	CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
7850942c5e3cSpl196000 	CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
7851942c5e3cSpl196000 	CQ_QUORUM_OP, "CQ_QUORUM_OP"
7852942c5e3cSpl196000 
7853942c5e3cSpl196000 #define	AAC_AIF_SUBCMD_KEY_STRINGS \
7854942c5e3cSpl196000 	AifCmdEventNotify, "AifCmdEventNotify", \
7855942c5e3cSpl196000 	AifCmdJobProgress, "AifCmdJobProgress", \
7856942c5e3cSpl196000 	AifCmdAPIReport, "AifCmdAPIReport", \
7857942c5e3cSpl196000 	AifCmdDriverNotify, "AifCmdDriverNotify", \
7858942c5e3cSpl196000 	AifReqJobList, "AifReqJobList", \
7859942c5e3cSpl196000 	AifReqJobsForCtr, "AifReqJobsForCtr", \
7860942c5e3cSpl196000 	AifReqJobsForScsi, "AifReqJobsForScsi", \
7861942c5e3cSpl196000 	AifReqJobReport, "AifReqJobReport", \
7862942c5e3cSpl196000 	AifReqTerminateJob, "AifReqTerminateJob", \
7863942c5e3cSpl196000 	AifReqSuspendJob, "AifReqSuspendJob", \
7864942c5e3cSpl196000 	AifReqResumeJob, "AifReqResumeJob", \
7865942c5e3cSpl196000 	AifReqSendAPIReport, "AifReqSendAPIReport", \
7866942c5e3cSpl196000 	AifReqAPIJobStart, "AifReqAPIJobStart", \
7867942c5e3cSpl196000 	AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
7868942c5e3cSpl196000 	AifReqAPIJobFinish, "AifReqAPIJobFinish"
7869942c5e3cSpl196000 
7870942c5e3cSpl196000 #define	AAC_IOCTL_SUBCMD_KEY_STRINGS \
7871942c5e3cSpl196000 	Reserved_IOCTL, "Reserved_IOCTL", \
7872942c5e3cSpl196000 	GetDeviceHandle, "GetDeviceHandle", \
7873942c5e3cSpl196000 	BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
7874942c5e3cSpl196000 	DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
7875942c5e3cSpl196000 	RescanBus, "RescanBus", \
7876942c5e3cSpl196000 	GetDeviceProbeInfo, "GetDeviceProbeInfo", \
7877942c5e3cSpl196000 	GetDeviceCapacity, "GetDeviceCapacity", \
7878942c5e3cSpl196000 	GetContainerProbeInfo, "GetContainerProbeInfo", \
7879942c5e3cSpl196000 	GetRequestedMemorySize, "GetRequestedMemorySize", \
7880942c5e3cSpl196000 	GetBusInfo, "GetBusInfo", \
7881942c5e3cSpl196000 	GetVendorSpecific, "GetVendorSpecific", \
7882942c5e3cSpl196000 	EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
7883942c5e3cSpl196000 	EnhancedGetBusInfo, "EnhancedGetBusInfo", \
7884942c5e3cSpl196000 	SetupExtendedCounters, "SetupExtendedCounters", \
7885942c5e3cSpl196000 	GetPerformanceCounters, "GetPerformanceCounters", \
7886942c5e3cSpl196000 	ResetPerformanceCounters, "ResetPerformanceCounters", \
7887942c5e3cSpl196000 	ReadModePage, "ReadModePage", \
7888942c5e3cSpl196000 	WriteModePage, "WriteModePage", \
7889942c5e3cSpl196000 	ReadDriveParameter, "ReadDriveParameter", \
7890942c5e3cSpl196000 	WriteDriveParameter, "WriteDriveParameter", \
7891942c5e3cSpl196000 	ResetAdapter, "ResetAdapter", \
7892942c5e3cSpl196000 	ResetBus, "ResetBus", \
7893942c5e3cSpl196000 	ResetBusDevice, "ResetBusDevice", \
7894942c5e3cSpl196000 	ExecuteSrb, "ExecuteSrb", \
7895942c5e3cSpl196000 	Create_IO_Task, "Create_IO_Task", \
7896942c5e3cSpl196000 	Delete_IO_Task, "Delete_IO_Task", \
7897942c5e3cSpl196000 	Get_IO_Task_Info, "Get_IO_Task_Info", \
7898942c5e3cSpl196000 	Check_Task_Progress, "Check_Task_Progress", \
7899942c5e3cSpl196000 	InjectError, "InjectError", \
7900942c5e3cSpl196000 	GetDeviceDefectCounts, "GetDeviceDefectCounts", \
7901942c5e3cSpl196000 	GetDeviceDefectInfo, "GetDeviceDefectInfo", \
7902942c5e3cSpl196000 	GetDeviceStatus, "GetDeviceStatus", \
7903942c5e3cSpl196000 	ClearDeviceStatus, "ClearDeviceStatus", \
7904942c5e3cSpl196000 	DiskSpinControl, "DiskSpinControl", \
7905942c5e3cSpl196000 	DiskSmartControl, "DiskSmartControl", \
7906942c5e3cSpl196000 	WriteSame, "WriteSame", \
7907942c5e3cSpl196000 	ReadWriteLong, "ReadWriteLong", \
7908942c5e3cSpl196000 	FormatUnit, "FormatUnit", \
7909942c5e3cSpl196000 	TargetDeviceControl, "TargetDeviceControl", \
7910942c5e3cSpl196000 	TargetChannelControl, "TargetChannelControl", \
7911942c5e3cSpl196000 	FlashNewCode, "FlashNewCode", \
7912942c5e3cSpl196000 	DiskCheck, "DiskCheck", \
7913942c5e3cSpl196000 	RequestSense, "RequestSense", \
7914942c5e3cSpl196000 	DiskPERControl, "DiskPERControl", \
7915942c5e3cSpl196000 	Read10, "Read10", \
7916942c5e3cSpl196000 	Write10, "Write10"
7917942c5e3cSpl196000 
7918942c5e3cSpl196000 #define	AAC_AIFEN_KEY_STRINGS \
7919942c5e3cSpl196000 	AifEnGeneric, "Generic", \
7920942c5e3cSpl196000 	AifEnTaskComplete, "TaskComplete", \
7921942c5e3cSpl196000 	AifEnConfigChange, "Config change", \
7922942c5e3cSpl196000 	AifEnContainerChange, "Container change", \
7923942c5e3cSpl196000 	AifEnDeviceFailure, "device failed", \
7924942c5e3cSpl196000 	AifEnMirrorFailover, "Mirror failover", \
7925942c5e3cSpl196000 	AifEnContainerEvent, "container event", \
7926942c5e3cSpl196000 	AifEnFileSystemChange, "File system changed", \
7927942c5e3cSpl196000 	AifEnConfigPause, "Container pause event", \
7928942c5e3cSpl196000 	AifEnConfigResume, "Container resume event", \
7929942c5e3cSpl196000 	AifEnFailoverChange, "Failover space assignment changed", \
7930942c5e3cSpl196000 	AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
7931942c5e3cSpl196000 	AifEnEnclosureManagement, "Enclosure management event", \
7932942c5e3cSpl196000 	AifEnBatteryEvent, "battery event", \
7933942c5e3cSpl196000 	AifEnAddContainer, "Add container", \
7934942c5e3cSpl196000 	AifEnDeleteContainer, "Delete container", \
7935942c5e3cSpl196000 	AifEnSMARTEvent, "SMART Event", \
7936942c5e3cSpl196000 	AifEnBatteryNeedsRecond, "battery needs reconditioning", \
7937942c5e3cSpl196000 	AifEnClusterEvent, "cluster event", \
7938942c5e3cSpl196000 	AifEnDiskSetEvent, "disk set event occured", \
7939942c5e3cSpl196000 	AifDenMorphComplete, "morph operation completed", \
7940942c5e3cSpl196000 	AifDenVolumeExtendComplete, "VolumeExtendComplete"
7941942c5e3cSpl196000 
7942942c5e3cSpl196000 struct aac_key_strings {
7943942c5e3cSpl196000 	int key;
7944942c5e3cSpl196000 	char *message;
7945942c5e3cSpl196000 };
7946942c5e3cSpl196000 
7947942c5e3cSpl196000 extern struct scsi_key_strings scsi_cmds[];
7948942c5e3cSpl196000 
7949942c5e3cSpl196000 static struct aac_key_strings aac_fib_cmds[] = {
7950942c5e3cSpl196000 	AAC_FIB_CMD_KEY_STRINGS,
7951942c5e3cSpl196000 	-1,			NULL
7952942c5e3cSpl196000 };
7953942c5e3cSpl196000 
7954942c5e3cSpl196000 static struct aac_key_strings aac_ctvm_subcmds[] = {
7955942c5e3cSpl196000 	AAC_CTVM_SUBCMD_KEY_STRINGS,
7956942c5e3cSpl196000 	-1,			NULL
7957942c5e3cSpl196000 };
7958942c5e3cSpl196000 
7959942c5e3cSpl196000 static struct aac_key_strings aac_ct_subcmds[] = {
7960942c5e3cSpl196000 	AAC_CT_SUBCMD_KEY_STRINGS,
7961942c5e3cSpl196000 	-1,			NULL
7962942c5e3cSpl196000 };
7963942c5e3cSpl196000 
7964942c5e3cSpl196000 static struct aac_key_strings aac_cl_subcmds[] = {
7965942c5e3cSpl196000 	AAC_CL_SUBCMD_KEY_STRINGS,
7966942c5e3cSpl196000 	-1,			NULL
7967942c5e3cSpl196000 };
7968942c5e3cSpl196000 
7969942c5e3cSpl196000 static struct aac_key_strings aac_aif_subcmds[] = {
7970942c5e3cSpl196000 	AAC_AIF_SUBCMD_KEY_STRINGS,
7971942c5e3cSpl196000 	-1,			NULL
7972942c5e3cSpl196000 };
7973942c5e3cSpl196000 
7974942c5e3cSpl196000 static struct aac_key_strings aac_ioctl_subcmds[] = {
7975942c5e3cSpl196000 	AAC_IOCTL_SUBCMD_KEY_STRINGS,
7976942c5e3cSpl196000 	-1,			NULL
7977942c5e3cSpl196000 };
7978942c5e3cSpl196000 
7979942c5e3cSpl196000 static struct aac_key_strings aac_aifens[] = {
7980942c5e3cSpl196000 	AAC_AIFEN_KEY_STRINGS,
7981942c5e3cSpl196000 	-1,			NULL
7982942c5e3cSpl196000 };
7983942c5e3cSpl196000 
7984942c5e3cSpl196000 /*
7985942c5e3cSpl196000  * The following function comes from Adaptec:
7986942c5e3cSpl196000  *
7987942c5e3cSpl196000  * Get the firmware print buffer parameters from the firmware,
7988942c5e3cSpl196000  * if the command was successful map in the address.
7989942c5e3cSpl196000  */
7990942c5e3cSpl196000 static int
aac_get_fw_debug_buffer(struct aac_softstate * softs)7991942c5e3cSpl196000 aac_get_fw_debug_buffer(struct aac_softstate *softs)
7992942c5e3cSpl196000 {
7993942c5e3cSpl196000 	if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
7994942c5e3cSpl196000 	    0, 0, 0, 0, NULL) == AACOK) {
7995942c5e3cSpl196000 		uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
7996942c5e3cSpl196000 		uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
7997942c5e3cSpl196000 		uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
7998942c5e3cSpl196000 		uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
7999942c5e3cSpl196000 
8000942c5e3cSpl196000 		if (mondrv_buf_size) {
8001942c5e3cSpl196000 			uint32_t offset = mondrv_buf_paddrl - \
8002942c5e3cSpl196000 			    softs->pci_mem_base_paddr;
8003942c5e3cSpl196000 
8004942c5e3cSpl196000 			/*
8005942c5e3cSpl196000 			 * See if the address is already mapped in, and
8006942c5e3cSpl196000 			 * if so set it up from the base address
8007942c5e3cSpl196000 			 */
8008942c5e3cSpl196000 			if ((mondrv_buf_paddrh == 0) &&
8009942c5e3cSpl196000 			    (offset + mondrv_buf_size < softs->map_size)) {
8010942c5e3cSpl196000 				mutex_enter(&aac_prt_mutex);
8011942c5e3cSpl196000 				softs->debug_buf_offset = offset;
8012942c5e3cSpl196000 				softs->debug_header_size = mondrv_hdr_size;
8013942c5e3cSpl196000 				softs->debug_buf_size = mondrv_buf_size;
8014942c5e3cSpl196000 				softs->debug_fw_flags = 0;
8015942c5e3cSpl196000 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8016942c5e3cSpl196000 				mutex_exit(&aac_prt_mutex);
8017942c5e3cSpl196000 
8018942c5e3cSpl196000 				return (AACOK);
8019942c5e3cSpl196000 			}
8020942c5e3cSpl196000 		}
8021942c5e3cSpl196000 	}
8022942c5e3cSpl196000 	return (AACERR);
8023942c5e3cSpl196000 }
8024942c5e3cSpl196000 
8025942c5e3cSpl196000 int
aac_dbflag_on(struct aac_softstate * softs,int flag)8026942c5e3cSpl196000 aac_dbflag_on(struct aac_softstate *softs, int flag)
8027942c5e3cSpl196000 {
8028942c5e3cSpl196000 	int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
8029942c5e3cSpl196000 
8030942c5e3cSpl196000 	return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
8031942c5e3cSpl196000 	    AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
8032942c5e3cSpl196000 }
8033942c5e3cSpl196000 
8034942c5e3cSpl196000 static void
aac_cmn_err(struct aac_softstate * softs,uint_t lev,char sl,int noheader)8035942c5e3cSpl196000 aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
8036942c5e3cSpl196000 {
8037942c5e3cSpl196000 	if (noheader) {
8038942c5e3cSpl196000 		if (sl) {
8039942c5e3cSpl196000 			aac_fmt[0] = sl;
8040942c5e3cSpl196000 			cmn_err(lev, aac_fmt, aac_prt_buf);
8041942c5e3cSpl196000 		} else {
8042942c5e3cSpl196000 			cmn_err(lev, &aac_fmt[1], aac_prt_buf);
8043942c5e3cSpl196000 		}
8044942c5e3cSpl196000 	} else {
8045942c5e3cSpl196000 		if (sl) {
8046942c5e3cSpl196000 			aac_fmt_header[0] = sl;
8047942c5e3cSpl196000 			cmn_err(lev, aac_fmt_header,
8048942c5e3cSpl196000 			    softs->vendor_name, softs->instance,
8049942c5e3cSpl196000 			    aac_prt_buf);
8050942c5e3cSpl196000 		} else {
8051942c5e3cSpl196000 			cmn_err(lev, &aac_fmt_header[1],
8052942c5e3cSpl196000 			    softs->vendor_name, softs->instance,
8053942c5e3cSpl196000 			    aac_prt_buf);
8054942c5e3cSpl196000 		}
8055942c5e3cSpl196000 	}
8056942c5e3cSpl196000 }
8057942c5e3cSpl196000 
8058942c5e3cSpl196000 /*
8059942c5e3cSpl196000  * The following function comes from Adaptec:
8060942c5e3cSpl196000  *
8061942c5e3cSpl196000  * Format and print out the data passed in to UART or console
8062942c5e3cSpl196000  * as specified by debug flags.
8063942c5e3cSpl196000  */
8064942c5e3cSpl196000 void
aac_printf(struct aac_softstate * softs,uint_t lev,const char * fmt,...)8065942c5e3cSpl196000 aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
8066942c5e3cSpl196000 {
8067942c5e3cSpl196000 	va_list args;
8068942c5e3cSpl196000 	char sl; /* system log character */
8069942c5e3cSpl196000 
8070942c5e3cSpl196000 	mutex_enter(&aac_prt_mutex);
8071942c5e3cSpl196000 	/* Set up parameters and call sprintf function to format the data */
8072942c5e3cSpl196000 	if (strchr("^!?", fmt[0]) == NULL) {
8073942c5e3cSpl196000 		sl = 0;
8074942c5e3cSpl196000 	} else {
8075942c5e3cSpl196000 		sl = fmt[0];
8076942c5e3cSpl196000 		fmt++;
8077942c5e3cSpl196000 	}
8078942c5e3cSpl196000 	va_start(args, fmt);
8079942c5e3cSpl196000 	(void) vsprintf(aac_prt_buf, fmt, args);
8080942c5e3cSpl196000 	va_end(args);
8081942c5e3cSpl196000 
8082942c5e3cSpl196000 	/* Make sure the softs structure has been passed in for this section */
8083942c5e3cSpl196000 	if (softs) {
8084942c5e3cSpl196000 		if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
8085942c5e3cSpl196000 		    /* If we are set up for a Firmware print */
8086942c5e3cSpl196000 		    (softs->debug_buf_size)) {
8087942c5e3cSpl196000 			uint32_t count, i;
8088942c5e3cSpl196000 
8089942c5e3cSpl196000 			/* Make sure the string size is within boundaries */
8090942c5e3cSpl196000 			count = strlen(aac_prt_buf);
8091942c5e3cSpl196000 			if (count > softs->debug_buf_size)
8092942c5e3cSpl196000 				count = (uint16_t)softs->debug_buf_size;
8093942c5e3cSpl196000 
8094942c5e3cSpl196000 			/*
8095942c5e3cSpl196000 			 * Wait for no more than AAC_PRINT_TIMEOUT for the
8096942c5e3cSpl196000 			 * previous message length to clear (the handshake).
8097942c5e3cSpl196000 			 */
8098942c5e3cSpl196000 			for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
8099942c5e3cSpl196000 				if (!PCI_MEM_GET32(softs,
8100942c5e3cSpl196000 				    softs->debug_buf_offset + \
8101942c5e3cSpl196000 				    AAC_FW_DBG_STRLEN_OFFSET))
8102942c5e3cSpl196000 					break;
8103942c5e3cSpl196000 
8104942c5e3cSpl196000 				drv_usecwait(1000);
8105942c5e3cSpl196000 			}
8106942c5e3cSpl196000 
8107942c5e3cSpl196000 			/*
8108942c5e3cSpl196000 			 * If the length is clear, copy over the message, the
8109942c5e3cSpl196000 			 * flags, and the length. Make sure the length is the
8110942c5e3cSpl196000 			 * last because that is the signal for the Firmware to
8111942c5e3cSpl196000 			 * pick it up.
8112942c5e3cSpl196000 			 */
8113942c5e3cSpl196000 			if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
8114942c5e3cSpl196000 			    AAC_FW_DBG_STRLEN_OFFSET)) {
8115942c5e3cSpl196000 				PCI_MEM_REP_PUT8(softs,
8116942c5e3cSpl196000 				    softs->debug_buf_offset + \
8117942c5e3cSpl196000 				    softs->debug_header_size,
8118942c5e3cSpl196000 				    aac_prt_buf, count);
8119942c5e3cSpl196000 				PCI_MEM_PUT32(softs,
8120942c5e3cSpl196000 				    softs->debug_buf_offset + \
8121942c5e3cSpl196000 				    AAC_FW_DBG_FLAGS_OFFSET,
8122942c5e3cSpl196000 				    softs->debug_fw_flags);
8123942c5e3cSpl196000 				PCI_MEM_PUT32(softs,
8124942c5e3cSpl196000 				    softs->debug_buf_offset + \
8125942c5e3cSpl196000 				    AAC_FW_DBG_STRLEN_OFFSET, count);
8126942c5e3cSpl196000 			} else {
8127942c5e3cSpl196000 				cmn_err(CE_WARN, "UART output fail");
8128942c5e3cSpl196000 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
8129942c5e3cSpl196000 			}
8130942c5e3cSpl196000 		}
8131942c5e3cSpl196000 
8132942c5e3cSpl196000 		/*
8133942c5e3cSpl196000 		 * If the Kernel Debug Print flag is set, send it off
8134942c5e3cSpl196000 		 * to the Kernel Debugger
8135942c5e3cSpl196000 		 */
8136942c5e3cSpl196000 		if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8137942c5e3cSpl196000 			aac_cmn_err(softs, lev, sl,
8138942c5e3cSpl196000 			    (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
8139942c5e3cSpl196000 	} else {
8140942c5e3cSpl196000 		/* Driver not initialized yet, no firmware or header output */
8141942c5e3cSpl196000 		if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
8142942c5e3cSpl196000 			aac_cmn_err(softs, lev, sl, 1);
8143942c5e3cSpl196000 	}
8144942c5e3cSpl196000 	mutex_exit(&aac_prt_mutex);
8145942c5e3cSpl196000 }
8146942c5e3cSpl196000 
8147942c5e3cSpl196000 /*
8148942c5e3cSpl196000  * Translate command number to description string
8149942c5e3cSpl196000  */
8150942c5e3cSpl196000 static char *
aac_cmd_name(int cmd,struct aac_key_strings * cmdlist)8151942c5e3cSpl196000 aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
8152942c5e3cSpl196000 {
8153942c5e3cSpl196000 	int i;
8154942c5e3cSpl196000 
8155942c5e3cSpl196000 	for (i = 0; cmdlist[i].key != -1; i++) {
8156942c5e3cSpl196000 		if (cmd == cmdlist[i].key)
8157942c5e3cSpl196000 			return (cmdlist[i].message);
8158942c5e3cSpl196000 	}
8159942c5e3cSpl196000 	return (NULL);
8160942c5e3cSpl196000 }
8161942c5e3cSpl196000 
8162942c5e3cSpl196000 static void
aac_print_scmd(struct aac_softstate * softs,struct aac_cmd * acp)8163942c5e3cSpl196000 aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
8164942c5e3cSpl196000 {
8165942c5e3cSpl196000 	struct scsi_pkt *pkt = acp->pkt;
8166942c5e3cSpl196000 	struct scsi_address *ap = &pkt->pkt_address;
816758bc78c7SXin Chen 	int is_pd = 0;
8168942c5e3cSpl196000 	int ctl = ddi_get_instance(softs->devinfo_p);
8169942c5e3cSpl196000 	int tgt = ap->a_target;
8170942c5e3cSpl196000 	int lun = ap->a_lun;
8171a74f7440Spl196000 	union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
8172942c5e3cSpl196000 	uchar_t cmd = cdbp->scc_cmd;
8173942c5e3cSpl196000 	char *desc;
8174942c5e3cSpl196000 
817558bc78c7SXin Chen 	if (tgt >= AAC_MAX_LD) {
817658bc78c7SXin Chen 		is_pd = 1;
817758bc78c7SXin Chen 		ctl = ((struct aac_nondasd *)acp->dvp)->bus;
817858bc78c7SXin Chen 		tgt = ((struct aac_nondasd *)acp->dvp)->tid;
817958bc78c7SXin Chen 		lun = 0;
818058bc78c7SXin Chen 	}
818158bc78c7SXin Chen 
8182942c5e3cSpl196000 	if ((desc = aac_cmd_name(cmd,
8183942c5e3cSpl196000 	    (struct aac_key_strings *)scsi_cmds)) == NULL) {
8184942c5e3cSpl196000 		aac_printf(softs, CE_NOTE,
818558bc78c7SXin Chen 		    "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
818658bc78c7SXin Chen 		    cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
8187942c5e3cSpl196000 		return;
8188942c5e3cSpl196000 	}
8189942c5e3cSpl196000 
8190942c5e3cSpl196000 	switch (cmd) {
8191942c5e3cSpl196000 	case SCMD_READ:
8192942c5e3cSpl196000 	case SCMD_WRITE:
8193942c5e3cSpl196000 		aac_printf(softs, CE_NOTE,
819458bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8195942c5e3cSpl196000 		    desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
8196942c5e3cSpl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
819758bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8198942c5e3cSpl196000 		break;
8199942c5e3cSpl196000 	case SCMD_READ_G1:
8200942c5e3cSpl196000 	case SCMD_WRITE_G1:
8201942c5e3cSpl196000 		aac_printf(softs, CE_NOTE,
820258bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
8203942c5e3cSpl196000 		    desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
8204942c5e3cSpl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
820558bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8206942c5e3cSpl196000 		break;
8207942c5e3cSpl196000 	case SCMD_READ_G4:
8208942c5e3cSpl196000 	case SCMD_WRITE_G4:
8209942c5e3cSpl196000 		aac_printf(softs, CE_NOTE,
821058bc78c7SXin Chen 		    "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
8211942c5e3cSpl196000 		    desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
8212942c5e3cSpl196000 		    GETG4COUNT(cdbp),
8213942c5e3cSpl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
821458bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
821558bc78c7SXin Chen 		break;
821658bc78c7SXin Chen 	case SCMD_READ_G5:
821758bc78c7SXin Chen 	case SCMD_WRITE_G5:
821858bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
821958bc78c7SXin Chen 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
822058bc78c7SXin Chen 		    desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
822158bc78c7SXin Chen 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
822258bc78c7SXin Chen 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
8223942c5e3cSpl196000 		break;
8224942c5e3cSpl196000 	default:
822558bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
822658bc78c7SXin Chen 		    desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
8227942c5e3cSpl196000 	}
8228942c5e3cSpl196000 }
8229942c5e3cSpl196000 
8230942c5e3cSpl196000 void
aac_print_fib(struct aac_softstate * softs,struct aac_slot * slotp)823158bc78c7SXin Chen aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
8232942c5e3cSpl196000 {
823358bc78c7SXin Chen 	struct aac_cmd *acp = slotp->acp;
823458bc78c7SXin Chen 	struct aac_fib *fibp = slotp->fibp;
823558bc78c7SXin Chen 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
8236942c5e3cSpl196000 	uint16_t fib_size;
823758bc78c7SXin Chen 	uint32_t fib_cmd, sub_cmd;
8238942c5e3cSpl196000 	char *cmdstr, *subcmdstr;
823958bc78c7SXin Chen 	char *caller;
824058bc78c7SXin Chen 	int i;
8241942c5e3cSpl196000 
824258bc78c7SXin Chen 	if (acp) {
824358bc78c7SXin Chen 		if (!(softs->debug_fib_flags & acp->fib_flags))
824458bc78c7SXin Chen 			return;
824558bc78c7SXin Chen 		if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
824658bc78c7SXin Chen 			caller = "SCMD";
824758bc78c7SXin Chen 		else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
824858bc78c7SXin Chen 			caller = "IOCTL";
824958bc78c7SXin Chen 		else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
825058bc78c7SXin Chen 			caller = "SRB";
825158bc78c7SXin Chen 		else
825258bc78c7SXin Chen 			return;
825358bc78c7SXin Chen 	} else {
825458bc78c7SXin Chen 		if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
825558bc78c7SXin Chen 			return;
825658bc78c7SXin Chen 		caller = "SYNC";
825758bc78c7SXin Chen 	}
825858bc78c7SXin Chen 
825958bc78c7SXin Chen 	fib_cmd = ddi_get16(acc, &fibp->Header.Command);
8260942c5e3cSpl196000 	cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
826158bc78c7SXin Chen 	sub_cmd = (uint32_t)-1;
8262942c5e3cSpl196000 	subcmdstr = NULL;
8263942c5e3cSpl196000 
826458bc78c7SXin Chen 	/* Print FIB header */
826558bc78c7SXin Chen 	if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
826658bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
826758bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     XferState  %d",
826858bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.XferState));
826958bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Command    %d",
827058bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.Command));
827158bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     StructType %d",
827258bc78c7SXin Chen 		    ddi_get8(acc, &fibp->Header.StructType));
827358bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Flags      0x%x",
827458bc78c7SXin Chen 		    ddi_get8(acc, &fibp->Header.Flags));
827558bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     Size       %d",
827658bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.Size));
827758bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderSize %d",
827858bc78c7SXin Chen 		    ddi_get16(acc, &fibp->Header.SenderSize));
827958bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderAddr 0x%x",
828058bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.SenderFibAddress));
828158bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     RcvrAddr   0x%x",
828258bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
828358bc78c7SXin Chen 		aac_printf(softs, CE_NOTE, "     SenderData 0x%x",
828458bc78c7SXin Chen 		    ddi_get32(acc, &fibp->Header.SenderData));
828558bc78c7SXin Chen 	}
828658bc78c7SXin Chen 
828758bc78c7SXin Chen 	/* Print FIB data */
8288942c5e3cSpl196000 	switch (fib_cmd) {
8289942c5e3cSpl196000 	case ContainerCommand:
829058bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
829158bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
8292942c5e3cSpl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
8293942c5e3cSpl196000 		if (subcmdstr == NULL)
8294942c5e3cSpl196000 			break;
829558bc78c7SXin Chen 
829658bc78c7SXin Chen 		switch (sub_cmd) {
829758bc78c7SXin Chen 		case VM_ContainerConfig: {
829858bc78c7SXin Chen 			struct aac_Container *pContainer =
829958bc78c7SXin Chen 			    (struct aac_Container *)fibp->data;
830058bc78c7SXin Chen 
8301942c5e3cSpl196000 			fib_cmd = sub_cmd;
8302942c5e3cSpl196000 			cmdstr = subcmdstr;
830358bc78c7SXin Chen 			sub_cmd = (uint32_t)-1;
8304942c5e3cSpl196000 			subcmdstr = NULL;
8305942c5e3cSpl196000 
830658bc78c7SXin Chen 			sub_cmd = ddi_get32(acc,
830758bc78c7SXin Chen 			    &pContainer->CTCommand.command);
8308942c5e3cSpl196000 			subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
8309942c5e3cSpl196000 			if (subcmdstr == NULL)
8310942c5e3cSpl196000 				break;
8311942c5e3cSpl196000 			aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
8312942c5e3cSpl196000 			    subcmdstr,
831358bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[0]),
831458bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[1]),
831558bc78c7SXin Chen 			    ddi_get32(acc, &pContainer->CTCommand.param[2]));
8316942c5e3cSpl196000 			return;
831758bc78c7SXin Chen 		}
831858bc78c7SXin Chen 
8319942c5e3cSpl196000 		case VM_Ioctl:
832058bc78c7SXin Chen 			fib_cmd = sub_cmd;
832158bc78c7SXin Chen 			cmdstr = subcmdstr;
832258bc78c7SXin Chen 			sub_cmd = (uint32_t)-1;
832358bc78c7SXin Chen 			subcmdstr = NULL;
832458bc78c7SXin Chen 
832558bc78c7SXin Chen 			sub_cmd = ddi_get32(acc,
832658bc78c7SXin Chen 			    (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
8327942c5e3cSpl196000 			subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
8328942c5e3cSpl196000 			break;
832958bc78c7SXin Chen 
833058bc78c7SXin Chen 		case VM_CtBlockRead:
833158bc78c7SXin Chen 		case VM_CtBlockWrite: {
833258bc78c7SXin Chen 			struct aac_blockread *br =
833358bc78c7SXin Chen 			    (struct aac_blockread *)fibp->data;
833458bc78c7SXin Chen 			struct aac_sg_table *sg = &br->SgMap;
833558bc78c7SXin Chen 			uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
833658bc78c7SXin Chen 
833758bc78c7SXin Chen 			aac_printf(softs, CE_NOTE,
833858bc78c7SXin Chen 			    "FIB> %s Container %d  0x%x/%d", subcmdstr,
833958bc78c7SXin Chen 			    ddi_get32(acc, &br->ContainerId),
834058bc78c7SXin Chen 			    ddi_get32(acc, &br->BlockNumber),
834158bc78c7SXin Chen 			    ddi_get32(acc, &br->ByteCount));
834258bc78c7SXin Chen 			for (i = 0; i < sgcount; i++)
834358bc78c7SXin Chen 				aac_printf(softs, CE_NOTE,
834458bc78c7SXin Chen 				    "     %d: 0x%08x/%d", i,
834558bc78c7SXin Chen 				    ddi_get32(acc, &sg->SgEntry[i].SgAddress),
834658bc78c7SXin Chen 				    ddi_get32(acc, &sg->SgEntry[i]. \
834758bc78c7SXin Chen 				    SgByteCount));
834858bc78c7SXin Chen 			return;
834958bc78c7SXin Chen 		}
8350942c5e3cSpl196000 		}
8351942c5e3cSpl196000 		break;
8352942c5e3cSpl196000 
835358bc78c7SXin Chen 	case ContainerCommand64: {
835458bc78c7SXin Chen 		struct aac_blockread64 *br =
835558bc78c7SXin Chen 		    (struct aac_blockread64 *)fibp->data;
835658bc78c7SXin Chen 		struct aac_sg_table64 *sg = &br->SgMap64;
835758bc78c7SXin Chen 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
835858bc78c7SXin Chen 		uint64_t sgaddr;
835958bc78c7SXin Chen 
836058bc78c7SXin Chen 		sub_cmd = br->Command;
836158bc78c7SXin Chen 		subcmdstr = NULL;
836258bc78c7SXin Chen 		if (sub_cmd == VM_CtHostRead64)
836358bc78c7SXin Chen 			subcmdstr = "VM_CtHostRead64";
836458bc78c7SXin Chen 		else if (sub_cmd == VM_CtHostWrite64)
836558bc78c7SXin Chen 			subcmdstr = "VM_CtHostWrite64";
836658bc78c7SXin Chen 		else
836758bc78c7SXin Chen 			break;
836858bc78c7SXin Chen 
836958bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
837058bc78c7SXin Chen 		    "FIB> %s Container %d  0x%x/%d", subcmdstr,
837158bc78c7SXin Chen 		    ddi_get16(acc, &br->ContainerId),
837258bc78c7SXin Chen 		    ddi_get32(acc, &br->BlockNumber),
837358bc78c7SXin Chen 		    ddi_get16(acc, &br->SectorCount));
837458bc78c7SXin Chen 		for (i = 0; i < sgcount; i++) {
837558bc78c7SXin Chen 			sgaddr = ddi_get64(acc,
837658bc78c7SXin Chen 			    &sg->SgEntry64[i].SgAddress);
837758bc78c7SXin Chen 			aac_printf(softs, CE_NOTE,
837858bc78c7SXin Chen 			    "     %d: 0x%08x.%08x/%d", i,
837958bc78c7SXin Chen 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
838058bc78c7SXin Chen 			    ddi_get32(acc, &sg->SgEntry64[i]. \
838158bc78c7SXin Chen 			    SgByteCount));
838258bc78c7SXin Chen 		}
838358bc78c7SXin Chen 		return;
838458bc78c7SXin Chen 	}
838558bc78c7SXin Chen 
838658bc78c7SXin Chen 	case RawIo: {
838758bc78c7SXin Chen 		struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
838858bc78c7SXin Chen 		struct aac_sg_tableraw *sg = &io->SgMapRaw;
838958bc78c7SXin Chen 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
839058bc78c7SXin Chen 		uint64_t sgaddr;
839158bc78c7SXin Chen 
839258bc78c7SXin Chen 		aac_printf(softs, CE_NOTE,
839358bc78c7SXin Chen 		    "FIB> RawIo Container %d  0x%llx/%d 0x%x",
839458bc78c7SXin Chen 		    ddi_get16(acc, &io->ContainerId),
839558bc78c7SXin Chen 		    ddi_get64(acc, &io->BlockNumber),
839658bc78c7SXin Chen 		    ddi_get32(acc, &io->ByteCount),
839758bc78c7SXin Chen 		    ddi_get16(acc, &io->Flags));
839858bc78c7SXin Chen 		for (i = 0; i < sgcount; i++) {
839958bc78c7SXin Chen 			sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
840058bc78c7SXin Chen 			aac_printf(softs, CE_NOTE, "     %d: 0x%08x.%08x/%d", i,
840158bc78c7SXin Chen 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
840258bc78c7SXin Chen 			    ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
840358bc78c7SXin Chen 		}
840458bc78c7SXin Chen 		return;
840558bc78c7SXin Chen 	}
840658bc78c7SXin Chen 
8407942c5e3cSpl196000 	case ClusterCommand:
840858bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
840958bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8410942c5e3cSpl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
8411942c5e3cSpl196000 		break;
8412942c5e3cSpl196000 
8413942c5e3cSpl196000 	case AifRequest:
841458bc78c7SXin Chen 		sub_cmd = ddi_get32(acc,
841558bc78c7SXin Chen 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
8416942c5e3cSpl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
8417942c5e3cSpl196000 		break;
8418942c5e3cSpl196000 
8419942c5e3cSpl196000 	default:
8420942c5e3cSpl196000 		break;
8421942c5e3cSpl196000 	}
8422942c5e3cSpl196000 
842358bc78c7SXin Chen 	fib_size = ddi_get16(acc, &(fibp->Header.Size));
8424942c5e3cSpl196000 	if (subcmdstr)
8425942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8426942c5e3cSpl196000 		    subcmdstr, fib_size);
842758bc78c7SXin Chen 	else if (cmdstr && sub_cmd == (uint32_t)-1)
8428942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
8429942c5e3cSpl196000 		    cmdstr, fib_size);
8430942c5e3cSpl196000 	else if (cmdstr)
8431942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
8432942c5e3cSpl196000 		    cmdstr, sub_cmd, fib_size);
8433942c5e3cSpl196000 	else
8434942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
8435942c5e3cSpl196000 		    fib_cmd, fib_size);
8436942c5e3cSpl196000 }
8437942c5e3cSpl196000 
8438942c5e3cSpl196000 static void
aac_print_aif(struct aac_softstate * softs,struct aac_aif_command * aif)8439942c5e3cSpl196000 aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
8440942c5e3cSpl196000 {
8441942c5e3cSpl196000 	int aif_command;
8442942c5e3cSpl196000 	uint32_t aif_seqnumber;
8443942c5e3cSpl196000 	int aif_en_type;
8444942c5e3cSpl196000 	char *str;
8445942c5e3cSpl196000 
8446942c5e3cSpl196000 	aif_command = LE_32(aif->command);
8447942c5e3cSpl196000 	aif_seqnumber = LE_32(aif->seqNumber);
8448942c5e3cSpl196000 	aif_en_type = LE_32(aif->data.EN.type);
8449942c5e3cSpl196000 
8450942c5e3cSpl196000 	switch (aif_command) {
8451942c5e3cSpl196000 	case AifCmdEventNotify:
8452942c5e3cSpl196000 		str = aac_cmd_name(aif_en_type, aac_aifens);
8453942c5e3cSpl196000 		if (str)
8454942c5e3cSpl196000 			aac_printf(softs, CE_NOTE, "AIF! %s", str);
8455942c5e3cSpl196000 		else
8456942c5e3cSpl196000 			aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
8457942c5e3cSpl196000 			    aif_en_type);
8458942c5e3cSpl196000 		break;
8459942c5e3cSpl196000 
8460942c5e3cSpl196000 	case AifCmdJobProgress:
8461942c5e3cSpl196000 		switch (LE_32(aif->data.PR[0].status)) {
8462942c5e3cSpl196000 		case AifJobStsSuccess:
8463942c5e3cSpl196000 			str = "success"; break;
8464942c5e3cSpl196000 		case AifJobStsFinished:
8465942c5e3cSpl196000 			str = "finished"; break;
8466942c5e3cSpl196000 		case AifJobStsAborted:
8467942c5e3cSpl196000 			str = "aborted"; break;
8468942c5e3cSpl196000 		case AifJobStsFailed:
8469942c5e3cSpl196000 			str = "failed"; break;
8470942c5e3cSpl196000 		case AifJobStsSuspended:
8471942c5e3cSpl196000 			str = "suspended"; break;
8472942c5e3cSpl196000 		case AifJobStsRunning:
8473942c5e3cSpl196000 			str = "running"; break;
8474942c5e3cSpl196000 		default:
8475942c5e3cSpl196000 			str = "unknown"; break;
8476942c5e3cSpl196000 		}
8477942c5e3cSpl196000 		aac_printf(softs, CE_NOTE,
8478942c5e3cSpl196000 		    "AIF! JobProgress (%d) - %s (%d, %d)",
8479942c5e3cSpl196000 		    aif_seqnumber, str,
8480942c5e3cSpl196000 		    LE_32(aif->data.PR[0].currentTick),
8481942c5e3cSpl196000 		    LE_32(aif->data.PR[0].finalTick));
8482942c5e3cSpl196000 		break;
8483942c5e3cSpl196000 
8484942c5e3cSpl196000 	case AifCmdAPIReport:
8485942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
8486942c5e3cSpl196000 		    aif_seqnumber);
8487942c5e3cSpl196000 		break;
8488942c5e3cSpl196000 
8489942c5e3cSpl196000 	case AifCmdDriverNotify:
8490942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
8491942c5e3cSpl196000 		    aif_seqnumber);
8492942c5e3cSpl196000 		break;
8493942c5e3cSpl196000 
8494942c5e3cSpl196000 	default:
8495942c5e3cSpl196000 		aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
8496942c5e3cSpl196000 		    aif_command, aif_seqnumber);
8497942c5e3cSpl196000 		break;
8498942c5e3cSpl196000 	}
8499942c5e3cSpl196000 }
8500942c5e3cSpl196000 
8501942c5e3cSpl196000 #endif /* DEBUG */
8502