xref: /onnv-gate/usr/src/uts/common/io/aac/aac.c (revision 12408:1b10f5564b76)
15678Spl196000 /*
2*12408SZhongyan.Gu@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
35678Spl196000  */
45678Spl196000 
55678Spl196000 /*
67567SXin.Chen@Sun.COM  * Copyright 2005-08 Adaptec, Inc.
77567SXin.Chen@Sun.COM  * Copyright (c) 2005-08 Adaptec Inc., Achim Leubner
85678Spl196000  * Copyright (c) 2000 Michael Smith
95678Spl196000  * Copyright (c) 2001 Scott Long
105678Spl196000  * Copyright (c) 2000 BSDi
115678Spl196000  * All rights reserved.
125678Spl196000  *
135678Spl196000  * Redistribution and use in source and binary forms, with or without
145678Spl196000  * modification, are permitted provided that the following conditions
155678Spl196000  * are met:
165678Spl196000  * 1. Redistributions of source code must retain the above copyright
175678Spl196000  *    notice, this list of conditions and the following disclaimer.
185678Spl196000  * 2. Redistributions in binary form must reproduce the above copyright
195678Spl196000  *    notice, this list of conditions and the following disclaimer in the
205678Spl196000  *    documentation and/or other materials provided with the distribution.
215678Spl196000  *
225678Spl196000  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
235678Spl196000  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
245678Spl196000  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
255678Spl196000  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
265678Spl196000  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
275678Spl196000  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
285678Spl196000  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
295678Spl196000  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
305678Spl196000  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
315678Spl196000  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325678Spl196000  * SUCH DAMAGE.
335678Spl196000  */
345678Spl196000 #include <sys/modctl.h>
355678Spl196000 #include <sys/conf.h>
365678Spl196000 #include <sys/cmn_err.h>
375678Spl196000 #include <sys/ddi.h>
385678Spl196000 #include <sys/devops.h>
395678Spl196000 #include <sys/pci.h>
405678Spl196000 #include <sys/types.h>
415678Spl196000 #include <sys/ddidmareq.h>
425678Spl196000 #include <sys/scsi/scsi.h>
435678Spl196000 #include <sys/ksynch.h>
445678Spl196000 #include <sys/sunddi.h>
455678Spl196000 #include <sys/byteorder.h>
465678Spl196000 #include "aac_regs.h"
475678Spl196000 #include "aac.h"
485678Spl196000 
495678Spl196000 /*
505678Spl196000  * FMA header files
515678Spl196000  */
525678Spl196000 #include <sys/ddifm.h>
535678Spl196000 #include <sys/fm/protocol.h>
545678Spl196000 #include <sys/fm/util.h>
555678Spl196000 #include <sys/fm/io/ddi.h>
565678Spl196000 
575678Spl196000 /*
585678Spl196000  * For minor nodes created by the SCSA framework, minor numbers are
595678Spl196000  * formed by left-shifting instance by INST_MINOR_SHIFT and OR in a
605678Spl196000  * number less than 64.
615678Spl196000  *
625678Spl196000  * To support cfgadm, need to confirm the SCSA framework by creating
635678Spl196000  * devctl/scsi and driver specific minor nodes under SCSA format,
645678Spl196000  * and calling scsi_hba_xxx() functions aacordingly.
655678Spl196000  */
665678Spl196000 
675678Spl196000 #define	AAC_MINOR		32
685678Spl196000 #define	INST2AAC(x)		(((x) << INST_MINOR_SHIFT) | AAC_MINOR)
695678Spl196000 #define	AAC_SCSA_MINOR(x)	((x) & TRAN_MINOR_MASK)
705678Spl196000 #define	AAC_IS_SCSA_NODE(x)	((x) == DEVCTL_MINOR || (x) == SCSI_MINOR)
715678Spl196000 
727567SXin.Chen@Sun.COM #define	SD2TRAN(sd)		((sd)->sd_address.a_hba_tran)
735678Spl196000 #define	AAC_TRAN2SOFTS(tran) ((struct aac_softstate *)(tran)->tran_hba_private)
745678Spl196000 #define	AAC_DIP2TRAN(dip)	((scsi_hba_tran_t *)ddi_get_driver_private(dip))
755678Spl196000 #define	AAC_DIP2SOFTS(dip)	(AAC_TRAN2SOFTS(AAC_DIP2TRAN(dip)))
767567SXin.Chen@Sun.COM #define	SD2AAC(sd)		(AAC_TRAN2SOFTS(SD2TRAN(sd)))
777567SXin.Chen@Sun.COM #define	AAC_PD(t)		((t) - AAC_MAX_LD)
787567SXin.Chen@Sun.COM #define	AAC_DEV(softs, t)	(((t) < AAC_MAX_LD) ? \
797567SXin.Chen@Sun.COM 				&(softs)->containers[(t)].dev : \
807567SXin.Chen@Sun.COM 				((t) < AAC_MAX_DEV(softs)) ? \
817567SXin.Chen@Sun.COM 				&(softs)->nondasds[AAC_PD(t)].dev : NULL)
827567SXin.Chen@Sun.COM #define	AAC_DEVCFG_BEGIN(softs, tgt) \
837567SXin.Chen@Sun.COM 				aac_devcfg((softs), (tgt), 1)
847567SXin.Chen@Sun.COM #define	AAC_DEVCFG_END(softs, tgt) \
857567SXin.Chen@Sun.COM 				aac_devcfg((softs), (tgt), 0)
865678Spl196000 #define	PKT2AC(pkt)		((struct aac_cmd *)(pkt)->pkt_ha_private)
875678Spl196000 #define	AAC_BUSYWAIT(cond, timeout /* in millisecond */) { \
885678Spl196000 		if (!(cond)) { \
895678Spl196000 			int count = (timeout) * 10; \
905678Spl196000 			while (count) { \
915678Spl196000 				drv_usecwait(100); \
925678Spl196000 				if (cond) \
935678Spl196000 					break; \
945678Spl196000 				count--; \
955678Spl196000 			} \
965678Spl196000 			(timeout) = (count + 9) / 10; \
975678Spl196000 		} \
985678Spl196000 	}
995678Spl196000 
1005678Spl196000 #define	AAC_SENSE_DATA_DESCR_LEN \
1015678Spl196000 	(sizeof (struct scsi_descr_sense_hdr) + \
1025678Spl196000 	sizeof (struct scsi_information_sense_descr))
1035678Spl196000 #define	AAC_ARQ64_LENGTH \
1045678Spl196000 	(sizeof (struct scsi_arq_status) + \
1055678Spl196000 	AAC_SENSE_DATA_DESCR_LEN - SENSE_LENGTH)
1065678Spl196000 
1075678Spl196000 /* NOTE: GETG4ADDRTL(cdbp) is int32_t */
1085678Spl196000 #define	AAC_GETGXADDR(cmdlen, cdbp) \
1095678Spl196000 	((cmdlen == 6) ? GETG0ADDR(cdbp) : \
1105678Spl196000 	(cmdlen == 10) ? (uint32_t)GETG1ADDR(cdbp) : \
1115678Spl196000 	((uint64_t)GETG4ADDR(cdbp) << 32) | (uint32_t)GETG4ADDRTL(cdbp))
1125678Spl196000 
1135678Spl196000 #define	AAC_CDB_INQUIRY_CMDDT	0x02
1145678Spl196000 #define	AAC_CDB_INQUIRY_EVPD	0x01
1155678Spl196000 #define	AAC_VPD_PAGE_CODE	1
1165678Spl196000 #define	AAC_VPD_PAGE_LENGTH	3
1175678Spl196000 #define	AAC_VPD_PAGE_DATA	4
1185678Spl196000 #define	AAC_VPD_ID_CODESET	0
1195678Spl196000 #define	AAC_VPD_ID_TYPE		1
1205678Spl196000 #define	AAC_VPD_ID_LENGTH	3
1215678Spl196000 #define	AAC_VPD_ID_DATA		4
1225678Spl196000 
1237567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_HEAD_SIZE			0x08
1247567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_ADDR_SIZE			0x08
1257567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_ADDR_MASK			0xC0
1267567SXin.Chen@Sun.COM /* 00b - peripheral device addressing method */
1277567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL		0x00
1287567SXin.Chen@Sun.COM /* 01b - flat space addressing method */
1297567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE		0x40
1307567SXin.Chen@Sun.COM /* 10b - logical unit addressing method */
1317567SXin.Chen@Sun.COM #define	AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT		0x80
1327567SXin.Chen@Sun.COM 
1335678Spl196000 /* Return the size of FIB with data part type data_type */
1345678Spl196000 #define	AAC_FIB_SIZEOF(data_type) \
1355678Spl196000 	(sizeof (struct aac_fib_header) + sizeof (data_type))
1365678Spl196000 /* Return the container size defined in mir */
1375678Spl196000 #define	AAC_MIR_SIZE(softs, acc, mir) \
1385678Spl196000 	(((softs)->flags & AAC_FLAGS_LBA_64BIT) ? \
1395678Spl196000 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity) + \
1405678Spl196000 	((uint64_t)ddi_get32((acc), &(mir)->MntObj.CapacityHigh) << 32) : \
1415678Spl196000 	(uint64_t)ddi_get32((acc), &(mir)->MntObj.Capacity))
1425678Spl196000 
1435678Spl196000 /* The last entry of aac_cards[] is for unknown cards */
1445678Spl196000 #define	AAC_UNKNOWN_CARD \
1455678Spl196000 	(sizeof (aac_cards) / sizeof (struct aac_card_type) - 1)
1465678Spl196000 #define	CARD_IS_UNKNOWN(i)	(i == AAC_UNKNOWN_CARD)
1475678Spl196000 #define	BUF_IS_READ(bp)		((bp)->b_flags & B_READ)
1485678Spl196000 #define	AAC_IS_Q_EMPTY(q)	((q)->q_head == NULL)
1495678Spl196000 #define	AAC_CMDQ(acp)		(!((acp)->flags & AAC_CMD_SYNC))
1505678Spl196000 
1515678Spl196000 #define	PCI_MEM_GET32(softs, off) \
1525678Spl196000 	ddi_get32((softs)->pci_mem_handle, \
1537100Spl196000 	    (void *)((softs)->pci_mem_base_vaddr + (off)))
1545678Spl196000 #define	PCI_MEM_PUT32(softs, off, val) \
1555678Spl196000 	ddi_put32((softs)->pci_mem_handle, \
1567100Spl196000 	    (void *)((softs)->pci_mem_base_vaddr + (off)), \
1575678Spl196000 	    (uint32_t)(val))
1585678Spl196000 #define	PCI_MEM_GET16(softs, off) \
1595678Spl196000 	ddi_get16((softs)->pci_mem_handle, \
1607100Spl196000 	(void *)((softs)->pci_mem_base_vaddr + (off)))
1615678Spl196000 #define	PCI_MEM_PUT16(softs, off, val) \
1625678Spl196000 	ddi_put16((softs)->pci_mem_handle, \
1637100Spl196000 	(void *)((softs)->pci_mem_base_vaddr + (off)), (uint16_t)(val))
1645678Spl196000 /* Write host data at valp to device mem[off] repeatedly count times */
1655678Spl196000 #define	PCI_MEM_REP_PUT8(softs, off, valp, count) \
1665678Spl196000 	ddi_rep_put8((softs)->pci_mem_handle, (uint8_t *)(valp), \
1675678Spl196000 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
1685678Spl196000 	    count, DDI_DEV_AUTOINCR)
1695678Spl196000 /* Read device data at mem[off] to host addr valp repeatedly count times */
1705678Spl196000 #define	PCI_MEM_REP_GET8(softs, off, valp, count) \
1715678Spl196000 	ddi_rep_get8((softs)->pci_mem_handle, (uint8_t *)(valp), \
1725678Spl196000 	    (uint8_t *)((softs)->pci_mem_base_vaddr + (off)), \
1735678Spl196000 	    count, DDI_DEV_AUTOINCR)
1745678Spl196000 #define	AAC_GET_FIELD8(acc, d, s, field) \
1755678Spl196000 	(d)->field = ddi_get8(acc, (uint8_t *)&(s)->field)
1765678Spl196000 #define	AAC_GET_FIELD32(acc, d, s, field) \
1775678Spl196000 	(d)->field = ddi_get32(acc, (uint32_t *)&(s)->field)
1785678Spl196000 #define	AAC_GET_FIELD64(acc, d, s, field) \
1795678Spl196000 	(d)->field = ddi_get64(acc, (uint64_t *)&(s)->field)
1805678Spl196000 #define	AAC_REP_GET_FIELD8(acc, d, s, field, r) \
1815678Spl196000 	ddi_rep_get8((acc), (uint8_t *)&(d)->field, \
1825678Spl196000 	    (uint8_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
1835678Spl196000 #define	AAC_REP_GET_FIELD32(acc, d, s, field, r) \
1845678Spl196000 	ddi_rep_get32((acc), (uint32_t *)&(d)->field, \
1855678Spl196000 	    (uint32_t *)&(s)->field, (r), DDI_DEV_AUTOINCR)
1865678Spl196000 
1875678Spl196000 #define	AAC_ENABLE_INTR(softs) { \
1885678Spl196000 		if (softs->flags & AAC_FLAGS_NEW_COMM) \
1895678Spl196000 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_NEW); \
1905678Spl196000 		else \
1915678Spl196000 			PCI_MEM_PUT32(softs, AAC_OIMR, ~AAC_DB_INTR_BITS); \
19211636SXin.Chen@Sun.COM 		softs->state |= AAC_STATE_INTR; \
19311636SXin.Chen@Sun.COM 	}
19411636SXin.Chen@Sun.COM 
19511636SXin.Chen@Sun.COM #define	AAC_DISABLE_INTR(softs)	{ \
19611636SXin.Chen@Sun.COM 		PCI_MEM_PUT32(softs, AAC_OIMR, ~0); \
19711636SXin.Chen@Sun.COM 		softs->state &= ~AAC_STATE_INTR; \
19811636SXin.Chen@Sun.COM 	}
1995678Spl196000 #define	AAC_STATUS_CLR(softs, mask)	PCI_MEM_PUT32(softs, AAC_ODBR, mask)
2005678Spl196000 #define	AAC_STATUS_GET(softs)		PCI_MEM_GET32(softs, AAC_ODBR)
2015678Spl196000 #define	AAC_NOTIFY(softs, val)		PCI_MEM_PUT32(softs, AAC_IDBR, val)
2025678Spl196000 #define	AAC_OUTB_GET(softs)		PCI_MEM_GET32(softs, AAC_OQUE)
2035678Spl196000 #define	AAC_OUTB_SET(softs, val)	PCI_MEM_PUT32(softs, AAC_OQUE, val)
2045678Spl196000 #define	AAC_FWSTATUS_GET(softs)	\
2055678Spl196000 	((softs)->aac_if.aif_get_fwstatus(softs))
2065678Spl196000 #define	AAC_MAILBOX_GET(softs, mb) \
2075678Spl196000 	((softs)->aac_if.aif_get_mailbox((softs), (mb)))
2085678Spl196000 #define	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3) \
2095678Spl196000 	((softs)->aac_if.aif_set_mailbox((softs), (cmd), \
2105678Spl196000 	    (arg0), (arg1), (arg2), (arg3)))
2115678Spl196000 
21211348SZhongyan.Gu@Sun.COM #define	AAC_MGT_SLOT_NUM	2
2135678Spl196000 #define	AAC_THROTTLE_DRAIN	-1
2145678Spl196000 
2155678Spl196000 #define	AAC_QUIESCE_TICK	1	/* 1 second */
2167567SXin.Chen@Sun.COM #define	AAC_QUIESCE_TIMEOUT	180	/* 180 seconds */
2175678Spl196000 #define	AAC_DEFAULT_TICK	10	/* 10 seconds */
2185678Spl196000 #define	AAC_SYNC_TICK		(30*60)	/* 30 minutes */
2195678Spl196000 
2205678Spl196000 /* Poll time for aac_do_poll_io() */
2215678Spl196000 #define	AAC_POLL_TIME		60	/* 60 seconds */
2225678Spl196000 
2237567SXin.Chen@Sun.COM /* IOP reset */
2247567SXin.Chen@Sun.COM #define	AAC_IOP_RESET_SUCCEED		0	/* IOP reset succeed */
2257567SXin.Chen@Sun.COM #define	AAC_IOP_RESET_FAILED		-1	/* IOP reset failed */
2267567SXin.Chen@Sun.COM #define	AAC_IOP_RESET_ABNORMAL		-2	/* Reset operation abnormal */
2277567SXin.Chen@Sun.COM 
2285678Spl196000 /*
2295678Spl196000  * Hardware access functions
2305678Spl196000  */
2315678Spl196000 static int aac_rx_get_fwstatus(struct aac_softstate *);
2325678Spl196000 static int aac_rx_get_mailbox(struct aac_softstate *, int);
2335678Spl196000 static void aac_rx_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
2345678Spl196000     uint32_t, uint32_t, uint32_t);
2355678Spl196000 static int aac_rkt_get_fwstatus(struct aac_softstate *);
2365678Spl196000 static int aac_rkt_get_mailbox(struct aac_softstate *, int);
2375678Spl196000 static void aac_rkt_set_mailbox(struct aac_softstate *, uint32_t, uint32_t,
2385678Spl196000     uint32_t, uint32_t, uint32_t);
2395678Spl196000 
2405678Spl196000 /*
2415678Spl196000  * SCSA function prototypes
2425678Spl196000  */
2435678Spl196000 static int aac_attach(dev_info_t *, ddi_attach_cmd_t);
2445678Spl196000 static int aac_detach(dev_info_t *, ddi_detach_cmd_t);
2455678Spl196000 static int aac_reset(dev_info_t *, ddi_reset_cmd_t);
2467656SSherry.Moore@Sun.COM static int aac_quiesce(dev_info_t *);
24711348SZhongyan.Gu@Sun.COM static int aac_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2485678Spl196000 
2495678Spl196000 /*
2505678Spl196000  * Interrupt handler functions
2515678Spl196000  */
2527000Sjd218194 static int aac_query_intrs(struct aac_softstate *, int);
2537000Sjd218194 static int aac_add_intrs(struct aac_softstate *);
2547000Sjd218194 static void aac_remove_intrs(struct aac_softstate *);
25511348SZhongyan.Gu@Sun.COM static int aac_enable_intrs(struct aac_softstate *);
25611348SZhongyan.Gu@Sun.COM static int aac_disable_intrs(struct aac_softstate *);
2575678Spl196000 static uint_t aac_intr_old(caddr_t);
2585678Spl196000 static uint_t aac_intr_new(caddr_t);
2595678Spl196000 static uint_t aac_softintr(caddr_t);
2605678Spl196000 
2615678Spl196000 /*
2625678Spl196000  * Internal functions in attach
2635678Spl196000  */
2645678Spl196000 static int aac_check_card_type(struct aac_softstate *);
2655678Spl196000 static int aac_check_firmware(struct aac_softstate *);
2665678Spl196000 static int aac_common_attach(struct aac_softstate *);
2675678Spl196000 static void aac_common_detach(struct aac_softstate *);
2685678Spl196000 static int aac_probe_containers(struct aac_softstate *);
2695678Spl196000 static int aac_alloc_comm_space(struct aac_softstate *);
2705678Spl196000 static int aac_setup_comm_space(struct aac_softstate *);
2715678Spl196000 static void aac_free_comm_space(struct aac_softstate *);
2725678Spl196000 static int aac_hba_setup(struct aac_softstate *);
2735678Spl196000 
2745678Spl196000 /*
2755678Spl196000  * Sync FIB operation functions
2765678Spl196000  */
2775678Spl196000 int aac_sync_mbcommand(struct aac_softstate *, uint32_t, uint32_t,
2785678Spl196000     uint32_t, uint32_t, uint32_t, uint32_t *);
2795678Spl196000 static int aac_sync_fib(struct aac_softstate *, uint16_t, uint16_t);
2805678Spl196000 
2815678Spl196000 /*
2825678Spl196000  * Command queue operation functions
2835678Spl196000  */
2845678Spl196000 static void aac_cmd_initq(struct aac_cmd_queue *);
2855678Spl196000 static void aac_cmd_enqueue(struct aac_cmd_queue *, struct aac_cmd *);
2865678Spl196000 static struct aac_cmd *aac_cmd_dequeue(struct aac_cmd_queue *);
2875678Spl196000 static void aac_cmd_delete(struct aac_cmd_queue *, struct aac_cmd *);
2885678Spl196000 
2895678Spl196000 /*
2905678Spl196000  * FIB queue operation functions
2915678Spl196000  */
2925678Spl196000 static int aac_fib_enqueue(struct aac_softstate *, int, uint32_t, uint32_t);
2935678Spl196000 static int aac_fib_dequeue(struct aac_softstate *, int, int *);
2945678Spl196000 
2955678Spl196000 /*
2965678Spl196000  * Slot operation functions
2975678Spl196000  */
2985678Spl196000 static int aac_create_slots(struct aac_softstate *);
2995678Spl196000 static void aac_destroy_slots(struct aac_softstate *);
3005678Spl196000 static void aac_alloc_fibs(struct aac_softstate *);
3015678Spl196000 static void aac_destroy_fibs(struct aac_softstate *);
3025678Spl196000 static struct aac_slot *aac_get_slot(struct aac_softstate *);
3035678Spl196000 static void aac_release_slot(struct aac_softstate *, struct aac_slot *);
3045678Spl196000 static int aac_alloc_fib(struct aac_softstate *, struct aac_slot *);
3055678Spl196000 static void aac_free_fib(struct aac_slot *);
3065678Spl196000 
3075678Spl196000 /*
3085678Spl196000  * Internal functions
3095678Spl196000  */
31011348SZhongyan.Gu@Sun.COM static void aac_cmd_fib_header(struct aac_softstate *, struct aac_cmd *,
31111348SZhongyan.Gu@Sun.COM     uint16_t);
3125678Spl196000 static void aac_cmd_fib_rawio(struct aac_softstate *, struct aac_cmd *);
3135678Spl196000 static void aac_cmd_fib_brw64(struct aac_softstate *, struct aac_cmd *);
3145678Spl196000 static void aac_cmd_fib_brw(struct aac_softstate *, struct aac_cmd *);
3155678Spl196000 static void aac_cmd_fib_sync(struct aac_softstate *, struct aac_cmd *);
3165678Spl196000 static void aac_cmd_fib_scsi32(struct aac_softstate *, struct aac_cmd *);
3175678Spl196000 static void aac_cmd_fib_scsi64(struct aac_softstate *, struct aac_cmd *);
31810976SZhongyan.Gu@Sun.COM static void aac_cmd_fib_startstop(struct aac_softstate *, struct aac_cmd *);
3195678Spl196000 static void aac_start_waiting_io(struct aac_softstate *);
3205678Spl196000 static void aac_drain_comp_q(struct aac_softstate *);
3215678Spl196000 int aac_do_io(struct aac_softstate *, struct aac_cmd *);
32211348SZhongyan.Gu@Sun.COM static int aac_sync_fib_slot_bind(struct aac_softstate *, struct aac_cmd *);
32311348SZhongyan.Gu@Sun.COM static void aac_sync_fib_slot_release(struct aac_softstate *, struct aac_cmd *);
32411348SZhongyan.Gu@Sun.COM static void aac_start_io(struct aac_softstate *, struct aac_cmd *);
3255678Spl196000 static int aac_do_poll_io(struct aac_softstate *, struct aac_cmd *);
3265678Spl196000 static int aac_do_sync_io(struct aac_softstate *, struct aac_cmd *);
3275678Spl196000 static int aac_send_command(struct aac_softstate *, struct aac_slot *);
3287567SXin.Chen@Sun.COM static void aac_cmd_timeout(struct aac_softstate *, struct aac_cmd *);
3295678Spl196000 static int aac_dma_sync_ac(struct aac_cmd *);
3305678Spl196000 static int aac_shutdown(struct aac_softstate *);
3315678Spl196000 static int aac_reset_adapter(struct aac_softstate *);
3325678Spl196000 static int aac_do_quiesce(struct aac_softstate *softs);
3335678Spl196000 static int aac_do_unquiesce(struct aac_softstate *softs);
3345678Spl196000 static void aac_unhold_bus(struct aac_softstate *, int);
3357567SXin.Chen@Sun.COM static void aac_set_throttle(struct aac_softstate *, struct aac_device *,
3365678Spl196000     int, int);
3375678Spl196000 
3385678Spl196000 /*
3395678Spl196000  * Adapter Initiated FIB handling function
3405678Spl196000  */
34111964SXin.Chen@Sun.COM static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
34211964SXin.Chen@Sun.COM     struct aac_fib *, int);
34311964SXin.Chen@Sun.COM static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
3445678Spl196000 
3455678Spl196000 /*
34611964SXin.Chen@Sun.COM  * Event handling related functions
3475678Spl196000  */
34811964SXin.Chen@Sun.COM static void aac_timer(void *);
34911964SXin.Chen@Sun.COM static void aac_event_thread(struct aac_softstate *);
35011964SXin.Chen@Sun.COM static void aac_event_disp(struct aac_softstate *, int);
3515678Spl196000 
3525678Spl196000 /*
3535678Spl196000  * IOCTL interface related functions
3545678Spl196000  */
3555678Spl196000 static int aac_open(dev_t *, int, int, cred_t *);
3565678Spl196000 static int aac_close(dev_t, int, int, cred_t *);
3575678Spl196000 static int aac_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
3585678Spl196000 extern int aac_do_ioctl(struct aac_softstate *, dev_t, int, intptr_t, int);
3595678Spl196000 
3605678Spl196000 /*
3615678Spl196000  * FMA Prototypes
3625678Spl196000  */
3635678Spl196000 static void aac_fm_init(struct aac_softstate *);
3645678Spl196000 static void aac_fm_fini(struct aac_softstate *);
3655678Spl196000 static int aac_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
3665678Spl196000 int aac_check_acc_handle(ddi_acc_handle_t);
3675678Spl196000 int aac_check_dma_handle(ddi_dma_handle_t);
3685678Spl196000 void aac_fm_ereport(struct aac_softstate *, char *);
3695678Spl196000 
3707567SXin.Chen@Sun.COM /*
3717567SXin.Chen@Sun.COM  * Auto enumeration functions
3727567SXin.Chen@Sun.COM  */
3737567SXin.Chen@Sun.COM static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
3747567SXin.Chen@Sun.COM static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
3757567SXin.Chen@Sun.COM     void *, dev_info_t **);
37611964SXin.Chen@Sun.COM static int aac_handle_dr(struct aac_softstate *, int, int, int);
37711964SXin.Chen@Sun.COM 
37811964SXin.Chen@Sun.COM extern pri_t minclsyspri;
3797567SXin.Chen@Sun.COM 
3805678Spl196000 #ifdef DEBUG
3815678Spl196000 /*
3825678Spl196000  * UART	debug output support
3835678Spl196000  */
3845678Spl196000 
3855678Spl196000 #define	AAC_PRINT_BUFFER_SIZE		512
3865678Spl196000 #define	AAC_PRINT_TIMEOUT		250	/* 1/4 sec. = 250 msec. */
3875678Spl196000 
3885678Spl196000 #define	AAC_FW_DBG_STRLEN_OFFSET	0x00
3895678Spl196000 #define	AAC_FW_DBG_FLAGS_OFFSET		0x04
3905678Spl196000 #define	AAC_FW_DBG_BLED_OFFSET		0x08
3915678Spl196000 
3925678Spl196000 static int aac_get_fw_debug_buffer(struct aac_softstate *);
3935678Spl196000 static void aac_print_scmd(struct aac_softstate *, struct aac_cmd *);
3945678Spl196000 static void aac_print_aif(struct aac_softstate *, struct aac_aif_command *);
3955678Spl196000 
3965678Spl196000 static char aac_prt_buf[AAC_PRINT_BUFFER_SIZE];
3975678Spl196000 static char aac_fmt[] = " %s";
3985678Spl196000 static char aac_fmt_header[] = " %s.%d: %s";
3995678Spl196000 static kmutex_t aac_prt_mutex;
4005678Spl196000 
4015678Spl196000 /*
4025678Spl196000  * Debug flags to be put into the softstate flags field
4035678Spl196000  * when initialized
4045678Spl196000  */
4055678Spl196000 uint32_t aac_debug_flags =
4065678Spl196000 /*    AACDB_FLAGS_KERNEL_PRINT | */
4075678Spl196000 /*    AACDB_FLAGS_FW_PRINT |	*/
4085678Spl196000 /*    AACDB_FLAGS_MISC |	*/
4095678Spl196000 /*    AACDB_FLAGS_FUNC1 |	*/
4105678Spl196000 /*    AACDB_FLAGS_FUNC2 |	*/
4115678Spl196000 /*    AACDB_FLAGS_SCMD |	*/
4125678Spl196000 /*    AACDB_FLAGS_AIF |		*/
4135678Spl196000 /*    AACDB_FLAGS_FIB |		*/
4145678Spl196000 /*    AACDB_FLAGS_IOCTL |	*/
4155678Spl196000 0;
4167567SXin.Chen@Sun.COM uint32_t aac_debug_fib_flags =
4177567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_RW |	*/
4187567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_IOCTL |	*/
4197567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_SRB |	*/
4207567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_SYNC |	*/
4217567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_HEADER |	*/
4227567SXin.Chen@Sun.COM /*    AACDB_FLAGS_FIB_TIMEOUT |	*/
4237567SXin.Chen@Sun.COM 0;
4245678Spl196000 
4255678Spl196000 #endif /* DEBUG */
4265678Spl196000 
4275678Spl196000 static struct cb_ops aac_cb_ops = {
4285678Spl196000 	aac_open,	/* open */
4295678Spl196000 	aac_close,	/* close */
4305678Spl196000 	nodev,		/* strategy */
4315678Spl196000 	nodev,		/* print */
4325678Spl196000 	nodev,		/* dump */
4335678Spl196000 	nodev,		/* read */
4345678Spl196000 	nodev,		/* write */
4355678Spl196000 	aac_ioctl,	/* ioctl */
4365678Spl196000 	nodev,		/* devmap */
4375678Spl196000 	nodev,		/* mmap */
4385678Spl196000 	nodev,		/* segmap */
4395678Spl196000 	nochpoll,	/* poll */
4405678Spl196000 	ddi_prop_op,	/* cb_prop_op */
4415678Spl196000 	NULL,		/* streamtab */
4425678Spl196000 	D_64BIT | D_NEW | D_MP | D_HOTPLUG,	/* cb_flag */
4435678Spl196000 	CB_REV,		/* cb_rev */
4445678Spl196000 	nodev,		/* async I/O read entry point */
4455678Spl196000 	nodev		/* async I/O write entry point */
4465678Spl196000 };
4475678Spl196000 
4485678Spl196000 static struct dev_ops aac_dev_ops = {
4495678Spl196000 	DEVO_REV,
4505678Spl196000 	0,
45111348SZhongyan.Gu@Sun.COM 	aac_getinfo,
4525678Spl196000 	nulldev,
4535678Spl196000 	nulldev,
4545678Spl196000 	aac_attach,
4555678Spl196000 	aac_detach,
4565678Spl196000 	aac_reset,
4575678Spl196000 	&aac_cb_ops,
4585678Spl196000 	NULL,
4597656SSherry.Moore@Sun.COM 	NULL,
4607656SSherry.Moore@Sun.COM 	aac_quiesce,
4615678Spl196000 };
4625678Spl196000 
4635678Spl196000 static struct modldrv aac_modldrv = {
4645678Spl196000 	&mod_driverops,
4655678Spl196000 	"AAC Driver " AAC_DRIVER_VERSION,
4665678Spl196000 	&aac_dev_ops,
4675678Spl196000 };
4685678Spl196000 
4695678Spl196000 static struct modlinkage aac_modlinkage = {
4705678Spl196000 	MODREV_1,
4715678Spl196000 	&aac_modldrv,
4725678Spl196000 	NULL
4735678Spl196000 };
4745678Spl196000 
4755678Spl196000 static struct aac_softstate  *aac_softstatep;
4765678Spl196000 
4775678Spl196000 /*
4785678Spl196000  * Supported card list
4795678Spl196000  * ordered in vendor id, subvendor id, subdevice id, and device id
4805678Spl196000  */
4815678Spl196000 static struct aac_card_type aac_cards[] = {
4825678Spl196000 	{0x1028, 0x1, 0x1028, 0x1, AAC_HWIF_I960RX,
4835678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4845678Spl196000 	    "Dell", "PERC 3/Di"},
4855678Spl196000 	{0x1028, 0x2, 0x1028, 0x2, AAC_HWIF_I960RX,
4865678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4875678Spl196000 	    "Dell", "PERC 3/Di"},
4885678Spl196000 	{0x1028, 0x3, 0x1028, 0x3, AAC_HWIF_I960RX,
4895678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4905678Spl196000 	    "Dell", "PERC 3/Si"},
4915678Spl196000 	{0x1028, 0x8, 0x1028, 0xcf, AAC_HWIF_I960RX,
4925678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4935678Spl196000 	    "Dell", "PERC 3/Di"},
4945678Spl196000 	{0x1028, 0x4, 0x1028, 0xd0, AAC_HWIF_I960RX,
4955678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4965678Spl196000 	    "Dell", "PERC 3/Si"},
4975678Spl196000 	{0x1028, 0x2, 0x1028, 0xd1, AAC_HWIF_I960RX,
4985678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
4995678Spl196000 	    "Dell", "PERC 3/Di"},
5005678Spl196000 	{0x1028, 0x2, 0x1028, 0xd9, AAC_HWIF_I960RX,
5015678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5025678Spl196000 	    "Dell", "PERC 3/Di"},
5035678Spl196000 	{0x1028, 0xa, 0x1028, 0x106, AAC_HWIF_I960RX,
5045678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5055678Spl196000 	    "Dell", "PERC 3/Di"},
5065678Spl196000 	{0x1028, 0xa, 0x1028, 0x11b, AAC_HWIF_I960RX,
5075678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5085678Spl196000 	    "Dell", "PERC 3/Di"},
5095678Spl196000 	{0x1028, 0xa, 0x1028, 0x121, AAC_HWIF_I960RX,
5105678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG, AAC_TYPE_SCSI,
5115678Spl196000 	    "Dell", "PERC 3/Di"},
5125678Spl196000 	{0x9005, 0x285, 0x1028, 0x287, AAC_HWIF_I960RX,
5135678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5145678Spl196000 	    "Dell", "PERC 320/DC"},
5155678Spl196000 	{0x9005, 0x285, 0x1028, 0x291, AAC_HWIF_I960RX,
5165678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Dell", "CERC SR2"},
5175678Spl196000 
5185678Spl196000 	{0x9005, 0x285, 0x1014, 0x2f2, AAC_HWIF_I960RX,
5195678Spl196000 	    0, AAC_TYPE_SCSI, "IBM", "ServeRAID 8i"},
5205678Spl196000 	{0x9005, 0x285, 0x1014, 0x34d, AAC_HWIF_I960RX,
5215678Spl196000 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8s"},
5225678Spl196000 	{0x9005, 0x286, 0x1014, 0x9580, AAC_HWIF_RKT,
5235678Spl196000 	    0, AAC_TYPE_SAS, "IBM", "ServeRAID 8k"},
5245678Spl196000 
5255678Spl196000 	{0x9005, 0x285, 0x103c, 0x3227, AAC_HWIF_I960RX,
5265678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
5275678Spl196000 	{0x9005, 0x285, 0xe11, 0x295, AAC_HWIF_I960RX,
5285678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2610SA"},
5295678Spl196000 
5305678Spl196000 	{0x9005, 0x285, 0x9005, 0x285, AAC_HWIF_I960RX,
5315678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5325678Spl196000 	    "Adaptec", "2200S"},
5335678Spl196000 	{0x9005, 0x285, 0x9005, 0x286, AAC_HWIF_I960RX,
5345678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5355678Spl196000 	    "Adaptec", "2120S"},
5365678Spl196000 	{0x9005, 0x285, 0x9005, 0x287, AAC_HWIF_I960RX,
5375678Spl196000 	    AAC_FLAGS_NO4GB | AAC_FLAGS_34SG | AAC_FLAGS_256FIBS, AAC_TYPE_SCSI,
5385678Spl196000 	    "Adaptec", "2200S"},
5395678Spl196000 	{0x9005, 0x285, 0x9005, 0x288, AAC_HWIF_I960RX,
5405678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "3230S"},
5415678Spl196000 	{0x9005, 0x285, 0x9005, 0x289, AAC_HWIF_I960RX,
5425678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "3240S"},
5435678Spl196000 	{0x9005, 0x285, 0x9005, 0x28a, AAC_HWIF_I960RX,
5445678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2020ZCR"},
5455678Spl196000 	{0x9005, 0x285, 0x9005, 0x28b, AAC_HWIF_I960RX,
5465678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2025ZCR"},
5475678Spl196000 	{0x9005, 0x286, 0x9005, 0x28c, AAC_HWIF_RKT,
5485678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2230S"},
5495678Spl196000 	{0x9005, 0x286, 0x9005, 0x28d, AAC_HWIF_RKT,
5505678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2130S"},
5515678Spl196000 	{0x9005, 0x285, 0x9005, 0x28e, AAC_HWIF_I960RX,
5525678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2020SA"},
5535678Spl196000 	{0x9005, 0x285, 0x9005, 0x28f, AAC_HWIF_I960RX,
5545678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2025SA"},
5555678Spl196000 	{0x9005, 0x285, 0x9005, 0x290, AAC_HWIF_I960RX,
5565678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2410SA"},
5575678Spl196000 	{0x9005, 0x285, 0x9005, 0x292, AAC_HWIF_I960RX,
5585678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "2810SA"},
5595678Spl196000 	{0x9005, 0x285, 0x9005, 0x293, AAC_HWIF_I960RX,
5605678Spl196000 	    AAC_FLAGS_17SG, AAC_TYPE_SATA, "Adaptec", "21610SA"},
5615678Spl196000 	{0x9005, 0x285, 0x9005, 0x294, AAC_HWIF_I960RX,
5625678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2026ZCR"},
5635678Spl196000 	{0x9005, 0x285, 0x9005, 0x296, AAC_HWIF_I960RX,
5645678Spl196000 	    0, AAC_TYPE_SCSI, "Adaptec", "2240S"},
5655678Spl196000 	{0x9005, 0x285, 0x9005, 0x297, AAC_HWIF_I960RX,
5665678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4005SAS"},
5675678Spl196000 	{0x9005, 0x285, 0x9005, 0x298, AAC_HWIF_I960RX,
5685678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 4000"},
5695678Spl196000 	{0x9005, 0x285, 0x9005, 0x299, AAC_HWIF_I960RX,
5705678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4800SAS"},
5715678Spl196000 	{0x9005, 0x285, 0x9005, 0x29a, AAC_HWIF_I960RX,
5725678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "4805SAS"},
5735678Spl196000 	{0x9005, 0x286, 0x9005, 0x29b, AAC_HWIF_RKT,
5745678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2820SA"},
5755678Spl196000 	{0x9005, 0x286, 0x9005, 0x29c, AAC_HWIF_RKT,
5765678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2620SA"},
5775678Spl196000 	{0x9005, 0x286, 0x9005, 0x29d, AAC_HWIF_RKT,
5785678Spl196000 	    0, AAC_TYPE_SATA, "Adaptec", "2420SA"},
5795678Spl196000 	{0x9005, 0x286, 0x9005, 0x29e, AAC_HWIF_RKT,
5805678Spl196000 	    0, AAC_TYPE_SATA, "ICP", "9024RO"},
5815678Spl196000 	{0x9005, 0x286, 0x9005, 0x29f, AAC_HWIF_RKT,
5825678Spl196000 	    0, AAC_TYPE_SATA, "ICP", "9014RO"},
5835678Spl196000 	{0x9005, 0x286, 0x9005, 0x2a0, AAC_HWIF_RKT,
5845678Spl196000 	    0, AAC_TYPE_SATA, "ICP", "9047MA"},
5855678Spl196000 	{0x9005, 0x286, 0x9005, 0x2a1, AAC_HWIF_RKT,
5865678Spl196000 	    0, AAC_TYPE_SATA, "ICP", "9087MA"},
5875678Spl196000 	{0x9005, 0x285, 0x9005, 0x2a4, AAC_HWIF_I960RX,
5885678Spl196000 	    0, AAC_TYPE_SAS, "ICP", "9085LI"},
5895678Spl196000 	{0x9005, 0x285, 0x9005, 0x2a5, AAC_HWIF_I960RX,
5905678Spl196000 	    0, AAC_TYPE_SAS, "ICP", "5085BR"},
5915678Spl196000 	{0x9005, 0x286, 0x9005, 0x2a6, AAC_HWIF_RKT,
5925678Spl196000 	    0, AAC_TYPE_SATA, "ICP", "9067MA"},
5935678Spl196000 	{0x9005, 0x285, 0x9005, 0x2b5, AAC_HWIF_I960RX,
5945678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5445"},
5955678Spl196000 	{0x9005, 0x285, 0x9005, 0x2b6, AAC_HWIF_I960RX,
5965678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5805"},
5975678Spl196000 	{0x9005, 0x285, 0x9005, 0x2b7, AAC_HWIF_I960RX,
5985678Spl196000 	    0, AAC_TYPE_SAS, "Adaptec", "RAID 5085"},
5995678Spl196000 	{0x9005, 0x285, 0x9005, 0x2b8, AAC_HWIF_I960RX,
6005678Spl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5445SL"},
6015678Spl196000 	{0x9005, 0x285, 0x9005, 0x2b9, AAC_HWIF_I960RX,
6025678Spl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5085SL"},
6035678Spl196000 	{0x9005, 0x285, 0x9005, 0x2ba, AAC_HWIF_I960RX,
6045678Spl196000 	    0, AAC_TYPE_SAS, "ICP", "RAID ICP5805SL"},
6055678Spl196000 
6065678Spl196000 	{0, 0, 0, 0, AAC_HWIF_UNKNOWN,
6075678Spl196000 	    0, AAC_TYPE_UNKNOWN, "Unknown", "AAC card"},
6085678Spl196000 };
6095678Spl196000 
6105678Spl196000 /*
6115678Spl196000  * Hardware access functions for i960 based cards
6125678Spl196000  */
6135678Spl196000 static struct aac_interface aac_rx_interface = {
6145678Spl196000 	aac_rx_get_fwstatus,
6155678Spl196000 	aac_rx_get_mailbox,
6165678Spl196000 	aac_rx_set_mailbox
6175678Spl196000 };
6185678Spl196000 
6195678Spl196000 /*
6205678Spl196000  * Hardware access functions for Rocket based cards
6215678Spl196000  */
6225678Spl196000 static struct aac_interface aac_rkt_interface = {
6235678Spl196000 	aac_rkt_get_fwstatus,
6245678Spl196000 	aac_rkt_get_mailbox,
6255678Spl196000 	aac_rkt_set_mailbox
6265678Spl196000 };
6275678Spl196000 
6285678Spl196000 ddi_device_acc_attr_t aac_acc_attr = {
62911236SStephen.Hanson@Sun.COM 	DDI_DEVICE_ATTR_V1,
6305678Spl196000 	DDI_STRUCTURE_LE_ACC,
63111236SStephen.Hanson@Sun.COM 	DDI_STRICTORDER_ACC,
63211236SStephen.Hanson@Sun.COM 	DDI_DEFAULT_ACC
6335678Spl196000 };
6345678Spl196000 
6355678Spl196000 static struct {
6365678Spl196000 	int	size;
6375678Spl196000 	int	notify;
6385678Spl196000 } aac_qinfo[] = {
6395678Spl196000 	{AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL},
6405678Spl196000 	{AAC_HOST_HIGH_CMD_ENTRIES, 0},
6415678Spl196000 	{AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY},
6425678Spl196000 	{AAC_ADAP_HIGH_CMD_ENTRIES, 0},
6435678Spl196000 	{AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL},
6445678Spl196000 	{AAC_HOST_HIGH_RESP_ENTRIES, 0},
6455678Spl196000 	{AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY},
6465678Spl196000 	{AAC_ADAP_HIGH_RESP_ENTRIES, 0}
6475678Spl196000 };
6485678Spl196000 
6495678Spl196000 /*
6505678Spl196000  * Default aac dma attributes
6515678Spl196000  */
6525678Spl196000 static ddi_dma_attr_t aac_dma_attr = {
6535678Spl196000 	DMA_ATTR_V0,
6545678Spl196000 	0,		/* lowest usable address */
6555678Spl196000 	0xffffffffull,	/* high DMA address range */
6565678Spl196000 	0xffffffffull,	/* DMA counter register */
6575678Spl196000 	AAC_DMA_ALIGN,	/* DMA address alignment */
6585678Spl196000 	1,		/* DMA burstsizes */
6595678Spl196000 	1,		/* min effective DMA size */
6605678Spl196000 	0xffffffffull,	/* max DMA xfer size */
6615678Spl196000 	0xffffffffull,	/* segment boundary */
6625678Spl196000 	1,		/* s/g list length */
6635678Spl196000 	AAC_BLK_SIZE,	/* granularity of device */
6647567SXin.Chen@Sun.COM 	0		/* DMA transfer flags */
6657567SXin.Chen@Sun.COM };
6667567SXin.Chen@Sun.COM 
6675678Spl196000 static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
6685678Spl196000 static uint32_t aac_timebase = 0;	/* internal timer in seconds */
6695678Spl196000 
6705678Spl196000 /*
6715678Spl196000  * Warlock directives
6725678Spl196000  *
6735678Spl196000  * Different variables with the same types have to be protected by the
6745678Spl196000  * same mutex; otherwise, warlock will complain with "variables don't
6755678Spl196000  * seem to be protected consistently". For example,
6765678Spl196000  * aac_softstate::{q_wait, q_comp} are type of aac_cmd_queue, and protected
6775678Spl196000  * by aac_softstate::{io_lock, q_comp_mutex} respectively. We have to
6785678Spl196000  * declare them as protected explictly at aac_cmd_dequeue().
6795678Spl196000  */
6805678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt scsi_cdb scsi_status \
6815678Spl196000     scsi_arq_status scsi_descr_sense_hdr scsi_information_sense_descr \
6825678Spl196000     mode_format mode_geometry mode_header aac_cmd))
6835678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_cmd", aac_fib ddi_dma_cookie_t \
6845678Spl196000     aac_sge))
6855678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique per aac_fib", aac_blockread aac_blockwrite \
6865678Spl196000     aac_blockread64 aac_raw_io aac_sg_entry aac_sg_entry64 aac_sg_entryraw \
6875678Spl196000     aac_sg_table aac_srb))
6885678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
6895678Spl196000 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
6907567SXin.Chen@Sun.COM _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
6915678Spl196000 
6925678Spl196000 int
_init(void)6935678Spl196000 _init(void)
6945678Spl196000 {
6955678Spl196000 	int rval = 0;
6965678Spl196000 
6975678Spl196000 #ifdef DEBUG
6985678Spl196000 	mutex_init(&aac_prt_mutex, NULL, MUTEX_DRIVER, NULL);
6995678Spl196000 #endif
7005678Spl196000 	DBCALLED(NULL, 1);
7015678Spl196000 
7025678Spl196000 	if ((rval = ddi_soft_state_init((void *)&aac_softstatep,
7035678Spl196000 	    sizeof (struct aac_softstate), 0)) != 0)
7045678Spl196000 		goto error;
7055678Spl196000 
7065678Spl196000 	if ((rval = scsi_hba_init(&aac_modlinkage)) != 0) {
7075678Spl196000 		ddi_soft_state_fini((void *)&aac_softstatep);
7085678Spl196000 		goto error;
7095678Spl196000 	}
7105678Spl196000 
7115678Spl196000 	if ((rval = mod_install(&aac_modlinkage)) != 0) {
7125678Spl196000 		ddi_soft_state_fini((void *)&aac_softstatep);
7135678Spl196000 		scsi_hba_fini(&aac_modlinkage);
7145678Spl196000 		goto error;
7155678Spl196000 	}
7165678Spl196000 	return (rval);
7175678Spl196000 
7185678Spl196000 error:
7195678Spl196000 	AACDB_PRINT(NULL, CE_WARN, "Mod init error!");
7205678Spl196000 #ifdef DEBUG
7215678Spl196000 	mutex_destroy(&aac_prt_mutex);
7225678Spl196000 #endif
7235678Spl196000 	return (rval);
7245678Spl196000 }
7255678Spl196000 
7265678Spl196000 int
_info(struct modinfo * modinfop)7275678Spl196000 _info(struct modinfo *modinfop)
7285678Spl196000 {
7295678Spl196000 	DBCALLED(NULL, 1);
7305678Spl196000 	return (mod_info(&aac_modlinkage, modinfop));
7315678Spl196000 }
7325678Spl196000 
7335678Spl196000 /*
7345678Spl196000  * An HBA driver cannot be unload unless you reboot,
7355678Spl196000  * so this function will be of no use.
7365678Spl196000  */
7375678Spl196000 int
_fini(void)7385678Spl196000 _fini(void)
7395678Spl196000 {
7405678Spl196000 	int rval;
7415678Spl196000 
7425678Spl196000 	DBCALLED(NULL, 1);
7435678Spl196000 
7445678Spl196000 	if ((rval = mod_remove(&aac_modlinkage)) != 0)
7455678Spl196000 		goto error;
7465678Spl196000 
7475678Spl196000 	scsi_hba_fini(&aac_modlinkage);
7485678Spl196000 	ddi_soft_state_fini((void *)&aac_softstatep);
7495678Spl196000 #ifdef DEBUG
7505678Spl196000 	mutex_destroy(&aac_prt_mutex);
7515678Spl196000 #endif
7525678Spl196000 	return (0);
7535678Spl196000 
7545678Spl196000 error:
7555678Spl196000 	AACDB_PRINT(NULL, CE_WARN, "AAC is busy, cannot unload!");
7565678Spl196000 	return (rval);
7575678Spl196000 }
7585678Spl196000 
7595678Spl196000 static int
aac_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)7605678Spl196000 aac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7615678Spl196000 {
7625678Spl196000 	int instance, i;
7635678Spl196000 	struct aac_softstate *softs = NULL;
7645678Spl196000 	int attach_state = 0;
7657567SXin.Chen@Sun.COM 	char *data;
7665678Spl196000 
7675678Spl196000 	DBCALLED(NULL, 1);
7685678Spl196000 
7695678Spl196000 	switch (cmd) {
7705678Spl196000 	case DDI_ATTACH:
7715678Spl196000 		break;
7725678Spl196000 	case DDI_RESUME:
7735678Spl196000 		return (DDI_FAILURE);
7745678Spl196000 	default:
7755678Spl196000 		return (DDI_FAILURE);
7765678Spl196000 	}
7775678Spl196000 
7785678Spl196000 	instance = ddi_get_instance(dip);
7795678Spl196000 
7805678Spl196000 	/* Get soft state */
7815678Spl196000 	if (ddi_soft_state_zalloc(aac_softstatep, instance) != DDI_SUCCESS) {
7825678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot alloc soft state");
7835678Spl196000 		goto error;
7845678Spl196000 	}
7855678Spl196000 	softs = ddi_get_soft_state(aac_softstatep, instance);
7865678Spl196000 	attach_state |= AAC_ATTACH_SOFTSTATE_ALLOCED;
7875678Spl196000 
7885678Spl196000 	softs->instance = instance;
7895678Spl196000 	softs->devinfo_p = dip;
7905678Spl196000 	softs->buf_dma_attr = softs->addr_dma_attr = aac_dma_attr;
7915678Spl196000 	softs->addr_dma_attr.dma_attr_granular = 1;
7927567SXin.Chen@Sun.COM 	softs->acc_attr = aac_acc_attr;
79311236SStephen.Hanson@Sun.COM 	softs->reg_attr = aac_acc_attr;
7945678Spl196000 	softs->card = AAC_UNKNOWN_CARD;
7955678Spl196000 #ifdef DEBUG
7965678Spl196000 	softs->debug_flags = aac_debug_flags;
7977567SXin.Chen@Sun.COM 	softs->debug_fib_flags = aac_debug_fib_flags;
7985678Spl196000 #endif
7995678Spl196000 
8007567SXin.Chen@Sun.COM 	/* Initialize FMA */
8017567SXin.Chen@Sun.COM 	aac_fm_init(softs);
8027567SXin.Chen@Sun.COM 
8035678Spl196000 	/* Check the card type */
8045678Spl196000 	if (aac_check_card_type(softs) == AACERR) {
8055678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Card not supported");
8065678Spl196000 		goto error;
8075678Spl196000 	}
8085678Spl196000 	/* We have found the right card and everything is OK */
8095678Spl196000 	attach_state |= AAC_ATTACH_CARD_DETECTED;
8105678Spl196000 
8115678Spl196000 	/* Map PCI mem space */
8125678Spl196000 	if (ddi_regs_map_setup(dip, 1,
8135678Spl196000 	    (caddr_t *)&softs->pci_mem_base_vaddr, 0,
81411236SStephen.Hanson@Sun.COM 	    softs->map_size_min, &softs->reg_attr,
8155678Spl196000 	    &softs->pci_mem_handle) != DDI_SUCCESS)
8165678Spl196000 		goto error;
8175678Spl196000 
8185678Spl196000 	softs->map_size = softs->map_size_min;
8195678Spl196000 	attach_state |= AAC_ATTACH_PCI_MEM_MAPPED;
8205678Spl196000 
8215678Spl196000 	AAC_DISABLE_INTR(softs);
8225678Spl196000 
82311348SZhongyan.Gu@Sun.COM 	/* Init mutexes and condvars */
82411964SXin.Chen@Sun.COM 	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
82511964SXin.Chen@Sun.COM 	    DDI_INTR_PRI(softs->intr_pri));
82611964SXin.Chen@Sun.COM 	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
82711964SXin.Chen@Sun.COM 	    DDI_INTR_PRI(softs->intr_pri));
82811964SXin.Chen@Sun.COM 	mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
82911964SXin.Chen@Sun.COM 	    DDI_INTR_PRI(softs->intr_pri));
83011964SXin.Chen@Sun.COM 	mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
83111964SXin.Chen@Sun.COM 	    DDI_INTR_PRI(softs->intr_pri));
83211964SXin.Chen@Sun.COM 	mutex_init(&softs->aifq_mutex, NULL,
8337000Sjd218194 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
8345678Spl196000 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
83511636SXin.Chen@Sun.COM 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
8365678Spl196000 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
83711964SXin.Chen@Sun.COM 	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
83811964SXin.Chen@Sun.COM 	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
83911964SXin.Chen@Sun.COM 	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
8405678Spl196000 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
8415678Spl196000 
84211348SZhongyan.Gu@Sun.COM 	/* Init the cmd queues */
84311348SZhongyan.Gu@Sun.COM 	for (i = 0; i < AAC_CMDQ_NUM; i++)
84411348SZhongyan.Gu@Sun.COM 		aac_cmd_initq(&softs->q_wait[i]);
84511348SZhongyan.Gu@Sun.COM 	aac_cmd_initq(&softs->q_busy);
84611348SZhongyan.Gu@Sun.COM 	aac_cmd_initq(&softs->q_comp);
84711348SZhongyan.Gu@Sun.COM 
8487567SXin.Chen@Sun.COM 	/* Check for legacy device naming support */
8497567SXin.Chen@Sun.COM 	softs->legacy = 1; /* default to use legacy name */
8507567SXin.Chen@Sun.COM 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
8517567SXin.Chen@Sun.COM 	    "legacy-name-enable", &data) == DDI_SUCCESS)) {
8527567SXin.Chen@Sun.COM 		if (strcmp(data, "no") == 0) {
8537567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "legacy-name disabled");
8547567SXin.Chen@Sun.COM 			softs->legacy = 0;
8557567SXin.Chen@Sun.COM 		}
8567567SXin.Chen@Sun.COM 		ddi_prop_free(data);
8577567SXin.Chen@Sun.COM 	}
8587567SXin.Chen@Sun.COM 
8595678Spl196000 	/*
8605678Spl196000 	 * Everything has been set up till now,
8615678Spl196000 	 * we will do some common attach.
8625678Spl196000 	 */
86311348SZhongyan.Gu@Sun.COM 	mutex_enter(&softs->io_lock);
86411348SZhongyan.Gu@Sun.COM 	if (aac_common_attach(softs) == AACERR) {
86511348SZhongyan.Gu@Sun.COM 		mutex_exit(&softs->io_lock);
8665678Spl196000 		goto error;
86711348SZhongyan.Gu@Sun.COM 	}
86811348SZhongyan.Gu@Sun.COM 	mutex_exit(&softs->io_lock);
8695678Spl196000 	attach_state |= AAC_ATTACH_COMM_SPACE_SETUP;
8705678Spl196000 
8718551SPeng.L@Sun.COM 	/* Check for buf breakup support */
8728551SPeng.L@Sun.COM 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
8738551SPeng.L@Sun.COM 	    "breakup-enable", &data) == DDI_SUCCESS)) {
8748551SPeng.L@Sun.COM 		if (strcmp(data, "yes") == 0) {
8758551SPeng.L@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "buf breakup enabled");
8768551SPeng.L@Sun.COM 			softs->flags |= AAC_FLAGS_BRKUP;
8778551SPeng.L@Sun.COM 		}
8788551SPeng.L@Sun.COM 		ddi_prop_free(data);
8798551SPeng.L@Sun.COM 	}
8808551SPeng.L@Sun.COM 	softs->dma_max = softs->buf_dma_attr.dma_attr_maxxfer;
8818551SPeng.L@Sun.COM 	if (softs->flags & AAC_FLAGS_BRKUP) {
8828551SPeng.L@Sun.COM 		softs->dma_max = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
8838551SPeng.L@Sun.COM 		    DDI_PROP_DONTPASS, "dma-max", softs->dma_max);
8848551SPeng.L@Sun.COM 	}
8858551SPeng.L@Sun.COM 
8865678Spl196000 	if (aac_hba_setup(softs) != AACOK)
8875678Spl196000 		goto error;
8885678Spl196000 	attach_state |= AAC_ATTACH_SCSI_TRAN_SETUP;
8895678Spl196000 
8905678Spl196000 	/* Create devctl/scsi nodes for cfgadm */
8915678Spl196000 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
8925678Spl196000 	    INST2DEVCTL(instance), DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) {
8935678Spl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create devctl node");
8945678Spl196000 		goto error;
8955678Spl196000 	}
8965678Spl196000 	attach_state |= AAC_ATTACH_CREATE_DEVCTL;
8975678Spl196000 
8985678Spl196000 	if (ddi_create_minor_node(dip, "scsi", S_IFCHR, INST2SCSI(instance),
8995678Spl196000 	    DDI_NT_SCSI_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
9005678Spl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create scsi node");
9015678Spl196000 		goto error;
9025678Spl196000 	}
9035678Spl196000 	attach_state |= AAC_ATTACH_CREATE_SCSI;
9045678Spl196000 
9055678Spl196000 	/* Create aac node for app. to issue ioctls */
9065678Spl196000 	if (ddi_create_minor_node(dip, "aac", S_IFCHR, INST2AAC(instance),
9075678Spl196000 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
9085678Spl196000 		AACDB_PRINT(softs, CE_WARN, "failed to create aac node");
9095678Spl196000 		goto error;
9105678Spl196000 	}
9115678Spl196000 
91211964SXin.Chen@Sun.COM 	/* Common attach is OK, so we are attached! */
91311964SXin.Chen@Sun.COM 	softs->state |= AAC_STATE_RUN;
91411964SXin.Chen@Sun.COM 
91511964SXin.Chen@Sun.COM 	/* Create event thread */
91611964SXin.Chen@Sun.COM 	softs->fibctx_p = &softs->aifctx;
91711964SXin.Chen@Sun.COM 	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
91811964SXin.Chen@Sun.COM 	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
91911964SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
92011964SXin.Chen@Sun.COM 		softs->state &= ~AAC_STATE_RUN;
9217567SXin.Chen@Sun.COM 		goto error;
9227567SXin.Chen@Sun.COM 	}
9237567SXin.Chen@Sun.COM 
9245678Spl196000 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
9255678Spl196000 
9265678Spl196000 	/* Create a thread for command timeout */
92711964SXin.Chen@Sun.COM 	softs->timeout_id = timeout(aac_timer, (void *)softs,
92811964SXin.Chen@Sun.COM 	    (aac_tick * drv_usectohz(1000000)));
9295678Spl196000 
9305678Spl196000 	/* Common attach is OK, so we are attached! */
9315678Spl196000 	ddi_report_dev(dip);
9325678Spl196000 	AACDB_PRINT(softs, CE_NOTE, "aac attached ok");
9335678Spl196000 	return (DDI_SUCCESS);
9345678Spl196000 
9355678Spl196000 error:
9365678Spl196000 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
9375678Spl196000 		ddi_remove_minor_node(dip, "scsi");
9385678Spl196000 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
9395678Spl196000 		ddi_remove_minor_node(dip, "devctl");
9405678Spl196000 	if (attach_state & AAC_ATTACH_COMM_SPACE_SETUP)
9415678Spl196000 		aac_common_detach(softs);
9425678Spl196000 	if (attach_state & AAC_ATTACH_SCSI_TRAN_SETUP) {
9435678Spl196000 		(void) scsi_hba_detach(dip);
9445678Spl196000 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
9455678Spl196000 	}
9465678Spl196000 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
94711964SXin.Chen@Sun.COM 		mutex_destroy(&softs->io_lock);
9485678Spl196000 		mutex_destroy(&softs->q_comp_mutex);
94911964SXin.Chen@Sun.COM 		mutex_destroy(&softs->time_mutex);
95011964SXin.Chen@Sun.COM 		mutex_destroy(&softs->ev_lock);
95111964SXin.Chen@Sun.COM 		mutex_destroy(&softs->aifq_mutex);
9525678Spl196000 		cv_destroy(&softs->event);
95311636SXin.Chen@Sun.COM 		cv_destroy(&softs->sync_fib_cv);
9545678Spl196000 		cv_destroy(&softs->drain_cv);
95511964SXin.Chen@Sun.COM 		cv_destroy(&softs->event_wait_cv);
95611964SXin.Chen@Sun.COM 		cv_destroy(&softs->event_disp_cv);
95711964SXin.Chen@Sun.COM 		cv_destroy(&softs->aifq_cv);
9585678Spl196000 	}
9595678Spl196000 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
9605678Spl196000 		ddi_regs_map_free(&softs->pci_mem_handle);
9615678Spl196000 	aac_fm_fini(softs);
9625678Spl196000 	if (attach_state & AAC_ATTACH_CARD_DETECTED)
9635678Spl196000 		softs->card = AACERR;
9645678Spl196000 	if (attach_state & AAC_ATTACH_SOFTSTATE_ALLOCED)
9655678Spl196000 		ddi_soft_state_free(aac_softstatep, instance);
9665678Spl196000 	return (DDI_FAILURE);
9675678Spl196000 }
9685678Spl196000 
9695678Spl196000 static int
aac_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)9705678Spl196000 aac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
9715678Spl196000 {
9725678Spl196000 	scsi_hba_tran_t *tran = AAC_DIP2TRAN(dip);
9735678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
9745678Spl196000 
9755678Spl196000 	DBCALLED(softs, 1);
9765678Spl196000 
9775678Spl196000 	switch (cmd) {
9785678Spl196000 	case DDI_DETACH:
9795678Spl196000 		break;
9805678Spl196000 	case DDI_SUSPEND:
9815678Spl196000 		return (DDI_FAILURE);
9825678Spl196000 	default:
9835678Spl196000 		return (DDI_FAILURE);
9845678Spl196000 	}
9855678Spl196000 
9865678Spl196000 	mutex_enter(&softs->io_lock);
9875678Spl196000 	AAC_DISABLE_INTR(softs);
9885678Spl196000 	softs->state = AAC_STATE_STOPPED;
9895678Spl196000 
9905678Spl196000 	ddi_remove_minor_node(dip, "aac");
9915678Spl196000 	ddi_remove_minor_node(dip, "scsi");
9925678Spl196000 	ddi_remove_minor_node(dip, "devctl");
9935678Spl196000 	mutex_exit(&softs->io_lock);
9945678Spl196000 
9955678Spl196000 	aac_common_detach(softs);
9965678Spl196000 
99711348SZhongyan.Gu@Sun.COM 	mutex_enter(&softs->io_lock);
9985678Spl196000 	(void) scsi_hba_detach(dip);
9995678Spl196000 	scsi_hba_tran_free(tran);
100011348SZhongyan.Gu@Sun.COM 	mutex_exit(&softs->io_lock);
10015678Spl196000 
100211964SXin.Chen@Sun.COM 	/* Stop timer */
100311964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
100411964SXin.Chen@Sun.COM 	if (softs->timeout_id) {
100511964SXin.Chen@Sun.COM 		timeout_id_t tid = softs->timeout_id;
100611964SXin.Chen@Sun.COM 		softs->timeout_id = 0;
100711964SXin.Chen@Sun.COM 
100811964SXin.Chen@Sun.COM 		mutex_exit(&softs->time_mutex);
100911964SXin.Chen@Sun.COM 		(void) untimeout(tid);
101011964SXin.Chen@Sun.COM 		mutex_enter(&softs->time_mutex);
101111964SXin.Chen@Sun.COM 	}
101211964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
101311964SXin.Chen@Sun.COM 
101411964SXin.Chen@Sun.COM 	/* Destroy event thread */
101511964SXin.Chen@Sun.COM 	mutex_enter(&softs->ev_lock);
101611964SXin.Chen@Sun.COM 	cv_signal(&softs->event_disp_cv);
101711964SXin.Chen@Sun.COM 	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
101811964SXin.Chen@Sun.COM 	mutex_exit(&softs->ev_lock);
101911964SXin.Chen@Sun.COM 
102011964SXin.Chen@Sun.COM 	cv_destroy(&softs->aifq_cv);
102111964SXin.Chen@Sun.COM 	cv_destroy(&softs->event_disp_cv);
102211964SXin.Chen@Sun.COM 	cv_destroy(&softs->event_wait_cv);
102311964SXin.Chen@Sun.COM 	cv_destroy(&softs->drain_cv);
102411636SXin.Chen@Sun.COM 	cv_destroy(&softs->sync_fib_cv);
102511964SXin.Chen@Sun.COM 	cv_destroy(&softs->event);
10265678Spl196000 	mutex_destroy(&softs->aifq_mutex);
102711964SXin.Chen@Sun.COM 	mutex_destroy(&softs->ev_lock);
102811964SXin.Chen@Sun.COM 	mutex_destroy(&softs->time_mutex);
102911964SXin.Chen@Sun.COM 	mutex_destroy(&softs->q_comp_mutex);
10305678Spl196000 	mutex_destroy(&softs->io_lock);
10315678Spl196000 
10325678Spl196000 	ddi_regs_map_free(&softs->pci_mem_handle);
10335678Spl196000 	aac_fm_fini(softs);
10345678Spl196000 	softs->hwif = AAC_HWIF_UNKNOWN;
10355678Spl196000 	softs->card = AAC_UNKNOWN_CARD;
10365678Spl196000 	ddi_soft_state_free(aac_softstatep, ddi_get_instance(dip));
10375678Spl196000 
10385678Spl196000 	return (DDI_SUCCESS);
10395678Spl196000 }
10405678Spl196000 
10415678Spl196000 /*ARGSUSED*/
10425678Spl196000 static int
aac_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)10435678Spl196000 aac_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
10445678Spl196000 {
10455678Spl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
10465678Spl196000 
10475678Spl196000 	DBCALLED(softs, 1);
10485678Spl196000 
10495678Spl196000 	mutex_enter(&softs->io_lock);
105011636SXin.Chen@Sun.COM 	AAC_DISABLE_INTR(softs);
10515678Spl196000 	(void) aac_shutdown(softs);
10525678Spl196000 	mutex_exit(&softs->io_lock);
10535678Spl196000 
10545678Spl196000 	return (DDI_SUCCESS);
10555678Spl196000 }
10565678Spl196000 
10575678Spl196000 /*
10587656SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
10597656SSherry.Moore@Sun.COM  *
10607656SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
10617656SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
10627656SSherry.Moore@Sun.COM  * blocked.
10637656SSherry.Moore@Sun.COM  *
10647656SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
10657656SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
10667656SSherry.Moore@Sun.COM  */
10677656SSherry.Moore@Sun.COM static int
aac_quiesce(dev_info_t * dip)10687656SSherry.Moore@Sun.COM aac_quiesce(dev_info_t *dip)
10697656SSherry.Moore@Sun.COM {
10707656SSherry.Moore@Sun.COM 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
10717656SSherry.Moore@Sun.COM 
10727656SSherry.Moore@Sun.COM 	if (softs == NULL)
10737656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
10747656SSherry.Moore@Sun.COM 
107511964SXin.Chen@Sun.COM 	_NOTE(ASSUMING_PROTECTED(softs->state))
10767656SSherry.Moore@Sun.COM 	AAC_DISABLE_INTR(softs);
10777656SSherry.Moore@Sun.COM 
10787656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
10797656SSherry.Moore@Sun.COM }
10807656SSherry.Moore@Sun.COM 
108111348SZhongyan.Gu@Sun.COM /* ARGSUSED */
108211348SZhongyan.Gu@Sun.COM static int
aac_getinfo(dev_info_t * self,ddi_info_cmd_t infocmd,void * arg,void ** result)108311348SZhongyan.Gu@Sun.COM aac_getinfo(dev_info_t *self, ddi_info_cmd_t infocmd, void *arg,
108411348SZhongyan.Gu@Sun.COM     void **result)
108511348SZhongyan.Gu@Sun.COM {
108611348SZhongyan.Gu@Sun.COM 	int error = DDI_SUCCESS;
108711348SZhongyan.Gu@Sun.COM 
108811348SZhongyan.Gu@Sun.COM 	switch (infocmd) {
108911348SZhongyan.Gu@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
109011348SZhongyan.Gu@Sun.COM 		*result = (void *)(intptr_t)(MINOR2INST(getminor((dev_t)arg)));
109111348SZhongyan.Gu@Sun.COM 		break;
109211348SZhongyan.Gu@Sun.COM 	default:
109311348SZhongyan.Gu@Sun.COM 		error = DDI_FAILURE;
109411348SZhongyan.Gu@Sun.COM 	}
109511348SZhongyan.Gu@Sun.COM 	return (error);
109611348SZhongyan.Gu@Sun.COM }
109711348SZhongyan.Gu@Sun.COM 
10987656SSherry.Moore@Sun.COM /*
10995678Spl196000  * Bring the controller down to a dormant state and detach all child devices.
11005678Spl196000  * This function is called before detach or system shutdown.
11015678Spl196000  * Note: we can assume that the q_wait on the controller is empty, as we
11025678Spl196000  * won't allow shutdown if any device is open.
11035678Spl196000  */
11045678Spl196000 static int
aac_shutdown(struct aac_softstate * softs)11055678Spl196000 aac_shutdown(struct aac_softstate *softs)
11065678Spl196000 {
110711348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
110811348SZhongyan.Gu@Sun.COM 	struct aac_close_command *cc;
11095678Spl196000 	int rval;
11105678Spl196000 
111111348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
111211348SZhongyan.Gu@Sun.COM 	acc = softs->sync_ac.slotp->fib_acc_handle;
111311348SZhongyan.Gu@Sun.COM 
111411348SZhongyan.Gu@Sun.COM 	cc = (struct aac_close_command *)&softs->sync_ac.slotp->fibp->data[0];
111511348SZhongyan.Gu@Sun.COM 
11165678Spl196000 	ddi_put32(acc, &cc->Command, VM_CloseAll);
11175678Spl196000 	ddi_put32(acc, &cc->ContainerId, 0xfffffffful);
11185678Spl196000 
11195678Spl196000 	/* Flush all caches, set FW to write through mode */
11205678Spl196000 	rval = aac_sync_fib(softs, ContainerCommand,
11215678Spl196000 	    AAC_FIB_SIZEOF(struct aac_close_command));
112211348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
11235678Spl196000 
11245678Spl196000 	AACDB_PRINT(softs, CE_NOTE,
11255678Spl196000 	    "shutting down aac %s", (rval == AACOK) ? "ok" : "fail");
11265678Spl196000 	return (rval);
11275678Spl196000 }
11285678Spl196000 
11295678Spl196000 static uint_t
aac_softintr(caddr_t arg)11305678Spl196000 aac_softintr(caddr_t arg)
11315678Spl196000 {
11327100Spl196000 	struct aac_softstate *softs = (void *)arg;
11335678Spl196000 
11345678Spl196000 	if (!AAC_IS_Q_EMPTY(&softs->q_comp)) {
11355678Spl196000 		aac_drain_comp_q(softs);
113611348SZhongyan.Gu@Sun.COM 	}
113711348SZhongyan.Gu@Sun.COM 	return (DDI_INTR_CLAIMED);
11385678Spl196000 }
11395678Spl196000 
11405678Spl196000 /*
11415678Spl196000  * Setup auto sense data for pkt
11425678Spl196000  */
11435678Spl196000 static void
aac_set_arq_data(struct scsi_pkt * pkt,uchar_t key,uchar_t add_code,uchar_t qual_code,uint64_t info)11445678Spl196000 aac_set_arq_data(struct scsi_pkt *pkt, uchar_t key,
11455678Spl196000     uchar_t add_code, uchar_t qual_code, uint64_t info)
11465678Spl196000 {
11477567SXin.Chen@Sun.COM 	struct scsi_arq_status *arqstat = (void *)(pkt->pkt_scbp);
11487567SXin.Chen@Sun.COM 
11497567SXin.Chen@Sun.COM 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
11507567SXin.Chen@Sun.COM 	pkt->pkt_state |= STATE_ARQ_DONE;
11517567SXin.Chen@Sun.COM 
11527567SXin.Chen@Sun.COM 	*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
11535678Spl196000 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
11545678Spl196000 	arqstat->sts_rqpkt_resid = 0;
11555678Spl196000 	arqstat->sts_rqpkt_state =
11565678Spl196000 	    STATE_GOT_BUS |
11575678Spl196000 	    STATE_GOT_TARGET |
11585678Spl196000 	    STATE_SENT_CMD |
11595678Spl196000 	    STATE_XFERRED_DATA;
11605678Spl196000 	arqstat->sts_rqpkt_statistics = 0;
11615678Spl196000 
11625678Spl196000 	if (info <= 0xfffffffful) {
11635678Spl196000 		arqstat->sts_sensedata.es_valid = 1;
11645678Spl196000 		arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
11655678Spl196000 		arqstat->sts_sensedata.es_code = CODE_FMT_FIXED_CURRENT;
11665678Spl196000 		arqstat->sts_sensedata.es_key = key;
11675678Spl196000 		arqstat->sts_sensedata.es_add_code = add_code;
11685678Spl196000 		arqstat->sts_sensedata.es_qual_code = qual_code;
11695678Spl196000 
11705678Spl196000 		arqstat->sts_sensedata.es_info_1 = (info >> 24) & 0xFF;
11715678Spl196000 		arqstat->sts_sensedata.es_info_2 = (info >> 16) & 0xFF;
11725678Spl196000 		arqstat->sts_sensedata.es_info_3 = (info >>  8) & 0xFF;
11735678Spl196000 		arqstat->sts_sensedata.es_info_4 = info & 0xFF;
11745678Spl196000 	} else { /* 64-bit LBA */
11755678Spl196000 		struct scsi_descr_sense_hdr *dsp;
11765678Spl196000 		struct scsi_information_sense_descr *isd;
11775678Spl196000 
11785678Spl196000 		dsp = (struct scsi_descr_sense_hdr *)&arqstat->sts_sensedata;
11795678Spl196000 		dsp->ds_class = CLASS_EXTENDED_SENSE;
11805678Spl196000 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
11815678Spl196000 		dsp->ds_key = key;
11825678Spl196000 		dsp->ds_add_code = add_code;
11835678Spl196000 		dsp->ds_qual_code = qual_code;
11845678Spl196000 		dsp->ds_addl_sense_length =
11855678Spl196000 		    sizeof (struct scsi_information_sense_descr);
11865678Spl196000 
11875678Spl196000 		isd = (struct scsi_information_sense_descr *)(dsp+1);
11885678Spl196000 		isd->isd_descr_type = DESCR_INFORMATION;
11895678Spl196000 		isd->isd_valid = 1;
11905678Spl196000 		isd->isd_information[0] = (info >> 56) & 0xFF;
11915678Spl196000 		isd->isd_information[1] = (info >> 48) & 0xFF;
11925678Spl196000 		isd->isd_information[2] = (info >> 40) & 0xFF;
11935678Spl196000 		isd->isd_information[3] = (info >> 32) & 0xFF;
11945678Spl196000 		isd->isd_information[4] = (info >> 24) & 0xFF;
11955678Spl196000 		isd->isd_information[5] = (info >> 16) & 0xFF;
11965678Spl196000 		isd->isd_information[6] = (info >>  8) & 0xFF;
11975678Spl196000 		isd->isd_information[7] = (info) & 0xFF;
11985678Spl196000 	}
11995678Spl196000 }
12005678Spl196000 
12015678Spl196000 /*
12025678Spl196000  * Setup auto sense data for HARDWARE ERROR
12035678Spl196000  */
12045678Spl196000 static void
aac_set_arq_data_hwerr(struct aac_cmd * acp)12055678Spl196000 aac_set_arq_data_hwerr(struct aac_cmd *acp)
12065678Spl196000 {
12075678Spl196000 	union scsi_cdb *cdbp;
12085678Spl196000 	uint64_t err_blkno;
12095678Spl196000 
12107100Spl196000 	cdbp = (void *)acp->pkt->pkt_cdbp;
12115678Spl196000 	err_blkno = AAC_GETGXADDR(acp->cmdlen, cdbp);
12125678Spl196000 	aac_set_arq_data(acp->pkt, KEY_HARDWARE_ERROR, 0x00, 0x00, err_blkno);
12135678Spl196000 }
12145678Spl196000 
12155678Spl196000 /*
12165678Spl196000  * Send a command to the adapter in New Comm. interface
12175678Spl196000  */
12185678Spl196000 static int
aac_send_command(struct aac_softstate * softs,struct aac_slot * slotp)12195678Spl196000 aac_send_command(struct aac_softstate *softs, struct aac_slot *slotp)
12205678Spl196000 {
12215678Spl196000 	uint32_t index, device;
12225678Spl196000 
12235678Spl196000 	index = PCI_MEM_GET32(softs, AAC_IQUE);
12245678Spl196000 	if (index == 0xffffffffUL) {
12255678Spl196000 		index = PCI_MEM_GET32(softs, AAC_IQUE);
12265678Spl196000 		if (index == 0xffffffffUL)
12275678Spl196000 			return (AACERR);
12285678Spl196000 	}
12295678Spl196000 
12305678Spl196000 	device = index;
12315678Spl196000 	PCI_MEM_PUT32(softs, device,
12325678Spl196000 	    (uint32_t)(slotp->fib_phyaddr & 0xfffffffful));
12335678Spl196000 	device += 4;
12345678Spl196000 	PCI_MEM_PUT32(softs, device, (uint32_t)(slotp->fib_phyaddr >> 32));
12355678Spl196000 	device += 4;
12365678Spl196000 	PCI_MEM_PUT32(softs, device, slotp->acp->fib_size);
12375678Spl196000 	PCI_MEM_PUT32(softs, AAC_IQUE, index);
12385678Spl196000 	return (AACOK);
12395678Spl196000 }
12405678Spl196000 
12415678Spl196000 static void
aac_end_io(struct aac_softstate * softs,struct aac_cmd * acp)12425678Spl196000 aac_end_io(struct aac_softstate *softs, struct aac_cmd *acp)
12435678Spl196000 {
12447567SXin.Chen@Sun.COM 	struct aac_device *dvp = acp->dvp;
12455678Spl196000 	int q = AAC_CMDQ(acp);
12465678Spl196000 
12475678Spl196000 	if (acp->slotp) { /* outstanding cmd */
124811348SZhongyan.Gu@Sun.COM 		if (!(acp->flags & AAC_CMD_IN_SYNC_SLOT)) {
124911348SZhongyan.Gu@Sun.COM 			aac_release_slot(softs, acp->slotp);
125011348SZhongyan.Gu@Sun.COM 			acp->slotp = NULL;
125111348SZhongyan.Gu@Sun.COM 		}
12525678Spl196000 		if (dvp) {
12535678Spl196000 			dvp->ncmds[q]--;
12545678Spl196000 			if (dvp->throttle[q] == AAC_THROTTLE_DRAIN &&
12555678Spl196000 			    dvp->ncmds[q] == 0 && q == AAC_CMDQ_ASYNC)
12565678Spl196000 				aac_set_throttle(softs, dvp, q,
12575678Spl196000 				    softs->total_slots);
125811348SZhongyan.Gu@Sun.COM 			/*
125911348SZhongyan.Gu@Sun.COM 			 * Setup auto sense data for UNIT ATTENTION
126011348SZhongyan.Gu@Sun.COM 			 * Each lun should generate a unit attention
126111348SZhongyan.Gu@Sun.COM 			 * condition when reset.
126211348SZhongyan.Gu@Sun.COM 			 * Phys. drives are treated as logical ones
126311348SZhongyan.Gu@Sun.COM 			 * during error recovery.
126411348SZhongyan.Gu@Sun.COM 			 */
126511348SZhongyan.Gu@Sun.COM 			if (dvp->type == AAC_DEV_LD) {
126611348SZhongyan.Gu@Sun.COM 				struct aac_container *ctp =
126711348SZhongyan.Gu@Sun.COM 				    (struct aac_container *)dvp;
126811348SZhongyan.Gu@Sun.COM 				if (ctp->reset == 0)
126911348SZhongyan.Gu@Sun.COM 					goto noreset;
127011348SZhongyan.Gu@Sun.COM 
127111348SZhongyan.Gu@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
127211348SZhongyan.Gu@Sun.COM 				    "Unit attention: reset");
127311348SZhongyan.Gu@Sun.COM 				ctp->reset = 0;
127411348SZhongyan.Gu@Sun.COM 				aac_set_arq_data(acp->pkt, KEY_UNIT_ATTENTION,
127511348SZhongyan.Gu@Sun.COM 				    0x29, 0x02, 0);
127611348SZhongyan.Gu@Sun.COM 			}
12775678Spl196000 		}
127811348SZhongyan.Gu@Sun.COM noreset:
12795678Spl196000 		softs->bus_ncmds[q]--;
128011348SZhongyan.Gu@Sun.COM 		aac_cmd_delete(&softs->q_busy, acp);
12815678Spl196000 	} else { /* cmd in waiting queue */
12825678Spl196000 		aac_cmd_delete(&softs->q_wait[q], acp);
12835678Spl196000 	}
12845678Spl196000 
12855678Spl196000 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR))) { /* async IO */
12865678Spl196000 		mutex_enter(&softs->q_comp_mutex);
12875678Spl196000 		aac_cmd_enqueue(&softs->q_comp, acp);
12885678Spl196000 		mutex_exit(&softs->q_comp_mutex);
12895678Spl196000 	} else if (acp->flags & AAC_CMD_NO_CB) { /* sync IO */
12905678Spl196000 		cv_broadcast(&softs->event);
12915678Spl196000 	}
12925678Spl196000 }
12935678Spl196000 
12945678Spl196000 static void
aac_handle_io(struct aac_softstate * softs,int index)12955678Spl196000 aac_handle_io(struct aac_softstate *softs, int index)
12965678Spl196000 {
12975678Spl196000 	struct aac_slot *slotp;
12985678Spl196000 	struct aac_cmd *acp;
12995678Spl196000 	uint32_t fast;
13005678Spl196000 
13015678Spl196000 	fast = index & AAC_SENDERADDR_MASK_FAST_RESPONSE;
13025678Spl196000 	index >>= 2;
13035678Spl196000 
13045678Spl196000 	/* Make sure firmware reported index is valid */
13055678Spl196000 	ASSERT(index >= 0 && index < softs->total_slots);
13065678Spl196000 	slotp = &softs->io_slot[index];
13075678Spl196000 	ASSERT(slotp->index == index);
13085678Spl196000 	acp = slotp->acp;
13097567SXin.Chen@Sun.COM 
13107567SXin.Chen@Sun.COM 	if (acp == NULL || acp->slotp != slotp) {
13117567SXin.Chen@Sun.COM 		cmn_err(CE_WARN,
13127567SXin.Chen@Sun.COM 		    "Firmware error: invalid slot index received from FW");
13137567SXin.Chen@Sun.COM 		return;
13147567SXin.Chen@Sun.COM 	}
13155678Spl196000 
13165678Spl196000 	acp->flags |= AAC_CMD_CMPLT;
13175678Spl196000 	(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
13185678Spl196000 
13195678Spl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) == DDI_SUCCESS) {
13205678Spl196000 		/*
13215678Spl196000 		 * For fast response IO, the firmware do not return any FIB
13225678Spl196000 		 * data, so we need to fill in the FIB status and state so that
13235678Spl196000 		 * FIB users can handle it correctly.
13245678Spl196000 		 */
13255678Spl196000 		if (fast) {
13265678Spl196000 			uint32_t state;
13275678Spl196000 
13285678Spl196000 			state = ddi_get32(slotp->fib_acc_handle,
13295678Spl196000 			    &slotp->fibp->Header.XferState);
13305678Spl196000 			/*
13315678Spl196000 			 * Update state for CPU not for device, no DMA sync
13325678Spl196000 			 * needed
13335678Spl196000 			 */
13345678Spl196000 			ddi_put32(slotp->fib_acc_handle,
13355678Spl196000 			    &slotp->fibp->Header.XferState,
13365678Spl196000 			    state | AAC_FIBSTATE_DONEADAP);
13375678Spl196000 			ddi_put32(slotp->fib_acc_handle,
13387100Spl196000 			    (void *)&slotp->fibp->data[0], ST_OK);
13395678Spl196000 		}
13405678Spl196000 
13415678Spl196000 		/* Handle completed ac */
13425678Spl196000 		acp->ac_comp(softs, acp);
13435678Spl196000 	} else {
13445678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
13455678Spl196000 		acp->flags |= AAC_CMD_ERR;
13465678Spl196000 		if (acp->pkt) {
13475678Spl196000 			acp->pkt->pkt_reason = CMD_TRAN_ERR;
13485678Spl196000 			acp->pkt->pkt_statistics = 0;
13495678Spl196000 		}
13505678Spl196000 	}
13515678Spl196000 	aac_end_io(softs, acp);
13525678Spl196000 }
13535678Spl196000 
13545678Spl196000 /*
13555678Spl196000  * Interrupt handler for New Comm. interface
13565678Spl196000  * New Comm. interface use a different mechanism for interrupt. No explict
13575678Spl196000  * message queues, and driver need only accesses the mapped PCI mem space to
13585678Spl196000  * find the completed FIB or AIF.
13595678Spl196000  */
13605678Spl196000 static int
aac_process_intr_new(struct aac_softstate * softs)13615678Spl196000 aac_process_intr_new(struct aac_softstate *softs)
13625678Spl196000 {
13635678Spl196000 	uint32_t index;
13645678Spl196000 
13655678Spl196000 	index = AAC_OUTB_GET(softs);
13665678Spl196000 	if (index == 0xfffffffful)
13675678Spl196000 		index = AAC_OUTB_GET(softs);
13685678Spl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
13695678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
13707567SXin.Chen@Sun.COM 		return (0);
13715678Spl196000 	}
13725678Spl196000 	if (index != 0xfffffffful) {
13735678Spl196000 		do {
13745678Spl196000 			if ((index & AAC_SENDERADDR_MASK_AIF) == 0) {
13755678Spl196000 				aac_handle_io(softs, index);
13765678Spl196000 			} else if (index != 0xfffffffeul) {
13775678Spl196000 				struct aac_fib *fibp;	/* FIB in AIF queue */
137811964SXin.Chen@Sun.COM 				uint16_t fib_size;
13795678Spl196000 
13805678Spl196000 				/*
13815678Spl196000 				 * 0xfffffffe means that the controller wants
13825678Spl196000 				 * more work, ignore it for now. Otherwise,
13835678Spl196000 				 * AIF received.
13845678Spl196000 				 */
13855678Spl196000 				index &= ~2;
13865678Spl196000 
138711964SXin.Chen@Sun.COM 				fibp = (struct aac_fib *)(softs-> \
138811964SXin.Chen@Sun.COM 				    pci_mem_base_vaddr + index);
138911964SXin.Chen@Sun.COM 				fib_size = PCI_MEM_GET16(softs, index + \
13905678Spl196000 				    offsetof(struct aac_fib, Header.Size));
139111964SXin.Chen@Sun.COM 
139211964SXin.Chen@Sun.COM 				aac_save_aif(softs, softs->pci_mem_handle,
139311964SXin.Chen@Sun.COM 				    fibp, fib_size);
13945678Spl196000 
13955678Spl196000 				/*
13965678Spl196000 				 * AIF memory is owned by the adapter, so let it
13975678Spl196000 				 * know that we are done with it.
13985678Spl196000 				 */
13995678Spl196000 				AAC_OUTB_SET(softs, index);
14005678Spl196000 				AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
14015678Spl196000 			}
14025678Spl196000 
14035678Spl196000 			index = AAC_OUTB_GET(softs);
14045678Spl196000 		} while (index != 0xfffffffful);
14055678Spl196000 
14065678Spl196000 		/*
14075678Spl196000 		 * Process waiting cmds before start new ones to
14085678Spl196000 		 * ensure first IOs are serviced first.
14095678Spl196000 		 */
14105678Spl196000 		aac_start_waiting_io(softs);
14115678Spl196000 		return (AAC_DB_COMMAND_READY);
14125678Spl196000 	} else {
14135678Spl196000 		return (0);
14145678Spl196000 	}
14155678Spl196000 }
14165678Spl196000 
14175678Spl196000 static uint_t
aac_intr_new(caddr_t arg)14185678Spl196000 aac_intr_new(caddr_t arg)
14195678Spl196000 {
14207100Spl196000 	struct aac_softstate *softs = (void *)arg;
14215678Spl196000 	uint_t rval;
14225678Spl196000 
14235678Spl196000 	mutex_enter(&softs->io_lock);
14245678Spl196000 	if (aac_process_intr_new(softs))
14255678Spl196000 		rval = DDI_INTR_CLAIMED;
14265678Spl196000 	else
14275678Spl196000 		rval = DDI_INTR_UNCLAIMED;
14285678Spl196000 	mutex_exit(&softs->io_lock);
14295678Spl196000 
14305678Spl196000 	aac_drain_comp_q(softs);
14315678Spl196000 	return (rval);
14325678Spl196000 }
14335678Spl196000 
14345678Spl196000 /*
14355678Spl196000  * Interrupt handler for old interface
14365678Spl196000  * Explicit message queues are used to send FIB to and get completed FIB from
14375678Spl196000  * the adapter. Driver and adapter maitain the queues in the producer/consumer
14385678Spl196000  * manner. The driver has to query the queues to find the completed FIB.
14395678Spl196000  */
14405678Spl196000 static int
aac_process_intr_old(struct aac_softstate * softs)14415678Spl196000 aac_process_intr_old(struct aac_softstate *softs)
14425678Spl196000 {
14435678Spl196000 	uint16_t status;
14445678Spl196000 
14455678Spl196000 	status = AAC_STATUS_GET(softs);
14465678Spl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
14475678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
14485678Spl196000 		return (DDI_INTR_UNCLAIMED);
14495678Spl196000 	}
14505678Spl196000 	if (status & AAC_DB_RESPONSE_READY) {
14515678Spl196000 		int slot_idx;
14525678Spl196000 
14535678Spl196000 		/* ACK the intr */
14545678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_READY);
14555678Spl196000 		(void) AAC_STATUS_GET(softs);
14565678Spl196000 		while (aac_fib_dequeue(softs, AAC_HOST_NORM_RESP_Q,
14575678Spl196000 		    &slot_idx) == AACOK)
14585678Spl196000 			aac_handle_io(softs, slot_idx);
14595678Spl196000 
14605678Spl196000 		/*
14615678Spl196000 		 * Process waiting cmds before start new ones to
14625678Spl196000 		 * ensure first IOs are serviced first.
14635678Spl196000 		 */
14645678Spl196000 		aac_start_waiting_io(softs);
14655678Spl196000 		return (AAC_DB_RESPONSE_READY);
14665678Spl196000 	} else if (status & AAC_DB_COMMAND_READY) {
14675678Spl196000 		int aif_idx;
14685678Spl196000 
14695678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_READY);
14705678Spl196000 		(void) AAC_STATUS_GET(softs);
14715678Spl196000 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
14725678Spl196000 		    AACOK) {
14735678Spl196000 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
147411964SXin.Chen@Sun.COM 			struct aac_fib *fibp;	/* FIB in communication space */
147511964SXin.Chen@Sun.COM 			uint16_t fib_size;
14765678Spl196000 			uint32_t fib_xfer_state;
14775678Spl196000 			uint32_t addr, size;
14785678Spl196000 
14795678Spl196000 			ASSERT((aif_idx >= 0) && (aif_idx < AAC_ADAPTER_FIBS));
14805678Spl196000 
14815678Spl196000 #define	AAC_SYNC_AIF(softs, aif_idx, type) \
14825678Spl196000 	{ (void) ddi_dma_sync((softs)->comm_space_dma_handle, \
14835678Spl196000 	    offsetof(struct aac_comm_space, \
14845678Spl196000 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
14855678Spl196000 	    (type)); }
14865678Spl196000 
14875678Spl196000 			/* Copy AIF from adapter to the empty AIF slot */
14885678Spl196000 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
148911964SXin.Chen@Sun.COM 			fibp = &softs->comm_space->adapter_fibs[aif_idx];
149011964SXin.Chen@Sun.COM 			fib_size = ddi_get16(acc, &fibp->Header.Size);
149111964SXin.Chen@Sun.COM 
149211964SXin.Chen@Sun.COM 			aac_save_aif(softs, acc, fibp, fib_size);
14935678Spl196000 
14945678Spl196000 			/* Complete AIF back to adapter with good status */
14955678Spl196000 			fib_xfer_state = LE_32(fibp->Header.XferState);
14965678Spl196000 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
149711964SXin.Chen@Sun.COM 				ddi_put32(acc, &fibp->Header.XferState,
14985678Spl196000 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
149911964SXin.Chen@Sun.COM 				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
150011964SXin.Chen@Sun.COM 				if (fib_size > AAC_FIB_SIZE)
150111964SXin.Chen@Sun.COM 					ddi_put16(acc, &fibp->Header.Size,
15025678Spl196000 					    AAC_FIB_SIZE);
15035678Spl196000 				AAC_SYNC_AIF(softs, aif_idx,
15045678Spl196000 				    DDI_DMA_SYNC_FORDEV);
15055678Spl196000 			}
15065678Spl196000 
15075678Spl196000 			/* Put the AIF response on the response queue */
15085678Spl196000 			addr = ddi_get32(acc,
15095678Spl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
15105678Spl196000 			    Header.SenderFibAddress);
15115678Spl196000 			size = (uint32_t)ddi_get16(acc,
15125678Spl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
15135678Spl196000 			    Header.Size);
15145678Spl196000 			ddi_put32(acc,
15155678Spl196000 			    &softs->comm_space->adapter_fibs[aif_idx]. \
15165678Spl196000 			    Header.ReceiverFibAddress, addr);
15175678Spl196000 			if (aac_fib_enqueue(softs, AAC_ADAP_NORM_RESP_Q,
15185678Spl196000 			    addr, size) == AACERR)
15195678Spl196000 				cmn_err(CE_NOTE, "!AIF ack failed");
15205678Spl196000 		}
15215678Spl196000 		return (AAC_DB_COMMAND_READY);
15225678Spl196000 	} else if (status & AAC_DB_PRINTF_READY) {
15235678Spl196000 		/* ACK the intr */
15245678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_PRINTF_READY);
15255678Spl196000 		(void) AAC_STATUS_GET(softs);
15265678Spl196000 		(void) ddi_dma_sync(softs->comm_space_dma_handle,
15275678Spl196000 		    offsetof(struct aac_comm_space, adapter_print_buf),
15285678Spl196000 		    AAC_ADAPTER_PRINT_BUFSIZE, DDI_DMA_SYNC_FORCPU);
15295678Spl196000 		if (aac_check_dma_handle(softs->comm_space_dma_handle) ==
15305678Spl196000 		    DDI_SUCCESS)
15315678Spl196000 			cmn_err(CE_NOTE, "MSG From Adapter: %s",
15325678Spl196000 			    softs->comm_space->adapter_print_buf);
15335678Spl196000 		else
15345678Spl196000 			ddi_fm_service_impact(softs->devinfo_p,
15355678Spl196000 			    DDI_SERVICE_UNAFFECTED);
15365678Spl196000 		AAC_NOTIFY(softs, AAC_DB_PRINTF_READY);
15375678Spl196000 		return (AAC_DB_PRINTF_READY);
15385678Spl196000 	} else if (status & AAC_DB_COMMAND_NOT_FULL) {
15395678Spl196000 		/*
15405678Spl196000 		 * Without these two condition statements, the OS could hang
15415678Spl196000 		 * after a while, especially if there are a lot of AIF's to
15425678Spl196000 		 * handle, for instance if a drive is pulled from an array
15435678Spl196000 		 * under heavy load.
15445678Spl196000 		 */
15455678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
15465678Spl196000 		return (AAC_DB_COMMAND_NOT_FULL);
15475678Spl196000 	} else if (status & AAC_DB_RESPONSE_NOT_FULL) {
15485678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_COMMAND_NOT_FULL);
15495678Spl196000 		AAC_STATUS_CLR(softs, AAC_DB_RESPONSE_NOT_FULL);
15505678Spl196000 		return (AAC_DB_RESPONSE_NOT_FULL);
15515678Spl196000 	} else {
15525678Spl196000 		return (0);
15535678Spl196000 	}
15545678Spl196000 }
15555678Spl196000 
15565678Spl196000 static uint_t
aac_intr_old(caddr_t arg)15575678Spl196000 aac_intr_old(caddr_t arg)
15585678Spl196000 {
15597100Spl196000 	struct aac_softstate *softs = (void *)arg;
15605678Spl196000 	int rval;
15615678Spl196000 
15625678Spl196000 	mutex_enter(&softs->io_lock);
15635678Spl196000 	if (aac_process_intr_old(softs))
15645678Spl196000 		rval = DDI_INTR_CLAIMED;
15655678Spl196000 	else
15665678Spl196000 		rval = DDI_INTR_UNCLAIMED;
15675678Spl196000 	mutex_exit(&softs->io_lock);
15685678Spl196000 
15695678Spl196000 	aac_drain_comp_q(softs);
15705678Spl196000 	return (rval);
15715678Spl196000 }
15725678Spl196000 
15735678Spl196000 /*
15747000Sjd218194  * Query FIXED or MSI interrupts
15757000Sjd218194  */
15767000Sjd218194 static int
aac_query_intrs(struct aac_softstate * softs,int intr_type)15777000Sjd218194 aac_query_intrs(struct aac_softstate *softs, int intr_type)
15787000Sjd218194 {
15797000Sjd218194 	dev_info_t *dip = softs->devinfo_p;
158011348SZhongyan.Gu@Sun.COM 	int avail, actual, count;
15817000Sjd218194 	int i, flag, ret;
15827000Sjd218194 
15837000Sjd218194 	AACDB_PRINT(softs, CE_NOTE,
15847000Sjd218194 	    "aac_query_intrs:interrupt type 0x%x", intr_type);
15857000Sjd218194 
15867000Sjd218194 	/* Get number of interrupts */
15877000Sjd218194 	ret = ddi_intr_get_nintrs(dip, intr_type, &count);
15887000Sjd218194 	if ((ret != DDI_SUCCESS) || (count == 0)) {
15897000Sjd218194 		AACDB_PRINT(softs, CE_WARN,
15907000Sjd218194 		    "ddi_intr_get_nintrs() failed, ret %d count %d",
15917000Sjd218194 		    ret, count);
15927000Sjd218194 		return (DDI_FAILURE);
15937000Sjd218194 	}
15947000Sjd218194 
15957000Sjd218194 	/* Get number of available interrupts */
15967000Sjd218194 	ret = ddi_intr_get_navail(dip, intr_type, &avail);
15977000Sjd218194 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
15987000Sjd218194 		AACDB_PRINT(softs, CE_WARN,
15997000Sjd218194 		    "ddi_intr_get_navail() failed, ret %d avail %d",
16007000Sjd218194 		    ret, avail);
16017000Sjd218194 		return (DDI_FAILURE);
16027000Sjd218194 	}
16037000Sjd218194 
16047000Sjd218194 	AACDB_PRINT(softs, CE_NOTE,
16057000Sjd218194 	    "ddi_intr_get_nvail returned %d, navail() returned %d",
16067000Sjd218194 	    count, avail);
16077000Sjd218194 
16087000Sjd218194 	/* Allocate an array of interrupt handles */
160911348SZhongyan.Gu@Sun.COM 	softs->intr_size = count * sizeof (ddi_intr_handle_t);
161011348SZhongyan.Gu@Sun.COM 	softs->htable = kmem_alloc(softs->intr_size, KM_SLEEP);
16117000Sjd218194 
16127000Sjd218194 	if (intr_type == DDI_INTR_TYPE_MSI) {
16137000Sjd218194 		count = 1; /* only one vector needed by now */
16147000Sjd218194 		flag = DDI_INTR_ALLOC_STRICT;
16157000Sjd218194 	} else { /* must be DDI_INTR_TYPE_FIXED */
16167000Sjd218194 		flag = DDI_INTR_ALLOC_NORMAL;
16177000Sjd218194 	}
16187000Sjd218194 
16197000Sjd218194 	/* Call ddi_intr_alloc() */
16207000Sjd218194 	ret = ddi_intr_alloc(dip, softs->htable, intr_type, 0,
16217000Sjd218194 	    count, &actual, flag);
16227000Sjd218194 
16237000Sjd218194 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
16247000Sjd218194 		AACDB_PRINT(softs, CE_WARN,
16257000Sjd218194 		    "ddi_intr_alloc() failed, ret = %d", ret);
16267000Sjd218194 		actual = 0;
16277000Sjd218194 		goto error;
16287000Sjd218194 	}
16297000Sjd218194 
16307000Sjd218194 	if (actual < count) {
16317000Sjd218194 		AACDB_PRINT(softs, CE_NOTE,
16327000Sjd218194 		    "Requested: %d, Received: %d", count, actual);
16337000Sjd218194 		goto error;
16347000Sjd218194 	}
16357000Sjd218194 
16367000Sjd218194 	softs->intr_cnt = actual;
16377000Sjd218194 
16387000Sjd218194 	/* Get priority for first msi, assume remaining are all the same */
16397000Sjd218194 	if ((ret = ddi_intr_get_pri(softs->htable[0],
16407000Sjd218194 	    &softs->intr_pri)) != DDI_SUCCESS) {
16417000Sjd218194 		AACDB_PRINT(softs, CE_WARN,
16427000Sjd218194 		    "ddi_intr_get_pri() failed, ret = %d", ret);
16437000Sjd218194 		goto error;
16447000Sjd218194 	}
16457000Sjd218194 
16467000Sjd218194 	/* Test for high level mutex */
16477000Sjd218194 	if (softs->intr_pri >= ddi_intr_get_hilevel_pri()) {
16487000Sjd218194 		AACDB_PRINT(softs, CE_WARN,
16497000Sjd218194 		    "aac_query_intrs: Hi level interrupt not supported");
16507000Sjd218194 		goto error;
16517000Sjd218194 	}
16527000Sjd218194 
16537000Sjd218194 	return (DDI_SUCCESS);
16547000Sjd218194 
16557000Sjd218194 error:
16567000Sjd218194 	/* Free already allocated intr */
16577000Sjd218194 	for (i = 0; i < actual; i++)
16587000Sjd218194 		(void) ddi_intr_free(softs->htable[i]);
16597000Sjd218194 
166011348SZhongyan.Gu@Sun.COM 	kmem_free(softs->htable, softs->intr_size);
16617000Sjd218194 	return (DDI_FAILURE);
16627000Sjd218194 }
16637000Sjd218194 
166410175SStuart.Maybee@Sun.COM 
16657000Sjd218194 /*
16667000Sjd218194  * Register FIXED or MSI interrupts, and enable them
16677000Sjd218194  */
16687000Sjd218194 static int
aac_add_intrs(struct aac_softstate * softs)16697000Sjd218194 aac_add_intrs(struct aac_softstate *softs)
16707000Sjd218194 {
16717000Sjd218194 	int i, ret;
167211348SZhongyan.Gu@Sun.COM 	int actual;
16737000Sjd218194 	ddi_intr_handler_t *aac_intr;
16747000Sjd218194 
16757000Sjd218194 	actual = softs->intr_cnt;
16767000Sjd218194 	aac_intr = (ddi_intr_handler_t *)((softs->flags & AAC_FLAGS_NEW_COMM) ?
16777000Sjd218194 	    aac_intr_new : aac_intr_old);
16787000Sjd218194 
16797000Sjd218194 	/* Call ddi_intr_add_handler() */
16807000Sjd218194 	for (i = 0; i < actual; i++) {
16817000Sjd218194 		if ((ret = ddi_intr_add_handler(softs->htable[i],
16827000Sjd218194 		    aac_intr, (caddr_t)softs, NULL)) != DDI_SUCCESS) {
16837000Sjd218194 			cmn_err(CE_WARN,
16847000Sjd218194 			    "ddi_intr_add_handler() failed ret = %d", ret);
16857000Sjd218194 
16867000Sjd218194 			/* Free already allocated intr */
16877000Sjd218194 			for (i = 0; i < actual; i++)
16887000Sjd218194 				(void) ddi_intr_free(softs->htable[i]);
16897000Sjd218194 
169011348SZhongyan.Gu@Sun.COM 			kmem_free(softs->htable, softs->intr_size);
16917000Sjd218194 			return (DDI_FAILURE);
16927000Sjd218194 		}
16937000Sjd218194 	}
16947000Sjd218194 
16957000Sjd218194 	if ((ret = ddi_intr_get_cap(softs->htable[0], &softs->intr_cap))
16967000Sjd218194 	    != DDI_SUCCESS) {
16977000Sjd218194 		cmn_err(CE_WARN, "ddi_intr_get_cap() failed, ret = %d", ret);
16987000Sjd218194 
16997000Sjd218194 		/* Free already allocated intr */
17007000Sjd218194 		for (i = 0; i < actual; i++)
17017000Sjd218194 			(void) ddi_intr_free(softs->htable[i]);
17027000Sjd218194 
170311348SZhongyan.Gu@Sun.COM 		kmem_free(softs->htable, softs->intr_size);
17047000Sjd218194 		return (DDI_FAILURE);
17057000Sjd218194 	}
17067000Sjd218194 
17077000Sjd218194 	return (DDI_SUCCESS);
17087000Sjd218194 }
17097000Sjd218194 
17107000Sjd218194 /*
17117000Sjd218194  * Unregister FIXED or MSI interrupts
17127000Sjd218194  */
17137000Sjd218194 static void
aac_remove_intrs(struct aac_softstate * softs)17147000Sjd218194 aac_remove_intrs(struct aac_softstate *softs)
17157000Sjd218194 {
17167000Sjd218194 	int i;
17177000Sjd218194 
17187000Sjd218194 	/* Disable all interrupts */
171911348SZhongyan.Gu@Sun.COM 	(void) aac_disable_intrs(softs);
17207000Sjd218194 	/* Call ddi_intr_remove_handler() */
17217000Sjd218194 	for (i = 0; i < softs->intr_cnt; i++) {
17227000Sjd218194 		(void) ddi_intr_remove_handler(softs->htable[i]);
17237000Sjd218194 		(void) ddi_intr_free(softs->htable[i]);
17247000Sjd218194 	}
17257000Sjd218194 
172611348SZhongyan.Gu@Sun.COM 	kmem_free(softs->htable, softs->intr_size);
172711348SZhongyan.Gu@Sun.COM }
172811348SZhongyan.Gu@Sun.COM 
172911348SZhongyan.Gu@Sun.COM static int
aac_enable_intrs(struct aac_softstate * softs)173011348SZhongyan.Gu@Sun.COM aac_enable_intrs(struct aac_softstate *softs)
173111348SZhongyan.Gu@Sun.COM {
173211348SZhongyan.Gu@Sun.COM 	int rval = AACOK;
173311348SZhongyan.Gu@Sun.COM 
173411348SZhongyan.Gu@Sun.COM 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
173511348SZhongyan.Gu@Sun.COM 		/* for MSI block enable */
173611348SZhongyan.Gu@Sun.COM 		if (ddi_intr_block_enable(softs->htable, softs->intr_cnt) !=
173711348SZhongyan.Gu@Sun.COM 		    DDI_SUCCESS)
173811348SZhongyan.Gu@Sun.COM 			rval = AACERR;
173911348SZhongyan.Gu@Sun.COM 	} else {
174011348SZhongyan.Gu@Sun.COM 		int i;
174111348SZhongyan.Gu@Sun.COM 
174211348SZhongyan.Gu@Sun.COM 		/* Call ddi_intr_enable() for legacy/MSI non block enable */
174311348SZhongyan.Gu@Sun.COM 		for (i = 0; i < softs->intr_cnt; i++) {
174411348SZhongyan.Gu@Sun.COM 			if (ddi_intr_enable(softs->htable[i]) != DDI_SUCCESS)
174511348SZhongyan.Gu@Sun.COM 				rval = AACERR;
174611348SZhongyan.Gu@Sun.COM 		}
174711348SZhongyan.Gu@Sun.COM 	}
174811348SZhongyan.Gu@Sun.COM 	return (rval);
174911348SZhongyan.Gu@Sun.COM }
175011348SZhongyan.Gu@Sun.COM 
175111348SZhongyan.Gu@Sun.COM static int
aac_disable_intrs(struct aac_softstate * softs)175211348SZhongyan.Gu@Sun.COM aac_disable_intrs(struct aac_softstate *softs)
175311348SZhongyan.Gu@Sun.COM {
175411348SZhongyan.Gu@Sun.COM 	int rval = AACOK;
175511348SZhongyan.Gu@Sun.COM 
175611348SZhongyan.Gu@Sun.COM 	if (softs->intr_cap & DDI_INTR_FLAG_BLOCK) {
175711348SZhongyan.Gu@Sun.COM 		/* Call ddi_intr_block_disable() */
175811348SZhongyan.Gu@Sun.COM 		if (ddi_intr_block_disable(softs->htable, softs->intr_cnt) !=
175911348SZhongyan.Gu@Sun.COM 		    DDI_SUCCESS)
176011348SZhongyan.Gu@Sun.COM 			rval = AACERR;
176111348SZhongyan.Gu@Sun.COM 	} else {
176211348SZhongyan.Gu@Sun.COM 		int i;
176311348SZhongyan.Gu@Sun.COM 
176411348SZhongyan.Gu@Sun.COM 		for (i = 0; i < softs->intr_cnt; i++) {
176511348SZhongyan.Gu@Sun.COM 			if (ddi_intr_disable(softs->htable[i]) != DDI_SUCCESS)
176611348SZhongyan.Gu@Sun.COM 				rval = AACERR;
176711348SZhongyan.Gu@Sun.COM 		}
176811348SZhongyan.Gu@Sun.COM 	}
176911348SZhongyan.Gu@Sun.COM 	return (rval);
17707000Sjd218194 }
17717000Sjd218194 
17727000Sjd218194 /*
17735678Spl196000  * Set pkt_reason and OR in pkt_statistics flag
17745678Spl196000  */
17755678Spl196000 static void
aac_set_pkt_reason(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason,uint_t stat)17765678Spl196000 aac_set_pkt_reason(struct aac_softstate *softs, struct aac_cmd *acp,
17775678Spl196000     uchar_t reason, uint_t stat)
17785678Spl196000 {
17795678Spl196000 #ifndef __lock_lint
17805678Spl196000 	_NOTE(ARGUNUSED(softs))
17815678Spl196000 #endif
17825678Spl196000 	if (acp->pkt->pkt_reason == CMD_CMPLT)
17835678Spl196000 		acp->pkt->pkt_reason = reason;
17845678Spl196000 	acp->pkt->pkt_statistics |= stat;
17855678Spl196000 }
17865678Spl196000 
17875678Spl196000 /*
17885678Spl196000  * Handle a finished pkt of soft SCMD
17895678Spl196000  */
17905678Spl196000 static void
aac_soft_callback(struct aac_softstate * softs,struct aac_cmd * acp)17915678Spl196000 aac_soft_callback(struct aac_softstate *softs, struct aac_cmd *acp)
17925678Spl196000 {
17935678Spl196000 	ASSERT(acp->pkt);
17945678Spl196000 
17955678Spl196000 	acp->flags |= AAC_CMD_CMPLT;
17965678Spl196000 
17975678Spl196000 	acp->pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | \
17987567SXin.Chen@Sun.COM 	    STATE_SENT_CMD | STATE_GOT_STATUS;
17995678Spl196000 	if (acp->pkt->pkt_state & STATE_XFERRED_DATA)
18005678Spl196000 		acp->pkt->pkt_resid = 0;
18015678Spl196000 
18025678Spl196000 	/* AAC_CMD_NO_INTR means no complete callback */
18035678Spl196000 	if (!(acp->flags & AAC_CMD_NO_INTR)) {
18045678Spl196000 		mutex_enter(&softs->q_comp_mutex);
18055678Spl196000 		aac_cmd_enqueue(&softs->q_comp, acp);
18065678Spl196000 		mutex_exit(&softs->q_comp_mutex);
18075678Spl196000 		ddi_trigger_softintr(softs->softint_id);
18085678Spl196000 	}
18095678Spl196000 }
18105678Spl196000 
18115678Spl196000 /*
18125678Spl196000  * Handlers for completed IOs, common to aac_intr_new() and aac_intr_old()
18135678Spl196000  */
18145678Spl196000 
18155678Spl196000 /*
18165678Spl196000  * Handle completed logical device IO command
18175678Spl196000  */
18185678Spl196000 /*ARGSUSED*/
18195678Spl196000 static void
aac_ld_complete(struct aac_softstate * softs,struct aac_cmd * acp)18205678Spl196000 aac_ld_complete(struct aac_softstate *softs, struct aac_cmd *acp)
18215678Spl196000 {
18225678Spl196000 	struct aac_slot *slotp = acp->slotp;
18235678Spl196000 	struct aac_blockread_response *resp;
18245678Spl196000 	uint32_t status;
18255678Spl196000 
18265678Spl196000 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
18275678Spl196000 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
18285678Spl196000 
18297567SXin.Chen@Sun.COM 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
18307567SXin.Chen@Sun.COM 
18315678Spl196000 	/*
18325678Spl196000 	 * block_read/write has a similar response header, use blockread
18335678Spl196000 	 * response for both.
18345678Spl196000 	 */
18355678Spl196000 	resp = (struct aac_blockread_response *)&slotp->fibp->data[0];
18365678Spl196000 	status = ddi_get32(slotp->fib_acc_handle, &resp->Status);
18375678Spl196000 	if (status == ST_OK) {
18385678Spl196000 		acp->pkt->pkt_resid = 0;
18395678Spl196000 		acp->pkt->pkt_state |= STATE_XFERRED_DATA;
18405678Spl196000 	} else {
18415678Spl196000 		aac_set_arq_data_hwerr(acp);
18425678Spl196000 	}
18435678Spl196000 }
18445678Spl196000 
18455678Spl196000 /*
18467567SXin.Chen@Sun.COM  * Handle completed phys. device IO command
18477567SXin.Chen@Sun.COM  */
18487567SXin.Chen@Sun.COM static void
aac_pd_complete(struct aac_softstate * softs,struct aac_cmd * acp)18497567SXin.Chen@Sun.COM aac_pd_complete(struct aac_softstate *softs, struct aac_cmd *acp)
18507567SXin.Chen@Sun.COM {
18517567SXin.Chen@Sun.COM 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
18527567SXin.Chen@Sun.COM 	struct aac_fib *fibp = acp->slotp->fibp;
18537567SXin.Chen@Sun.COM 	struct scsi_pkt *pkt = acp->pkt;
18547567SXin.Chen@Sun.COM 	struct aac_srb_reply *resp;
18557567SXin.Chen@Sun.COM 	uint32_t resp_status;
18567567SXin.Chen@Sun.COM 
18577567SXin.Chen@Sun.COM 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
18587567SXin.Chen@Sun.COM 	ASSERT(!(acp->flags & AAC_CMD_NO_CB));
18597567SXin.Chen@Sun.COM 
18607567SXin.Chen@Sun.COM 	resp = (struct aac_srb_reply *)&fibp->data[0];
18617567SXin.Chen@Sun.COM 	resp_status = ddi_get32(acc, &resp->status);
18627567SXin.Chen@Sun.COM 
18637567SXin.Chen@Sun.COM 	/* First check FIB status */
18647567SXin.Chen@Sun.COM 	if (resp_status == ST_OK) {
18657567SXin.Chen@Sun.COM 		uint32_t scsi_status;
18667567SXin.Chen@Sun.COM 		uint32_t srb_status;
18677567SXin.Chen@Sun.COM 		uint32_t data_xfer_length;
18687567SXin.Chen@Sun.COM 
18697567SXin.Chen@Sun.COM 		scsi_status = ddi_get32(acc, &resp->scsi_status);
18707567SXin.Chen@Sun.COM 		srb_status = ddi_get32(acc, &resp->srb_status);
18717567SXin.Chen@Sun.COM 		data_xfer_length = ddi_get32(acc, &resp->data_xfer_length);
18727567SXin.Chen@Sun.COM 
18737567SXin.Chen@Sun.COM 		*pkt->pkt_scbp = (uint8_t)scsi_status;
18747567SXin.Chen@Sun.COM 		pkt->pkt_state |= STATE_GOT_STATUS;
18757567SXin.Chen@Sun.COM 		if (scsi_status == STATUS_GOOD) {
18767567SXin.Chen@Sun.COM 			uchar_t cmd = ((union scsi_cdb *)(void *)
18777567SXin.Chen@Sun.COM 			    (pkt->pkt_cdbp))->scc_cmd;
18787567SXin.Chen@Sun.COM 
18797567SXin.Chen@Sun.COM 			/* Next check SRB status */
18807567SXin.Chen@Sun.COM 			switch (srb_status & 0x3f) {
18817567SXin.Chen@Sun.COM 			case SRB_STATUS_DATA_OVERRUN:
18827567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE, "DATA_OVERRUN: " \
18837567SXin.Chen@Sun.COM 				    "scmd=%d, xfer=%d, buflen=%d",
18847567SXin.Chen@Sun.COM 				    (uint32_t)cmd, data_xfer_length,
18857567SXin.Chen@Sun.COM 				    acp->bcount);
18867567SXin.Chen@Sun.COM 
18877567SXin.Chen@Sun.COM 				switch (cmd) {
18887567SXin.Chen@Sun.COM 				case SCMD_READ:
18897567SXin.Chen@Sun.COM 				case SCMD_WRITE:
18907567SXin.Chen@Sun.COM 				case SCMD_READ_G1:
18917567SXin.Chen@Sun.COM 				case SCMD_WRITE_G1:
18927567SXin.Chen@Sun.COM 				case SCMD_READ_G4:
18937567SXin.Chen@Sun.COM 				case SCMD_WRITE_G4:
18947567SXin.Chen@Sun.COM 				case SCMD_READ_G5:
18957567SXin.Chen@Sun.COM 				case SCMD_WRITE_G5:
18967567SXin.Chen@Sun.COM 					aac_set_pkt_reason(softs, acp,
18977567SXin.Chen@Sun.COM 					    CMD_DATA_OVR, 0);
18987567SXin.Chen@Sun.COM 					break;
18997567SXin.Chen@Sun.COM 				}
19007567SXin.Chen@Sun.COM 				/*FALLTHRU*/
19017567SXin.Chen@Sun.COM 			case SRB_STATUS_ERROR_RECOVERY:
19027567SXin.Chen@Sun.COM 			case SRB_STATUS_PENDING:
19037567SXin.Chen@Sun.COM 			case SRB_STATUS_SUCCESS:
19047567SXin.Chen@Sun.COM 				/*
19057567SXin.Chen@Sun.COM 				 * pkt_resid should only be calculated if the
19067567SXin.Chen@Sun.COM 				 * status is ERROR_RECOVERY/PENDING/SUCCESS/
19077567SXin.Chen@Sun.COM 				 * OVERRUN/UNDERRUN
19087567SXin.Chen@Sun.COM 				 */
19097567SXin.Chen@Sun.COM 				if (data_xfer_length) {
19107567SXin.Chen@Sun.COM 					pkt->pkt_state |= STATE_XFERRED_DATA;
19117567SXin.Chen@Sun.COM 					pkt->pkt_resid = acp->bcount - \
19127567SXin.Chen@Sun.COM 					    data_xfer_length;
19137567SXin.Chen@Sun.COM 					ASSERT(pkt->pkt_resid >= 0);
19147567SXin.Chen@Sun.COM 				}
19157567SXin.Chen@Sun.COM 				break;
19167567SXin.Chen@Sun.COM 			case SRB_STATUS_ABORTED:
19177567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
19187567SXin.Chen@Sun.COM 				    "SRB_STATUS_ABORTED, xfer=%d, resid=%d",
19197567SXin.Chen@Sun.COM 				    data_xfer_length, pkt->pkt_resid);
19207567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_ABORTED,
19217567SXin.Chen@Sun.COM 				    STAT_ABORTED);
19227567SXin.Chen@Sun.COM 				break;
19237567SXin.Chen@Sun.COM 			case SRB_STATUS_ABORT_FAILED:
19247567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
19257567SXin.Chen@Sun.COM 				    "SRB_STATUS_ABORT_FAILED, xfer=%d, " \
19267567SXin.Chen@Sun.COM 				    "resid=%d", data_xfer_length,
19277567SXin.Chen@Sun.COM 				    pkt->pkt_resid);
19287567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_ABORT_FAIL,
19297567SXin.Chen@Sun.COM 				    0);
19307567SXin.Chen@Sun.COM 				break;
19317567SXin.Chen@Sun.COM 			case SRB_STATUS_PARITY_ERROR:
19327567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
19337567SXin.Chen@Sun.COM 				    "SRB_STATUS_PARITY_ERROR, xfer=%d, " \
19347567SXin.Chen@Sun.COM 				    "resid=%d", data_xfer_length,
19357567SXin.Chen@Sun.COM 				    pkt->pkt_resid);
19367567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_PER_FAIL, 0);
19377567SXin.Chen@Sun.COM 				break;
19387567SXin.Chen@Sun.COM 			case SRB_STATUS_NO_DEVICE:
19397567SXin.Chen@Sun.COM 			case SRB_STATUS_INVALID_PATH_ID:
19407567SXin.Chen@Sun.COM 			case SRB_STATUS_INVALID_TARGET_ID:
19417567SXin.Chen@Sun.COM 			case SRB_STATUS_INVALID_LUN:
19427567SXin.Chen@Sun.COM 			case SRB_STATUS_SELECTION_TIMEOUT:
19437567SXin.Chen@Sun.COM #ifdef DEBUG
19447567SXin.Chen@Sun.COM 				if (AAC_DEV_IS_VALID(acp->dvp)) {
19457567SXin.Chen@Sun.COM 					AACDB_PRINT(softs, CE_NOTE,
19467567SXin.Chen@Sun.COM 					    "SRB_STATUS_NO_DEVICE(%d), " \
19477567SXin.Chen@Sun.COM 					    "xfer=%d, resid=%d ",
19487567SXin.Chen@Sun.COM 					    srb_status & 0x3f,
19497567SXin.Chen@Sun.COM 					    data_xfer_length, pkt->pkt_resid);
19507567SXin.Chen@Sun.COM 				}
19517567SXin.Chen@Sun.COM #endif
19527567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_DEV_GONE, 0);
19537567SXin.Chen@Sun.COM 				break;
19547567SXin.Chen@Sun.COM 			case SRB_STATUS_COMMAND_TIMEOUT:
19557567SXin.Chen@Sun.COM 			case SRB_STATUS_TIMEOUT:
19567567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
19577567SXin.Chen@Sun.COM 				    "SRB_STATUS_COMMAND_TIMEOUT, xfer=%d, " \
19587567SXin.Chen@Sun.COM 				    "resid=%d", data_xfer_length,
19597567SXin.Chen@Sun.COM 				    pkt->pkt_resid);
19607567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
19617567SXin.Chen@Sun.COM 				    STAT_TIMEOUT);
19627567SXin.Chen@Sun.COM 				break;
19637567SXin.Chen@Sun.COM 			case SRB_STATUS_BUS_RESET:
19647567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
19657567SXin.Chen@Sun.COM 				    "SRB_STATUS_BUS_RESET, xfer=%d, " \
19667567SXin.Chen@Sun.COM 				    "resid=%d", data_xfer_length,
19677567SXin.Chen@Sun.COM 				    pkt->pkt_resid);
19687567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_RESET,
19697567SXin.Chen@Sun.COM 				    STAT_BUS_RESET);
19707567SXin.Chen@Sun.COM 				break;
19717567SXin.Chen@Sun.COM 			default:
19727567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE, "srb_status=%d, " \
19737567SXin.Chen@Sun.COM 				    "xfer=%d, resid=%d", srb_status & 0x3f,
19747567SXin.Chen@Sun.COM 				    data_xfer_length, pkt->pkt_resid);
19757567SXin.Chen@Sun.COM 				aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
19767567SXin.Chen@Sun.COM 				break;
19777567SXin.Chen@Sun.COM 			}
19787567SXin.Chen@Sun.COM 		} else if (scsi_status == STATUS_CHECK) {
19797567SXin.Chen@Sun.COM 			/* CHECK CONDITION */
19807567SXin.Chen@Sun.COM 			struct scsi_arq_status *arqstat =
19817567SXin.Chen@Sun.COM 			    (void *)(pkt->pkt_scbp);
19827567SXin.Chen@Sun.COM 			uint32_t sense_data_size;
19837567SXin.Chen@Sun.COM 
19847567SXin.Chen@Sun.COM 			pkt->pkt_state |= STATE_ARQ_DONE;
19857567SXin.Chen@Sun.COM 
19867567SXin.Chen@Sun.COM 			*(uint8_t *)&arqstat->sts_rqpkt_status = STATUS_GOOD;
19877567SXin.Chen@Sun.COM 			arqstat->sts_rqpkt_reason = CMD_CMPLT;
19887567SXin.Chen@Sun.COM 			arqstat->sts_rqpkt_resid = 0;
19897567SXin.Chen@Sun.COM 			arqstat->sts_rqpkt_state =
19907567SXin.Chen@Sun.COM 			    STATE_GOT_BUS |
19917567SXin.Chen@Sun.COM 			    STATE_GOT_TARGET |
19927567SXin.Chen@Sun.COM 			    STATE_SENT_CMD |
19937567SXin.Chen@Sun.COM 			    STATE_XFERRED_DATA;
19947567SXin.Chen@Sun.COM 			arqstat->sts_rqpkt_statistics = 0;
19957567SXin.Chen@Sun.COM 
19967567SXin.Chen@Sun.COM 			sense_data_size = ddi_get32(acc,
19977567SXin.Chen@Sun.COM 			    &resp->sense_data_size);
19987567SXin.Chen@Sun.COM 			ASSERT(sense_data_size <= AAC_SENSE_BUFFERSIZE);
19997567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE,
20007567SXin.Chen@Sun.COM 			    "CHECK CONDITION: sense len=%d, xfer len=%d",
20017567SXin.Chen@Sun.COM 			    sense_data_size, data_xfer_length);
20027567SXin.Chen@Sun.COM 
20037567SXin.Chen@Sun.COM 			if (sense_data_size > SENSE_LENGTH)
20047567SXin.Chen@Sun.COM 				sense_data_size = SENSE_LENGTH;
20057567SXin.Chen@Sun.COM 			ddi_rep_get8(acc, (uint8_t *)&arqstat->sts_sensedata,
20067567SXin.Chen@Sun.COM 			    (uint8_t *)resp->sense_data, sense_data_size,
20077567SXin.Chen@Sun.COM 			    DDI_DEV_AUTOINCR);
20087567SXin.Chen@Sun.COM 		} else {
20097567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN, "invaild scsi status: " \
20107567SXin.Chen@Sun.COM 			    "scsi_status=%d, srb_status=%d",
20117567SXin.Chen@Sun.COM 			    scsi_status, srb_status);
20127567SXin.Chen@Sun.COM 			aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
20137567SXin.Chen@Sun.COM 		}
20147567SXin.Chen@Sun.COM 	} else {
20157567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_NOTE, "SRB failed: fib status %d",
20167567SXin.Chen@Sun.COM 		    resp_status);
20177567SXin.Chen@Sun.COM 		aac_set_pkt_reason(softs, acp, CMD_TRAN_ERR, 0);
20187567SXin.Chen@Sun.COM 	}
20197567SXin.Chen@Sun.COM }
20207567SXin.Chen@Sun.COM 
20217567SXin.Chen@Sun.COM /*
20225678Spl196000  * Handle completed IOCTL command
20235678Spl196000  */
20245678Spl196000 /*ARGSUSED*/
20255678Spl196000 void
aac_ioctl_complete(struct aac_softstate * softs,struct aac_cmd * acp)20265678Spl196000 aac_ioctl_complete(struct aac_softstate *softs, struct aac_cmd *acp)
20275678Spl196000 {
20285678Spl196000 	struct aac_slot *slotp = acp->slotp;
20295678Spl196000 
20305678Spl196000 	/*
20315678Spl196000 	 * NOTE: Both aac_ioctl_send_fib() and aac_send_raw_srb()
20325678Spl196000 	 * may wait on softs->event, so use cv_broadcast() instead
20335678Spl196000 	 * of cv_signal().
20345678Spl196000 	 */
20355678Spl196000 	ASSERT(acp->flags & AAC_CMD_SYNC);
20365678Spl196000 	ASSERT(acp->flags & AAC_CMD_NO_CB);
20375678Spl196000 
20385678Spl196000 	/* Get the size of the response FIB from its FIB.Header.Size field */
20395678Spl196000 	acp->fib_size = ddi_get16(slotp->fib_acc_handle,
20405678Spl196000 	    &slotp->fibp->Header.Size);
20415678Spl196000 
20425678Spl196000 	ASSERT(acp->fib_size <= softs->aac_max_fib_size);
20435678Spl196000 	ddi_rep_get8(slotp->fib_acc_handle, (uint8_t *)acp->fibp,
20445678Spl196000 	    (uint8_t *)slotp->fibp, acp->fib_size, DDI_DEV_AUTOINCR);
20455678Spl196000 }
20465678Spl196000 
20475678Spl196000 /*
204811348SZhongyan.Gu@Sun.COM  * Handle completed sync fib command
204911348SZhongyan.Gu@Sun.COM  */
205011348SZhongyan.Gu@Sun.COM /*ARGSUSED*/
205111348SZhongyan.Gu@Sun.COM void
aac_sync_complete(struct aac_softstate * softs,struct aac_cmd * acp)205211348SZhongyan.Gu@Sun.COM aac_sync_complete(struct aac_softstate *softs, struct aac_cmd *acp)
205311348SZhongyan.Gu@Sun.COM {
205411348SZhongyan.Gu@Sun.COM }
205511348SZhongyan.Gu@Sun.COM 
205611348SZhongyan.Gu@Sun.COM /*
20575678Spl196000  * Handle completed Flush command
20585678Spl196000  */
20595678Spl196000 /*ARGSUSED*/
20605678Spl196000 static void
aac_synccache_complete(struct aac_softstate * softs,struct aac_cmd * acp)20615678Spl196000 aac_synccache_complete(struct aac_softstate *softs, struct aac_cmd *acp)
20625678Spl196000 {
20635678Spl196000 	struct aac_slot *slotp = acp->slotp;
20645678Spl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
20655678Spl196000 	struct aac_synchronize_reply *resp;
20665678Spl196000 	uint32_t status;
20675678Spl196000 
20685678Spl196000 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
20695678Spl196000 
20707567SXin.Chen@Sun.COM 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
20717567SXin.Chen@Sun.COM 
20725678Spl196000 	resp = (struct aac_synchronize_reply *)&slotp->fibp->data[0];
20735678Spl196000 	status = ddi_get32(acc, &resp->Status);
20745678Spl196000 	if (status != CT_OK)
20755678Spl196000 		aac_set_arq_data_hwerr(acp);
20765678Spl196000 }
20775678Spl196000 
207811636SXin.Chen@Sun.COM /*ARGSUSED*/
207910976SZhongyan.Gu@Sun.COM static void
aac_startstop_complete(struct aac_softstate * softs,struct aac_cmd * acp)208010976SZhongyan.Gu@Sun.COM aac_startstop_complete(struct aac_softstate *softs, struct aac_cmd *acp)
208110976SZhongyan.Gu@Sun.COM {
208210976SZhongyan.Gu@Sun.COM 	struct aac_slot *slotp = acp->slotp;
208310976SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
208410976SZhongyan.Gu@Sun.COM 	struct aac_Container_resp *resp;
208510976SZhongyan.Gu@Sun.COM 	uint32_t status;
208610976SZhongyan.Gu@Sun.COM 
208710976SZhongyan.Gu@Sun.COM 	ASSERT(!(acp->flags & AAC_CMD_SYNC));
208810976SZhongyan.Gu@Sun.COM 
208910976SZhongyan.Gu@Sun.COM 	acp->pkt->pkt_state |= STATE_GOT_STATUS;
209010976SZhongyan.Gu@Sun.COM 
209110976SZhongyan.Gu@Sun.COM 	resp = (struct aac_Container_resp *)&slotp->fibp->data[0];
209210976SZhongyan.Gu@Sun.COM 	status = ddi_get32(acc, &resp->Status);
209310976SZhongyan.Gu@Sun.COM 	if (status != 0) {
209410976SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_WARN, "Cannot start/stop a unit");
209510976SZhongyan.Gu@Sun.COM 		aac_set_arq_data_hwerr(acp);
209610976SZhongyan.Gu@Sun.COM 	}
209710976SZhongyan.Gu@Sun.COM }
209810976SZhongyan.Gu@Sun.COM 
20995678Spl196000 /*
21005678Spl196000  * Access PCI space to see if the driver can support the card
21015678Spl196000  */
21025678Spl196000 static int
aac_check_card_type(struct aac_softstate * softs)21035678Spl196000 aac_check_card_type(struct aac_softstate *softs)
21045678Spl196000 {
21055678Spl196000 	ddi_acc_handle_t pci_config_handle;
21065678Spl196000 	int card_index;
21075678Spl196000 	uint32_t pci_cmd;
21085678Spl196000 
21095678Spl196000 	/* Map pci configuration space */
21105678Spl196000 	if ((pci_config_setup(softs->devinfo_p, &pci_config_handle)) !=
21115678Spl196000 	    DDI_SUCCESS) {
21125678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot setup pci config space");
21135678Spl196000 		return (AACERR);
21145678Spl196000 	}
21155678Spl196000 
21165678Spl196000 	softs->vendid = pci_config_get16(pci_config_handle, PCI_CONF_VENID);
21175678Spl196000 	softs->devid = pci_config_get16(pci_config_handle, PCI_CONF_DEVID);
21185678Spl196000 	softs->subvendid = pci_config_get16(pci_config_handle,
21195678Spl196000 	    PCI_CONF_SUBVENID);
21205678Spl196000 	softs->subsysid = pci_config_get16(pci_config_handle,
21215678Spl196000 	    PCI_CONF_SUBSYSID);
21225678Spl196000 
21235678Spl196000 	card_index = 0;
21245678Spl196000 	while (!CARD_IS_UNKNOWN(card_index)) {
21255678Spl196000 		if ((aac_cards[card_index].vendor == softs->vendid) &&
21265678Spl196000 		    (aac_cards[card_index].device == softs->devid) &&
21275678Spl196000 		    (aac_cards[card_index].subvendor == softs->subvendid) &&
21285678Spl196000 		    (aac_cards[card_index].subsys == softs->subsysid)) {
21295678Spl196000 			break;
21305678Spl196000 		}
21315678Spl196000 		card_index++;
21325678Spl196000 	}
21335678Spl196000 
21345678Spl196000 	softs->card = card_index;
21355678Spl196000 	softs->hwif = aac_cards[card_index].hwif;
21365678Spl196000 
21375678Spl196000 	/*
21385678Spl196000 	 * Unknown aac card
21395678Spl196000 	 * do a generic match based on the VendorID and DeviceID to
21405678Spl196000 	 * support the new cards in the aac family
21415678Spl196000 	 */
21425678Spl196000 	if (CARD_IS_UNKNOWN(card_index)) {
21435678Spl196000 		if (softs->vendid != 0x9005) {
21445678Spl196000 			AACDB_PRINT(softs, CE_WARN,
21455678Spl196000 			    "Unknown vendor 0x%x", softs->vendid);
21465678Spl196000 			goto error;
21475678Spl196000 		}
21485678Spl196000 		switch (softs->devid) {
21495678Spl196000 		case 0x285:
21505678Spl196000 			softs->hwif = AAC_HWIF_I960RX;
21515678Spl196000 			break;
21525678Spl196000 		case 0x286:
21535678Spl196000 			softs->hwif = AAC_HWIF_RKT;
21545678Spl196000 			break;
21555678Spl196000 		default:
21565678Spl196000 			AACDB_PRINT(softs, CE_WARN,
21575678Spl196000 			    "Unknown device \"pci9005,%x\"", softs->devid);
21585678Spl196000 			goto error;
21595678Spl196000 		}
21605678Spl196000 	}
21615678Spl196000 
21625678Spl196000 	/* Set hardware dependent interface */
21635678Spl196000 	switch (softs->hwif) {
21645678Spl196000 	case AAC_HWIF_I960RX:
21655678Spl196000 		softs->aac_if = aac_rx_interface;
21665678Spl196000 		softs->map_size_min = AAC_MAP_SIZE_MIN_RX;
21675678Spl196000 		break;
21685678Spl196000 	case AAC_HWIF_RKT:
21695678Spl196000 		softs->aac_if = aac_rkt_interface;
21705678Spl196000 		softs->map_size_min = AAC_MAP_SIZE_MIN_RKT;
21715678Spl196000 		break;
21725678Spl196000 	default:
21735678Spl196000 		AACDB_PRINT(softs, CE_WARN,
21745678Spl196000 		    "Unknown hardware interface %d", softs->hwif);
21755678Spl196000 		goto error;
21765678Spl196000 	}
21775678Spl196000 
21785678Spl196000 	/* Set card names */
21795678Spl196000 	(void *)strncpy(softs->vendor_name, aac_cards[card_index].vid,
21805678Spl196000 	    AAC_VENDOR_LEN);
21815678Spl196000 	(void *)strncpy(softs->product_name, aac_cards[card_index].desc,
21825678Spl196000 	    AAC_PRODUCT_LEN);
21835678Spl196000 
21845678Spl196000 	/* Set up quirks */
21855678Spl196000 	softs->flags = aac_cards[card_index].quirks;
21865678Spl196000 
21875678Spl196000 	/* Force the busmaster enable bit on */
21885678Spl196000 	pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
21895678Spl196000 	if ((pci_cmd & PCI_COMM_ME) == 0) {
21905678Spl196000 		pci_cmd |= PCI_COMM_ME;
21915678Spl196000 		pci_config_put16(pci_config_handle, PCI_CONF_COMM, pci_cmd);
21925678Spl196000 		pci_cmd = pci_config_get16(pci_config_handle, PCI_CONF_COMM);
21935678Spl196000 		if ((pci_cmd & PCI_COMM_ME) == 0) {
21945678Spl196000 			cmn_err(CE_CONT, "?Cannot enable busmaster bit");
21955678Spl196000 			goto error;
21965678Spl196000 		}
21975678Spl196000 	}
21985678Spl196000 
21995678Spl196000 	/* Set memory base to map */
22005678Spl196000 	softs->pci_mem_base_paddr = 0xfffffff0UL & \
22015678Spl196000 	    pci_config_get32(pci_config_handle, PCI_CONF_BASE0);
22025678Spl196000 
22035678Spl196000 	pci_config_teardown(&pci_config_handle);
22045678Spl196000 
22055678Spl196000 	return (AACOK); /* card type detected */
22065678Spl196000 error:
22075678Spl196000 	pci_config_teardown(&pci_config_handle);
22085678Spl196000 	return (AACERR); /* no matched card found */
22095678Spl196000 }
22105678Spl196000 
22115678Spl196000 /*
221211348SZhongyan.Gu@Sun.COM  * Do the usual interrupt handler setup stuff.
221311348SZhongyan.Gu@Sun.COM  */
221411348SZhongyan.Gu@Sun.COM static int
aac_register_intrs(struct aac_softstate * softs)221511348SZhongyan.Gu@Sun.COM aac_register_intrs(struct aac_softstate *softs)
221611348SZhongyan.Gu@Sun.COM {
221711348SZhongyan.Gu@Sun.COM 	dev_info_t *dip;
221811348SZhongyan.Gu@Sun.COM 	int intr_types;
221911348SZhongyan.Gu@Sun.COM 
222011348SZhongyan.Gu@Sun.COM 	ASSERT(softs->devinfo_p);
222111348SZhongyan.Gu@Sun.COM 	dip = softs->devinfo_p;
222211348SZhongyan.Gu@Sun.COM 
222311348SZhongyan.Gu@Sun.COM 	/* Get the type of device intrrupts */
222411348SZhongyan.Gu@Sun.COM 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
222511348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
222611348SZhongyan.Gu@Sun.COM 		    "ddi_intr_get_supported_types() failed");
222711348SZhongyan.Gu@Sun.COM 		return (AACERR);
222811348SZhongyan.Gu@Sun.COM 	}
222911348SZhongyan.Gu@Sun.COM 	AACDB_PRINT(softs, CE_NOTE,
223011348SZhongyan.Gu@Sun.COM 	    "ddi_intr_get_supported_types() ret: 0x%x", intr_types);
223111348SZhongyan.Gu@Sun.COM 
223211348SZhongyan.Gu@Sun.COM 	/* Query interrupt, and alloc/init all needed struct */
223311348SZhongyan.Gu@Sun.COM 	if (intr_types & DDI_INTR_TYPE_MSI) {
223411348SZhongyan.Gu@Sun.COM 		if (aac_query_intrs(softs, DDI_INTR_TYPE_MSI)
223511348SZhongyan.Gu@Sun.COM 		    != DDI_SUCCESS) {
223611348SZhongyan.Gu@Sun.COM 			AACDB_PRINT(softs, CE_WARN,
223711348SZhongyan.Gu@Sun.COM 			    "MSI interrupt query failed");
223811348SZhongyan.Gu@Sun.COM 			return (AACERR);
223911348SZhongyan.Gu@Sun.COM 		}
224011348SZhongyan.Gu@Sun.COM 		softs->intr_type = DDI_INTR_TYPE_MSI;
224111348SZhongyan.Gu@Sun.COM 	} else if (intr_types & DDI_INTR_TYPE_FIXED) {
224211348SZhongyan.Gu@Sun.COM 		if (aac_query_intrs(softs, DDI_INTR_TYPE_FIXED)
224311348SZhongyan.Gu@Sun.COM 		    != DDI_SUCCESS) {
224411348SZhongyan.Gu@Sun.COM 			AACDB_PRINT(softs, CE_WARN,
224511348SZhongyan.Gu@Sun.COM 			    "FIXED interrupt query failed");
224611348SZhongyan.Gu@Sun.COM 			return (AACERR);
224711348SZhongyan.Gu@Sun.COM 		}
224811348SZhongyan.Gu@Sun.COM 		softs->intr_type = DDI_INTR_TYPE_FIXED;
224911348SZhongyan.Gu@Sun.COM 	} else {
225011348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
225111348SZhongyan.Gu@Sun.COM 		    "Device cannot suppport both FIXED and MSI interrupts");
225211348SZhongyan.Gu@Sun.COM 		return (AACERR);
225311348SZhongyan.Gu@Sun.COM 	}
225411348SZhongyan.Gu@Sun.COM 
225511348SZhongyan.Gu@Sun.COM 	/* Connect interrupt handlers */
225611348SZhongyan.Gu@Sun.COM 	if (aac_add_intrs(softs) != DDI_SUCCESS) {
225711348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
225811348SZhongyan.Gu@Sun.COM 		    "Interrupt registration failed, intr type: %s",
225911348SZhongyan.Gu@Sun.COM 		    softs->intr_type == DDI_INTR_TYPE_MSI ? "MSI" : "FIXED");
226011348SZhongyan.Gu@Sun.COM 		return (AACERR);
226111348SZhongyan.Gu@Sun.COM 	}
226211348SZhongyan.Gu@Sun.COM 	(void) aac_enable_intrs(softs);
226311348SZhongyan.Gu@Sun.COM 
226411348SZhongyan.Gu@Sun.COM 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softs->softint_id,
226511348SZhongyan.Gu@Sun.COM 	    NULL, NULL, aac_softintr, (caddr_t)softs) != DDI_SUCCESS) {
226611348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
226711348SZhongyan.Gu@Sun.COM 		    "Can not setup soft interrupt handler!");
226811348SZhongyan.Gu@Sun.COM 		aac_remove_intrs(softs);
226911348SZhongyan.Gu@Sun.COM 		return (AACERR);
227011348SZhongyan.Gu@Sun.COM 	}
227111348SZhongyan.Gu@Sun.COM 
227211348SZhongyan.Gu@Sun.COM 	return (AACOK);
227311348SZhongyan.Gu@Sun.COM }
227411348SZhongyan.Gu@Sun.COM 
227511348SZhongyan.Gu@Sun.COM static void
aac_unregister_intrs(struct aac_softstate * softs)227611348SZhongyan.Gu@Sun.COM aac_unregister_intrs(struct aac_softstate *softs)
227711348SZhongyan.Gu@Sun.COM {
227811348SZhongyan.Gu@Sun.COM 	aac_remove_intrs(softs);
227911348SZhongyan.Gu@Sun.COM 	ddi_remove_softintr(softs->softint_id);
228011348SZhongyan.Gu@Sun.COM }
228111348SZhongyan.Gu@Sun.COM 
228211348SZhongyan.Gu@Sun.COM /*
22835678Spl196000  * Check the firmware to determine the features to support and the FIB
22845678Spl196000  * parameters to use.
22855678Spl196000  */
22865678Spl196000 static int
aac_check_firmware(struct aac_softstate * softs)22875678Spl196000 aac_check_firmware(struct aac_softstate *softs)
22885678Spl196000 {
22895678Spl196000 	uint32_t options;
22905678Spl196000 	uint32_t atu_size;
22915678Spl196000 	ddi_acc_handle_t pci_handle;
22927567SXin.Chen@Sun.COM 	uint8_t *data;
22935678Spl196000 	uint32_t max_fibs;
22945678Spl196000 	uint32_t max_fib_size;
22955678Spl196000 	uint32_t sg_tablesize;
22965678Spl196000 	uint32_t max_sectors;
22975678Spl196000 	uint32_t status;
22985678Spl196000 
22995678Spl196000 	/* Get supported options */
23005678Spl196000 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETINFO, 0, 0, 0, 0,
23015678Spl196000 	    &status)) != AACOK) {
23025678Spl196000 		if (status != SRB_STATUS_INVALID_REQUEST) {
23035678Spl196000 			cmn_err(CE_CONT,
23045678Spl196000 			    "?Fatal error: request adapter info error");
23055678Spl196000 			return (AACERR);
23065678Spl196000 		}
23075678Spl196000 		options = 0;
23085678Spl196000 		atu_size = 0;
23095678Spl196000 	} else {
23105678Spl196000 		options = AAC_MAILBOX_GET(softs, 1);
23115678Spl196000 		atu_size = AAC_MAILBOX_GET(softs, 2);
23125678Spl196000 	}
23135678Spl196000 
23145678Spl196000 	if (softs->state & AAC_STATE_RESET) {
23155678Spl196000 		if ((softs->support_opt == options) &&
23165678Spl196000 		    (softs->atu_size == atu_size))
23175678Spl196000 			return (AACOK);
23185678Spl196000 
23195678Spl196000 		cmn_err(CE_WARN,
23205678Spl196000 		    "?Fatal error: firmware changed, system needs reboot");
23215678Spl196000 		return (AACERR);
23225678Spl196000 	}
23235678Spl196000 
23245678Spl196000 	/*
23255678Spl196000 	 * The following critical settings are initialized only once during
23265678Spl196000 	 * driver attachment.
23275678Spl196000 	 */
23285678Spl196000 	softs->support_opt = options;
23295678Spl196000 	softs->atu_size = atu_size;
23305678Spl196000 
23315678Spl196000 	/* Process supported options */
23325678Spl196000 	if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 &&
23335678Spl196000 	    (softs->flags & AAC_FLAGS_NO4GB) == 0) {
23345678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable FIB map 4GB window");
23355678Spl196000 		softs->flags |= AAC_FLAGS_4GB_WINDOW;
23365678Spl196000 	} else {
23375678Spl196000 		/*
23385678Spl196000 		 * Quirk AAC_FLAGS_NO4GB is for FIB address and thus comm space
23395678Spl196000 		 * only. IO is handled by the DMA engine which does not suffer
23405678Spl196000 		 * from the ATU window programming workarounds necessary for
23415678Spl196000 		 * CPU copy operations.
23425678Spl196000 		 */
23435678Spl196000 		softs->addr_dma_attr.dma_attr_addr_lo = 0x2000ull;
23445678Spl196000 		softs->addr_dma_attr.dma_attr_addr_hi = 0x7fffffffull;
23455678Spl196000 	}
23465678Spl196000 
23475678Spl196000 	if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0) {
23485678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable SG map 64-bit address");
23495678Spl196000 		softs->buf_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
23505678Spl196000 		softs->buf_dma_attr.dma_attr_seg = 0xffffffffffffffffull;
23515678Spl196000 		softs->flags |= AAC_FLAGS_SG_64BIT;
23525678Spl196000 	}
23535678Spl196000 
23545678Spl196000 	if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) {
23555678Spl196000 		softs->flags |= AAC_FLAGS_ARRAY_64BIT;
23565678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array size");
23575678Spl196000 	}
23585678Spl196000 
23597567SXin.Chen@Sun.COM 	if (options & AAC_SUPPORTED_NONDASD) {
23607567SXin.Chen@Sun.COM 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p, 0,
23617567SXin.Chen@Sun.COM 		    "nondasd-enable", (char **)&data) == DDI_SUCCESS)) {
23627567SXin.Chen@Sun.COM 			if (strcmp((char *)data, "yes") == 0) {
23637567SXin.Chen@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
23647567SXin.Chen@Sun.COM 				    "!Enable Non-DASD access");
23657567SXin.Chen@Sun.COM 				softs->flags |= AAC_FLAGS_NONDASD;
23667567SXin.Chen@Sun.COM 			}
23677567SXin.Chen@Sun.COM 			ddi_prop_free(data);
23687567SXin.Chen@Sun.COM 		}
23697567SXin.Chen@Sun.COM 	}
23707567SXin.Chen@Sun.COM 
23715678Spl196000 	/* Read preferred settings */
23725678Spl196000 	max_fib_size = 0;
23735678Spl196000 	if ((aac_sync_mbcommand(softs, AAC_MONKER_GETCOMMPREF,
23745678Spl196000 	    0, 0, 0, 0, NULL)) == AACOK) {
23755678Spl196000 		options = AAC_MAILBOX_GET(softs, 1);
23765678Spl196000 		max_fib_size = (options & 0xffff);
23775678Spl196000 		max_sectors = (options >> 16) << 1;
23785678Spl196000 		options = AAC_MAILBOX_GET(softs, 2);
23795678Spl196000 		sg_tablesize = (options >> 16);
23805678Spl196000 		options = AAC_MAILBOX_GET(softs, 3);
23815678Spl196000 		max_fibs = (options & 0xffff);
23825678Spl196000 	}
23835678Spl196000 
23845678Spl196000 	/* Enable new comm. and rawio at the same time */
23855678Spl196000 	if ((softs->support_opt & AAC_SUPPORTED_NEW_COMM) &&
23865678Spl196000 	    (max_fib_size != 0)) {
23877567SXin.Chen@Sun.COM 		/* read out and save PCI MBR */
23885678Spl196000 		if ((atu_size > softs->map_size) &&
23895678Spl196000 		    (ddi_regs_map_setup(softs->devinfo_p, 1,
239011236SStephen.Hanson@Sun.COM 		    (caddr_t *)&data, 0, atu_size, &softs->reg_attr,
23915678Spl196000 		    &pci_handle) == DDI_SUCCESS)) {
23925678Spl196000 			ddi_regs_map_free(&softs->pci_mem_handle);
23935678Spl196000 			softs->pci_mem_handle = pci_handle;
23947567SXin.Chen@Sun.COM 			softs->pci_mem_base_vaddr = data;
23955678Spl196000 			softs->map_size = atu_size;
23965678Spl196000 		}
23975678Spl196000 		if (atu_size == softs->map_size) {
23985678Spl196000 			softs->flags |= AAC_FLAGS_NEW_COMM;
23995678Spl196000 			AACDB_PRINT(softs, CE_NOTE,
24005678Spl196000 			    "!Enable New Comm. interface");
24015678Spl196000 		}
24025678Spl196000 	}
24035678Spl196000 
24045678Spl196000 	/* Set FIB parameters */
24055678Spl196000 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
24065678Spl196000 		softs->aac_max_fibs = max_fibs;
24075678Spl196000 		softs->aac_max_fib_size = max_fib_size;
24085678Spl196000 		softs->aac_max_sectors = max_sectors;
24095678Spl196000 		softs->aac_sg_tablesize = sg_tablesize;
24105678Spl196000 
24115678Spl196000 		softs->flags |= AAC_FLAGS_RAW_IO;
24125678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable RawIO");
24135678Spl196000 	} else {
24145678Spl196000 		softs->aac_max_fibs =
24155678Spl196000 		    (softs->flags & AAC_FLAGS_256FIBS) ? 256 : 512;
24165678Spl196000 		softs->aac_max_fib_size = AAC_FIB_SIZE;
24175678Spl196000 		softs->aac_max_sectors = 128;	/* 64K */
24185678Spl196000 		if (softs->flags & AAC_FLAGS_17SG)
24195678Spl196000 			softs->aac_sg_tablesize = 17;
24205678Spl196000 		else if (softs->flags & AAC_FLAGS_34SG)
24215678Spl196000 			softs->aac_sg_tablesize = 34;
24225678Spl196000 		else if (softs->flags & AAC_FLAGS_SG_64BIT)
24235678Spl196000 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
24245678Spl196000 			    sizeof (struct aac_blockwrite64) +
24255678Spl196000 			    sizeof (struct aac_sg_entry64)) /
24265678Spl196000 			    sizeof (struct aac_sg_entry64);
24275678Spl196000 		else
24285678Spl196000 			softs->aac_sg_tablesize = (AAC_FIB_DATASIZE -
24295678Spl196000 			    sizeof (struct aac_blockwrite) +
24305678Spl196000 			    sizeof (struct aac_sg_entry)) /
24315678Spl196000 			    sizeof (struct aac_sg_entry);
24325678Spl196000 	}
24335678Spl196000 
24345678Spl196000 	if ((softs->flags & AAC_FLAGS_RAW_IO) &&
24355678Spl196000 	    (softs->flags & AAC_FLAGS_ARRAY_64BIT)) {
24365678Spl196000 		softs->flags |= AAC_FLAGS_LBA_64BIT;
24375678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "!Enable 64-bit array");
24385678Spl196000 	}
24395678Spl196000 	softs->buf_dma_attr.dma_attr_sgllen = softs->aac_sg_tablesize;
24405678Spl196000 	softs->buf_dma_attr.dma_attr_maxxfer = softs->aac_max_sectors << 9;
24415678Spl196000 	/*
24425678Spl196000 	 * 64K maximum segment size in scatter gather list is controlled by
24435678Spl196000 	 * the NEW_COMM bit in the adapter information. If not set, the card
24445678Spl196000 	 * can only accept a maximum of 64K. It is not recommended to permit
24455678Spl196000 	 * more than 128KB of total transfer size to the adapters because
24465678Spl196000 	 * performance is negatively impacted.
24475678Spl196000 	 *
24485678Spl196000 	 * For new comm, segment size equals max xfer size. For old comm,
24495678Spl196000 	 * we use 64K for both.
24505678Spl196000 	 */
24515678Spl196000 	softs->buf_dma_attr.dma_attr_count_max =
24525678Spl196000 	    softs->buf_dma_attr.dma_attr_maxxfer - 1;
24535678Spl196000 
24547567SXin.Chen@Sun.COM 	/* Setup FIB operations */
24555678Spl196000 	if (softs->flags & AAC_FLAGS_RAW_IO)
24565678Spl196000 		softs->aac_cmd_fib = aac_cmd_fib_rawio;
24575678Spl196000 	else if (softs->flags & AAC_FLAGS_SG_64BIT)
24585678Spl196000 		softs->aac_cmd_fib = aac_cmd_fib_brw64;
24595678Spl196000 	else
24605678Spl196000 		softs->aac_cmd_fib = aac_cmd_fib_brw;
24615678Spl196000 	softs->aac_cmd_fib_scsi = (softs->flags & AAC_FLAGS_SG_64BIT) ? \
24625678Spl196000 	    aac_cmd_fib_scsi64 : aac_cmd_fib_scsi32;
24635678Spl196000 
24645678Spl196000 	/* 64-bit LBA needs descriptor format sense data */
24655678Spl196000 	softs->slen = sizeof (struct scsi_arq_status);
24665678Spl196000 	if ((softs->flags & AAC_FLAGS_LBA_64BIT) &&
24675678Spl196000 	    softs->slen < AAC_ARQ64_LENGTH)
24685678Spl196000 		softs->slen = AAC_ARQ64_LENGTH;
24695678Spl196000 
24705678Spl196000 	AACDB_PRINT(softs, CE_NOTE,
24715678Spl196000 	    "!max_fibs %d max_fibsize 0x%x max_sectors %d max_sg %d",
24725678Spl196000 	    softs->aac_max_fibs, softs->aac_max_fib_size,
24735678Spl196000 	    softs->aac_max_sectors, softs->aac_sg_tablesize);
24745678Spl196000 
24755678Spl196000 	return (AACOK);
24765678Spl196000 }
24775678Spl196000 
24785678Spl196000 static void
aac_fsa_rev(struct aac_softstate * softs,struct FsaRev * fsarev0,struct FsaRev * fsarev1)24795678Spl196000 aac_fsa_rev(struct aac_softstate *softs, struct FsaRev *fsarev0,
24805678Spl196000     struct FsaRev *fsarev1)
24815678Spl196000 {
248211348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
24835678Spl196000 
24845678Spl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.dash);
24855678Spl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.type);
24865678Spl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.minor);
24875678Spl196000 	AAC_GET_FIELD8(acc, fsarev1, fsarev0, external.comp.major);
24885678Spl196000 	AAC_GET_FIELD32(acc, fsarev1, fsarev0, buildNumber);
24895678Spl196000 }
24905678Spl196000 
24915678Spl196000 /*
24925678Spl196000  * The following function comes from Adaptec:
24935678Spl196000  *
24945678Spl196000  * Query adapter information and supplement adapter information
24955678Spl196000  */
24965678Spl196000 static int
aac_get_adapter_info(struct aac_softstate * softs,struct aac_adapter_info * ainfr,struct aac_supplement_adapter_info * sinfr)24975678Spl196000 aac_get_adapter_info(struct aac_softstate *softs,
24985678Spl196000     struct aac_adapter_info *ainfr, struct aac_supplement_adapter_info *sinfr)
24995678Spl196000 {
250011348SZhongyan.Gu@Sun.COM 	struct aac_cmd *acp = &softs->sync_ac;
250111348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
250211348SZhongyan.Gu@Sun.COM 	struct aac_fib *fibp;
25035678Spl196000 	struct aac_adapter_info *ainfp;
25045678Spl196000 	struct aac_supplement_adapter_info *sinfp;
250511348SZhongyan.Gu@Sun.COM 	int rval;
250611348SZhongyan.Gu@Sun.COM 
250711348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, acp);
250811348SZhongyan.Gu@Sun.COM 	acc = acp->slotp->fib_acc_handle;
250911348SZhongyan.Gu@Sun.COM 	fibp = acp->slotp->fibp;
25105678Spl196000 
25115678Spl196000 	ddi_put8(acc, &fibp->data[0], 0);
25125678Spl196000 	if (aac_sync_fib(softs, RequestAdapterInfo,
2513*12408SZhongyan.Gu@Sun.COM 	    AAC_FIB_SIZEOF(struct aac_adapter_info)) != AACOK) {
25145678Spl196000 		AACDB_PRINT(softs, CE_WARN, "RequestAdapterInfo failed");
251511348SZhongyan.Gu@Sun.COM 		rval = AACERR;
251611348SZhongyan.Gu@Sun.COM 		goto finish;
25175678Spl196000 	}
25185678Spl196000 	ainfp = (struct aac_adapter_info *)fibp->data;
25195678Spl196000 	if (ainfr) {
25205678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
25215678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, PlatformBase);
25225678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuArchitecture);
25235678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, CpuVariant);
25245678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClockSpeed);
25255678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ExecutionMem);
25265678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, BufferMem);
25275678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, TotalMem);
25285678Spl196000 		aac_fsa_rev(softs, &ainfp->KernelRevision,
25295678Spl196000 		    &ainfr->KernelRevision);
25305678Spl196000 		aac_fsa_rev(softs, &ainfp->MonitorRevision,
25315678Spl196000 		    &ainfr->MonitorRevision);
25325678Spl196000 		aac_fsa_rev(softs, &ainfp->HardwareRevision,
25335678Spl196000 		    &ainfr->HardwareRevision);
25345678Spl196000 		aac_fsa_rev(softs, &ainfp->BIOSRevision,
25355678Spl196000 		    &ainfr->BIOSRevision);
25365678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusteringEnabled);
25375678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, ClusterChannelMask);
25385678Spl196000 		AAC_GET_FIELD64(acc, ainfr, ainfp, SerialNumber);
25395678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, batteryPlatform);
25405678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, SupportedOptions);
25415678Spl196000 		AAC_GET_FIELD32(acc, ainfr, ainfp, OemVariant);
25425678Spl196000 	}
25435678Spl196000 	if (sinfr) {
25445678Spl196000 		if (!(softs->support_opt &
25455678Spl196000 		    AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO)) {
25465678Spl196000 			AACDB_PRINT(softs, CE_WARN,
25475678Spl196000 			    "SupplementAdapterInfo not supported");
254811348SZhongyan.Gu@Sun.COM 			rval = AACERR;
254911348SZhongyan.Gu@Sun.COM 			goto finish;
25505678Spl196000 		}
25515678Spl196000 		ddi_put8(acc, &fibp->data[0], 0);
25525678Spl196000 		if (aac_sync_fib(softs, RequestSupplementAdapterInfo,
2553*12408SZhongyan.Gu@Sun.COM 		    AAC_FIB_SIZEOF(struct aac_supplement_adapter_info))
2554*12408SZhongyan.Gu@Sun.COM 		    != AACOK) {
25555678Spl196000 			AACDB_PRINT(softs, CE_WARN,
25565678Spl196000 			    "RequestSupplementAdapterInfo failed");
255711348SZhongyan.Gu@Sun.COM 			rval = AACERR;
255811348SZhongyan.Gu@Sun.COM 			goto finish;
25595678Spl196000 		}
25605678Spl196000 		sinfp = (struct aac_supplement_adapter_info *)fibp->data;
25615678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, AdapterTypeText[0], 17+1);
25625678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, Pad[0], 2);
25635678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashMemoryByteSize);
25645678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FlashImageId);
25655678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, MaxNumberPorts);
25665678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, Version);
25675678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits);
25685678Spl196000 		AAC_GET_FIELD8(acc, sinfr, sinfp, SlotNumber);
25695678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, ReservedPad0[0], 3);
25705678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, BuildDate[0], 12);
25715678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, CurrentNumberPorts);
25725678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, VpdInfo,
25735678Spl196000 		    sizeof (struct vpd_info));
25745678Spl196000 		aac_fsa_rev(softs, &sinfp->FlashFirmwareRevision,
25755678Spl196000 		    &sinfr->FlashFirmwareRevision);
25765678Spl196000 		AAC_GET_FIELD32(acc, sinfr, sinfp, RaidTypeMorphOptions);
25775678Spl196000 		aac_fsa_rev(softs, &sinfp->FlashFirmwareBootRevision,
25785678Spl196000 		    &sinfr->FlashFirmwareBootRevision);
25795678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgPcbaSerialNo,
25805678Spl196000 		    MFG_PCBA_SERIAL_NUMBER_WIDTH);
25815678Spl196000 		AAC_REP_GET_FIELD8(acc, sinfr, sinfp, MfgWWNName[0],
25825678Spl196000 		    MFG_WWN_WIDTH);
258310976SZhongyan.Gu@Sun.COM 		AAC_GET_FIELD32(acc, sinfr, sinfp, SupportedOptions2);
258410976SZhongyan.Gu@Sun.COM 		AAC_GET_FIELD32(acc, sinfr, sinfp, ExpansionFlag);
258510976SZhongyan.Gu@Sun.COM 		if (sinfr->ExpansionFlag == 1) {
258610976SZhongyan.Gu@Sun.COM 			AAC_GET_FIELD32(acc, sinfr, sinfp, FeatureBits3);
258710976SZhongyan.Gu@Sun.COM 			AAC_GET_FIELD32(acc, sinfr, sinfp,
258810976SZhongyan.Gu@Sun.COM 			    SupportedPerformanceMode);
258910976SZhongyan.Gu@Sun.COM 			AAC_REP_GET_FIELD32(acc, sinfr, sinfp,
259010976SZhongyan.Gu@Sun.COM 			    ReservedGrowth[0], 80);
259110976SZhongyan.Gu@Sun.COM 		}
25925678Spl196000 	}
259311348SZhongyan.Gu@Sun.COM 	rval = AACOK;
259411348SZhongyan.Gu@Sun.COM finish:
259511348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, acp);
259611348SZhongyan.Gu@Sun.COM 	return (rval);
25975678Spl196000 }
25985678Spl196000 
25997567SXin.Chen@Sun.COM static int
aac_get_bus_info(struct aac_softstate * softs,uint32_t * bus_max,uint32_t * tgt_max)26007567SXin.Chen@Sun.COM aac_get_bus_info(struct aac_softstate *softs, uint32_t *bus_max,
26017567SXin.Chen@Sun.COM     uint32_t *tgt_max)
26027567SXin.Chen@Sun.COM {
260311348SZhongyan.Gu@Sun.COM 	struct aac_cmd *acp = &softs->sync_ac;
260411348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
260511348SZhongyan.Gu@Sun.COM 	struct aac_fib *fibp;
26067567SXin.Chen@Sun.COM 	struct aac_ctcfg *c_cmd;
26077567SXin.Chen@Sun.COM 	struct aac_ctcfg_resp *c_resp;
26087567SXin.Chen@Sun.COM 	uint32_t scsi_method_id;
26097567SXin.Chen@Sun.COM 	struct aac_bus_info *cmd;
26107567SXin.Chen@Sun.COM 	struct aac_bus_info_response *resp;
26117567SXin.Chen@Sun.COM 	int rval;
26127567SXin.Chen@Sun.COM 
261311348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, acp);
261411348SZhongyan.Gu@Sun.COM 	acc = acp->slotp->fib_acc_handle;
261511348SZhongyan.Gu@Sun.COM 	fibp = acp->slotp->fibp;
261611348SZhongyan.Gu@Sun.COM 
26177567SXin.Chen@Sun.COM 	/* Detect MethodId */
26187567SXin.Chen@Sun.COM 	c_cmd = (struct aac_ctcfg *)&fibp->data[0];
26197567SXin.Chen@Sun.COM 	ddi_put32(acc, &c_cmd->Command, VM_ContainerConfig);
26207567SXin.Chen@Sun.COM 	ddi_put32(acc, &c_cmd->cmd, CT_GET_SCSI_METHOD);
26217567SXin.Chen@Sun.COM 	ddi_put32(acc, &c_cmd->param, 0);
26227567SXin.Chen@Sun.COM 	rval = aac_sync_fib(softs, ContainerCommand,
26237567SXin.Chen@Sun.COM 	    AAC_FIB_SIZEOF(struct aac_ctcfg));
26247567SXin.Chen@Sun.COM 	c_resp = (struct aac_ctcfg_resp *)&fibp->data[0];
26257567SXin.Chen@Sun.COM 	if (rval != AACOK || ddi_get32(acc, &c_resp->Status) != 0) {
26267567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
26277567SXin.Chen@Sun.COM 		    "VM_ContainerConfig command fail");
262811348SZhongyan.Gu@Sun.COM 		rval = AACERR;
262911348SZhongyan.Gu@Sun.COM 		goto finish;
26307567SXin.Chen@Sun.COM 	}
26317567SXin.Chen@Sun.COM 	scsi_method_id = ddi_get32(acc, &c_resp->param);
26327567SXin.Chen@Sun.COM 
26337567SXin.Chen@Sun.COM 	/* Detect phys. bus count and max. target id first */
26347567SXin.Chen@Sun.COM 	cmd = (struct aac_bus_info *)&fibp->data[0];
26357567SXin.Chen@Sun.COM 	ddi_put32(acc, &cmd->Command, VM_Ioctl);
26367567SXin.Chen@Sun.COM 	ddi_put32(acc, &cmd->ObjType, FT_DRIVE); /* physical drive */
26377567SXin.Chen@Sun.COM 	ddi_put32(acc, &cmd->MethodId, scsi_method_id);
26387567SXin.Chen@Sun.COM 	ddi_put32(acc, &cmd->ObjectId, 0);
26397567SXin.Chen@Sun.COM 	ddi_put32(acc, &cmd->CtlCmd, GetBusInfo);
26407567SXin.Chen@Sun.COM 	/*
26417567SXin.Chen@Sun.COM 	 * For VM_Ioctl, the firmware uses the Header.Size filled from the
26427567SXin.Chen@Sun.COM 	 * driver as the size to be returned. Therefore the driver has to use
26437567SXin.Chen@Sun.COM 	 * sizeof (struct aac_bus_info_response) because it is greater than
26447567SXin.Chen@Sun.COM 	 * sizeof (struct aac_bus_info).
26457567SXin.Chen@Sun.COM 	 */
26467567SXin.Chen@Sun.COM 	rval = aac_sync_fib(softs, ContainerCommand,
26477567SXin.Chen@Sun.COM 	    AAC_FIB_SIZEOF(struct aac_bus_info_response));
26487567SXin.Chen@Sun.COM 	resp = (struct aac_bus_info_response *)cmd;
26497567SXin.Chen@Sun.COM 
26507567SXin.Chen@Sun.COM 	/* Scan all coordinates with INQUIRY */
26517567SXin.Chen@Sun.COM 	if ((rval != AACOK) || (ddi_get32(acc, &resp->Status) != 0)) {
26527567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_WARN, "GetBusInfo command fail");
265311348SZhongyan.Gu@Sun.COM 		rval = AACERR;
265411348SZhongyan.Gu@Sun.COM 		goto finish;
26557567SXin.Chen@Sun.COM 	}
26567567SXin.Chen@Sun.COM 	*bus_max = ddi_get32(acc, &resp->BusCount);
26577567SXin.Chen@Sun.COM 	*tgt_max = ddi_get32(acc, &resp->TargetsPerBus);
265811348SZhongyan.Gu@Sun.COM 
265911348SZhongyan.Gu@Sun.COM finish:
266011348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, acp);
26617567SXin.Chen@Sun.COM 	return (AACOK);
26627567SXin.Chen@Sun.COM }
26637567SXin.Chen@Sun.COM 
26645678Spl196000 /*
26655678Spl196000  * The following function comes from Adaptec:
26665678Spl196000  *
26675678Spl196000  * Routine to be called during initialization of communications with
26685678Spl196000  * the adapter to handle possible adapter configuration issues. When
26695678Spl196000  * the adapter first boots up, it examines attached drives, etc, and
26705678Spl196000  * potentially comes up with a new or revised configuration (relative to
26715678Spl196000  * what's stored in it's NVRAM). Additionally it may discover problems
26725678Spl196000  * that make the current physical configuration unworkable (currently
26735678Spl196000  * applicable only to cluster configuration issues).
26745678Spl196000  *
26755678Spl196000  * If there are no configuration issues or the issues are considered
26765678Spl196000  * trival by the adapter, it will set it's configuration status to
26775678Spl196000  * "FSACT_CONTINUE" and execute the "commit confiuguration" action
26785678Spl196000  * automatically on it's own.
26795678Spl196000  *
26805678Spl196000  * However, if there are non-trivial issues, the adapter will set it's
26815678Spl196000  * internal configuration status to "FSACT_PAUSE" or "FASCT_ABORT"
26825678Spl196000  * and wait for some agent on the host to issue the "\ContainerCommand
26835678Spl196000  * \VM_ContainerConfig\CT_COMMIT_CONFIG" FIB command to cause the
26845678Spl196000  * adapter to commit the new/updated configuration and enable
26855678Spl196000  * un-inhibited operation.  The host agent should first issue the
26865678Spl196000  * "\ContainerCommand\VM_ContainerConfig\CT_GET_CONFIG_STATUS" FIB
26875678Spl196000  * command to obtain information about config issues detected by
26885678Spl196000  * the adapter.
26895678Spl196000  *
26905678Spl196000  * Normally the adapter's PC BIOS will execute on the host following
26915678Spl196000  * adapter poweron and reset and will be responsible for querring the
26925678Spl196000  * adapter with CT_GET_CONFIG_STATUS and issuing the CT_COMMIT_CONFIG
26935678Spl196000  * command if appropriate.
26945678Spl196000  *
26955678Spl196000  * However, with the introduction of IOP reset support, the adapter may
26965678Spl196000  * boot up without the benefit of the adapter's PC BIOS host agent.
26975678Spl196000  * This routine is intended to take care of these issues in situations
26985678Spl196000  * where BIOS doesn't execute following adapter poweron or reset.  The
26995678Spl196000  * CT_COMMIT_CONFIG command is a no-op if it's already been issued, so
27005678Spl196000  * there is no harm in doing this when it's already been done.
27015678Spl196000  */
27025678Spl196000 static int
aac_handle_adapter_config_issues(struct aac_softstate * softs)27035678Spl196000 aac_handle_adapter_config_issues(struct aac_softstate *softs)
27045678Spl196000 {
270511348SZhongyan.Gu@Sun.COM 	struct aac_cmd *acp = &softs->sync_ac;
270611348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
270711348SZhongyan.Gu@Sun.COM 	struct aac_fib *fibp;
27085678Spl196000 	struct aac_Container *cmd;
27095678Spl196000 	struct aac_Container_resp *resp;
27105678Spl196000 	struct aac_cf_status_header *cfg_sts_hdr;
27115678Spl196000 	uint32_t resp_status;
27125678Spl196000 	uint32_t ct_status;
27135678Spl196000 	uint32_t cfg_stat_action;
27145678Spl196000 	int rval;
27155678Spl196000 
271611348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, acp);
271711348SZhongyan.Gu@Sun.COM 	acc = acp->slotp->fib_acc_handle;
271811348SZhongyan.Gu@Sun.COM 	fibp = acp->slotp->fibp;
271911348SZhongyan.Gu@Sun.COM 
27205678Spl196000 	/* Get adapter config status */
27215678Spl196000 	cmd = (struct aac_Container *)&fibp->data[0];
27225678Spl196000 
27235678Spl196000 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
27245678Spl196000 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
27255678Spl196000 	ddi_put32(acc, &cmd->CTCommand.command, CT_GET_CONFIG_STATUS);
27265678Spl196000 	ddi_put32(acc, &cmd->CTCommand.param[CNT_SIZE],
27275678Spl196000 	    sizeof (struct aac_cf_status_header));
27285678Spl196000 	rval = aac_sync_fib(softs, ContainerCommand,
27295678Spl196000 	    AAC_FIB_SIZEOF(struct aac_Container));
27305678Spl196000 	resp = (struct aac_Container_resp *)cmd;
27315678Spl196000 	cfg_sts_hdr = (struct aac_cf_status_header *)resp->CTResponse.data;
27325678Spl196000 
27335678Spl196000 	resp_status = ddi_get32(acc, &resp->Status);
27345678Spl196000 	ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
27355678Spl196000 	if ((rval == AACOK) && (resp_status == 0) && (ct_status == CT_OK)) {
27365678Spl196000 		cfg_stat_action = ddi_get32(acc, &cfg_sts_hdr->action);
27375678Spl196000 
27385678Spl196000 		/* Commit configuration if it's reasonable to do so. */
27395678Spl196000 		if (cfg_stat_action <= CFACT_PAUSE) {
27405678Spl196000 			bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
27415678Spl196000 			ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
27425678Spl196000 			ddi_put32(acc, &cmd->CTCommand.command,
27435678Spl196000 			    CT_COMMIT_CONFIG);
27445678Spl196000 			rval = aac_sync_fib(softs, ContainerCommand,
27455678Spl196000 			    AAC_FIB_SIZEOF(struct aac_Container));
27465678Spl196000 
27475678Spl196000 			resp_status = ddi_get32(acc, &resp->Status);
27485678Spl196000 			ct_status = ddi_get32(acc, &resp->CTResponse.param[0]);
27495678Spl196000 			if ((rval == AACOK) && (resp_status == 0) &&
27505678Spl196000 			    (ct_status == CT_OK))
27515678Spl196000 				/* Successful completion */
27525678Spl196000 				rval = AACMPE_OK;
27535678Spl196000 			else
27545678Spl196000 				/* Auto-commit aborted due to error(s). */
27555678Spl196000 				rval = AACMPE_COMMIT_CONFIG;
27565678Spl196000 		} else {
27575678Spl196000 			/*
27585678Spl196000 			 * Auto-commit aborted due to adapter indicating
27595678Spl196000 			 * configuration issue(s) too dangerous to auto-commit.
27605678Spl196000 			 */
27615678Spl196000 			rval = AACMPE_CONFIG_STATUS;
27625678Spl196000 		}
27635678Spl196000 	} else {
27645678Spl196000 		cmn_err(CE_WARN, "!Configuration issue, auto-commit aborted");
27655678Spl196000 		rval = AACMPE_CONFIG_STATUS;
27665678Spl196000 	}
276711348SZhongyan.Gu@Sun.COM 
276811348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, acp);
27695678Spl196000 	return (rval);
27705678Spl196000 }
27715678Spl196000 
27725678Spl196000 /*
27735678Spl196000  * Hardware initialization and resource allocation
27745678Spl196000  */
27755678Spl196000 static int
aac_common_attach(struct aac_softstate * softs)27765678Spl196000 aac_common_attach(struct aac_softstate *softs)
27775678Spl196000 {
27785678Spl196000 	uint32_t status;
27795678Spl196000 	int i;
278011964SXin.Chen@Sun.COM 	struct aac_supplement_adapter_info sinf;
27815678Spl196000 
27825678Spl196000 	DBCALLED(softs, 1);
27835678Spl196000 
27845678Spl196000 	/*
27855678Spl196000 	 * Do a little check here to make sure there aren't any outstanding
27865678Spl196000 	 * FIBs in the message queue. At this point there should not be and
27875678Spl196000 	 * if there are they are probably left over from another instance of
27885678Spl196000 	 * the driver like when the system crashes and the crash dump driver
27895678Spl196000 	 * gets loaded.
27905678Spl196000 	 */
27915678Spl196000 	while (AAC_OUTB_GET(softs) != 0xfffffffful)
27925678Spl196000 		;
27935678Spl196000 
27945678Spl196000 	/*
27955678Spl196000 	 * Wait the card to complete booting up before do anything that
27965678Spl196000 	 * attempts to communicate with it.
27975678Spl196000 	 */
27985678Spl196000 	status = AAC_FWSTATUS_GET(softs);
27995678Spl196000 	if (status == AAC_SELF_TEST_FAILED || status == AAC_KERNEL_PANIC)
28005678Spl196000 		goto error;
28015678Spl196000 	i = AAC_FWUP_TIMEOUT * 1000; /* set timeout */
28025678Spl196000 	AAC_BUSYWAIT(AAC_FWSTATUS_GET(softs) & AAC_KERNEL_UP_AND_RUNNING, i);
28035678Spl196000 	if (i == 0) {
28045678Spl196000 		cmn_err(CE_CONT, "?Fatal error: controller not ready");
28055678Spl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28065678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28075678Spl196000 		goto error;
28085678Spl196000 	}
28095678Spl196000 
28105678Spl196000 	/* Read and set card supported options and settings */
28115678Spl196000 	if (aac_check_firmware(softs) == AACERR) {
28125678Spl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28135678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28145678Spl196000 		goto error;
28155678Spl196000 	}
28165678Spl196000 
281711348SZhongyan.Gu@Sun.COM 	/* Add interrupt handlers */
281811348SZhongyan.Gu@Sun.COM 	if (aac_register_intrs(softs) == AACERR) {
281911348SZhongyan.Gu@Sun.COM 		cmn_err(CE_CONT,
282011348SZhongyan.Gu@Sun.COM 		    "?Fatal error: interrupts register failed");
282111348SZhongyan.Gu@Sun.COM 		goto error;
282211348SZhongyan.Gu@Sun.COM 	}
28235678Spl196000 
28245678Spl196000 	/* Setup communication space with the card */
28255678Spl196000 	if (softs->comm_space_dma_handle == NULL) {
28265678Spl196000 		if (aac_alloc_comm_space(softs) != AACOK)
28275678Spl196000 			goto error;
28285678Spl196000 	}
28295678Spl196000 	if (aac_setup_comm_space(softs) != AACOK) {
28305678Spl196000 		cmn_err(CE_CONT, "?Setup communication space failed");
28315678Spl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
28325678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
28335678Spl196000 		goto error;
28345678Spl196000 	}
28355678Spl196000 
28365678Spl196000 #ifdef DEBUG
28375678Spl196000 	if (aac_get_fw_debug_buffer(softs) != AACOK)
28385678Spl196000 		cmn_err(CE_CONT, "?firmware UART trace not supported");
28395678Spl196000 #endif
28405678Spl196000 
28415678Spl196000 	/* Allocate slots */
28425678Spl196000 	if ((softs->total_slots == 0) && (aac_create_slots(softs) != AACOK)) {
28435678Spl196000 		cmn_err(CE_CONT, "?Fatal error: slots allocate failed");
28445678Spl196000 		goto error;
28455678Spl196000 	}
28465678Spl196000 	AACDB_PRINT(softs, CE_NOTE, "%d slots allocated", softs->total_slots);
28475678Spl196000 
28485678Spl196000 	/* Allocate FIBs */
28495678Spl196000 	if (softs->total_fibs < softs->total_slots) {
28505678Spl196000 		aac_alloc_fibs(softs);
28515678Spl196000 		if (softs->total_fibs == 0)
28525678Spl196000 			goto error;
28535678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "%d fibs allocated",
28545678Spl196000 		    softs->total_fibs);
28555678Spl196000 	}
28565678Spl196000 
285711348SZhongyan.Gu@Sun.COM 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
285811348SZhongyan.Gu@Sun.COM 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
285911348SZhongyan.Gu@Sun.COM 
286011964SXin.Chen@Sun.COM 	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
2861*12408SZhongyan.Gu@Sun.COM 		softs->feature_bits = sinf.FeatureBits;
2862*12408SZhongyan.Gu@Sun.COM 		softs->support_opt2 = sinf.SupportedOptions2;
2863*12408SZhongyan.Gu@Sun.COM 
286411964SXin.Chen@Sun.COM 		/* Get adapter names */
286511964SXin.Chen@Sun.COM 		if (CARD_IS_UNKNOWN(softs->card)) {
28665678Spl196000 			char *p, *p0, *p1;
28675678Spl196000 
28685678Spl196000 			/*
28695678Spl196000 			 * Now find the controller name in supp_adapter_info->
28705678Spl196000 			 * AdapterTypeText. Use the first word as the vendor
28715678Spl196000 			 * and the other words as the product name.
28725678Spl196000 			 */
28735678Spl196000 			AACDB_PRINT(softs, CE_NOTE, "sinf.AdapterTypeText = "
28745678Spl196000 			    "\"%s\"", sinf.AdapterTypeText);
28755678Spl196000 			p = sinf.AdapterTypeText;
28765678Spl196000 			p0 = p1 = NULL;
28775678Spl196000 			/* Skip heading spaces */
28785678Spl196000 			while (*p && (*p == ' ' || *p == '\t'))
28795678Spl196000 				p++;
28805678Spl196000 			p0 = p;
28815678Spl196000 			while (*p && (*p != ' ' && *p != '\t'))
28825678Spl196000 				p++;
28835678Spl196000 			/* Remove middle spaces */
28845678Spl196000 			while (*p && (*p == ' ' || *p == '\t'))
28855678Spl196000 				*p++ = 0;
28865678Spl196000 			p1 = p;
28875678Spl196000 			/* Remove trailing spaces */
28885678Spl196000 			p = p1 + strlen(p1) - 1;
28895678Spl196000 			while (p > p1 && (*p == ' ' || *p == '\t'))
28905678Spl196000 				*p-- = 0;
28915678Spl196000 			if (*p0 && *p1) {
28925678Spl196000 				(void *)strncpy(softs->vendor_name, p0,
28935678Spl196000 				    AAC_VENDOR_LEN);
28945678Spl196000 				(void *)strncpy(softs->product_name, p1,
28955678Spl196000 				    AAC_PRODUCT_LEN);
28965678Spl196000 			} else {
28975678Spl196000 				cmn_err(CE_WARN,
28985678Spl196000 				    "?adapter name mis-formatted\n");
28995678Spl196000 				if (*p0)
29005678Spl196000 					(void *)strncpy(softs->product_name,
29015678Spl196000 					    p0, AAC_PRODUCT_LEN);
29025678Spl196000 			}
29035678Spl196000 		}
290411964SXin.Chen@Sun.COM 	} else {
290511964SXin.Chen@Sun.COM 		cmn_err(CE_CONT, "?Query adapter information failed");
290611964SXin.Chen@Sun.COM 	}
290711964SXin.Chen@Sun.COM 
29085678Spl196000 
29095678Spl196000 	cmn_err(CE_NOTE,
29105678Spl196000 	    "!aac driver %d.%02d.%02d-%d, found card: " \
29115678Spl196000 	    "%s %s(pci0x%x.%x.%x.%x) at 0x%x",
29125678Spl196000 	    AAC_DRIVER_MAJOR_VERSION,
29135678Spl196000 	    AAC_DRIVER_MINOR_VERSION,
29145678Spl196000 	    AAC_DRIVER_BUGFIX_LEVEL,
29155678Spl196000 	    AAC_DRIVER_BUILD,
29165678Spl196000 	    softs->vendor_name, softs->product_name,
29175678Spl196000 	    softs->vendid, softs->devid, softs->subvendid, softs->subsysid,
29185678Spl196000 	    softs->pci_mem_base_paddr);
29195678Spl196000 
29205678Spl196000 	/* Perform acceptance of adapter-detected config changes if possible */
29215678Spl196000 	if (aac_handle_adapter_config_issues(softs) != AACMPE_OK) {
29225678Spl196000 		cmn_err(CE_CONT, "?Handle adapter config issues failed");
29235678Spl196000 		aac_fm_ereport(softs, DDI_FM_DEVICE_NO_RESPONSE);
29245678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29255678Spl196000 		goto error;
29265678Spl196000 	}
29275678Spl196000 
29287567SXin.Chen@Sun.COM 	/* Setup containers (logical devices) */
29295678Spl196000 	if (aac_probe_containers(softs) != AACOK) {
29305678Spl196000 		cmn_err(CE_CONT, "?Fatal error: get container info error");
29315678Spl196000 		goto error;
29325678Spl196000 	}
29335678Spl196000 
2934*12408SZhongyan.Gu@Sun.COM 	/* Check for JBOD support. Default disable */
2935*12408SZhongyan.Gu@Sun.COM 	char *data;
2936*12408SZhongyan.Gu@Sun.COM 	if (softs->feature_bits & AAC_FEATURE_SUPPORTED_JBOD) {
2937*12408SZhongyan.Gu@Sun.COM 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, softs->devinfo_p,
2938*12408SZhongyan.Gu@Sun.COM 		    0, "jbod-enable", &data) == DDI_SUCCESS)) {
2939*12408SZhongyan.Gu@Sun.COM 			if (strcmp(data, "yes") == 0) {
2940*12408SZhongyan.Gu@Sun.COM 				AACDB_PRINT(softs, CE_NOTE,
2941*12408SZhongyan.Gu@Sun.COM 				    "Enable JBOD access");
2942*12408SZhongyan.Gu@Sun.COM 				softs->flags |= AAC_FLAGS_JBOD;
2943*12408SZhongyan.Gu@Sun.COM 			}
2944*12408SZhongyan.Gu@Sun.COM 			ddi_prop_free(data);
2945*12408SZhongyan.Gu@Sun.COM 		}
2946*12408SZhongyan.Gu@Sun.COM 	}
2947*12408SZhongyan.Gu@Sun.COM 
29487567SXin.Chen@Sun.COM 	/* Setup phys. devices */
2949*12408SZhongyan.Gu@Sun.COM 	if (softs->flags & (AAC_FLAGS_NONDASD | AAC_FLAGS_JBOD)) {
29507567SXin.Chen@Sun.COM 		uint32_t bus_max, tgt_max;
29517567SXin.Chen@Sun.COM 		uint32_t bus, tgt;
29527567SXin.Chen@Sun.COM 		int index;
29537567SXin.Chen@Sun.COM 
29547567SXin.Chen@Sun.COM 		if (aac_get_bus_info(softs, &bus_max, &tgt_max) != AACOK) {
29557567SXin.Chen@Sun.COM 			cmn_err(CE_CONT, "?Fatal error: get bus info error");
29567567SXin.Chen@Sun.COM 			goto error;
29577567SXin.Chen@Sun.COM 		}
29587567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_NOTE, "bus_max=%d, tgt_max=%d",
29597567SXin.Chen@Sun.COM 		    bus_max, tgt_max);
29607567SXin.Chen@Sun.COM 		if (bus_max != softs->bus_max || tgt_max != softs->tgt_max) {
29617567SXin.Chen@Sun.COM 			if (softs->state & AAC_STATE_RESET) {
29627567SXin.Chen@Sun.COM 				cmn_err(CE_WARN,
29637567SXin.Chen@Sun.COM 				    "?Fatal error: bus map changed");
29647567SXin.Chen@Sun.COM 				goto error;
29657567SXin.Chen@Sun.COM 			}
29667567SXin.Chen@Sun.COM 			softs->bus_max = bus_max;
29677567SXin.Chen@Sun.COM 			softs->tgt_max = tgt_max;
29687567SXin.Chen@Sun.COM 			if (softs->nondasds) {
29697567SXin.Chen@Sun.COM 				kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
29707567SXin.Chen@Sun.COM 				    sizeof (struct aac_nondasd));
29717567SXin.Chen@Sun.COM 			}
29727567SXin.Chen@Sun.COM 			softs->nondasds = kmem_zalloc(AAC_MAX_PD(softs) * \
29737567SXin.Chen@Sun.COM 			    sizeof (struct aac_nondasd), KM_SLEEP);
29747567SXin.Chen@Sun.COM 
29757567SXin.Chen@Sun.COM 			index = 0;
29767567SXin.Chen@Sun.COM 			for (bus = 0; bus < softs->bus_max; bus++) {
29777567SXin.Chen@Sun.COM 				for (tgt = 0; tgt < softs->tgt_max; tgt++) {
29787567SXin.Chen@Sun.COM 					struct aac_nondasd *dvp =
29797567SXin.Chen@Sun.COM 					    &softs->nondasds[index++];
29807567SXin.Chen@Sun.COM 					dvp->dev.type = AAC_DEV_PD;
29817567SXin.Chen@Sun.COM 					dvp->bus = bus;
29827567SXin.Chen@Sun.COM 					dvp->tid = tgt;
29837567SXin.Chen@Sun.COM 				}
29847567SXin.Chen@Sun.COM 			}
29857567SXin.Chen@Sun.COM 		}
29867567SXin.Chen@Sun.COM 	}
29877567SXin.Chen@Sun.COM 
29885678Spl196000 	/* Check dma & acc handles allocated in attach */
29895678Spl196000 	if (aac_check_dma_handle(softs->comm_space_dma_handle) != DDI_SUCCESS) {
29905678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29915678Spl196000 		goto error;
29925678Spl196000 	}
29935678Spl196000 
29945678Spl196000 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
29955678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
29965678Spl196000 		goto error;
29975678Spl196000 	}
29985678Spl196000 
29995678Spl196000 	for (i = 0; i < softs->total_slots; i++) {
30005678Spl196000 		if (aac_check_dma_handle(softs->io_slot[i].fib_dma_handle) !=
30015678Spl196000 		    DDI_SUCCESS) {
30025678Spl196000 			ddi_fm_service_impact(softs->devinfo_p,
30035678Spl196000 			    DDI_SERVICE_LOST);
30045678Spl196000 			goto error;
30055678Spl196000 		}
30065678Spl196000 	}
30075678Spl196000 
30085678Spl196000 	return (AACOK);
30095678Spl196000 error:
30105678Spl196000 	if (softs->state & AAC_STATE_RESET)
30115678Spl196000 		return (AACERR);
30127567SXin.Chen@Sun.COM 	if (softs->nondasds) {
30137567SXin.Chen@Sun.COM 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
30147567SXin.Chen@Sun.COM 		    sizeof (struct aac_nondasd));
30157567SXin.Chen@Sun.COM 		softs->nondasds = NULL;
30167567SXin.Chen@Sun.COM 	}
30175678Spl196000 	if (softs->total_fibs > 0)
30185678Spl196000 		aac_destroy_fibs(softs);
30195678Spl196000 	if (softs->total_slots > 0)
30205678Spl196000 		aac_destroy_slots(softs);
30215678Spl196000 	if (softs->comm_space_dma_handle)
30225678Spl196000 		aac_free_comm_space(softs);
30235678Spl196000 	return (AACERR);
30245678Spl196000 }
30255678Spl196000 
30265678Spl196000 /*
30275678Spl196000  * Hardware shutdown and resource release
30285678Spl196000  */
30295678Spl196000 static void
aac_common_detach(struct aac_softstate * softs)30305678Spl196000 aac_common_detach(struct aac_softstate *softs)
30315678Spl196000 {
30325678Spl196000 	DBCALLED(softs, 1);
30335678Spl196000 
303411348SZhongyan.Gu@Sun.COM 	aac_unregister_intrs(softs);
303511348SZhongyan.Gu@Sun.COM 
303611348SZhongyan.Gu@Sun.COM 	mutex_enter(&softs->io_lock);
30375678Spl196000 	(void) aac_shutdown(softs);
30385678Spl196000 
30397567SXin.Chen@Sun.COM 	if (softs->nondasds) {
30407567SXin.Chen@Sun.COM 		kmem_free(softs->nondasds, AAC_MAX_PD(softs) * \
30417567SXin.Chen@Sun.COM 		    sizeof (struct aac_nondasd));
30427567SXin.Chen@Sun.COM 		softs->nondasds = NULL;
30437567SXin.Chen@Sun.COM 	}
30445678Spl196000 	aac_destroy_fibs(softs);
30455678Spl196000 	aac_destroy_slots(softs);
30465678Spl196000 	aac_free_comm_space(softs);
304711348SZhongyan.Gu@Sun.COM 	mutex_exit(&softs->io_lock);
30485678Spl196000 }
30495678Spl196000 
30505678Spl196000 /*
30515678Spl196000  * Send a synchronous command to the controller and wait for a result.
30525678Spl196000  * Indicate if the controller completed the command with an error status.
30535678Spl196000  */
30545678Spl196000 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)30555678Spl196000 aac_sync_mbcommand(struct aac_softstate *softs, uint32_t cmd,
30565678Spl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3,
30575678Spl196000     uint32_t *statusp)
30585678Spl196000 {
30595678Spl196000 	int timeout;
30605678Spl196000 	uint32_t status;
30615678Spl196000 
30625678Spl196000 	if (statusp != NULL)
30635678Spl196000 		*statusp = SRB_STATUS_SUCCESS;
30645678Spl196000 
30655678Spl196000 	/* Fill in mailbox */
30665678Spl196000 	AAC_MAILBOX_SET(softs, cmd, arg0, arg1, arg2, arg3);
30675678Spl196000 
30685678Spl196000 	/* Ensure the sync command doorbell flag is cleared */
30695678Spl196000 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30705678Spl196000 
30715678Spl196000 	/* Then set it to signal the adapter */
30725678Spl196000 	AAC_NOTIFY(softs, AAC_DB_SYNC_COMMAND);
30735678Spl196000 
30745678Spl196000 	/* Spin waiting for the command to complete */
30755678Spl196000 	timeout = AAC_IMMEDIATE_TIMEOUT * 1000;
30765678Spl196000 	AAC_BUSYWAIT(AAC_STATUS_GET(softs) & AAC_DB_SYNC_COMMAND, timeout);
30775678Spl196000 	if (!timeout) {
30785678Spl196000 		AACDB_PRINT(softs, CE_WARN,
30795678Spl196000 		    "Sync command timed out after %d seconds (0x%x)!",
30805678Spl196000 		    AAC_IMMEDIATE_TIMEOUT, AAC_FWSTATUS_GET(softs));
30815678Spl196000 		return (AACERR);
30825678Spl196000 	}
30835678Spl196000 
30845678Spl196000 	/* Clear the completion flag */
30855678Spl196000 	AAC_STATUS_CLR(softs, AAC_DB_SYNC_COMMAND);
30865678Spl196000 
30875678Spl196000 	/* Get the command status */
30885678Spl196000 	status = AAC_MAILBOX_GET(softs, 0);
30895678Spl196000 	if (statusp != NULL)
30905678Spl196000 		*statusp = status;
30915678Spl196000 	if (status != SRB_STATUS_SUCCESS) {
30925678Spl196000 		AACDB_PRINT(softs, CE_WARN,
30935678Spl196000 		    "Sync command fail: status = 0x%x", status);
30945678Spl196000 		return (AACERR);
30955678Spl196000 	}
30965678Spl196000 
30975678Spl196000 	return (AACOK);
30985678Spl196000 }
30995678Spl196000 
31005678Spl196000 /*
31015678Spl196000  * Send a synchronous FIB to the adapter and wait for its completion
31025678Spl196000  */
31035678Spl196000 static int
aac_sync_fib(struct aac_softstate * softs,uint16_t cmd,uint16_t fibsize)31045678Spl196000 aac_sync_fib(struct aac_softstate *softs, uint16_t cmd, uint16_t fibsize)
31055678Spl196000 {
310611348SZhongyan.Gu@Sun.COM 	struct aac_cmd *acp = &softs->sync_ac;
310711348SZhongyan.Gu@Sun.COM 
310811636SXin.Chen@Sun.COM 	acp->flags = AAC_CMD_SYNC | AAC_CMD_IN_SYNC_SLOT;
310911636SXin.Chen@Sun.COM 	if (softs->state & AAC_STATE_INTR)
311011636SXin.Chen@Sun.COM 		acp->flags |= AAC_CMD_NO_CB;
311111636SXin.Chen@Sun.COM 	else
311211636SXin.Chen@Sun.COM 		acp->flags |= AAC_CMD_NO_INTR;
311311636SXin.Chen@Sun.COM 
311411348SZhongyan.Gu@Sun.COM 	acp->ac_comp = aac_sync_complete;
311511348SZhongyan.Gu@Sun.COM 	acp->timeout = AAC_SYNC_TIMEOUT;
311611348SZhongyan.Gu@Sun.COM 	acp->fib_size = fibsize;
311711636SXin.Chen@Sun.COM 
31185678Spl196000 	/*
311911348SZhongyan.Gu@Sun.COM 	 * Only need to setup sync fib header, caller should have init
312011348SZhongyan.Gu@Sun.COM 	 * fib data
31215678Spl196000 	 */
312211348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, cmd);
312311348SZhongyan.Gu@Sun.COM 
312411636SXin.Chen@Sun.COM 	(void) ddi_dma_sync(acp->slotp->fib_dma_handle, 0, fibsize,
312511636SXin.Chen@Sun.COM 	    DDI_DMA_SYNC_FORDEV);
312611636SXin.Chen@Sun.COM 
312711348SZhongyan.Gu@Sun.COM 	aac_start_io(softs, acp);
312811348SZhongyan.Gu@Sun.COM 
312911636SXin.Chen@Sun.COM 	if (softs->state & AAC_STATE_INTR)
313011636SXin.Chen@Sun.COM 		return (aac_do_sync_io(softs, acp));
313111636SXin.Chen@Sun.COM 	else
313211636SXin.Chen@Sun.COM 		return (aac_do_poll_io(softs, acp));
31335678Spl196000 }
31345678Spl196000 
31355678Spl196000 static void
aac_cmd_initq(struct aac_cmd_queue * q)31365678Spl196000 aac_cmd_initq(struct aac_cmd_queue *q)
31375678Spl196000 {
31385678Spl196000 	q->q_head = NULL;
31395678Spl196000 	q->q_tail = (struct aac_cmd *)&q->q_head;
31405678Spl196000 }
31415678Spl196000 
31425678Spl196000 /*
31435678Spl196000  * Remove a cmd from the head of q
31445678Spl196000  */
31455678Spl196000 static struct aac_cmd *
aac_cmd_dequeue(struct aac_cmd_queue * q)31465678Spl196000 aac_cmd_dequeue(struct aac_cmd_queue *q)
31475678Spl196000 {
31485678Spl196000 	struct aac_cmd *acp;
31495678Spl196000 
31505678Spl196000 	_NOTE(ASSUMING_PROTECTED(*q))
31515678Spl196000 
31525678Spl196000 	if ((acp = q->q_head) != NULL) {
31535678Spl196000 		if ((q->q_head = acp->next) != NULL)
31545678Spl196000 			acp->next = NULL;
31555678Spl196000 		else
31565678Spl196000 			q->q_tail = (struct aac_cmd *)&q->q_head;
31575678Spl196000 		acp->prev = NULL;
31585678Spl196000 	}
31595678Spl196000 	return (acp);
31605678Spl196000 }
31615678Spl196000 
31625678Spl196000 /*
31635678Spl196000  * Add a cmd to the tail of q
31645678Spl196000  */
31655678Spl196000 static void
aac_cmd_enqueue(struct aac_cmd_queue * q,struct aac_cmd * acp)31665678Spl196000 aac_cmd_enqueue(struct aac_cmd_queue *q, struct aac_cmd *acp)
31675678Spl196000 {
31685678Spl196000 	ASSERT(acp->next == NULL);
31695678Spl196000 	acp->prev = q->q_tail;
31705678Spl196000 	q->q_tail->next = acp;
31715678Spl196000 	q->q_tail = acp;
31725678Spl196000 }
31735678Spl196000 
31745678Spl196000 /*
31755678Spl196000  * Remove the cmd ac from q
31765678Spl196000  */
31775678Spl196000 static void
aac_cmd_delete(struct aac_cmd_queue * q,struct aac_cmd * acp)31785678Spl196000 aac_cmd_delete(struct aac_cmd_queue *q, struct aac_cmd *acp)
31795678Spl196000 {
31805678Spl196000 	if (acp->prev) {
31815678Spl196000 		if ((acp->prev->next = acp->next) != NULL) {
31825678Spl196000 			acp->next->prev = acp->prev;
31835678Spl196000 			acp->next = NULL;
31845678Spl196000 		} else {
31855678Spl196000 			q->q_tail = acp->prev;
31865678Spl196000 		}
31875678Spl196000 		acp->prev = NULL;
31885678Spl196000 	}
31895678Spl196000 	/* ac is not in the queue */
31905678Spl196000 }
31915678Spl196000 
31925678Spl196000 /*
31935678Spl196000  * Atomically insert an entry into the nominated queue, returns 0 on success or
31945678Spl196000  * AACERR if the queue is full.
31955678Spl196000  *
31965678Spl196000  * Note: it would be more efficient to defer notifying the controller in
31975678Spl196000  *	 the case where we may be inserting several entries in rapid succession,
31985678Spl196000  *	 but implementing this usefully may be difficult (it would involve a
31995678Spl196000  *	 separate queue/notify interface).
32005678Spl196000  */
32015678Spl196000 static int
aac_fib_enqueue(struct aac_softstate * softs,int queue,uint32_t fib_addr,uint32_t fib_size)32025678Spl196000 aac_fib_enqueue(struct aac_softstate *softs, int queue, uint32_t fib_addr,
32035678Spl196000     uint32_t fib_size)
32045678Spl196000 {
32055678Spl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
32065678Spl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
32075678Spl196000 	uint32_t pi, ci;
32085678Spl196000 
32095678Spl196000 	DBCALLED(softs, 2);
32105678Spl196000 
32115678Spl196000 	ASSERT(queue == AAC_ADAP_NORM_CMD_Q || queue == AAC_ADAP_NORM_RESP_Q);
32125678Spl196000 
32135678Spl196000 	/* Get the producer/consumer indices */
32147100Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
32157100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32165678Spl196000 	    DDI_DMA_SYNC_FORCPU);
32175678Spl196000 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
32185678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
32195678Spl196000 		return (AACERR);
32205678Spl196000 	}
32215678Spl196000 
32225678Spl196000 	pi = ddi_get32(acc,
32235678Spl196000 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
32245678Spl196000 	ci = ddi_get32(acc,
32255678Spl196000 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
32265678Spl196000 
32275678Spl196000 	/*
32285678Spl196000 	 * Wrap the queue first before we check the queue to see
32295678Spl196000 	 * if it is full
32305678Spl196000 	 */
32315678Spl196000 	if (pi >= aac_qinfo[queue].size)
32325678Spl196000 		pi = 0;
32335678Spl196000 
32345678Spl196000 	/* XXX queue full */
32355678Spl196000 	if ((pi + 1) == ci)
32365678Spl196000 		return (AACERR);
32375678Spl196000 
32385678Spl196000 	/* Fill in queue entry */
32395678Spl196000 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_size), fib_size);
32405678Spl196000 	ddi_put32(acc, &((softs->qentries[queue] + pi)->aq_fib_addr), fib_addr);
32417100Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
32427100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
32435678Spl196000 	    DDI_DMA_SYNC_FORDEV);
32445678Spl196000 
32455678Spl196000 	/* Update producer index */
32465678Spl196000 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX],
32475678Spl196000 	    pi + 1);
32485678Spl196000 	(void) ddi_dma_sync(dma,
32497100Spl196000 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX] - \
32507100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
32515678Spl196000 	    DDI_DMA_SYNC_FORDEV);
32525678Spl196000 
32535678Spl196000 	if (aac_qinfo[queue].notify != 0)
32545678Spl196000 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
32555678Spl196000 	return (AACOK);
32565678Spl196000 }
32575678Spl196000 
32585678Spl196000 /*
32595678Spl196000  * Atomically remove one entry from the nominated queue, returns 0 on
32605678Spl196000  * success or AACERR if the queue is empty.
32615678Spl196000  */
32625678Spl196000 static int
aac_fib_dequeue(struct aac_softstate * softs,int queue,int * idxp)32635678Spl196000 aac_fib_dequeue(struct aac_softstate *softs, int queue, int *idxp)
32645678Spl196000 {
32655678Spl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
32665678Spl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
32675678Spl196000 	uint32_t pi, ci;
32685678Spl196000 	int unfull = 0;
32695678Spl196000 
32705678Spl196000 	DBCALLED(softs, 2);
32715678Spl196000 
32725678Spl196000 	ASSERT(idxp);
32735678Spl196000 
32745678Spl196000 	/* Get the producer/consumer indices */
32757100Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)softs->qtablep->qt_qindex[queue] - \
32767100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t) * 2,
32775678Spl196000 	    DDI_DMA_SYNC_FORCPU);
32785678Spl196000 	pi = ddi_get32(acc,
32795678Spl196000 	    &softs->qtablep->qt_qindex[queue][AAC_PRODUCER_INDEX]);
32805678Spl196000 	ci = ddi_get32(acc,
32815678Spl196000 	    &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX]);
32825678Spl196000 
32835678Spl196000 	/* Check for queue empty */
32845678Spl196000 	if (ci == pi)
32855678Spl196000 		return (AACERR);
32865678Spl196000 
32875678Spl196000 	if (pi >= aac_qinfo[queue].size)
32885678Spl196000 		pi = 0;
32895678Spl196000 
32905678Spl196000 	/* Check for queue full */
32915678Spl196000 	if (ci == pi + 1)
32925678Spl196000 		unfull = 1;
32935678Spl196000 
32945678Spl196000 	/*
32955678Spl196000 	 * The controller does not wrap the queue,
32965678Spl196000 	 * so we have to do it by ourselves
32975678Spl196000 	 */
32985678Spl196000 	if (ci >= aac_qinfo[queue].size)
32995678Spl196000 		ci = 0;
33005678Spl196000 
33015678Spl196000 	/* Fetch the entry */
33027100Spl196000 	(void) ddi_dma_sync(dma, (uintptr_t)(softs->qentries[queue] + pi) - \
33037100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (struct aac_queue_entry),
33045678Spl196000 	    DDI_DMA_SYNC_FORCPU);
33055678Spl196000 	if (aac_check_dma_handle(dma) != DDI_SUCCESS) {
33065678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
33075678Spl196000 		return (AACERR);
33085678Spl196000 	}
33095678Spl196000 
33105678Spl196000 	switch (queue) {
33115678Spl196000 	case AAC_HOST_NORM_RESP_Q:
33125678Spl196000 	case AAC_HOST_HIGH_RESP_Q:
33135678Spl196000 		*idxp = ddi_get32(acc,
33145678Spl196000 		    &(softs->qentries[queue] + ci)->aq_fib_addr);
33155678Spl196000 		break;
33165678Spl196000 
33175678Spl196000 	case AAC_HOST_NORM_CMD_Q:
33185678Spl196000 	case AAC_HOST_HIGH_CMD_Q:
33195678Spl196000 		*idxp = ddi_get32(acc,
33205678Spl196000 		    &(softs->qentries[queue] + ci)->aq_fib_addr) / AAC_FIB_SIZE;
33215678Spl196000 		break;
33225678Spl196000 
33235678Spl196000 	default:
33245678Spl196000 		cmn_err(CE_NOTE, "!Invalid queue in aac_fib_dequeue()");
33255678Spl196000 		return (AACERR);
33265678Spl196000 	}
33275678Spl196000 
33285678Spl196000 	/* Update consumer index */
33295678Spl196000 	ddi_put32(acc, &softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX],
33305678Spl196000 	    ci + 1);
33315678Spl196000 	(void) ddi_dma_sync(dma,
33327100Spl196000 	    (uintptr_t)&softs->qtablep->qt_qindex[queue][AAC_CONSUMER_INDEX] - \
33337100Spl196000 	    (uintptr_t)softs->comm_space, sizeof (uint32_t),
33345678Spl196000 	    DDI_DMA_SYNC_FORDEV);
33355678Spl196000 
33365678Spl196000 	if (unfull && aac_qinfo[queue].notify != 0)
33375678Spl196000 		AAC_NOTIFY(softs, aac_qinfo[queue].notify);
33385678Spl196000 	return (AACOK);
33395678Spl196000 }
33405678Spl196000 
33415678Spl196000 static struct aac_mntinforesp *
aac_get_mntinfo(struct aac_softstate * softs,int cid)334211348SZhongyan.Gu@Sun.COM aac_get_mntinfo(struct aac_softstate *softs, int cid)
334311348SZhongyan.Gu@Sun.COM {
334411348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
334511348SZhongyan.Gu@Sun.COM 	struct aac_fib *fibp = softs->sync_ac.slotp->fibp;
33465678Spl196000 	struct aac_mntinfo *mi = (struct aac_mntinfo *)&fibp->data[0];
33475678Spl196000 	struct aac_mntinforesp *mir;
33485678Spl196000 
33495678Spl196000 	ddi_put32(acc, &mi->Command, /* Use 64-bit LBA if enabled */
33505678Spl196000 	    (softs->flags & AAC_FLAGS_LBA_64BIT) ?
33515678Spl196000 	    VM_NameServe64 : VM_NameServe);
33525678Spl196000 	ddi_put32(acc, &mi->MntType, FT_FILESYS);
33535678Spl196000 	ddi_put32(acc, &mi->MntCount, cid);
33545678Spl196000 
33555678Spl196000 	if (aac_sync_fib(softs, ContainerCommand,
33565678Spl196000 	    AAC_FIB_SIZEOF(struct aac_mntinfo)) == AACERR) {
33575678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Error probe container %d", cid);
33585678Spl196000 		return (NULL);
33595678Spl196000 	}
33605678Spl196000 
33615678Spl196000 	mir = (struct aac_mntinforesp *)&fibp->data[0];
33625678Spl196000 	if (ddi_get32(acc, &mir->Status) == ST_OK)
33635678Spl196000 		return (mir);
33645678Spl196000 	return (NULL);
33655678Spl196000 }
33665678Spl196000 
33675678Spl196000 static int
aac_get_container_count(struct aac_softstate * softs,int * count)33685678Spl196000 aac_get_container_count(struct aac_softstate *softs, int *count)
33695678Spl196000 {
337011348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
33715678Spl196000 	struct aac_mntinforesp *mir;
337211348SZhongyan.Gu@Sun.COM 	int rval;
337311348SZhongyan.Gu@Sun.COM 
337411348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
337511348SZhongyan.Gu@Sun.COM 	acc = softs->sync_ac.slotp->fib_acc_handle;
337611348SZhongyan.Gu@Sun.COM 
337711348SZhongyan.Gu@Sun.COM 	if ((mir = aac_get_mntinfo(softs, 0)) == NULL) {
337811348SZhongyan.Gu@Sun.COM 		rval = AACERR;
337911348SZhongyan.Gu@Sun.COM 		goto finish;
338011348SZhongyan.Gu@Sun.COM 	}
33815678Spl196000 	*count = ddi_get32(acc, &mir->MntRespCount);
33825678Spl196000 	if (*count > AAC_MAX_LD) {
33835678Spl196000 		AACDB_PRINT(softs, CE_CONT,
33845678Spl196000 		    "container count(%d) > AAC_MAX_LD", *count);
338511348SZhongyan.Gu@Sun.COM 		rval = AACERR;
338611348SZhongyan.Gu@Sun.COM 		goto finish;
338711348SZhongyan.Gu@Sun.COM 	}
338811348SZhongyan.Gu@Sun.COM 	rval = AACOK;
338911348SZhongyan.Gu@Sun.COM 
339011348SZhongyan.Gu@Sun.COM finish:
339111348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
339211348SZhongyan.Gu@Sun.COM 	return (rval);
33935678Spl196000 }
33945678Spl196000 
33955678Spl196000 static int
aac_get_container_uid(struct aac_softstate * softs,uint32_t cid,uint32_t * uid)33965678Spl196000 aac_get_container_uid(struct aac_softstate *softs, uint32_t cid, uint32_t *uid)
33975678Spl196000 {
339811348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
33995678Spl196000 	struct aac_Container *ct = (struct aac_Container *) \
340011348SZhongyan.Gu@Sun.COM 	    &softs->sync_ac.slotp->fibp->data[0];
34015678Spl196000 
34025678Spl196000 	bzero(ct, sizeof (*ct) - CT_PACKET_SIZE);
34035678Spl196000 	ddi_put32(acc, &ct->Command, VM_ContainerConfig);
34045678Spl196000 	ddi_put32(acc, &ct->CTCommand.command, CT_CID_TO_32BITS_UID);
34055678Spl196000 	ddi_put32(acc, &ct->CTCommand.param[0], cid);
34065678Spl196000 
34075678Spl196000 	if (aac_sync_fib(softs, ContainerCommand,
34085678Spl196000 	    AAC_FIB_SIZEOF(struct aac_Container)) == AACERR)
34095678Spl196000 		return (AACERR);
34105678Spl196000 	if (ddi_get32(acc, &ct->CTCommand.param[0]) != CT_OK)
34115678Spl196000 		return (AACERR);
34125678Spl196000 
34135678Spl196000 	*uid = ddi_get32(acc, &ct->CTCommand.param[1]);
34145678Spl196000 	return (AACOK);
34155678Spl196000 }
34165678Spl196000 
341711348SZhongyan.Gu@Sun.COM /*
341811348SZhongyan.Gu@Sun.COM  * Request information of the container cid
341911348SZhongyan.Gu@Sun.COM  */
342011348SZhongyan.Gu@Sun.COM static struct aac_mntinforesp *
aac_get_container_info(struct aac_softstate * softs,int cid)342111348SZhongyan.Gu@Sun.COM aac_get_container_info(struct aac_softstate *softs, int cid)
342211348SZhongyan.Gu@Sun.COM {
342311348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = softs->sync_ac.slotp->fib_acc_handle;
342411348SZhongyan.Gu@Sun.COM 	struct aac_mntinforesp *mir;
342511348SZhongyan.Gu@Sun.COM 	int rval_uid;
342611348SZhongyan.Gu@Sun.COM 	uint32_t uid;
342711348SZhongyan.Gu@Sun.COM 
342811348SZhongyan.Gu@Sun.COM 	/* Get container UID first so that it will not overwrite mntinfo */
342911348SZhongyan.Gu@Sun.COM 	rval_uid = aac_get_container_uid(softs, cid, &uid);
343011348SZhongyan.Gu@Sun.COM 
343111348SZhongyan.Gu@Sun.COM 	/* Get container basic info */
343211348SZhongyan.Gu@Sun.COM 	if ((mir = aac_get_mntinfo(softs, cid)) == NULL) {
343311348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_CONT,
343411348SZhongyan.Gu@Sun.COM 		    "query container %d info failed", cid);
343511348SZhongyan.Gu@Sun.COM 		return (NULL);
343611348SZhongyan.Gu@Sun.COM 	}
343711348SZhongyan.Gu@Sun.COM 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE)
343811348SZhongyan.Gu@Sun.COM 		return (mir);
343911348SZhongyan.Gu@Sun.COM 	if (rval_uid != AACOK) {
344011348SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_CONT,
344111348SZhongyan.Gu@Sun.COM 		    "query container %d uid failed", cid);
344211348SZhongyan.Gu@Sun.COM 		return (NULL);
344311348SZhongyan.Gu@Sun.COM 	}
344411348SZhongyan.Gu@Sun.COM 
344511348SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &mir->Status, uid);
344611348SZhongyan.Gu@Sun.COM 	return (mir);
344711348SZhongyan.Gu@Sun.COM }
344811348SZhongyan.Gu@Sun.COM 
344911964SXin.Chen@Sun.COM static enum aac_cfg_event
aac_probe_container(struct aac_softstate * softs,uint32_t cid)34505678Spl196000 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
34515678Spl196000 {
345211964SXin.Chen@Sun.COM 	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
34535678Spl196000 	struct aac_container *dvp = &softs->containers[cid];
345411964SXin.Chen@Sun.COM 	struct aac_mntinforesp *mir;
345511348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
345611348SZhongyan.Gu@Sun.COM 
345711348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
345811348SZhongyan.Gu@Sun.COM 	acc = softs->sync_ac.slotp->fib_acc_handle;
34595678Spl196000 
34605678Spl196000 	/* Get container basic info */
346111348SZhongyan.Gu@Sun.COM 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
346211964SXin.Chen@Sun.COM 		/* AAC_CFG_NULL_NOEXIST */
346311348SZhongyan.Gu@Sun.COM 		goto finish;
346411348SZhongyan.Gu@Sun.COM 	}
34655678Spl196000 
34665678Spl196000 	if (ddi_get32(acc, &mir->MntObj.VolType) == CT_NONE) {
34677567SXin.Chen@Sun.COM 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
34685678Spl196000 			AACDB_PRINT(softs, CE_NOTE,
34695678Spl196000 			    ">>> Container %d deleted", cid);
34707567SXin.Chen@Sun.COM 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
347111964SXin.Chen@Sun.COM 			event = AAC_CFG_DELETE;
347211964SXin.Chen@Sun.COM 		}
347311964SXin.Chen@Sun.COM 		/* AAC_CFG_NULL_NOEXIST */
34745678Spl196000 	} else {
347511964SXin.Chen@Sun.COM 		uint64_t size;
347611964SXin.Chen@Sun.COM 		uint32_t uid;
347711964SXin.Chen@Sun.COM 
347811964SXin.Chen@Sun.COM 		event = AAC_CFG_NULL_EXIST;
347911964SXin.Chen@Sun.COM 
34805678Spl196000 		size = AAC_MIR_SIZE(softs, acc, mir);
348111348SZhongyan.Gu@Sun.COM 		uid = ddi_get32(acc, &mir->Status);
34827567SXin.Chen@Sun.COM 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
34835678Spl196000 			if (dvp->uid != uid) {
34845678Spl196000 				AACDB_PRINT(softs, CE_WARN,
34855678Spl196000 				    ">>> Container %u uid changed to %d",
34865678Spl196000 				    cid, uid);
34875678Spl196000 				dvp->uid = uid;
348811964SXin.Chen@Sun.COM 				event = AAC_CFG_CHANGE;
34895678Spl196000 			}
34905678Spl196000 			if (dvp->size != size) {
34915678Spl196000 				AACDB_PRINT(softs, CE_NOTE,
34925678Spl196000 				    ">>> Container %u size changed to %"PRIu64,
34935678Spl196000 				    cid, size);
34945678Spl196000 				dvp->size = size;
349511964SXin.Chen@Sun.COM 				event = AAC_CFG_CHANGE;
34965678Spl196000 			}
34975678Spl196000 		} else { /* Init new container */
34985678Spl196000 			AACDB_PRINT(softs, CE_NOTE,
34997567SXin.Chen@Sun.COM 			    ">>> Container %d added: " \
35007567SXin.Chen@Sun.COM 			    "size=0x%x.%08x, type=%d, name=%s",
35017567SXin.Chen@Sun.COM 			    cid,
35027567SXin.Chen@Sun.COM 			    ddi_get32(acc, &mir->MntObj.CapacityHigh),
35037567SXin.Chen@Sun.COM 			    ddi_get32(acc, &mir->MntObj.Capacity),
35047567SXin.Chen@Sun.COM 			    ddi_get32(acc, &mir->MntObj.VolType),
35057567SXin.Chen@Sun.COM 			    mir->MntObj.FileSystemName);
35067567SXin.Chen@Sun.COM 			dvp->dev.flags |= AAC_DFLAG_VALID;
35077567SXin.Chen@Sun.COM 			dvp->dev.type = AAC_DEV_LD;
35085678Spl196000 
35095678Spl196000 			dvp->cid = cid;
35105678Spl196000 			dvp->uid = uid;
35115678Spl196000 			dvp->size = size;
35125678Spl196000 			dvp->locked = 0;
35135678Spl196000 			dvp->deleted = 0;
351411964SXin.Chen@Sun.COM 
351511964SXin.Chen@Sun.COM 			event = AAC_CFG_ADD;
351611964SXin.Chen@Sun.COM 		}
351711964SXin.Chen@Sun.COM 	}
351811348SZhongyan.Gu@Sun.COM 
351911348SZhongyan.Gu@Sun.COM finish:
352011348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
352111964SXin.Chen@Sun.COM 	return (event);
35225678Spl196000 }
35235678Spl196000 
35245678Spl196000 /*
35255678Spl196000  * Do a rescan of all the possible containers and update the container list
35267567SXin.Chen@Sun.COM  * with newly online/offline containers, and prepare for autoconfiguration.
35275678Spl196000  */
35285678Spl196000 static int
aac_probe_containers(struct aac_softstate * softs)35295678Spl196000 aac_probe_containers(struct aac_softstate *softs)
35305678Spl196000 {
35315678Spl196000 	int i, count, total;
35325678Spl196000 
35335678Spl196000 	/* Loop over possible containers */
35345678Spl196000 	count = softs->container_count;
35355678Spl196000 	if (aac_get_container_count(softs, &count) == AACERR)
35365678Spl196000 		return (AACERR);
353711964SXin.Chen@Sun.COM 
35385678Spl196000 	for (i = total = 0; i < count; i++) {
353911964SXin.Chen@Sun.COM 		enum aac_cfg_event event = aac_probe_container(softs, i);
354011964SXin.Chen@Sun.COM 		if ((event != AAC_CFG_NULL_NOEXIST) &&
354111964SXin.Chen@Sun.COM 		    (event != AAC_CFG_NULL_EXIST)) {
354211964SXin.Chen@Sun.COM 			(void) aac_handle_dr(softs, i, -1, event);
35435678Spl196000 			total++;
354411964SXin.Chen@Sun.COM 		}
354511964SXin.Chen@Sun.COM 	}
354611964SXin.Chen@Sun.COM 
35475678Spl196000 	if (count < softs->container_count) {
35485678Spl196000 		struct aac_container *dvp;
35495678Spl196000 
35505678Spl196000 		for (dvp = &softs->containers[count];
35515678Spl196000 		    dvp < &softs->containers[softs->container_count]; dvp++) {
35527567SXin.Chen@Sun.COM 			if (!AAC_DEV_IS_VALID(&dvp->dev))
35535678Spl196000 				continue;
35545678Spl196000 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
35555678Spl196000 			    dvp->cid);
35567567SXin.Chen@Sun.COM 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
355711964SXin.Chen@Sun.COM 			(void) aac_handle_dr(softs, dvp->cid, -1,
355811964SXin.Chen@Sun.COM 			    AAC_CFG_DELETE);
355911964SXin.Chen@Sun.COM 		}
356011964SXin.Chen@Sun.COM 	}
356111964SXin.Chen@Sun.COM 
35625678Spl196000 	softs->container_count = count;
35635678Spl196000 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
35645678Spl196000 	return (AACOK);
35655678Spl196000 }
35665678Spl196000 
35675678Spl196000 static int
aac_probe_jbod(struct aac_softstate * softs,int tgt,int event)3568*12408SZhongyan.Gu@Sun.COM aac_probe_jbod(struct aac_softstate *softs, int tgt, int event)
3569*12408SZhongyan.Gu@Sun.COM {
3570*12408SZhongyan.Gu@Sun.COM 	ASSERT(AAC_MAX_LD <= tgt < AAC_MAX_DEV(softs));
3571*12408SZhongyan.Gu@Sun.COM 	struct aac_device *dvp;
3572*12408SZhongyan.Gu@Sun.COM 	dvp = AAC_DEV(softs, tgt);
3573*12408SZhongyan.Gu@Sun.COM 
3574*12408SZhongyan.Gu@Sun.COM 	switch (event) {
3575*12408SZhongyan.Gu@Sun.COM 	case AAC_CFG_ADD:
3576*12408SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_NOTE,
3577*12408SZhongyan.Gu@Sun.COM 		    ">>> Jbod %d added", tgt - AAC_MAX_LD);
3578*12408SZhongyan.Gu@Sun.COM 		dvp->flags |= AAC_DFLAG_VALID;
3579*12408SZhongyan.Gu@Sun.COM 		dvp->type = AAC_DEV_PD;
3580*12408SZhongyan.Gu@Sun.COM 		break;
3581*12408SZhongyan.Gu@Sun.COM 	case AAC_CFG_DELETE:
3582*12408SZhongyan.Gu@Sun.COM 		AACDB_PRINT(softs, CE_NOTE,
3583*12408SZhongyan.Gu@Sun.COM 		    ">>> Jbod %d deleted", tgt - AAC_MAX_LD);
3584*12408SZhongyan.Gu@Sun.COM 		dvp->flags &= ~AAC_DFLAG_VALID;
3585*12408SZhongyan.Gu@Sun.COM 		break;
3586*12408SZhongyan.Gu@Sun.COM 	default:
3587*12408SZhongyan.Gu@Sun.COM 		return (AACERR);
3588*12408SZhongyan.Gu@Sun.COM 	}
3589*12408SZhongyan.Gu@Sun.COM 	(void) aac_handle_dr(softs, tgt, 0, event);
3590*12408SZhongyan.Gu@Sun.COM 	return (AACOK);
3591*12408SZhongyan.Gu@Sun.COM }
3592*12408SZhongyan.Gu@Sun.COM 
3593*12408SZhongyan.Gu@Sun.COM static int
aac_alloc_comm_space(struct aac_softstate * softs)35945678Spl196000 aac_alloc_comm_space(struct aac_softstate *softs)
35955678Spl196000 {
35965678Spl196000 	size_t rlen;
35975678Spl196000 	ddi_dma_cookie_t cookie;
35985678Spl196000 	uint_t cookien;
35995678Spl196000 
36005678Spl196000 	/* Allocate DMA for comm. space */
36015678Spl196000 	if (ddi_dma_alloc_handle(
36025678Spl196000 	    softs->devinfo_p,
36035678Spl196000 	    &softs->addr_dma_attr,
36045678Spl196000 	    DDI_DMA_SLEEP,
36055678Spl196000 	    NULL,
36065678Spl196000 	    &softs->comm_space_dma_handle) != DDI_SUCCESS) {
36075678Spl196000 		AACDB_PRINT(softs, CE_WARN,
36085678Spl196000 		    "Cannot alloc dma handle for communication area");
36095678Spl196000 		goto error;
36105678Spl196000 	}
36115678Spl196000 	if (ddi_dma_mem_alloc(
36125678Spl196000 	    softs->comm_space_dma_handle,
36135678Spl196000 	    sizeof (struct aac_comm_space),
36147567SXin.Chen@Sun.COM 	    &softs->acc_attr,
36155678Spl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
36165678Spl196000 	    DDI_DMA_SLEEP,
36175678Spl196000 	    NULL,
36185678Spl196000 	    (caddr_t *)&softs->comm_space,
36195678Spl196000 	    &rlen,
36205678Spl196000 	    &softs->comm_space_acc_handle) != DDI_SUCCESS) {
36215678Spl196000 		AACDB_PRINT(softs, CE_WARN,
36225678Spl196000 		    "Cannot alloc mem for communication area");
36235678Spl196000 		goto error;
36245678Spl196000 	}
36255678Spl196000 	if (ddi_dma_addr_bind_handle(
36265678Spl196000 	    softs->comm_space_dma_handle,
36275678Spl196000 	    NULL,
36285678Spl196000 	    (caddr_t)softs->comm_space,
36295678Spl196000 	    sizeof (struct aac_comm_space),
36305678Spl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
36315678Spl196000 	    DDI_DMA_SLEEP,
36325678Spl196000 	    NULL,
36335678Spl196000 	    &cookie,
36345678Spl196000 	    &cookien) != DDI_DMA_MAPPED) {
36355678Spl196000 		AACDB_PRINT(softs, CE_WARN,
36365678Spl196000 		    "DMA bind failed for communication area");
36375678Spl196000 		goto error;
36385678Spl196000 	}
36395678Spl196000 	softs->comm_space_phyaddr = cookie.dmac_address;
36405678Spl196000 
36415678Spl196000 	return (AACOK);
36425678Spl196000 error:
36435678Spl196000 	if (softs->comm_space_acc_handle) {
36445678Spl196000 		ddi_dma_mem_free(&softs->comm_space_acc_handle);
36455678Spl196000 		softs->comm_space_acc_handle = NULL;
36465678Spl196000 	}
36475678Spl196000 	if (softs->comm_space_dma_handle) {
36485678Spl196000 		ddi_dma_free_handle(&softs->comm_space_dma_handle);
36495678Spl196000 		softs->comm_space_dma_handle = NULL;
36505678Spl196000 	}
36515678Spl196000 	return (AACERR);
36525678Spl196000 }
36535678Spl196000 
36545678Spl196000 static void
aac_free_comm_space(struct aac_softstate * softs)36555678Spl196000 aac_free_comm_space(struct aac_softstate *softs)
36565678Spl196000 {
36575678Spl196000 
36585678Spl196000 	(void) ddi_dma_unbind_handle(softs->comm_space_dma_handle);
36595678Spl196000 	ddi_dma_mem_free(&softs->comm_space_acc_handle);
36605678Spl196000 	softs->comm_space_acc_handle = NULL;
36615678Spl196000 	ddi_dma_free_handle(&softs->comm_space_dma_handle);
36625678Spl196000 	softs->comm_space_dma_handle = NULL;
36635678Spl196000 	softs->comm_space_phyaddr = NULL;
36645678Spl196000 }
36655678Spl196000 
36665678Spl196000 /*
36675678Spl196000  * Initialize the data structures that are required for the communication
36685678Spl196000  * interface to operate
36695678Spl196000  */
36705678Spl196000 static int
aac_setup_comm_space(struct aac_softstate * softs)36715678Spl196000 aac_setup_comm_space(struct aac_softstate *softs)
36725678Spl196000 {
36735678Spl196000 	ddi_dma_handle_t dma = softs->comm_space_dma_handle;
36745678Spl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
36755678Spl196000 	uint32_t comm_space_phyaddr;
36765678Spl196000 	struct aac_adapter_init *initp;
36775678Spl196000 	int qoffset;
36785678Spl196000 
36795678Spl196000 	comm_space_phyaddr = softs->comm_space_phyaddr;
36805678Spl196000 
36815678Spl196000 	/* Setup adapter init struct */
36825678Spl196000 	initp = &softs->comm_space->init_data;
36835678Spl196000 	bzero(initp, sizeof (struct aac_adapter_init));
36845678Spl196000 
36855678Spl196000 	ddi_put32(acc, &initp->InitStructRevision, AAC_INIT_STRUCT_REVISION);
36865678Spl196000 	ddi_put32(acc, &initp->HostElapsedSeconds, ddi_get_time());
36875678Spl196000 
36885678Spl196000 	/* Setup new/old comm. specific data */
36895678Spl196000 	if (softs->flags & AAC_FLAGS_RAW_IO) {
369010976SZhongyan.Gu@Sun.COM 		uint32_t init_flags = 0;
369110976SZhongyan.Gu@Sun.COM 
369210976SZhongyan.Gu@Sun.COM 		if (softs->flags & AAC_FLAGS_NEW_COMM)
369310976SZhongyan.Gu@Sun.COM 			init_flags |= AAC_INIT_FLAGS_NEW_COMM_SUPPORTED;
369410976SZhongyan.Gu@Sun.COM 		/* AAC_SUPPORTED_POWER_MANAGEMENT */
369510976SZhongyan.Gu@Sun.COM 		init_flags |= AAC_INIT_FLAGS_DRIVER_SUPPORTS_PM;
369610976SZhongyan.Gu@Sun.COM 		init_flags |= AAC_INIT_FLAGS_DRIVER_USES_UTC_TIME;
369710976SZhongyan.Gu@Sun.COM 
36985678Spl196000 		ddi_put32(acc, &initp->InitStructRevision,
36995678Spl196000 		    AAC_INIT_STRUCT_REVISION_4);
370010976SZhongyan.Gu@Sun.COM 		ddi_put32(acc, &initp->InitFlags, init_flags);
37015678Spl196000 		/* Setup the preferred settings */
37025678Spl196000 		ddi_put32(acc, &initp->MaxIoCommands, softs->aac_max_fibs);
37035678Spl196000 		ddi_put32(acc, &initp->MaxIoSize,
37045678Spl196000 		    (softs->aac_max_sectors << 9));
37055678Spl196000 		ddi_put32(acc, &initp->MaxFibSize, softs->aac_max_fib_size);
37065678Spl196000 	} else {
37075678Spl196000 		/*
37085678Spl196000 		 * Tells the adapter about the physical location of various
37095678Spl196000 		 * important shared data structures
37105678Spl196000 		 */
37115678Spl196000 		ddi_put32(acc, &initp->AdapterFibsPhysicalAddress,
37125678Spl196000 		    comm_space_phyaddr + \
37135678Spl196000 		    offsetof(struct aac_comm_space, adapter_fibs));
37145678Spl196000 		ddi_put32(acc, &initp->AdapterFibsVirtualAddress, 0);
37155678Spl196000 		ddi_put32(acc, &initp->AdapterFibAlign, AAC_FIB_SIZE);
37165678Spl196000 		ddi_put32(acc, &initp->AdapterFibsSize,
37175678Spl196000 		    AAC_ADAPTER_FIBS * AAC_FIB_SIZE);
37185678Spl196000 		ddi_put32(acc, &initp->PrintfBufferAddress,
37195678Spl196000 		    comm_space_phyaddr + \
37205678Spl196000 		    offsetof(struct aac_comm_space, adapter_print_buf));
37215678Spl196000 		ddi_put32(acc, &initp->PrintfBufferSize,
37225678Spl196000 		    AAC_ADAPTER_PRINT_BUFSIZE);
37235678Spl196000 		ddi_put32(acc, &initp->MiniPortRevision,
37245678Spl196000 		    AAC_INIT_STRUCT_MINIPORT_REVISION);
37255678Spl196000 		ddi_put32(acc, &initp->HostPhysMemPages, AAC_MAX_PFN);
37265678Spl196000 
37275678Spl196000 		qoffset = (comm_space_phyaddr + \
37285678Spl196000 		    offsetof(struct aac_comm_space, qtable)) % \
37295678Spl196000 		    AAC_QUEUE_ALIGN;
37305678Spl196000 		if (qoffset)
37315678Spl196000 			qoffset = AAC_QUEUE_ALIGN - qoffset;
37325678Spl196000 		softs->qtablep = (struct aac_queue_table *) \
37335678Spl196000 		    ((char *)&softs->comm_space->qtable + qoffset);
37345678Spl196000 		ddi_put32(acc, &initp->CommHeaderAddress, comm_space_phyaddr + \
37355678Spl196000 		    offsetof(struct aac_comm_space, qtable) + qoffset);
37365678Spl196000 
37375678Spl196000 		/* Init queue table */
37385678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37395678Spl196000 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_PRODUCER_INDEX],
37405678Spl196000 		    AAC_HOST_NORM_CMD_ENTRIES);
37415678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37425678Spl196000 		    qt_qindex[AAC_HOST_NORM_CMD_Q][AAC_CONSUMER_INDEX],
37435678Spl196000 		    AAC_HOST_NORM_CMD_ENTRIES);
37445678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37455678Spl196000 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
37465678Spl196000 		    AAC_HOST_HIGH_CMD_ENTRIES);
37475678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37485678Spl196000 		    qt_qindex[AAC_HOST_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
37495678Spl196000 		    AAC_HOST_HIGH_CMD_ENTRIES);
37505678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37515678Spl196000 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_PRODUCER_INDEX],
37525678Spl196000 		    AAC_ADAP_NORM_CMD_ENTRIES);
37535678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37545678Spl196000 		    qt_qindex[AAC_ADAP_NORM_CMD_Q][AAC_CONSUMER_INDEX],
37555678Spl196000 		    AAC_ADAP_NORM_CMD_ENTRIES);
37565678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37575678Spl196000 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_PRODUCER_INDEX],
37585678Spl196000 		    AAC_ADAP_HIGH_CMD_ENTRIES);
37595678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37605678Spl196000 		    qt_qindex[AAC_ADAP_HIGH_CMD_Q][AAC_CONSUMER_INDEX],
37615678Spl196000 		    AAC_ADAP_HIGH_CMD_ENTRIES);
37625678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37635678Spl196000 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_PRODUCER_INDEX],
37645678Spl196000 		    AAC_HOST_NORM_RESP_ENTRIES);
37655678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37665678Spl196000 		    qt_qindex[AAC_HOST_NORM_RESP_Q][AAC_CONSUMER_INDEX],
37675678Spl196000 		    AAC_HOST_NORM_RESP_ENTRIES);
37685678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37695678Spl196000 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
37705678Spl196000 		    AAC_HOST_HIGH_RESP_ENTRIES);
37715678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37725678Spl196000 		    qt_qindex[AAC_HOST_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
37735678Spl196000 		    AAC_HOST_HIGH_RESP_ENTRIES);
37745678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37755678Spl196000 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_PRODUCER_INDEX],
37765678Spl196000 		    AAC_ADAP_NORM_RESP_ENTRIES);
37775678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37785678Spl196000 		    qt_qindex[AAC_ADAP_NORM_RESP_Q][AAC_CONSUMER_INDEX],
37795678Spl196000 		    AAC_ADAP_NORM_RESP_ENTRIES);
37805678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37815678Spl196000 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_PRODUCER_INDEX],
37825678Spl196000 		    AAC_ADAP_HIGH_RESP_ENTRIES);
37835678Spl196000 		ddi_put32(acc, &softs->qtablep-> \
37845678Spl196000 		    qt_qindex[AAC_ADAP_HIGH_RESP_Q][AAC_CONSUMER_INDEX],
37855678Spl196000 		    AAC_ADAP_HIGH_RESP_ENTRIES);
37865678Spl196000 
37875678Spl196000 		/* Init queue entries */
37885678Spl196000 		softs->qentries[AAC_HOST_NORM_CMD_Q] =
37895678Spl196000 		    &softs->qtablep->qt_HostNormCmdQueue[0];
37905678Spl196000 		softs->qentries[AAC_HOST_HIGH_CMD_Q] =
37915678Spl196000 		    &softs->qtablep->qt_HostHighCmdQueue[0];
37925678Spl196000 		softs->qentries[AAC_ADAP_NORM_CMD_Q] =
37935678Spl196000 		    &softs->qtablep->qt_AdapNormCmdQueue[0];
37945678Spl196000 		softs->qentries[AAC_ADAP_HIGH_CMD_Q] =
37955678Spl196000 		    &softs->qtablep->qt_AdapHighCmdQueue[0];
37965678Spl196000 		softs->qentries[AAC_HOST_NORM_RESP_Q] =
37975678Spl196000 		    &softs->qtablep->qt_HostNormRespQueue[0];
37985678Spl196000 		softs->qentries[AAC_HOST_HIGH_RESP_Q] =
37995678Spl196000 		    &softs->qtablep->qt_HostHighRespQueue[0];
38005678Spl196000 		softs->qentries[AAC_ADAP_NORM_RESP_Q] =
38015678Spl196000 		    &softs->qtablep->qt_AdapNormRespQueue[0];
38025678Spl196000 		softs->qentries[AAC_ADAP_HIGH_RESP_Q] =
38035678Spl196000 		    &softs->qtablep->qt_AdapHighRespQueue[0];
38045678Spl196000 	}
38055678Spl196000 	(void) ddi_dma_sync(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
38065678Spl196000 
38075678Spl196000 	/* Send init structure to the card */
38085678Spl196000 	if (aac_sync_mbcommand(softs, AAC_MONKER_INITSTRUCT,
38095678Spl196000 	    comm_space_phyaddr + \
38105678Spl196000 	    offsetof(struct aac_comm_space, init_data),
38115678Spl196000 	    0, 0, 0, NULL) == AACERR) {
38125678Spl196000 		AACDB_PRINT(softs, CE_WARN,
38135678Spl196000 		    "Cannot send init structure to adapter");
38145678Spl196000 		return (AACERR);
38155678Spl196000 	}
38165678Spl196000 
38175678Spl196000 	return (AACOK);
38185678Spl196000 }
38195678Spl196000 
38205678Spl196000 static uchar_t *
aac_vendor_id(struct aac_softstate * softs,uchar_t * buf)38215678Spl196000 aac_vendor_id(struct aac_softstate *softs, uchar_t *buf)
38225678Spl196000 {
38235678Spl196000 	(void) memset(buf, ' ', AAC_VENDOR_LEN);
38245678Spl196000 	bcopy(softs->vendor_name, buf, strlen(softs->vendor_name));
38255678Spl196000 	return (buf + AAC_VENDOR_LEN);
38265678Spl196000 }
38275678Spl196000 
38285678Spl196000 static uchar_t *
aac_product_id(struct aac_softstate * softs,uchar_t * buf)38295678Spl196000 aac_product_id(struct aac_softstate *softs, uchar_t *buf)
38305678Spl196000 {
38315678Spl196000 	(void) memset(buf, ' ', AAC_PRODUCT_LEN);
38325678Spl196000 	bcopy(softs->product_name, buf, strlen(softs->product_name));
38335678Spl196000 	return (buf + AAC_PRODUCT_LEN);
38345678Spl196000 }
38355678Spl196000 
38365678Spl196000 /*
38375678Spl196000  * Construct unit serial number from container uid
38385678Spl196000  */
38395678Spl196000 static uchar_t *
aac_lun_serialno(struct aac_softstate * softs,int tgt,uchar_t * buf)38405678Spl196000 aac_lun_serialno(struct aac_softstate *softs, int tgt, uchar_t *buf)
38415678Spl196000 {
38425678Spl196000 	int i, d;
38437567SXin.Chen@Sun.COM 	uint32_t uid;
38447567SXin.Chen@Sun.COM 
38457567SXin.Chen@Sun.COM 	ASSERT(tgt >= 0 && tgt < AAC_MAX_LD);
38467567SXin.Chen@Sun.COM 
38477567SXin.Chen@Sun.COM 	uid = softs->containers[tgt].uid;
38485678Spl196000 	for (i = 7; i >= 0; i--) {
38495678Spl196000 		d = uid & 0xf;
38505678Spl196000 		buf[i] = d > 9 ? 'A' + (d - 0xa) : '0' + d;
38515678Spl196000 		uid >>= 4;
38525678Spl196000 	}
38535678Spl196000 	return (buf + 8);
38545678Spl196000 }
38555678Spl196000 
38565678Spl196000 /*
38575678Spl196000  * SPC-3 7.5 INQUIRY command implementation
38585678Spl196000  */
38595678Spl196000 static void
aac_inquiry(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp)38605678Spl196000 aac_inquiry(struct aac_softstate *softs, struct scsi_pkt *pkt,
38615678Spl196000     union scsi_cdb *cdbp, struct buf *bp)
38625678Spl196000 {
38635678Spl196000 	int tgt = pkt->pkt_address.a_target;
38645678Spl196000 	char *b_addr = NULL;
38655678Spl196000 	uchar_t page = cdbp->cdb_opaque[2];
38665678Spl196000 
38675678Spl196000 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_CMDDT) {
38685678Spl196000 		/* Command Support Data is not supported */
38695678Spl196000 		aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST, 0x24, 0x00, 0);
38705678Spl196000 		return;
38715678Spl196000 	}
38725678Spl196000 
38735678Spl196000 	if (bp && bp->b_un.b_addr && bp->b_bcount) {
38745678Spl196000 		if (bp->b_flags & (B_PHYS | B_PAGEIO))
38755678Spl196000 			bp_mapin(bp);
38765678Spl196000 		b_addr = bp->b_un.b_addr;
38775678Spl196000 	}
38785678Spl196000 
38795678Spl196000 	if (cdbp->cdb_opaque[1] & AAC_CDB_INQUIRY_EVPD) {
38805678Spl196000 		uchar_t *vpdp = (uchar_t *)b_addr;
38815678Spl196000 		uchar_t *idp, *sp;
38825678Spl196000 
38835678Spl196000 		/* SPC-3 8.4 Vital product data parameters */
38845678Spl196000 		switch (page) {
38855678Spl196000 		case 0x00:
38865678Spl196000 			/* Supported VPD pages */
38876799Sjd218194 			if (vpdp == NULL ||
38886799Sjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 3))
38895678Spl196000 				return;
38905678Spl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
38915678Spl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x00;
38925678Spl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = 3;
38935678Spl196000 
38945678Spl196000 			vpdp[AAC_VPD_PAGE_DATA] = 0x00;
38955678Spl196000 			vpdp[AAC_VPD_PAGE_DATA + 1] = 0x80;
38965678Spl196000 			vpdp[AAC_VPD_PAGE_DATA + 2] = 0x83;
38975678Spl196000 
38985678Spl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
38995678Spl196000 			break;
39005678Spl196000 
39015678Spl196000 		case 0x80:
39025678Spl196000 			/* Unit serial number page */
39036799Sjd218194 			if (vpdp == NULL ||
39046799Sjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 8))
39055678Spl196000 				return;
39065678Spl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
39075678Spl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x80;
39085678Spl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = 8;
39095678Spl196000 
39105678Spl196000 			sp = &vpdp[AAC_VPD_PAGE_DATA];
39115678Spl196000 			(void) aac_lun_serialno(softs, tgt, sp);
39125678Spl196000 
39135678Spl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
39145678Spl196000 			break;
39155678Spl196000 
39165678Spl196000 		case 0x83:
39175678Spl196000 			/* Device identification page */
39186799Sjd218194 			if (vpdp == NULL ||
39196799Sjd218194 			    bp->b_bcount < (AAC_VPD_PAGE_DATA + 32))
39205678Spl196000 				return;
39215678Spl196000 			bzero(vpdp, AAC_VPD_PAGE_LENGTH);
39225678Spl196000 			vpdp[AAC_VPD_PAGE_CODE] = 0x83;
39235678Spl196000 
39245678Spl196000 			idp = &vpdp[AAC_VPD_PAGE_DATA];
39255678Spl196000 			bzero(idp, AAC_VPD_ID_LENGTH);
39265678Spl196000 			idp[AAC_VPD_ID_CODESET] = 0x02;
39275678Spl196000 			idp[AAC_VPD_ID_TYPE] = 0x01;
39285678Spl196000 
39295678Spl196000 			/*
39305678Spl196000 			 * SPC-3 Table 111 - Identifier type
39315678Spl196000 			 * One recommanded method of constructing the remainder
39325678Spl196000 			 * of identifier field is to concatenate the product
39335678Spl196000 			 * identification field from the standard INQUIRY data
39345678Spl196000 			 * field and the product serial number field from the
39355678Spl196000 			 * unit serial number page.
39365678Spl196000 			 */
39375678Spl196000 			sp = &idp[AAC_VPD_ID_DATA];
39385678Spl196000 			sp = aac_vendor_id(softs, sp);
39395678Spl196000 			sp = aac_product_id(softs, sp);
39405678Spl196000 			sp = aac_lun_serialno(softs, tgt, sp);
39417100Spl196000 			idp[AAC_VPD_ID_LENGTH] = (uintptr_t)sp - \
39427100Spl196000 			    (uintptr_t)&idp[AAC_VPD_ID_DATA];
39437100Spl196000 
39447100Spl196000 			vpdp[AAC_VPD_PAGE_LENGTH] = (uintptr_t)sp - \
39457100Spl196000 			    (uintptr_t)&vpdp[AAC_VPD_PAGE_DATA];
39465678Spl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
39475678Spl196000 			break;
39485678Spl196000 
39495678Spl196000 		default:
39505678Spl196000 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
39515678Spl196000 			    0x24, 0x00, 0);
39525678Spl196000 			break;
39535678Spl196000 		}
39545678Spl196000 	} else {
39555678Spl196000 		struct scsi_inquiry *inqp = (struct scsi_inquiry *)b_addr;
39565678Spl196000 		size_t len = sizeof (struct scsi_inquiry);
39575678Spl196000 
39585678Spl196000 		if (page != 0) {
39595678Spl196000 			aac_set_arq_data(pkt, KEY_ILLEGAL_REQUEST,
39605678Spl196000 			    0x24, 0x00, 0);
39615678Spl196000 			return;
39625678Spl196000 		}
39636799Sjd218194 		if (inqp == NULL || bp->b_bcount < len)
39645678Spl196000 			return;
39655678Spl196000 
39665678Spl196000 		bzero(inqp, len);
39675678Spl196000 		inqp->inq_len = AAC_ADDITIONAL_LEN;
39685678Spl196000 		inqp->inq_ansi = AAC_ANSI_VER;
39695678Spl196000 		inqp->inq_rdf = AAC_RESP_DATA_FORMAT;
39705678Spl196000 		(void) aac_vendor_id(softs, (uchar_t *)inqp->inq_vid);
39715678Spl196000 		(void) aac_product_id(softs, (uchar_t *)inqp->inq_pid);
39725678Spl196000 		bcopy("V1.0", inqp->inq_revision, 4);
39735678Spl196000 		inqp->inq_cmdque = 1; /* enable tagged-queuing */
39745678Spl196000 		/*
39755678Spl196000 		 * For "sd-max-xfer-size" property which may impact performance
39765678Spl196000 		 * when IO threads increase.
39775678Spl196000 		 */
39785678Spl196000 		inqp->inq_wbus32 = 1;
39795678Spl196000 
39805678Spl196000 		pkt->pkt_state |= STATE_XFERRED_DATA;
39815678Spl196000 	}
39825678Spl196000 }
39835678Spl196000 
39845678Spl196000 /*
39855678Spl196000  * SPC-3 7.10 MODE SENSE command implementation
39865678Spl196000  */
39875678Spl196000 static void
aac_mode_sense(struct aac_softstate * softs,struct scsi_pkt * pkt,union scsi_cdb * cdbp,struct buf * bp,int capacity)39885678Spl196000 aac_mode_sense(struct aac_softstate *softs, struct scsi_pkt *pkt,
39895678Spl196000     union scsi_cdb *cdbp, struct buf *bp, int capacity)
39905678Spl196000 {
39915678Spl196000 	uchar_t pagecode;
39925678Spl196000 	struct mode_header *headerp;
39936799Sjd218194 	struct mode_header_g1 *g1_headerp;
39945678Spl196000 	unsigned int ncyl;
39956799Sjd218194 	caddr_t sense_data;
39966799Sjd218194 	caddr_t next_page;
39976799Sjd218194 	size_t sdata_size;
39986799Sjd218194 	size_t pages_size;
39996799Sjd218194 	int unsupport_page = 0;
40006799Sjd218194 
40016799Sjd218194 	ASSERT(cdbp->scc_cmd == SCMD_MODE_SENSE ||
40026799Sjd218194 	    cdbp->scc_cmd == SCMD_MODE_SENSE_G1);
40035678Spl196000 
40045678Spl196000 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
40055678Spl196000 		return;
40065678Spl196000 
40075678Spl196000 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
40085678Spl196000 		bp_mapin(bp);
40095678Spl196000 	pkt->pkt_state |= STATE_XFERRED_DATA;
40106799Sjd218194 	pagecode = cdbp->cdb_un.sg.scsi[0] & 0x3F;
40116799Sjd218194 
40126799Sjd218194 	/* calculate the size of needed buffer */
40136799Sjd218194 	if (cdbp->scc_cmd == SCMD_MODE_SENSE)
40146799Sjd218194 		sdata_size = MODE_HEADER_LENGTH;
40156799Sjd218194 	else /* must be SCMD_MODE_SENSE_G1 */
40166799Sjd218194 		sdata_size = MODE_HEADER_LENGTH_G1;
40176799Sjd218194 
40186799Sjd218194 	pages_size = 0;
40195678Spl196000 	switch (pagecode) {
40205678Spl196000 	case SD_MODE_SENSE_PAGE3_CODE:
40216799Sjd218194 		pages_size += sizeof (struct mode_format);
40226799Sjd218194 		break;
40236799Sjd218194 
40246799Sjd218194 	case SD_MODE_SENSE_PAGE4_CODE:
40256799Sjd218194 		pages_size += sizeof (struct mode_geometry);
40266799Sjd218194 		break;
40276799Sjd218194 
40286799Sjd218194 	case MODEPAGE_CTRL_MODE:
40296799Sjd218194 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
40306799Sjd218194 			pages_size += sizeof (struct mode_control_scsi3);
40316799Sjd218194 		} else {
40326799Sjd218194 			unsupport_page = 1;
40336799Sjd218194 		}
40346799Sjd218194 		break;
40356799Sjd218194 
40366799Sjd218194 	case MODEPAGE_ALLPAGES:
40376799Sjd218194 		if (softs->flags & AAC_FLAGS_LBA_64BIT) {
40386799Sjd218194 			pages_size += sizeof (struct mode_format) +
40396799Sjd218194 			    sizeof (struct mode_geometry) +
40406799Sjd218194 			    sizeof (struct mode_control_scsi3);
40416799Sjd218194 		} else {
40426799Sjd218194 			pages_size += sizeof (struct mode_format) +
40436799Sjd218194 			    sizeof (struct mode_geometry);
40446799Sjd218194 		}
40456799Sjd218194 		break;
40466799Sjd218194 
40476799Sjd218194 	default:
40486799Sjd218194 		/* unsupported pages */
40496799Sjd218194 		unsupport_page = 1;
40506799Sjd218194 	}
40516799Sjd218194 
40526799Sjd218194 	/* allocate buffer to fill the send data */
40536799Sjd218194 	sdata_size += pages_size;
40546799Sjd218194 	sense_data = kmem_zalloc(sdata_size, KM_SLEEP);
40556799Sjd218194 
40566799Sjd218194 	if (cdbp->scc_cmd == SCMD_MODE_SENSE) {
40576799Sjd218194 		headerp = (struct mode_header *)sense_data;
40586799Sjd218194 		headerp->length = MODE_HEADER_LENGTH + pages_size -
40596799Sjd218194 		    sizeof (headerp->length);
40606799Sjd218194 		headerp->bdesc_length = 0;
40616799Sjd218194 		next_page = sense_data + sizeof (struct mode_header);
40626799Sjd218194 	} else {
40637100Spl196000 		g1_headerp = (void *)sense_data;
40647000Sjd218194 		g1_headerp->length = BE_16(MODE_HEADER_LENGTH_G1 + pages_size -
40657000Sjd218194 		    sizeof (g1_headerp->length));
40666799Sjd218194 		g1_headerp->bdesc_length = 0;
40676799Sjd218194 		next_page = sense_data + sizeof (struct mode_header_g1);
40686799Sjd218194 	}
40696799Sjd218194 
40706799Sjd218194 	if (unsupport_page)
40716799Sjd218194 		goto finish;
40726799Sjd218194 
40736799Sjd218194 	if (pagecode == SD_MODE_SENSE_PAGE3_CODE ||
40746799Sjd218194 	    pagecode == MODEPAGE_ALLPAGES) {
40756799Sjd218194 		/* SBC-3 7.1.3.3 Format device page */
40766799Sjd218194 		struct mode_format *page3p;
40776799Sjd218194 
40787100Spl196000 		page3p = (void *)next_page;
40795678Spl196000 		page3p->mode_page.code = SD_MODE_SENSE_PAGE3_CODE;
40805678Spl196000 		page3p->mode_page.length = sizeof (struct mode_format);
40815678Spl196000 		page3p->data_bytes_sect = BE_16(AAC_SECTOR_SIZE);
40825678Spl196000 		page3p->sect_track = BE_16(AAC_SECTORS_PER_TRACK);
40836799Sjd218194 
40846799Sjd218194 		next_page += sizeof (struct mode_format);
40856799Sjd218194 	}
40866799Sjd218194 
40876799Sjd218194 	if (pagecode == SD_MODE_SENSE_PAGE4_CODE ||
40886799Sjd218194 	    pagecode == MODEPAGE_ALLPAGES) {
40896799Sjd218194 		/* SBC-3 7.1.3.8 Rigid disk device geometry page */
40906799Sjd218194 		struct mode_geometry *page4p;
40916799Sjd218194 
40927100Spl196000 		page4p = (void *)next_page;
40935678Spl196000 		page4p->mode_page.code = SD_MODE_SENSE_PAGE4_CODE;
40945678Spl196000 		page4p->mode_page.length = sizeof (struct mode_geometry);
40955678Spl196000 		page4p->heads = AAC_NUMBER_OF_HEADS;
40965678Spl196000 		page4p->rpm = BE_16(AAC_ROTATION_SPEED);
40975678Spl196000 		ncyl = capacity / (AAC_NUMBER_OF_HEADS * AAC_SECTORS_PER_TRACK);
40985678Spl196000 		page4p->cyl_lb = ncyl & 0xff;
40995678Spl196000 		page4p->cyl_mb = (ncyl >> 8) & 0xff;
41005678Spl196000 		page4p->cyl_ub = (ncyl >> 16) & 0xff;
41016799Sjd218194 
41026799Sjd218194 		next_page += sizeof (struct mode_geometry);
41036799Sjd218194 	}
41046799Sjd218194 
41056799Sjd218194 	if ((pagecode == MODEPAGE_CTRL_MODE || pagecode == MODEPAGE_ALLPAGES) &&
41066799Sjd218194 	    softs->flags & AAC_FLAGS_LBA_64BIT) {
41076799Sjd218194 		/* 64-bit LBA need large sense data */
41086799Sjd218194 		struct mode_control_scsi3 *mctl;
41096799Sjd218194 
41107100Spl196000 		mctl = (void *)next_page;
41116799Sjd218194 		mctl->mode_page.code = MODEPAGE_CTRL_MODE;
41126799Sjd218194 		mctl->mode_page.length =
41136799Sjd218194 		    sizeof (struct mode_control_scsi3) -
41146799Sjd218194 		    sizeof (struct mode_page);
41156799Sjd218194 		mctl->d_sense = 1;
41166799Sjd218194 	}
41176799Sjd218194 
41186799Sjd218194 finish:
41196799Sjd218194 	/* copyout the valid data. */
41206799Sjd218194 	bcopy(sense_data, bp->b_un.b_addr, min(sdata_size, bp->b_bcount));
41216799Sjd218194 	kmem_free(sense_data, sdata_size);
41225678Spl196000 }
41235678Spl196000 
41247567SXin.Chen@Sun.COM static int
aac_name_node(dev_info_t * dip,char * name,int len)41257567SXin.Chen@Sun.COM aac_name_node(dev_info_t *dip, char *name, int len)
41267567SXin.Chen@Sun.COM {
41277567SXin.Chen@Sun.COM 	int tgt, lun;
41287567SXin.Chen@Sun.COM 
41297567SXin.Chen@Sun.COM 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
41307567SXin.Chen@Sun.COM 	    DDI_PROP_DONTPASS, "target", -1);
41317567SXin.Chen@Sun.COM 	if (tgt == -1)
41327567SXin.Chen@Sun.COM 		return (DDI_FAILURE);
41337567SXin.Chen@Sun.COM 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
41347567SXin.Chen@Sun.COM 	    DDI_PROP_DONTPASS, "lun", -1);
41357567SXin.Chen@Sun.COM 	if (lun == -1)
41367567SXin.Chen@Sun.COM 		return (DDI_FAILURE);
41377567SXin.Chen@Sun.COM 
41387567SXin.Chen@Sun.COM 	(void) snprintf(name, len, "%x,%x", tgt, lun);
41397567SXin.Chen@Sun.COM 	return (DDI_SUCCESS);
41407567SXin.Chen@Sun.COM }
41417567SXin.Chen@Sun.COM 
41425678Spl196000 /*ARGSUSED*/
41435678Spl196000 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)41445678Spl196000 aac_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
41455678Spl196000     scsi_hba_tran_t *tran, struct scsi_device *sd)
41465678Spl196000 {
41475678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(tran);
41485678Spl196000 #if defined(DEBUG) || defined(__lock_lint)
41495678Spl196000 	int ctl = ddi_get_instance(softs->devinfo_p);
41505678Spl196000 #endif
41517567SXin.Chen@Sun.COM 	uint16_t tgt = sd->sd_address.a_target;
41527567SXin.Chen@Sun.COM 	uint8_t lun = sd->sd_address.a_lun;
41537567SXin.Chen@Sun.COM 	struct aac_device *dvp;
41545678Spl196000 
41555678Spl196000 	DBCALLED(softs, 2);
41565678Spl196000 
41577567SXin.Chen@Sun.COM 	if (ndi_dev_is_persistent_node(tgt_dip) == 0) {
41587567SXin.Chen@Sun.COM 		/*
41597567SXin.Chen@Sun.COM 		 * If no persistent node exist, we don't allow .conf node
41607567SXin.Chen@Sun.COM 		 * to be created.
41617567SXin.Chen@Sun.COM 		 */
41627567SXin.Chen@Sun.COM 		if (aac_find_child(softs, tgt, lun) != NULL) {
41637567SXin.Chen@Sun.COM 			if (ndi_merge_node(tgt_dip, aac_name_node) !=
41647567SXin.Chen@Sun.COM 			    DDI_SUCCESS)
41657567SXin.Chen@Sun.COM 				/* Create this .conf node */
41667567SXin.Chen@Sun.COM 				return (DDI_SUCCESS);
41677567SXin.Chen@Sun.COM 		}
41685678Spl196000 		return (DDI_FAILURE);
41695678Spl196000 	}
41705678Spl196000 
41715678Spl196000 	/*
41727567SXin.Chen@Sun.COM 	 * Only support container/phys. device that has been
41737567SXin.Chen@Sun.COM 	 * detected and valid
41745678Spl196000 	 */
41755678Spl196000 	mutex_enter(&softs->io_lock);
41767567SXin.Chen@Sun.COM 	if (tgt >= AAC_MAX_DEV(softs)) {
41777567SXin.Chen@Sun.COM 		AACDB_PRINT_TRAN(softs,
41787567SXin.Chen@Sun.COM 		    "aac_tran_tgt_init: c%dt%dL%d out", ctl, tgt, lun);
41795678Spl196000 		mutex_exit(&softs->io_lock);
41805678Spl196000 		return (DDI_FAILURE);
41815678Spl196000 	}
41827567SXin.Chen@Sun.COM 
41837567SXin.Chen@Sun.COM 	if (tgt < AAC_MAX_LD) {
41847567SXin.Chen@Sun.COM 		dvp = (struct aac_device *)&softs->containers[tgt];
41857567SXin.Chen@Sun.COM 		if (lun != 0 || !AAC_DEV_IS_VALID(dvp)) {
41867567SXin.Chen@Sun.COM 			AACDB_PRINT_TRAN(softs, "aac_tran_tgt_init: c%dt%dL%d",
41877567SXin.Chen@Sun.COM 			    ctl, tgt, lun);
41887567SXin.Chen@Sun.COM 			mutex_exit(&softs->io_lock);
41897567SXin.Chen@Sun.COM 			return (DDI_FAILURE);
41907567SXin.Chen@Sun.COM 		}
41917567SXin.Chen@Sun.COM 		/*
41927567SXin.Chen@Sun.COM 		 * Save the tgt_dip for the given target if one doesn't exist
41937567SXin.Chen@Sun.COM 		 * already. Dip's for non-existance tgt's will be cleared in
41947567SXin.Chen@Sun.COM 		 * tgt_free.
41957567SXin.Chen@Sun.COM 		 */
41967567SXin.Chen@Sun.COM 		if (softs->containers[tgt].dev.dip == NULL &&
41977567SXin.Chen@Sun.COM 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
41987567SXin.Chen@Sun.COM 			softs->containers[tgt].dev.dip = tgt_dip;
41997567SXin.Chen@Sun.COM 	} else {
42007567SXin.Chen@Sun.COM 		dvp = (struct aac_device *)&softs->nondasds[AAC_PD(tgt)];
4201*12408SZhongyan.Gu@Sun.COM 		/*
4202*12408SZhongyan.Gu@Sun.COM 		 * Save the tgt_dip for the given target if one doesn't exist
4203*12408SZhongyan.Gu@Sun.COM 		 * already. Dip's for non-existance tgt's will be cleared in
4204*12408SZhongyan.Gu@Sun.COM 		 * tgt_free.
4205*12408SZhongyan.Gu@Sun.COM 		 */
4206*12408SZhongyan.Gu@Sun.COM 
4207*12408SZhongyan.Gu@Sun.COM 		if (softs->nondasds[AAC_PD(tgt)].dev.dip  == NULL &&
4208*12408SZhongyan.Gu@Sun.COM 		    strcmp(ddi_driver_name(sd->sd_dev), "sd") == 0)
4209*12408SZhongyan.Gu@Sun.COM 			softs->nondasds[AAC_PD(tgt)].dev.dip  = tgt_dip;
42107567SXin.Chen@Sun.COM 	}
42117567SXin.Chen@Sun.COM 
42128551SPeng.L@Sun.COM 	if (softs->flags & AAC_FLAGS_BRKUP) {
42138551SPeng.L@Sun.COM 		if (ndi_prop_update_int(DDI_DEV_T_NONE, tgt_dip,
42148551SPeng.L@Sun.COM 		    "buf_break", 1) != DDI_PROP_SUCCESS) {
42158551SPeng.L@Sun.COM 			cmn_err(CE_CONT, "unable to create "
42168551SPeng.L@Sun.COM 			    "property for t%dL%d (buf_break)", tgt, lun);
42178551SPeng.L@Sun.COM 		}
42189106SSrivijitha.Dugganapalli@Sun.COM 	}
42198551SPeng.L@Sun.COM 
42207567SXin.Chen@Sun.COM 	AACDB_PRINT(softs, CE_NOTE,
42217567SXin.Chen@Sun.COM 	    "aac_tran_tgt_init: c%dt%dL%d ok (%s)", ctl, tgt, lun,
42227567SXin.Chen@Sun.COM 	    (dvp->type == AAC_DEV_PD) ? "pd" : "ld");
42237567SXin.Chen@Sun.COM 	mutex_exit(&softs->io_lock);
42247567SXin.Chen@Sun.COM 	return (DDI_SUCCESS);
42257567SXin.Chen@Sun.COM }
42267567SXin.Chen@Sun.COM 
42277567SXin.Chen@Sun.COM 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)42287567SXin.Chen@Sun.COM aac_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
42297567SXin.Chen@Sun.COM     scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
42307567SXin.Chen@Sun.COM {
42317567SXin.Chen@Sun.COM #ifndef __lock_lint
42327567SXin.Chen@Sun.COM 	_NOTE(ARGUNUSED(hba_dip, tgt_dip, hba_tran))
42337567SXin.Chen@Sun.COM #endif
42347567SXin.Chen@Sun.COM 
42357567SXin.Chen@Sun.COM 	struct aac_softstate *softs = SD2AAC(sd);
42367567SXin.Chen@Sun.COM 	int tgt = sd->sd_address.a_target;
42377567SXin.Chen@Sun.COM 
42387567SXin.Chen@Sun.COM 	mutex_enter(&softs->io_lock);
42397567SXin.Chen@Sun.COM 	if (tgt < AAC_MAX_LD) {
42407567SXin.Chen@Sun.COM 		if (softs->containers[tgt].dev.dip == tgt_dip)
42417567SXin.Chen@Sun.COM 			softs->containers[tgt].dev.dip = NULL;
42427567SXin.Chen@Sun.COM 	} else {
4243*12408SZhongyan.Gu@Sun.COM 		if (softs->nondasds[AAC_PD(tgt)].dev.dip == tgt_dip)
4244*12408SZhongyan.Gu@Sun.COM 			softs->nondasds[AAC_PD(tgt)].dev.dip = NULL;
42457567SXin.Chen@Sun.COM 		softs->nondasds[AAC_PD(tgt)].dev.flags &= ~AAC_DFLAG_VALID;
42467567SXin.Chen@Sun.COM 	}
42477567SXin.Chen@Sun.COM 	mutex_exit(&softs->io_lock);
42485678Spl196000 }
42495678Spl196000 
42505678Spl196000 /*
42515678Spl196000  * Check if the firmware is Up And Running. If it is in the Kernel Panic
42525678Spl196000  * state, (BlinkLED code + 1) is returned.
42535678Spl196000  *    0 -- firmware up and running
42545678Spl196000  *   -1 -- firmware dead
42555678Spl196000  *   >0 -- firmware kernel panic
42565678Spl196000  */
42575678Spl196000 static int
aac_check_adapter_health(struct aac_softstate * softs)42585678Spl196000 aac_check_adapter_health(struct aac_softstate *softs)
42595678Spl196000 {
42605678Spl196000 	int rval;
42615678Spl196000 
42625678Spl196000 	rval = PCI_MEM_GET32(softs, AAC_OMR0);
42635678Spl196000 
42645678Spl196000 	if (rval & AAC_KERNEL_UP_AND_RUNNING) {
42655678Spl196000 		rval = 0;
42665678Spl196000 	} else if (rval & AAC_KERNEL_PANIC) {
42675678Spl196000 		cmn_err(CE_WARN, "firmware panic");
42685678Spl196000 		rval = ((rval >> 16) & 0xff) + 1; /* avoid 0 as return value */
42695678Spl196000 	} else {
42705678Spl196000 		cmn_err(CE_WARN, "firmware dead");
42715678Spl196000 		rval = -1;
42725678Spl196000 	}
42735678Spl196000 	return (rval);
42745678Spl196000 }
42755678Spl196000 
42765678Spl196000 static void
aac_abort_iocmd(struct aac_softstate * softs,struct aac_cmd * acp,uchar_t reason)42775678Spl196000 aac_abort_iocmd(struct aac_softstate *softs, struct aac_cmd *acp,
42785678Spl196000     uchar_t reason)
42795678Spl196000 {
42805678Spl196000 	acp->flags |= AAC_CMD_ABORT;
42815678Spl196000 
42825678Spl196000 	if (acp->pkt) {
42837567SXin.Chen@Sun.COM 		if (acp->slotp) { /* outstanding cmd */
42847567SXin.Chen@Sun.COM 			acp->pkt->pkt_state |= STATE_GOT_STATUS;
42857567SXin.Chen@Sun.COM 		}
42865678Spl196000 
42875678Spl196000 		switch (reason) {
42885678Spl196000 		case CMD_TIMEOUT:
42897567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "CMD_TIMEOUT: acp=0x%p",
42907567SXin.Chen@Sun.COM 			    acp);
42915678Spl196000 			aac_set_pkt_reason(softs, acp, CMD_TIMEOUT,
42925678Spl196000 			    STAT_TIMEOUT | STAT_BUS_RESET);
42935678Spl196000 			break;
42945678Spl196000 		case CMD_RESET:
42955678Spl196000 			/* aac support only RESET_ALL */
42967567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "CMD_RESET: acp=0x%p", acp);
42975678Spl196000 			aac_set_pkt_reason(softs, acp, CMD_RESET,
42985678Spl196000 			    STAT_BUS_RESET);
42995678Spl196000 			break;
43005678Spl196000 		case CMD_ABORTED:
43017567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "CMD_ABORTED: acp=0x%p",
43027567SXin.Chen@Sun.COM 			    acp);
43035678Spl196000 			aac_set_pkt_reason(softs, acp, CMD_ABORTED,
43045678Spl196000 			    STAT_ABORTED);
43055678Spl196000 			break;
43065678Spl196000 		}
43075678Spl196000 	}
43085678Spl196000 	aac_end_io(softs, acp);
43095678Spl196000 }
43105678Spl196000 
43115678Spl196000 /*
43125678Spl196000  * Abort all the pending commands of type iocmd or just the command pkt
43135678Spl196000  * corresponding to pkt
43145678Spl196000  */
43155678Spl196000 static void
aac_abort_iocmds(struct aac_softstate * softs,int iocmd,struct scsi_pkt * pkt,int reason)43165678Spl196000 aac_abort_iocmds(struct aac_softstate *softs, int iocmd, struct scsi_pkt *pkt,
43175678Spl196000     int reason)
43185678Spl196000 {
43195678Spl196000 	struct aac_cmd *ac_arg, *acp;
43205678Spl196000 	int i;
43215678Spl196000 
43225678Spl196000 	if (pkt == NULL) {
43235678Spl196000 		ac_arg = NULL;
43245678Spl196000 	} else {
43255678Spl196000 		ac_arg = PKT2AC(pkt);
43265678Spl196000 		iocmd = (ac_arg->flags & AAC_CMD_SYNC) ?
43275678Spl196000 		    AAC_IOCMD_SYNC : AAC_IOCMD_ASYNC;
43285678Spl196000 	}
43295678Spl196000 
43305678Spl196000 	/*
43315678Spl196000 	 * a) outstanding commands on the controller
43325678Spl196000 	 * Note: should abort outstanding commands only after one
43335678Spl196000 	 * IOP reset has been done.
43345678Spl196000 	 */
43355678Spl196000 	if (iocmd & AAC_IOCMD_OUTSTANDING) {
43365678Spl196000 		struct aac_cmd *acp;
43375678Spl196000 
43385678Spl196000 		for (i = 0; i < AAC_MAX_LD; i++) {
43397567SXin.Chen@Sun.COM 			if (AAC_DEV_IS_VALID(&softs->containers[i].dev))
43405678Spl196000 				softs->containers[i].reset = 1;
43415678Spl196000 		}
43425678Spl196000 		while ((acp = softs->q_busy.q_head) != NULL)
43435678Spl196000 			aac_abort_iocmd(softs, acp, reason);
43445678Spl196000 	}
43455678Spl196000 
43465678Spl196000 	/* b) commands in the waiting queues */
43475678Spl196000 	for (i = 0; i < AAC_CMDQ_NUM; i++) {
43485678Spl196000 		if (iocmd & (1 << i)) {
43495678Spl196000 			if (ac_arg) {
43505678Spl196000 				aac_abort_iocmd(softs, ac_arg, reason);
43515678Spl196000 			} else {
43525678Spl196000 				while ((acp = softs->q_wait[i].q_head) != NULL)
43535678Spl196000 					aac_abort_iocmd(softs, acp, reason);
43545678Spl196000 			}
43555678Spl196000 		}
43565678Spl196000 	}
43575678Spl196000 }
43585678Spl196000 
43595678Spl196000 /*
43605678Spl196000  * The draining thread is shared among quiesce threads. It terminates
43615678Spl196000  * when the adapter is quiesced or stopped by aac_stop_drain().
43625678Spl196000  */
43635678Spl196000 static void
aac_check_drain(void * arg)43645678Spl196000 aac_check_drain(void *arg)
43655678Spl196000 {
43665678Spl196000 	struct aac_softstate *softs = arg;
43675678Spl196000 
43685678Spl196000 	mutex_enter(&softs->io_lock);
43695678Spl196000 	if (softs->ndrains) {
43707567SXin.Chen@Sun.COM 		softs->drain_timeid = 0;
43715678Spl196000 		/*
43725678Spl196000 		 * If both ASYNC and SYNC bus throttle are held,
43735678Spl196000 		 * wake up threads only when both are drained out.
43745678Spl196000 		 */
43755678Spl196000 		if ((softs->bus_throttle[AAC_CMDQ_ASYNC] > 0 ||
43765678Spl196000 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) &&
43775678Spl196000 		    (softs->bus_throttle[AAC_CMDQ_SYNC] > 0 ||
43785678Spl196000 		    softs->bus_ncmds[AAC_CMDQ_SYNC] == 0))
43795678Spl196000 			cv_broadcast(&softs->drain_cv);
43805678Spl196000 		else
43815678Spl196000 			softs->drain_timeid = timeout(aac_check_drain, softs,
43825678Spl196000 			    AAC_QUIESCE_TICK * drv_usectohz(1000000));
43835678Spl196000 	}
43845678Spl196000 	mutex_exit(&softs->io_lock);
43855678Spl196000 }
43865678Spl196000 
43875678Spl196000 /*
43885678Spl196000  * If not draining the outstanding cmds, drain them. Otherwise,
43895678Spl196000  * only update ndrains.
43905678Spl196000  */
43915678Spl196000 static void
aac_start_drain(struct aac_softstate * softs)43925678Spl196000 aac_start_drain(struct aac_softstate *softs)
43935678Spl196000 {
43945678Spl196000 	if (softs->ndrains == 0) {
43957567SXin.Chen@Sun.COM 		ASSERT(softs->drain_timeid == 0);
43965678Spl196000 		softs->drain_timeid = timeout(aac_check_drain, softs,
43975678Spl196000 		    AAC_QUIESCE_TICK * drv_usectohz(1000000));
43985678Spl196000 	}
43995678Spl196000 	softs->ndrains++;
44005678Spl196000 }
44015678Spl196000 
44025678Spl196000 /*
44035678Spl196000  * Stop the draining thread when no other threads use it any longer.
44045678Spl196000  * Side effect: io_lock may be released in the middle.
44055678Spl196000  */
44065678Spl196000 static void
aac_stop_drain(struct aac_softstate * softs)44075678Spl196000 aac_stop_drain(struct aac_softstate *softs)
44085678Spl196000 {
44095678Spl196000 	softs->ndrains--;
44105678Spl196000 	if (softs->ndrains == 0) {
44115678Spl196000 		if (softs->drain_timeid != 0) {
44125678Spl196000 			timeout_id_t tid = softs->drain_timeid;
44135678Spl196000 
44145678Spl196000 			softs->drain_timeid = 0;
44155678Spl196000 			mutex_exit(&softs->io_lock);
44165678Spl196000 			(void) untimeout(tid);
44175678Spl196000 			mutex_enter(&softs->io_lock);
44185678Spl196000 		}
44195678Spl196000 	}
44205678Spl196000 }
44215678Spl196000 
44225678Spl196000 /*
44235678Spl196000  * The following function comes from Adaptec:
44245678Spl196000  *
44255678Spl196000  * Once do an IOP reset, basically the driver have to re-initialize the card
44265678Spl196000  * as if up from a cold boot, and the driver is responsible for any IO that
44275678Spl196000  * is outstanding to the adapter at the time of the IOP RESET. And prepare
44285678Spl196000  * for IOP RESET by making the init code modular with the ability to call it
44295678Spl196000  * from multiple places.
44305678Spl196000  */
44315678Spl196000 static int
aac_reset_adapter(struct aac_softstate * softs)44325678Spl196000 aac_reset_adapter(struct aac_softstate *softs)
44335678Spl196000 {
44345678Spl196000 	int health;
44355678Spl196000 	uint32_t status;
44367567SXin.Chen@Sun.COM 	int rval = AAC_IOP_RESET_FAILED;
44375678Spl196000 
44385678Spl196000 	DBCALLED(softs, 1);
44395678Spl196000 
44405678Spl196000 	ASSERT(softs->state & AAC_STATE_RESET);
44415678Spl196000 
44425678Spl196000 	ddi_fm_acc_err_clear(softs->pci_mem_handle, DDI_FME_VER0);
44435678Spl196000 	/* Disable interrupt */
44445678Spl196000 	AAC_DISABLE_INTR(softs);
44455678Spl196000 
44465678Spl196000 	health = aac_check_adapter_health(softs);
44475678Spl196000 	if (health == -1) {
44485678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
44495678Spl196000 		goto finish;
44505678Spl196000 	}
44515678Spl196000 	if (health == 0) /* flush drives if possible */
44525678Spl196000 		(void) aac_shutdown(softs);
44535678Spl196000 
44545678Spl196000 	/* Execute IOP reset */
44555678Spl196000 	if ((aac_sync_mbcommand(softs, AAC_IOP_RESET, 0, 0, 0, 0,
44565678Spl196000 	    &status)) != AACOK) {
445711348SZhongyan.Gu@Sun.COM 		ddi_acc_handle_t acc;
44585678Spl196000 		struct aac_fib *fibp;
44595678Spl196000 		struct aac_pause_command *pc;
44605678Spl196000 
44615678Spl196000 		if ((status & 0xf) == 0xf) {
44625678Spl196000 			uint32_t wait_count;
44635678Spl196000 
44645678Spl196000 			/*
44655678Spl196000 			 * Sunrise Lake has dual cores and we must drag the
44665678Spl196000 			 * other core with us to reset simultaneously. There
44675678Spl196000 			 * are 2 bits in the Inbound Reset Control and Status
44685678Spl196000 			 * Register (offset 0x38) of the Sunrise Lake to reset
44695678Spl196000 			 * the chip without clearing out the PCI configuration
44705678Spl196000 			 * info (COMMAND & BARS).
44715678Spl196000 			 */
44725678Spl196000 			PCI_MEM_PUT32(softs, AAC_IRCSR, AAC_IRCSR_CORES_RST);
44735678Spl196000 
44745678Spl196000 			/*
44755678Spl196000 			 * We need to wait for 5 seconds before accessing the MU
44765678Spl196000 			 * again 10000 * 100us = 1000,000us = 1000ms = 1s
44775678Spl196000 			 */
44785678Spl196000 			wait_count = 5 * 10000;
44795678Spl196000 			while (wait_count) {
44805678Spl196000 				drv_usecwait(100); /* delay 100 microseconds */
44815678Spl196000 				wait_count--;
44825678Spl196000 			}
44835678Spl196000 		} else {
44845678Spl196000 			if (status == SRB_STATUS_INVALID_REQUEST)
44855678Spl196000 				cmn_err(CE_WARN, "!IOP_RESET not supported");
44865678Spl196000 			else /* probably timeout */
44875678Spl196000 				cmn_err(CE_WARN, "!IOP_RESET failed");
44885678Spl196000 
44895678Spl196000 			/* Unwind aac_shutdown() */
449011348SZhongyan.Gu@Sun.COM 			(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
449111348SZhongyan.Gu@Sun.COM 			acc = softs->sync_ac.slotp->fib_acc_handle;
449211348SZhongyan.Gu@Sun.COM 
449311348SZhongyan.Gu@Sun.COM 			fibp = softs->sync_ac.slotp->fibp;
44945678Spl196000 			pc = (struct aac_pause_command *)&fibp->data[0];
44955678Spl196000 
44965678Spl196000 			bzero(pc, sizeof (*pc));
44975678Spl196000 			ddi_put32(acc, &pc->Command, VM_ContainerConfig);
44985678Spl196000 			ddi_put32(acc, &pc->Type, CT_PAUSE_IO);
44995678Spl196000 			ddi_put32(acc, &pc->Timeout, 1);
45005678Spl196000 			ddi_put32(acc, &pc->Min, 1);
45015678Spl196000 			ddi_put32(acc, &pc->NoRescan, 1);
45025678Spl196000 
45035678Spl196000 			(void) aac_sync_fib(softs, ContainerCommand,
45045678Spl196000 			    AAC_FIB_SIZEOF(struct aac_pause_command));
450511348SZhongyan.Gu@Sun.COM 			aac_sync_fib_slot_release(softs, &softs->sync_ac);
45065678Spl196000 
45077567SXin.Chen@Sun.COM 			if (aac_check_adapter_health(softs) != 0)
45087567SXin.Chen@Sun.COM 				ddi_fm_service_impact(softs->devinfo_p,
45097567SXin.Chen@Sun.COM 				    DDI_SERVICE_LOST);
45107567SXin.Chen@Sun.COM 			else
45117567SXin.Chen@Sun.COM 				/*
45127567SXin.Chen@Sun.COM 				 * IOP reset not supported or IOP not reseted
45137567SXin.Chen@Sun.COM 				 */
45147567SXin.Chen@Sun.COM 				rval = AAC_IOP_RESET_ABNORMAL;
45155678Spl196000 			goto finish;
45165678Spl196000 		}
45175678Spl196000 	}
45185678Spl196000 
45195678Spl196000 	/*
45205678Spl196000 	 * Re-read and renegotiate the FIB parameters, as one of the actions
45215678Spl196000 	 * that can result from an IOP reset is the running of a new firmware
45225678Spl196000 	 * image.
45235678Spl196000 	 */
45245678Spl196000 	if (aac_common_attach(softs) != AACOK)
45255678Spl196000 		goto finish;
45265678Spl196000 
45277567SXin.Chen@Sun.COM 	rval = AAC_IOP_RESET_SUCCEED;
45285678Spl196000 
45295678Spl196000 finish:
45305678Spl196000 	AAC_ENABLE_INTR(softs);
45315678Spl196000 	return (rval);
45325678Spl196000 }
45335678Spl196000 
45345678Spl196000 static void
aac_set_throttle(struct aac_softstate * softs,struct aac_device * dvp,int q,int throttle)45357567SXin.Chen@Sun.COM aac_set_throttle(struct aac_softstate *softs, struct aac_device *dvp, int q,
45365678Spl196000     int throttle)
45375678Spl196000 {
45385678Spl196000 	/*
45395678Spl196000 	 * If the bus is draining/quiesced, no changes to the throttles
45405678Spl196000 	 * are allowed. All throttles should have been set to 0.
45415678Spl196000 	 */
45425678Spl196000 	if ((softs->state & AAC_STATE_QUIESCED) || softs->ndrains)
45435678Spl196000 		return;
45445678Spl196000 	dvp->throttle[q] = throttle;
45455678Spl196000 }
45465678Spl196000 
45475678Spl196000 static void
aac_hold_bus(struct aac_softstate * softs,int iocmds)45485678Spl196000 aac_hold_bus(struct aac_softstate *softs, int iocmds)
45495678Spl196000 {
45505678Spl196000 	int i, q;
45515678Spl196000 
45525678Spl196000 	/* Hold bus by holding every device on the bus */
45535678Spl196000 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
45545678Spl196000 		if (iocmds & (1 << q)) {
45555678Spl196000 			softs->bus_throttle[q] = 0;
45565678Spl196000 			for (i = 0; i < AAC_MAX_LD; i++)
45577567SXin.Chen@Sun.COM 				aac_set_throttle(softs,
45587567SXin.Chen@Sun.COM 				    &softs->containers[i].dev, q, 0);
45597567SXin.Chen@Sun.COM 			for (i = 0; i < AAC_MAX_PD(softs); i++)
45607567SXin.Chen@Sun.COM 				aac_set_throttle(softs,
45617567SXin.Chen@Sun.COM 				    &softs->nondasds[i].dev, q, 0);
45625678Spl196000 		}
45635678Spl196000 	}
45645678Spl196000 }
45655678Spl196000 
45665678Spl196000 static void
aac_unhold_bus(struct aac_softstate * softs,int iocmds)45675678Spl196000 aac_unhold_bus(struct aac_softstate *softs, int iocmds)
45685678Spl196000 {
456911348SZhongyan.Gu@Sun.COM 	int i, q, max_throttle;
45705678Spl196000 
45715678Spl196000 	for (q = 0; q < AAC_CMDQ_NUM; q++) {
45725678Spl196000 		if (iocmds & (1 << q)) {
45735678Spl196000 			/*
45745678Spl196000 			 * Should not unhold AAC_IOCMD_ASYNC bus, if it has been
45755678Spl196000 			 * quiesced or being drained by possibly some quiesce
45765678Spl196000 			 * threads.
45775678Spl196000 			 */
45785678Spl196000 			if (q == AAC_CMDQ_ASYNC && ((softs->state &
45795678Spl196000 			    AAC_STATE_QUIESCED) || softs->ndrains))
45805678Spl196000 				continue;
458111348SZhongyan.Gu@Sun.COM 			if (q == AAC_CMDQ_ASYNC)
458211348SZhongyan.Gu@Sun.COM 				max_throttle = softs->total_slots -
458311348SZhongyan.Gu@Sun.COM 				    AAC_MGT_SLOT_NUM;
458411348SZhongyan.Gu@Sun.COM 			else
458511348SZhongyan.Gu@Sun.COM 				max_throttle = softs->total_slots - 1;
458611348SZhongyan.Gu@Sun.COM 			softs->bus_throttle[q] = max_throttle;
45875678Spl196000 			for (i = 0; i < AAC_MAX_LD; i++)
45887567SXin.Chen@Sun.COM 				aac_set_throttle(softs,
45897567SXin.Chen@Sun.COM 				    &softs->containers[i].dev,
459011348SZhongyan.Gu@Sun.COM 				    q, max_throttle);
45917567SXin.Chen@Sun.COM 			for (i = 0; i < AAC_MAX_PD(softs); i++)
45927567SXin.Chen@Sun.COM 				aac_set_throttle(softs, &softs->nondasds[i].dev,
459311348SZhongyan.Gu@Sun.COM 				    q, max_throttle);
45945678Spl196000 		}
45955678Spl196000 	}
45965678Spl196000 }
45975678Spl196000 
45985678Spl196000 static int
aac_do_reset(struct aac_softstate * softs)45995678Spl196000 aac_do_reset(struct aac_softstate *softs)
46005678Spl196000 {
46015678Spl196000 	int health;
46025678Spl196000 	int rval;
46035678Spl196000 
46045678Spl196000 	softs->state |= AAC_STATE_RESET;
46055678Spl196000 	health = aac_check_adapter_health(softs);
46065678Spl196000 
46075678Spl196000 	/*
46085678Spl196000 	 * Hold off new io commands and wait all outstanding io
46095678Spl196000 	 * commands to complete.
46105678Spl196000 	 */
46117567SXin.Chen@Sun.COM 	if (health == 0) {
46127567SXin.Chen@Sun.COM 		int sync_cmds = softs->bus_ncmds[AAC_CMDQ_SYNC];
46137567SXin.Chen@Sun.COM 		int async_cmds = softs->bus_ncmds[AAC_CMDQ_ASYNC];
46147567SXin.Chen@Sun.COM 
46157567SXin.Chen@Sun.COM 		if (sync_cmds == 0 && async_cmds == 0) {
46167567SXin.Chen@Sun.COM 			rval = AAC_IOP_RESET_SUCCEED;
46177567SXin.Chen@Sun.COM 			goto finish;
46187567SXin.Chen@Sun.COM 		}
46195678Spl196000 		/*
46205678Spl196000 		 * Give the adapter up to AAC_QUIESCE_TIMEOUT more seconds
46215678Spl196000 		 * to complete the outstanding io commands
46225678Spl196000 		 */
46235678Spl196000 		int timeout = AAC_QUIESCE_TIMEOUT * 1000 * 10;
46245678Spl196000 		int (*intr_handler)(struct aac_softstate *);
46255678Spl196000 
46265678Spl196000 		aac_hold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
46275678Spl196000 		/*
46285678Spl196000 		 * Poll the adapter by ourselves in case interrupt is disabled
46295678Spl196000 		 * and to avoid releasing the io_lock.
46305678Spl196000 		 */
46315678Spl196000 		intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
46325678Spl196000 		    aac_process_intr_new : aac_process_intr_old;
46335678Spl196000 		while ((softs->bus_ncmds[AAC_CMDQ_SYNC] ||
46345678Spl196000 		    softs->bus_ncmds[AAC_CMDQ_ASYNC]) && timeout) {
46355678Spl196000 			drv_usecwait(100);
46365678Spl196000 			(void) intr_handler(softs);
46375678Spl196000 			timeout--;
46385678Spl196000 		}
46395678Spl196000 		aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
46407567SXin.Chen@Sun.COM 
46417567SXin.Chen@Sun.COM 		if (softs->bus_ncmds[AAC_CMDQ_SYNC] == 0 &&
46427567SXin.Chen@Sun.COM 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] == 0) {
46437567SXin.Chen@Sun.COM 			/* Cmds drained out */
46447567SXin.Chen@Sun.COM 			rval = AAC_IOP_RESET_SUCCEED;
46457567SXin.Chen@Sun.COM 			goto finish;
46467567SXin.Chen@Sun.COM 		} else if (softs->bus_ncmds[AAC_CMDQ_SYNC] < sync_cmds ||
46477567SXin.Chen@Sun.COM 		    softs->bus_ncmds[AAC_CMDQ_ASYNC] < async_cmds) {
46487567SXin.Chen@Sun.COM 			/* Cmds not drained out, adapter overloaded */
46497567SXin.Chen@Sun.COM 			rval = AAC_IOP_RESET_ABNORMAL;
46507567SXin.Chen@Sun.COM 			goto finish;
46517567SXin.Chen@Sun.COM 		}
46525678Spl196000 	}
46535678Spl196000 
46545678Spl196000 	/*
46557567SXin.Chen@Sun.COM 	 * If a longer waiting time still can't drain any outstanding io
46565678Spl196000 	 * commands, do IOP reset.
46575678Spl196000 	 */
46587567SXin.Chen@Sun.COM 	if ((rval = aac_reset_adapter(softs)) == AAC_IOP_RESET_FAILED)
46597567SXin.Chen@Sun.COM 		softs->state |= AAC_STATE_DEAD;
46607567SXin.Chen@Sun.COM 
46617567SXin.Chen@Sun.COM finish:
46625678Spl196000 	softs->state &= ~AAC_STATE_RESET;
46635678Spl196000 	return (rval);
46645678Spl196000 }
46655678Spl196000 
46665678Spl196000 static int
aac_tran_reset(struct scsi_address * ap,int level)46675678Spl196000 aac_tran_reset(struct scsi_address *ap, int level)
46685678Spl196000 {
46695678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
46705678Spl196000 	int rval;
46715678Spl196000 
46725678Spl196000 	DBCALLED(softs, 1);
46735678Spl196000 
46745678Spl196000 	if (level != RESET_ALL) {
46755678Spl196000 		cmn_err(CE_NOTE, "!reset target/lun not supported");
46765678Spl196000 		return (0);
46775678Spl196000 	}
46785678Spl196000 
46795678Spl196000 	mutex_enter(&softs->io_lock);
46807567SXin.Chen@Sun.COM 	switch (rval = aac_do_reset(softs)) {
46817567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_SUCCEED:
46825678Spl196000 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING | AAC_IOCMD_ASYNC,
46835678Spl196000 		    NULL, CMD_RESET);
46845678Spl196000 		aac_start_waiting_io(softs);
46857567SXin.Chen@Sun.COM 		break;
46867567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_FAILED:
46877567SXin.Chen@Sun.COM 		/* Abort IOCTL cmds when adapter is dead */
46885678Spl196000 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_RESET);
46897567SXin.Chen@Sun.COM 		break;
46907567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_ABNORMAL:
46917567SXin.Chen@Sun.COM 		aac_start_waiting_io(softs);
46925678Spl196000 	}
46935678Spl196000 	mutex_exit(&softs->io_lock);
46945678Spl196000 
46955678Spl196000 	aac_drain_comp_q(softs);
46967567SXin.Chen@Sun.COM 	return (rval == 0);
46975678Spl196000 }
46985678Spl196000 
46995678Spl196000 static int
aac_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)47005678Spl196000 aac_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
47015678Spl196000 {
47025678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
47035678Spl196000 
47045678Spl196000 	DBCALLED(softs, 1);
47055678Spl196000 
47065678Spl196000 	mutex_enter(&softs->io_lock);
47075678Spl196000 	aac_abort_iocmds(softs, 0, pkt, CMD_ABORTED);
47085678Spl196000 	mutex_exit(&softs->io_lock);
47095678Spl196000 
47105678Spl196000 	aac_drain_comp_q(softs);
47115678Spl196000 	return (1);
47125678Spl196000 }
47135678Spl196000 
47145678Spl196000 void
aac_free_dmamap(struct aac_cmd * acp)47155678Spl196000 aac_free_dmamap(struct aac_cmd *acp)
47165678Spl196000 {
47175678Spl196000 	/* Free dma mapping */
47185678Spl196000 	if (acp->flags & AAC_CMD_DMA_VALID) {
47195678Spl196000 		ASSERT(acp->buf_dma_handle);
47205678Spl196000 		(void) ddi_dma_unbind_handle(acp->buf_dma_handle);
47215678Spl196000 		acp->flags &= ~AAC_CMD_DMA_VALID;
47225678Spl196000 	}
47235678Spl196000 
47245678Spl196000 	if (acp->abp != NULL) { /* free non-aligned buf DMA */
47255678Spl196000 		ASSERT(acp->buf_dma_handle);
47265678Spl196000 		if ((acp->flags & AAC_CMD_BUF_WRITE) == 0 && acp->bp)
47275678Spl196000 			ddi_rep_get8(acp->abh, (uint8_t *)acp->bp->b_un.b_addr,
47285678Spl196000 			    (uint8_t *)acp->abp, acp->bp->b_bcount,
47295678Spl196000 			    DDI_DEV_AUTOINCR);
47305678Spl196000 		ddi_dma_mem_free(&acp->abh);
47315678Spl196000 		acp->abp = NULL;
47325678Spl196000 	}
47335678Spl196000 
47345678Spl196000 	if (acp->buf_dma_handle) {
47355678Spl196000 		ddi_dma_free_handle(&acp->buf_dma_handle);
47365678Spl196000 		acp->buf_dma_handle = NULL;
47375678Spl196000 	}
47385678Spl196000 }
47395678Spl196000 
47405678Spl196000 static void
aac_unknown_scmd(struct aac_softstate * softs,struct aac_cmd * acp)47415678Spl196000 aac_unknown_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
47425678Spl196000 {
47435678Spl196000 	AACDB_PRINT(softs, CE_CONT, "SCMD 0x%x not supported",
47447100Spl196000 	    ((union scsi_cdb *)(void *)acp->pkt->pkt_cdbp)->scc_cmd);
47455678Spl196000 	aac_free_dmamap(acp);
47465678Spl196000 	aac_set_arq_data(acp->pkt, KEY_ILLEGAL_REQUEST, 0x20, 0x00, 0);
47475678Spl196000 	aac_soft_callback(softs, acp);
47485678Spl196000 }
47495678Spl196000 
47505678Spl196000 /*
47515678Spl196000  * Handle command to logical device
47525678Spl196000  */
47535678Spl196000 static int
aac_tran_start_ld(struct aac_softstate * softs,struct aac_cmd * acp)47545678Spl196000 aac_tran_start_ld(struct aac_softstate *softs, struct aac_cmd *acp)
47555678Spl196000 {
47565678Spl196000 	struct aac_container *dvp;
47575678Spl196000 	struct scsi_pkt *pkt;
47585678Spl196000 	union scsi_cdb *cdbp;
47595678Spl196000 	struct buf *bp;
47605678Spl196000 	int rval;
47615678Spl196000 
47627567SXin.Chen@Sun.COM 	dvp = (struct aac_container *)acp->dvp;
47635678Spl196000 	pkt = acp->pkt;
47647100Spl196000 	cdbp = (void *)pkt->pkt_cdbp;
47655678Spl196000 	bp = acp->bp;
47665678Spl196000 
47675678Spl196000 	switch (cdbp->scc_cmd) {
47685678Spl196000 	case SCMD_INQUIRY: /* inquiry */
47695678Spl196000 		aac_free_dmamap(acp);
47705678Spl196000 		aac_inquiry(softs, pkt, cdbp, bp);
47715678Spl196000 		aac_soft_callback(softs, acp);
47725678Spl196000 		rval = TRAN_ACCEPT;
47735678Spl196000 		break;
47745678Spl196000 
47755678Spl196000 	case SCMD_READ_CAPACITY: /* read capacity */
47765678Spl196000 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
47775678Spl196000 			struct scsi_capacity cap;
47785678Spl196000 			uint64_t last_lba;
47795678Spl196000 
47805678Spl196000 			/* check 64-bit LBA */
47815678Spl196000 			last_lba = dvp->size - 1;
47825678Spl196000 			if (last_lba > 0xffffffffull) {
47835678Spl196000 				cap.capacity = 0xfffffffful;
47845678Spl196000 			} else {
47855678Spl196000 				cap.capacity = BE_32(last_lba);
47865678Spl196000 			}
47875678Spl196000 			cap.lbasize = BE_32(AAC_SECTOR_SIZE);
47885678Spl196000 
47895678Spl196000 			aac_free_dmamap(acp);
47905678Spl196000 			if (bp->b_flags & (B_PHYS|B_PAGEIO))
47915678Spl196000 				bp_mapin(bp);
47926799Sjd218194 			bcopy(&cap, bp->b_un.b_addr, min(bp->b_bcount, 8));
47935678Spl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
47945678Spl196000 		}
47955678Spl196000 		aac_soft_callback(softs, acp);
47965678Spl196000 		rval = TRAN_ACCEPT;
47975678Spl196000 		break;
47985678Spl196000 
47995678Spl196000 	case SCMD_SVC_ACTION_IN_G4: /* read capacity 16 */
48005678Spl196000 		/* Check if containers need 64-bit LBA support */
48015678Spl196000 		if (cdbp->cdb_opaque[1] == SSVC_ACTION_READ_CAPACITY_G4) {
48025678Spl196000 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
48035678Spl196000 				struct scsi_capacity_16 cap16;
48045678Spl196000 				int cap_len = sizeof (struct scsi_capacity_16);
48055678Spl196000 
48065678Spl196000 				bzero(&cap16, cap_len);
48077000Sjd218194 				cap16.sc_capacity = BE_64(dvp->size - 1);
48085678Spl196000 				cap16.sc_lbasize = BE_32(AAC_SECTOR_SIZE);
48095678Spl196000 
48105678Spl196000 				aac_free_dmamap(acp);
48115678Spl196000 				if (bp->b_flags & (B_PHYS | B_PAGEIO))
48125678Spl196000 					bp_mapin(bp);
48136799Sjd218194 				bcopy(&cap16, bp->b_un.b_addr,
48146799Sjd218194 				    min(bp->b_bcount, cap_len));
48155678Spl196000 				pkt->pkt_state |= STATE_XFERRED_DATA;
48165678Spl196000 			}
48175678Spl196000 			aac_soft_callback(softs, acp);
48185678Spl196000 		} else {
48195678Spl196000 			aac_unknown_scmd(softs, acp);
48205678Spl196000 		}
48215678Spl196000 		rval = TRAN_ACCEPT;
48225678Spl196000 		break;
48235678Spl196000 
48245678Spl196000 	case SCMD_READ_G4: /* read_16 */
48255678Spl196000 	case SCMD_WRITE_G4: /* write_16 */
48265678Spl196000 		if (softs->flags & AAC_FLAGS_RAW_IO) {
48275678Spl196000 			/* NOTE: GETG4ADDRTL(cdbp) is int32_t */
48285678Spl196000 			acp->blkno = ((uint64_t) \
48295678Spl196000 			    GETG4ADDR(cdbp) << 32) | \
48305678Spl196000 			    (uint32_t)GETG4ADDRTL(cdbp);
48315678Spl196000 			goto do_io;
48325678Spl196000 		}
48335678Spl196000 		AACDB_PRINT(softs, CE_WARN, "64-bit LBA not supported");
48345678Spl196000 		aac_unknown_scmd(softs, acp);
48355678Spl196000 		rval = TRAN_ACCEPT;
48365678Spl196000 		break;
48375678Spl196000 
48385678Spl196000 	case SCMD_READ: /* read_6 */
48395678Spl196000 	case SCMD_WRITE: /* write_6 */
48405678Spl196000 		acp->blkno = GETG0ADDR(cdbp);
48415678Spl196000 		goto do_io;
48425678Spl196000 
48437567SXin.Chen@Sun.COM 	case SCMD_READ_G5: /* read_12 */
48447567SXin.Chen@Sun.COM 	case SCMD_WRITE_G5: /* write_12 */
48457567SXin.Chen@Sun.COM 		acp->blkno = GETG5ADDR(cdbp);
48467567SXin.Chen@Sun.COM 		goto do_io;
48477567SXin.Chen@Sun.COM 
48485678Spl196000 	case SCMD_READ_G1: /* read_10 */
48495678Spl196000 	case SCMD_WRITE_G1: /* write_10 */
48505678Spl196000 		acp->blkno = (uint32_t)GETG1ADDR(cdbp);
48515678Spl196000 do_io:
48525678Spl196000 		if (acp->flags & AAC_CMD_DMA_VALID) {
48535678Spl196000 			uint64_t cnt_size = dvp->size;
48545678Spl196000 
48555678Spl196000 			/*
48565678Spl196000 			 * If LBA > array size AND rawio, the
48575678Spl196000 			 * adapter may hang. So check it before
48585678Spl196000 			 * sending.
48595678Spl196000 			 * NOTE: (blkno + blkcnt) may overflow
48605678Spl196000 			 */
48615678Spl196000 			if ((acp->blkno < cnt_size) &&
48625678Spl196000 			    ((acp->blkno + acp->bcount /
48635678Spl196000 			    AAC_BLK_SIZE) <= cnt_size)) {
48645678Spl196000 				rval = aac_do_io(softs, acp);
48655678Spl196000 			} else {
48665678Spl196000 			/*
48675678Spl196000 			 * Request exceeds the capacity of disk,
48685678Spl196000 			 * set error block number to last LBA
48695678Spl196000 			 * + 1.
48705678Spl196000 			 */
48715678Spl196000 				aac_set_arq_data(pkt,
48725678Spl196000 				    KEY_ILLEGAL_REQUEST, 0x21,
48735678Spl196000 				    0x00, cnt_size);
48745678Spl196000 				aac_soft_callback(softs, acp);
48755678Spl196000 				rval = TRAN_ACCEPT;
48765678Spl196000 			}
48775678Spl196000 		} else if (acp->bcount == 0) {
48785678Spl196000 			/* For 0 length IO, just return ok */
48795678Spl196000 			aac_soft_callback(softs, acp);
48805678Spl196000 			rval = TRAN_ACCEPT;
48815678Spl196000 		} else {
48825678Spl196000 			rval = TRAN_BADPKT;
48835678Spl196000 		}
48845678Spl196000 		break;
48855678Spl196000 
48865678Spl196000 	case SCMD_MODE_SENSE: /* mode_sense_6 */
48875678Spl196000 	case SCMD_MODE_SENSE_G1: { /* mode_sense_10 */
48885678Spl196000 		int capacity;
48895678Spl196000 
48905678Spl196000 		aac_free_dmamap(acp);
48915678Spl196000 		if (dvp->size > 0xffffffffull)
48925678Spl196000 			capacity = 0xfffffffful; /* 64-bit LBA */
48935678Spl196000 		else
48945678Spl196000 			capacity = dvp->size;
48955678Spl196000 		aac_mode_sense(softs, pkt, cdbp, bp, capacity);
48965678Spl196000 		aac_soft_callback(softs, acp);
48975678Spl196000 		rval = TRAN_ACCEPT;
48985678Spl196000 		break;
48995678Spl196000 	}
49005678Spl196000 
490110976SZhongyan.Gu@Sun.COM 	case SCMD_START_STOP:
490210976SZhongyan.Gu@Sun.COM 		if (softs->support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) {
490310976SZhongyan.Gu@Sun.COM 			acp->aac_cmd_fib = aac_cmd_fib_startstop;
490410976SZhongyan.Gu@Sun.COM 			acp->ac_comp = aac_startstop_complete;
490510976SZhongyan.Gu@Sun.COM 			rval = aac_do_io(softs, acp);
490610976SZhongyan.Gu@Sun.COM 			break;
490710976SZhongyan.Gu@Sun.COM 		}
490810976SZhongyan.Gu@Sun.COM 	/* FALLTHRU */
49095678Spl196000 	case SCMD_TEST_UNIT_READY:
49105678Spl196000 	case SCMD_REQUEST_SENSE:
49115678Spl196000 	case SCMD_FORMAT:
49125678Spl196000 		aac_free_dmamap(acp);
49135678Spl196000 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
49145678Spl196000 			if (acp->flags & AAC_CMD_BUF_READ) {
49155678Spl196000 				if (bp->b_flags & (B_PHYS|B_PAGEIO))
49165678Spl196000 					bp_mapin(bp);
49175678Spl196000 				bzero(bp->b_un.b_addr, bp->b_bcount);
49185678Spl196000 			}
49195678Spl196000 			pkt->pkt_state |= STATE_XFERRED_DATA;
49205678Spl196000 		}
49215678Spl196000 		aac_soft_callback(softs, acp);
49225678Spl196000 		rval = TRAN_ACCEPT;
49235678Spl196000 		break;
49245678Spl196000 
49255678Spl196000 	case SCMD_SYNCHRONIZE_CACHE:
49265678Spl196000 		acp->flags |= AAC_CMD_NTAG;
49275678Spl196000 		acp->aac_cmd_fib = aac_cmd_fib_sync;
49285678Spl196000 		acp->ac_comp = aac_synccache_complete;
49295678Spl196000 		rval = aac_do_io(softs, acp);
49305678Spl196000 		break;
49315678Spl196000 
49325678Spl196000 	case SCMD_DOORLOCK:
49335678Spl196000 		aac_free_dmamap(acp);
49345678Spl196000 		dvp->locked = (pkt->pkt_cdbp[4] & 0x01) ? 1 : 0;
49355678Spl196000 		aac_soft_callback(softs, acp);
49365678Spl196000 		rval = TRAN_ACCEPT;
49375678Spl196000 		break;
49385678Spl196000 
49395678Spl196000 	default: /* unknown command */
49405678Spl196000 		aac_unknown_scmd(softs, acp);
49415678Spl196000 		rval = TRAN_ACCEPT;
49425678Spl196000 		break;
49435678Spl196000 	}
49445678Spl196000 
49455678Spl196000 	return (rval);
49465678Spl196000 }
49475678Spl196000 
49485678Spl196000 static int
aac_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)49495678Spl196000 aac_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
49505678Spl196000 {
49515678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
49525678Spl196000 	struct aac_cmd *acp = PKT2AC(pkt);
49537567SXin.Chen@Sun.COM 	struct aac_device *dvp = acp->dvp;
49545678Spl196000 	int rval;
49555678Spl196000 
49565678Spl196000 	DBCALLED(softs, 2);
49575678Spl196000 
49585678Spl196000 	/*
49595678Spl196000 	 * Reinitialize some fields of ac and pkt; the packet may
49605678Spl196000 	 * have been resubmitted
49615678Spl196000 	 */
49625678Spl196000 	acp->flags &= AAC_CMD_CONSISTENT | AAC_CMD_DMA_PARTIAL | \
49635678Spl196000 	    AAC_CMD_BUF_READ | AAC_CMD_BUF_WRITE | AAC_CMD_DMA_VALID;
49645678Spl196000 	acp->timeout = acp->pkt->pkt_time;
49655678Spl196000 	if (pkt->pkt_flags & FLAG_NOINTR)
49665678Spl196000 		acp->flags |= AAC_CMD_NO_INTR;
49677567SXin.Chen@Sun.COM #ifdef DEBUG
49687567SXin.Chen@Sun.COM 	acp->fib_flags = AACDB_FLAGS_FIB_SCMD;
49697567SXin.Chen@Sun.COM #endif
49705678Spl196000 	pkt->pkt_reason = CMD_CMPLT;
49715678Spl196000 	pkt->pkt_state = 0;
49725678Spl196000 	pkt->pkt_statistics = 0;
49737567SXin.Chen@Sun.COM 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
49745678Spl196000 
49755678Spl196000 	if (acp->flags & AAC_CMD_DMA_VALID) {
49765678Spl196000 		pkt->pkt_resid = acp->bcount;
49775678Spl196000 		/* Consistent packets need to be sync'ed first */
49785678Spl196000 		if ((acp->flags & AAC_CMD_CONSISTENT) &&
49795678Spl196000 		    (acp->flags & AAC_CMD_BUF_WRITE))
49805678Spl196000 			if (aac_dma_sync_ac(acp) != AACOK) {
49815678Spl196000 				ddi_fm_service_impact(softs->devinfo_p,
49825678Spl196000 				    DDI_SERVICE_UNAFFECTED);
49835678Spl196000 				return (TRAN_BADPKT);
49845678Spl196000 			}
49855678Spl196000 	} else {
49865678Spl196000 		pkt->pkt_resid = 0;
49875678Spl196000 	}
49885678Spl196000 
49895678Spl196000 	mutex_enter(&softs->io_lock);
49905678Spl196000 	AACDB_PRINT_SCMD(softs, acp);
49917567SXin.Chen@Sun.COM 	if ((dvp->flags & (AAC_DFLAG_VALID | AAC_DFLAG_CONFIGURING)) &&
49927567SXin.Chen@Sun.COM 	    !(softs->state & AAC_STATE_DEAD)) {
49937567SXin.Chen@Sun.COM 		if (dvp->type == AAC_DEV_LD) {
49947567SXin.Chen@Sun.COM 			if (ap->a_lun == 0)
49957567SXin.Chen@Sun.COM 				rval = aac_tran_start_ld(softs, acp);
49967567SXin.Chen@Sun.COM 			else
49977567SXin.Chen@Sun.COM 				goto error;
49987567SXin.Chen@Sun.COM 		} else {
49997567SXin.Chen@Sun.COM 			rval = aac_do_io(softs, acp);
50007567SXin.Chen@Sun.COM 		}
50015678Spl196000 	} else {
50027567SXin.Chen@Sun.COM error:
50037567SXin.Chen@Sun.COM #ifdef DEBUG
50047567SXin.Chen@Sun.COM 		if (!(softs->state & AAC_STATE_DEAD)) {
50057567SXin.Chen@Sun.COM 			AACDB_PRINT_TRAN(softs,
50067567SXin.Chen@Sun.COM 			    "Cannot send cmd to target t%dL%d: %s",
50077567SXin.Chen@Sun.COM 			    ap->a_target, ap->a_lun,
50087567SXin.Chen@Sun.COM 			    "target invalid");
50097567SXin.Chen@Sun.COM 		} else {
50107567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN,
50117567SXin.Chen@Sun.COM 			    "Cannot send cmd to target t%dL%d: %s",
50127567SXin.Chen@Sun.COM 			    ap->a_target, ap->a_lun,
50137567SXin.Chen@Sun.COM 			    "adapter dead");
50147567SXin.Chen@Sun.COM 		}
50157567SXin.Chen@Sun.COM #endif
50165678Spl196000 		rval = TRAN_FATAL_ERROR;
50175678Spl196000 	}
50185678Spl196000 	mutex_exit(&softs->io_lock);
50195678Spl196000 	return (rval);
50205678Spl196000 }
50215678Spl196000 
50225678Spl196000 static int
aac_tran_getcap(struct scsi_address * ap,char * cap,int whom)50235678Spl196000 aac_tran_getcap(struct scsi_address *ap, char *cap, int whom)
50245678Spl196000 {
50255678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
50267567SXin.Chen@Sun.COM 	struct aac_device *dvp;
50275678Spl196000 	int rval;
50285678Spl196000 
50295678Spl196000 	DBCALLED(softs, 2);
50305678Spl196000 
50315678Spl196000 	/* We don't allow inquiring about capabilities for other targets */
50325678Spl196000 	if (cap == NULL || whom == 0) {
50335678Spl196000 		AACDB_PRINT(softs, CE_WARN,
50345678Spl196000 		    "GetCap> %s not supported: whom=%d", cap, whom);
50355678Spl196000 		return (-1);
50365678Spl196000 	}
50375678Spl196000 
50385678Spl196000 	mutex_enter(&softs->io_lock);
50397567SXin.Chen@Sun.COM 	dvp = AAC_DEV(softs, ap->a_target);
50407567SXin.Chen@Sun.COM 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
50415678Spl196000 		mutex_exit(&softs->io_lock);
50427567SXin.Chen@Sun.COM 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to getcap",
50435678Spl196000 		    ap->a_target, ap->a_lun);
50445678Spl196000 		return (-1);
50455678Spl196000 	}
50465678Spl196000 
50475678Spl196000 	switch (scsi_hba_lookup_capstr(cap)) {
50485678Spl196000 	case SCSI_CAP_ARQ: /* auto request sense */
50495678Spl196000 		rval = 1;
50505678Spl196000 		break;
50515678Spl196000 	case SCSI_CAP_UNTAGGED_QING:
50525678Spl196000 	case SCSI_CAP_TAGGED_QING:
50535678Spl196000 		rval = 1;
50545678Spl196000 		break;
50555678Spl196000 	case SCSI_CAP_DMA_MAX:
50568551SPeng.L@Sun.COM 		rval = softs->dma_max;
50575678Spl196000 		break;
50585678Spl196000 	default:
50595678Spl196000 		rval = -1;
50605678Spl196000 		break;
50615678Spl196000 	}
50625678Spl196000 	mutex_exit(&softs->io_lock);
50635678Spl196000 
50645678Spl196000 	AACDB_PRINT_TRAN(softs, "GetCap> %s t%dL%d: rval=%d",
50655678Spl196000 	    cap, ap->a_target, ap->a_lun, rval);
50665678Spl196000 	return (rval);
50675678Spl196000 }
50685678Spl196000 
50695678Spl196000 /*ARGSUSED*/
50705678Spl196000 static int
aac_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)50715678Spl196000 aac_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
50725678Spl196000 {
50735678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
50747567SXin.Chen@Sun.COM 	struct aac_device *dvp;
50755678Spl196000 	int rval;
50765678Spl196000 
50775678Spl196000 	DBCALLED(softs, 2);
50785678Spl196000 
50795678Spl196000 	/* We don't allow inquiring about capabilities for other targets */
50805678Spl196000 	if (cap == NULL || whom == 0) {
50815678Spl196000 		AACDB_PRINT(softs, CE_WARN,
50825678Spl196000 		    "SetCap> %s not supported: whom=%d", cap, whom);
50835678Spl196000 		return (-1);
50845678Spl196000 	}
50855678Spl196000 
50865678Spl196000 	mutex_enter(&softs->io_lock);
50877567SXin.Chen@Sun.COM 	dvp = AAC_DEV(softs, ap->a_target);
50887567SXin.Chen@Sun.COM 	if (dvp == NULL || !AAC_DEV_IS_VALID(dvp)) {
50895678Spl196000 		mutex_exit(&softs->io_lock);
50907567SXin.Chen@Sun.COM 		AACDB_PRINT_TRAN(softs, "Bad target t%dL%d to setcap",
50915678Spl196000 		    ap->a_target, ap->a_lun);
50925678Spl196000 		return (-1);
50935678Spl196000 	}
50945678Spl196000 
50955678Spl196000 	switch (scsi_hba_lookup_capstr(cap)) {
50965678Spl196000 	case SCSI_CAP_ARQ:
50975678Spl196000 		/* Force auto request sense */
50985678Spl196000 		rval = (value == 1) ? 1 : 0;
50995678Spl196000 		break;
51005678Spl196000 	case SCSI_CAP_UNTAGGED_QING:
51015678Spl196000 	case SCSI_CAP_TAGGED_QING:
51025678Spl196000 		rval = (value == 1) ? 1 : 0;
51035678Spl196000 		break;
51045678Spl196000 	default:
51055678Spl196000 		rval = -1;
51065678Spl196000 		break;
51075678Spl196000 	}
51085678Spl196000 	mutex_exit(&softs->io_lock);
51095678Spl196000 
51105678Spl196000 	AACDB_PRINT_TRAN(softs, "SetCap> %s t%dL%d val=%d: rval=%d",
51115678Spl196000 	    cap, ap->a_target, ap->a_lun, value, rval);
51125678Spl196000 	return (rval);
51135678Spl196000 }
51145678Spl196000 
51155678Spl196000 static void
aac_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)51165678Spl196000 aac_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
51175678Spl196000 {
51185678Spl196000 	struct aac_cmd *acp = PKT2AC(pkt);
51195678Spl196000 
51205678Spl196000 	DBCALLED(NULL, 2);
51215678Spl196000 
51225678Spl196000 	if (acp->sgt) {
51235678Spl196000 		kmem_free(acp->sgt, sizeof (struct aac_sge) * \
51245678Spl196000 		    acp->left_cookien);
51255678Spl196000 	}
51265678Spl196000 	aac_free_dmamap(acp);
51275678Spl196000 	ASSERT(acp->slotp == NULL);
51285678Spl196000 	scsi_hba_pkt_free(ap, pkt);
51295678Spl196000 }
51305678Spl196000 
51315678Spl196000 int
aac_cmd_dma_alloc(struct aac_softstate * softs,struct aac_cmd * acp,struct buf * bp,int flags,int (* cb)(),caddr_t arg)51325678Spl196000 aac_cmd_dma_alloc(struct aac_softstate *softs, struct aac_cmd *acp,
51335678Spl196000     struct buf *bp, int flags, int (*cb)(), caddr_t arg)
51345678Spl196000 {
51355678Spl196000 	int kf = (cb == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
51365678Spl196000 	uint_t oldcookiec;
51375678Spl196000 	int bioerr;
51385678Spl196000 	int rval;
51395678Spl196000 
51405678Spl196000 	oldcookiec = acp->left_cookien;
51415678Spl196000 
51425678Spl196000 	/* Move window to build s/g map */
51435678Spl196000 	if (acp->total_nwin > 0) {
51445678Spl196000 		if (++acp->cur_win < acp->total_nwin) {
51455678Spl196000 			off_t off;
51465678Spl196000 			size_t len;
51475678Spl196000 
51485678Spl196000 			rval = ddi_dma_getwin(acp->buf_dma_handle, acp->cur_win,
51495678Spl196000 			    &off, &len, &acp->cookie, &acp->left_cookien);
51505678Spl196000 			if (rval == DDI_SUCCESS)
51515678Spl196000 				goto get_dma_cookies;
51525678Spl196000 			AACDB_PRINT(softs, CE_WARN,
51535678Spl196000 			    "ddi_dma_getwin() fail %d", rval);
51547567SXin.Chen@Sun.COM 			return (AACERR);
51555678Spl196000 		}
51565678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Nothing to transfer");
51577567SXin.Chen@Sun.COM 		return (AACERR);
51585678Spl196000 	}
51595678Spl196000 
51605678Spl196000 	/* We need to transfer data, so we alloc DMA resources for this pkt */
51615678Spl196000 	if (bp && bp->b_bcount != 0 && !(acp->flags & AAC_CMD_DMA_VALID)) {
51625678Spl196000 		uint_t dma_flags = 0;
51635678Spl196000 		struct aac_sge *sge;
51645678Spl196000 
51655678Spl196000 		/*
51665678Spl196000 		 * We will still use this point to fake some
51675678Spl196000 		 * infomation in tran_start
51685678Spl196000 		 */
51695678Spl196000 		acp->bp = bp;
51705678Spl196000 
51715678Spl196000 		/* Set dma flags */
51725678Spl196000 		if (BUF_IS_READ(bp)) {
51735678Spl196000 			dma_flags |= DDI_DMA_READ;
51745678Spl196000 			acp->flags |= AAC_CMD_BUF_READ;
51755678Spl196000 		} else {
51765678Spl196000 			dma_flags |= DDI_DMA_WRITE;
51775678Spl196000 			acp->flags |= AAC_CMD_BUF_WRITE;
51785678Spl196000 		}
51795678Spl196000 		if (flags & PKT_CONSISTENT)
51805678Spl196000 			dma_flags |= DDI_DMA_CONSISTENT;
51815678Spl196000 		if (flags & PKT_DMA_PARTIAL)
51825678Spl196000 			dma_flags |= DDI_DMA_PARTIAL;
51835678Spl196000 
51845678Spl196000 		/* Alloc buf dma handle */
51855678Spl196000 		if (!acp->buf_dma_handle) {
51865678Spl196000 			rval = ddi_dma_alloc_handle(softs->devinfo_p,
51875678Spl196000 			    &softs->buf_dma_attr, cb, arg,
51885678Spl196000 			    &acp->buf_dma_handle);
51895678Spl196000 			if (rval != DDI_SUCCESS) {
51905678Spl196000 				AACDB_PRINT(softs, CE_WARN,
51915678Spl196000 				    "Can't allocate DMA handle, errno=%d",
51925678Spl196000 				    rval);
51935678Spl196000 				goto error_out;
51945678Spl196000 			}
51955678Spl196000 		}
51965678Spl196000 
51975678Spl196000 		/* Bind buf */
51985678Spl196000 		if (((uintptr_t)bp->b_un.b_addr & AAC_DMA_ALIGN_MASK) == 0) {
51995678Spl196000 			rval = ddi_dma_buf_bind_handle(acp->buf_dma_handle,
52005678Spl196000 			    bp, dma_flags, cb, arg, &acp->cookie,
52015678Spl196000 			    &acp->left_cookien);
52025678Spl196000 		} else {
52035678Spl196000 			size_t bufsz;
52045678Spl196000 
52055678Spl196000 			AACDB_PRINT_TRAN(softs,
52065678Spl196000 			    "non-aligned buffer: addr=0x%p, cnt=%lu",
52075678Spl196000 			    (void *)bp->b_un.b_addr, bp->b_bcount);
52085678Spl196000 			if (bp->b_flags & (B_PAGEIO|B_PHYS))
52095678Spl196000 				bp_mapin(bp);
52105678Spl196000 
52115678Spl196000 			rval = ddi_dma_mem_alloc(acp->buf_dma_handle,
52125678Spl196000 			    AAC_ROUNDUP(bp->b_bcount, AAC_DMA_ALIGN),
52137567SXin.Chen@Sun.COM 			    &softs->acc_attr, DDI_DMA_STREAMING,
52145678Spl196000 			    cb, arg, &acp->abp, &bufsz, &acp->abh);
52155678Spl196000 
52165678Spl196000 			if (rval != DDI_SUCCESS) {
52175678Spl196000 				AACDB_PRINT(softs, CE_NOTE,
52185678Spl196000 				    "Cannot alloc DMA to non-aligned buf");
52195678Spl196000 				bioerr = 0;
52205678Spl196000 				goto error_out;
52215678Spl196000 			}
52225678Spl196000 
52235678Spl196000 			if (acp->flags & AAC_CMD_BUF_WRITE)
52245678Spl196000 				ddi_rep_put8(acp->abh,
52255678Spl196000 				    (uint8_t *)bp->b_un.b_addr,
52265678Spl196000 				    (uint8_t *)acp->abp, bp->b_bcount,
52275678Spl196000 				    DDI_DEV_AUTOINCR);
52285678Spl196000 
52295678Spl196000 			rval = ddi_dma_addr_bind_handle(acp->buf_dma_handle,
52305678Spl196000 			    NULL, acp->abp, bufsz, dma_flags, cb, arg,
52315678Spl196000 			    &acp->cookie, &acp->left_cookien);
52325678Spl196000 		}
52335678Spl196000 
52345678Spl196000 		switch (rval) {
52355678Spl196000 		case DDI_DMA_PARTIAL_MAP:
52365678Spl196000 			if (ddi_dma_numwin(acp->buf_dma_handle,
52375678Spl196000 			    &acp->total_nwin) == DDI_FAILURE) {
52385678Spl196000 				AACDB_PRINT(softs, CE_WARN,
52395678Spl196000 				    "Cannot get number of DMA windows");
52405678Spl196000 				bioerr = 0;
52415678Spl196000 				goto error_out;
52425678Spl196000 			}
52435678Spl196000 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52445678Spl196000 			    acp->left_cookien);
52455678Spl196000 			acp->cur_win = 0;
52465678Spl196000 			break;
52475678Spl196000 
52485678Spl196000 		case DDI_DMA_MAPPED:
52495678Spl196000 			AACDB_PRINT_TRAN(softs, "buf bind, %d seg(s)",
52505678Spl196000 			    acp->left_cookien);
52515678Spl196000 			acp->cur_win = 0;
52525678Spl196000 			acp->total_nwin = 1;
52535678Spl196000 			break;
52545678Spl196000 
52555678Spl196000 		case DDI_DMA_NORESOURCES:
52565678Spl196000 			bioerr = 0;
52575678Spl196000 			AACDB_PRINT(softs, CE_WARN,
52585678Spl196000 			    "Cannot bind buf for DMA: DDI_DMA_NORESOURCES");
52595678Spl196000 			goto error_out;
52605678Spl196000 		case DDI_DMA_BADATTR:
52615678Spl196000 		case DDI_DMA_NOMAPPING:
52625678Spl196000 			bioerr = EFAULT;
52635678Spl196000 			AACDB_PRINT(softs, CE_WARN,
52645678Spl196000 			    "Cannot bind buf for DMA: DDI_DMA_NOMAPPING");
52655678Spl196000 			goto error_out;
52665678Spl196000 		case DDI_DMA_TOOBIG:
52675678Spl196000 			bioerr = EINVAL;
52685678Spl196000 			AACDB_PRINT(softs, CE_WARN,
52695678Spl196000 			    "Cannot bind buf for DMA: DDI_DMA_TOOBIG(%d)",
52705678Spl196000 			    bp->b_bcount);
52715678Spl196000 			goto error_out;
52725678Spl196000 		default:
52735678Spl196000 			bioerr = EINVAL;
52745678Spl196000 			AACDB_PRINT(softs, CE_WARN,
52755678Spl196000 			    "Cannot bind buf for DMA: %d", rval);
52765678Spl196000 			goto error_out;
52775678Spl196000 		}
52785678Spl196000 		acp->flags |= AAC_CMD_DMA_VALID;
52795678Spl196000 
52805678Spl196000 get_dma_cookies:
52815678Spl196000 		ASSERT(acp->left_cookien > 0);
52825678Spl196000 		if (acp->left_cookien > softs->aac_sg_tablesize) {
52835678Spl196000 			AACDB_PRINT(softs, CE_NOTE, "large cookiec received %d",
52845678Spl196000 			    acp->left_cookien);
52855678Spl196000 			bioerr = EINVAL;
52865678Spl196000 			goto error_out;
52875678Spl196000 		}
52885678Spl196000 		if (oldcookiec != acp->left_cookien && acp->sgt != NULL) {
52895678Spl196000 			kmem_free(acp->sgt, sizeof (struct aac_sge) * \
52905678Spl196000 			    oldcookiec);
52915678Spl196000 			acp->sgt = NULL;
52925678Spl196000 		}
52935678Spl196000 		if (acp->sgt == NULL) {
52945678Spl196000 			acp->sgt = kmem_alloc(sizeof (struct aac_sge) * \
52955678Spl196000 			    acp->left_cookien, kf);
52965678Spl196000 			if (acp->sgt == NULL) {
52975678Spl196000 				AACDB_PRINT(softs, CE_WARN,
52985678Spl196000 				    "sgt kmem_alloc fail");
52995678Spl196000 				bioerr = ENOMEM;
53005678Spl196000 				goto error_out;
53015678Spl196000 			}
53025678Spl196000 		}
53035678Spl196000 
53045678Spl196000 		sge = &acp->sgt[0];
53055678Spl196000 		sge->bcount = acp->cookie.dmac_size;
53065678Spl196000 		sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
53075678Spl196000 		sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
53085678Spl196000 		acp->bcount = acp->cookie.dmac_size;
53095678Spl196000 		for (sge++; sge < &acp->sgt[acp->left_cookien]; sge++) {
53105678Spl196000 			ddi_dma_nextcookie(acp->buf_dma_handle, &acp->cookie);
53115678Spl196000 			sge->bcount = acp->cookie.dmac_size;
53125678Spl196000 			sge->addr.ad64.lo = AAC_LS32(acp->cookie.dmac_laddress);
53135678Spl196000 			sge->addr.ad64.hi = AAC_MS32(acp->cookie.dmac_laddress);
53145678Spl196000 			acp->bcount += acp->cookie.dmac_size;
53155678Spl196000 		}
53165678Spl196000 
53175678Spl196000 		/*
53185678Spl196000 		 * Note: The old DMA engine do not correctly handle
53195678Spl196000 		 * dma_attr_maxxfer attribute. So we have to ensure
53205678Spl196000 		 * it by ourself.
53215678Spl196000 		 */
53225678Spl196000 		if (acp->bcount > softs->buf_dma_attr.dma_attr_maxxfer) {
53235678Spl196000 			AACDB_PRINT(softs, CE_NOTE,
53245678Spl196000 			    "large xfer size received %d\n", acp->bcount);
53255678Spl196000 			bioerr = EINVAL;
53265678Spl196000 			goto error_out;
53275678Spl196000 		}
53285678Spl196000 
53295678Spl196000 		acp->total_xfer += acp->bcount;
53305678Spl196000 
53315678Spl196000 		if (acp->pkt) {
53325678Spl196000 			/* Return remaining byte count */
53337567SXin.Chen@Sun.COM 			if (acp->total_xfer <= bp->b_bcount) {
53347567SXin.Chen@Sun.COM 				acp->pkt->pkt_resid = bp->b_bcount - \
53357567SXin.Chen@Sun.COM 				    acp->total_xfer;
53367567SXin.Chen@Sun.COM 			} else {
53377567SXin.Chen@Sun.COM 				/*
53387567SXin.Chen@Sun.COM 				 * Allocated DMA size is greater than the buf
53397567SXin.Chen@Sun.COM 				 * size of bp. This is caused by devices like
53407567SXin.Chen@Sun.COM 				 * tape. we have extra bytes allocated, but
53417567SXin.Chen@Sun.COM 				 * the packet residual has to stay correct.
53427567SXin.Chen@Sun.COM 				 */
53437567SXin.Chen@Sun.COM 				acp->pkt->pkt_resid = 0;
53447567SXin.Chen@Sun.COM 			}
53455678Spl196000 			AACDB_PRINT_TRAN(softs,
53465678Spl196000 			    "bp=0x%p, xfered=%d/%d, resid=%d",
53475678Spl196000 			    (void *)bp->b_un.b_addr, (int)acp->total_xfer,
53485678Spl196000 			    (int)bp->b_bcount, (int)acp->pkt->pkt_resid);
53495678Spl196000 		}
53505678Spl196000 	}
53515678Spl196000 	return (AACOK);
53525678Spl196000 
53535678Spl196000 error_out:
53545678Spl196000 	bioerror(bp, bioerr);
53555678Spl196000 	return (AACERR);
53565678Spl196000 }
53575678Spl196000 
53585678Spl196000 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)53595678Spl196000 aac_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
53605678Spl196000     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
53615678Spl196000     int (*callback)(), caddr_t arg)
53625678Spl196000 {
53635678Spl196000 	struct aac_softstate *softs = AAC_TRAN2SOFTS(ap->a_hba_tran);
53645678Spl196000 	struct aac_cmd *acp, *new_acp;
53655678Spl196000 
53665678Spl196000 	DBCALLED(softs, 2);
53675678Spl196000 
53685678Spl196000 	/* Allocate pkt */
53695678Spl196000 	if (pkt == NULL) {
53705678Spl196000 		int slen;
53715678Spl196000 
53725678Spl196000 		/* Force auto request sense */
53735678Spl196000 		slen = (statuslen > softs->slen) ? statuslen : softs->slen;
53745678Spl196000 		pkt = scsi_hba_pkt_alloc(softs->devinfo_p, ap, cmdlen,
53755678Spl196000 		    slen, tgtlen, sizeof (struct aac_cmd), callback, arg);
53765678Spl196000 		if (pkt == NULL) {
53775678Spl196000 			AACDB_PRINT(softs, CE_WARN, "Alloc scsi pkt failed");
53785678Spl196000 			return (NULL);
53795678Spl196000 		}
53805678Spl196000 		acp = new_acp = PKT2AC(pkt);
53815678Spl196000 		acp->pkt = pkt;
53825678Spl196000 		acp->cmdlen = cmdlen;
53835678Spl196000 
53847567SXin.Chen@Sun.COM 		if (ap->a_target < AAC_MAX_LD) {
53857567SXin.Chen@Sun.COM 			acp->dvp = &softs->containers[ap->a_target].dev;
53867567SXin.Chen@Sun.COM 			acp->aac_cmd_fib = softs->aac_cmd_fib;
53877567SXin.Chen@Sun.COM 			acp->ac_comp = aac_ld_complete;
53887567SXin.Chen@Sun.COM 		} else {
53897567SXin.Chen@Sun.COM 			_NOTE(ASSUMING_PROTECTED(softs->nondasds))
53907567SXin.Chen@Sun.COM 
53917567SXin.Chen@Sun.COM 			acp->dvp = &softs->nondasds[AAC_PD(ap->a_target)].dev;
53927567SXin.Chen@Sun.COM 			acp->aac_cmd_fib = softs->aac_cmd_fib_scsi;
53937567SXin.Chen@Sun.COM 			acp->ac_comp = aac_pd_complete;
53947567SXin.Chen@Sun.COM 		}
53955678Spl196000 	} else {
53965678Spl196000 		acp = PKT2AC(pkt);
53975678Spl196000 		new_acp = NULL;
53985678Spl196000 	}
53995678Spl196000 
54005678Spl196000 	if (aac_cmd_dma_alloc(softs, acp, bp, flags, callback, arg) == AACOK)
54015678Spl196000 		return (pkt);
54025678Spl196000 
54035678Spl196000 	if (new_acp)
54045678Spl196000 		aac_tran_destroy_pkt(ap, pkt);
54055678Spl196000 	return (NULL);
54065678Spl196000 }
54075678Spl196000 
54085678Spl196000 /*
54095678Spl196000  * tran_sync_pkt(9E) - explicit DMA synchronization
54105678Spl196000  */
54115678Spl196000 /*ARGSUSED*/
54125678Spl196000 static void
aac_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)54135678Spl196000 aac_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
54145678Spl196000 {
54155678Spl196000 	struct aac_cmd *acp = PKT2AC(pkt);
54165678Spl196000 
54175678Spl196000 	DBCALLED(NULL, 2);
54185678Spl196000 
54195678Spl196000 	if (aac_dma_sync_ac(acp) != AACOK)
54205678Spl196000 		ddi_fm_service_impact(
54215678Spl196000 		    (AAC_TRAN2SOFTS(ap->a_hba_tran))->devinfo_p,
54225678Spl196000 		    DDI_SERVICE_UNAFFECTED);
54235678Spl196000 }
54245678Spl196000 
54255678Spl196000 /*
54265678Spl196000  * tran_dmafree(9E) - deallocate DMA resources allocated for command
54275678Spl196000  */
54285678Spl196000 /*ARGSUSED*/
54295678Spl196000 static void
aac_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)54305678Spl196000 aac_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
54315678Spl196000 {
54325678Spl196000 	struct aac_cmd *acp = PKT2AC(pkt);
54335678Spl196000 
54345678Spl196000 	DBCALLED(NULL, 2);
54355678Spl196000 
54365678Spl196000 	aac_free_dmamap(acp);
54375678Spl196000 }
54385678Spl196000 
54395678Spl196000 static int
aac_do_quiesce(struct aac_softstate * softs)54405678Spl196000 aac_do_quiesce(struct aac_softstate *softs)
54415678Spl196000 {
54425678Spl196000 	aac_hold_bus(softs, AAC_IOCMD_ASYNC);
54435678Spl196000 	if (softs->bus_ncmds[AAC_CMDQ_ASYNC]) {
54445678Spl196000 		aac_start_drain(softs);
54455678Spl196000 		do {
54465678Spl196000 			if (cv_wait_sig(&softs->drain_cv,
54475678Spl196000 			    &softs->io_lock) == 0) {
54485678Spl196000 				/* Quiesce has been interrupted */
54495678Spl196000 				aac_stop_drain(softs);
54505678Spl196000 				aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
54515678Spl196000 				aac_start_waiting_io(softs);
54525678Spl196000 				return (AACERR);
54535678Spl196000 			}
54545678Spl196000 		} while (softs->bus_ncmds[AAC_CMDQ_ASYNC]);
54555678Spl196000 		aac_stop_drain(softs);
54565678Spl196000 	}
54575678Spl196000 
54585678Spl196000 	softs->state |= AAC_STATE_QUIESCED;
54595678Spl196000 	return (AACOK);
54605678Spl196000 }
54615678Spl196000 
54625678Spl196000 static int
aac_tran_quiesce(dev_info_t * dip)54635678Spl196000 aac_tran_quiesce(dev_info_t *dip)
54645678Spl196000 {
54655678Spl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
54665678Spl196000 	int rval;
54675678Spl196000 
54685678Spl196000 	DBCALLED(softs, 1);
54695678Spl196000 
54705678Spl196000 	mutex_enter(&softs->io_lock);
54715678Spl196000 	if (aac_do_quiesce(softs) == AACOK)
54725678Spl196000 		rval = 0;
54735678Spl196000 	else
54745678Spl196000 		rval = 1;
54755678Spl196000 	mutex_exit(&softs->io_lock);
54765678Spl196000 	return (rval);
54775678Spl196000 }
54785678Spl196000 
54795678Spl196000 static int
aac_do_unquiesce(struct aac_softstate * softs)54805678Spl196000 aac_do_unquiesce(struct aac_softstate *softs)
54815678Spl196000 {
54825678Spl196000 	softs->state &= ~AAC_STATE_QUIESCED;
54835678Spl196000 	aac_unhold_bus(softs, AAC_IOCMD_ASYNC);
54845678Spl196000 
54855678Spl196000 	aac_start_waiting_io(softs);
54865678Spl196000 	return (AACOK);
54875678Spl196000 }
54885678Spl196000 
54895678Spl196000 static int
aac_tran_unquiesce(dev_info_t * dip)54905678Spl196000 aac_tran_unquiesce(dev_info_t *dip)
54915678Spl196000 {
54925678Spl196000 	struct aac_softstate *softs = AAC_DIP2SOFTS(dip);
54935678Spl196000 	int rval;
54945678Spl196000 
54955678Spl196000 	DBCALLED(softs, 1);
54965678Spl196000 
54975678Spl196000 	mutex_enter(&softs->io_lock);
54985678Spl196000 	if (aac_do_unquiesce(softs) == AACOK)
54995678Spl196000 		rval = 0;
55005678Spl196000 	else
55015678Spl196000 		rval = 1;
55025678Spl196000 	mutex_exit(&softs->io_lock);
55035678Spl196000 	return (rval);
55045678Spl196000 }
55055678Spl196000 
55065678Spl196000 static int
aac_hba_setup(struct aac_softstate * softs)55075678Spl196000 aac_hba_setup(struct aac_softstate *softs)
55085678Spl196000 {
55095678Spl196000 	scsi_hba_tran_t *hba_tran;
55105678Spl196000 	int rval;
55115678Spl196000 
55125678Spl196000 	hba_tran = scsi_hba_tran_alloc(softs->devinfo_p, SCSI_HBA_CANSLEEP);
55135678Spl196000 	if (hba_tran == NULL)
55145678Spl196000 		return (AACERR);
55155678Spl196000 	hba_tran->tran_hba_private = softs;
55165678Spl196000 	hba_tran->tran_tgt_init = aac_tran_tgt_init;
55177567SXin.Chen@Sun.COM 	hba_tran->tran_tgt_free = aac_tran_tgt_free;
55185678Spl196000 	hba_tran->tran_tgt_probe = scsi_hba_probe;
55195678Spl196000 	hba_tran->tran_start = aac_tran_start;
55205678Spl196000 	hba_tran->tran_getcap = aac_tran_getcap;
55215678Spl196000 	hba_tran->tran_setcap = aac_tran_setcap;
55225678Spl196000 	hba_tran->tran_init_pkt = aac_tran_init_pkt;
55235678Spl196000 	hba_tran->tran_destroy_pkt = aac_tran_destroy_pkt;
55245678Spl196000 	hba_tran->tran_reset = aac_tran_reset;
55255678Spl196000 	hba_tran->tran_abort = aac_tran_abort;
55265678Spl196000 	hba_tran->tran_sync_pkt = aac_tran_sync_pkt;
55275678Spl196000 	hba_tran->tran_dmafree = aac_tran_dmafree;
55285678Spl196000 	hba_tran->tran_quiesce = aac_tran_quiesce;
55295678Spl196000 	hba_tran->tran_unquiesce = aac_tran_unquiesce;
55307567SXin.Chen@Sun.COM 	hba_tran->tran_bus_config = aac_tran_bus_config;
55315678Spl196000 	rval = scsi_hba_attach_setup(softs->devinfo_p, &softs->buf_dma_attr,
55325678Spl196000 	    hba_tran, 0);
55335678Spl196000 	if (rval != DDI_SUCCESS) {
55345678Spl196000 		scsi_hba_tran_free(hba_tran);
55355678Spl196000 		AACDB_PRINT(softs, CE_WARN, "aac_hba_setup failed");
55365678Spl196000 		return (AACERR);
55375678Spl196000 	}
55385678Spl196000 
55397567SXin.Chen@Sun.COM 	softs->hba_tran = hba_tran;
55405678Spl196000 	return (AACOK);
55415678Spl196000 }
55425678Spl196000 
55435678Spl196000 /*
55445678Spl196000  * FIB setup operations
55455678Spl196000  */
55465678Spl196000 
55475678Spl196000 /*
55485678Spl196000  * Init FIB header
55495678Spl196000  */
55505678Spl196000 static void
aac_cmd_fib_header(struct aac_softstate * softs,struct aac_cmd * acp,uint16_t cmd)555111348SZhongyan.Gu@Sun.COM aac_cmd_fib_header(struct aac_softstate *softs, struct aac_cmd *acp,
555211348SZhongyan.Gu@Sun.COM     uint16_t cmd)
555311348SZhongyan.Gu@Sun.COM {
555411348SZhongyan.Gu@Sun.COM 	struct aac_slot *slotp = acp->slotp;
55555678Spl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
55565678Spl196000 	struct aac_fib *fibp = slotp->fibp;
55575678Spl196000 	uint32_t xfer_state;
55585678Spl196000 
55595678Spl196000 	xfer_state =
55605678Spl196000 	    AAC_FIBSTATE_HOSTOWNED |
55615678Spl196000 	    AAC_FIBSTATE_INITIALISED |
55625678Spl196000 	    AAC_FIBSTATE_EMPTY |
556311964SXin.Chen@Sun.COM 	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
55645678Spl196000 	    AAC_FIBSTATE_FROMHOST |
55655678Spl196000 	    AAC_FIBSTATE_REXPECTED |
55665678Spl196000 	    AAC_FIBSTATE_NORM;
556711348SZhongyan.Gu@Sun.COM 
556811964SXin.Chen@Sun.COM 	if (!(acp->flags & AAC_CMD_SYNC))
556911964SXin.Chen@Sun.COM 		xfer_state |= AAC_FIBSTATE_ASYNC;
55705678Spl196000 
55715678Spl196000 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
55725678Spl196000 	ddi_put16(acc, &fibp->Header.Command, cmd);
55735678Spl196000 	ddi_put8(acc, &fibp->Header.StructType, AAC_FIBTYPE_TFIB);
55745678Spl196000 	ddi_put8(acc, &fibp->Header.Flags, 0); /* don't care */
557511348SZhongyan.Gu@Sun.COM 	ddi_put16(acc, &fibp->Header.Size, acp->fib_size);
557611348SZhongyan.Gu@Sun.COM 	ddi_put16(acc, &fibp->Header.SenderSize, softs->aac_max_fib_size);
55775678Spl196000 	ddi_put32(acc, &fibp->Header.SenderFibAddress, (slotp->index << 2));
55785678Spl196000 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
55795678Spl196000 	ddi_put32(acc, &fibp->Header.SenderData, 0); /* don't care */
55805678Spl196000 }
55815678Spl196000 
55825678Spl196000 /*
55835678Spl196000  * Init FIB for raw IO command
55845678Spl196000  */
55855678Spl196000 static void
aac_cmd_fib_rawio(struct aac_softstate * softs,struct aac_cmd * acp)55865678Spl196000 aac_cmd_fib_rawio(struct aac_softstate *softs, struct aac_cmd *acp)
55875678Spl196000 {
55885678Spl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
55895678Spl196000 	struct aac_raw_io *io = (struct aac_raw_io *)&acp->slotp->fibp->data[0];
55905678Spl196000 	struct aac_sg_entryraw *sgp;
55915678Spl196000 	struct aac_sge *sge;
55925678Spl196000 
55935678Spl196000 	/* Calculate FIB size */
55945678Spl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
55955678Spl196000 	    sizeof (struct aac_raw_io) + (acp->left_cookien - 1) * \
55965678Spl196000 	    sizeof (struct aac_sg_entryraw);
55975678Spl196000 
559811348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, RawIo);
55995678Spl196000 
56005678Spl196000 	ddi_put16(acc, &io->Flags, (acp->flags & AAC_CMD_BUF_READ) ? 1 : 0);
56015678Spl196000 	ddi_put16(acc, &io->BpTotal, 0);
56025678Spl196000 	ddi_put16(acc, &io->BpComplete, 0);
56035678Spl196000 
56045678Spl196000 	ddi_put32(acc, AAC_LO32(&io->BlockNumber), AAC_LS32(acp->blkno));
56055678Spl196000 	ddi_put32(acc, AAC_HI32(&io->BlockNumber), AAC_MS32(acp->blkno));
56065678Spl196000 	ddi_put16(acc, &io->ContainerId,
56075678Spl196000 	    ((struct aac_container *)acp->dvp)->cid);
56085678Spl196000 
56095678Spl196000 	/* Fill SG table */
56105678Spl196000 	ddi_put32(acc, &io->SgMapRaw.SgCount, acp->left_cookien);
56115678Spl196000 	ddi_put32(acc, &io->ByteCount, acp->bcount);
56125678Spl196000 
56135678Spl196000 	for (sge = &acp->sgt[0], sgp = &io->SgMapRaw.SgEntryRaw[0];
56145678Spl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
56155678Spl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
56165678Spl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
56175678Spl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
56185678Spl196000 		sgp->Next = 0;
56195678Spl196000 		sgp->Prev = 0;
56205678Spl196000 		sgp->Flags = 0;
56215678Spl196000 	}
56225678Spl196000 }
56235678Spl196000 
56245678Spl196000 /* Init FIB for 64-bit block IO command */
56255678Spl196000 static void
aac_cmd_fib_brw64(struct aac_softstate * softs,struct aac_cmd * acp)56265678Spl196000 aac_cmd_fib_brw64(struct aac_softstate *softs, struct aac_cmd *acp)
56275678Spl196000 {
56285678Spl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
56295678Spl196000 	struct aac_blockread64 *br = (struct aac_blockread64 *) \
56305678Spl196000 	    &acp->slotp->fibp->data[0];
56315678Spl196000 	struct aac_sg_entry64 *sgp;
56325678Spl196000 	struct aac_sge *sge;
56335678Spl196000 
56345678Spl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
56355678Spl196000 	    sizeof (struct aac_blockread64) + (acp->left_cookien - 1) * \
56365678Spl196000 	    sizeof (struct aac_sg_entry64);
56375678Spl196000 
563811348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ContainerCommand64);
56395678Spl196000 
56405678Spl196000 	/*
56415678Spl196000 	 * The definitions for aac_blockread64 and aac_blockwrite64
56425678Spl196000 	 * are the same.
56435678Spl196000 	 */
56445678Spl196000 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
56455678Spl196000 	ddi_put16(acc, &br->ContainerId,
56465678Spl196000 	    ((struct aac_container *)acp->dvp)->cid);
56475678Spl196000 	ddi_put32(acc, &br->Command, (acp->flags & AAC_CMD_BUF_READ) ?
56485678Spl196000 	    VM_CtHostRead64 : VM_CtHostWrite64);
56495678Spl196000 	ddi_put16(acc, &br->Pad, 0);
56505678Spl196000 	ddi_put16(acc, &br->Flags, 0);
56515678Spl196000 
56525678Spl196000 	/* Fill SG table */
56535678Spl196000 	ddi_put32(acc, &br->SgMap64.SgCount, acp->left_cookien);
56545678Spl196000 	ddi_put16(acc, &br->SectorCount, acp->bcount / AAC_BLK_SIZE);
56555678Spl196000 
56565678Spl196000 	for (sge = &acp->sgt[0], sgp = &br->SgMap64.SgEntry64[0];
56575678Spl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
56585678Spl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
56595678Spl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
56605678Spl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
56615678Spl196000 	}
56625678Spl196000 }
56635678Spl196000 
56645678Spl196000 /* Init FIB for block IO command */
56655678Spl196000 static void
aac_cmd_fib_brw(struct aac_softstate * softs,struct aac_cmd * acp)56665678Spl196000 aac_cmd_fib_brw(struct aac_softstate *softs, struct aac_cmd *acp)
56675678Spl196000 {
56685678Spl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
56695678Spl196000 	struct aac_blockread *br = (struct aac_blockread *) \
56705678Spl196000 	    &acp->slotp->fibp->data[0];
56715678Spl196000 	struct aac_sg_entry *sgp;
56725678Spl196000 	struct aac_sge *sge = &acp->sgt[0];
56735678Spl196000 
56745678Spl196000 	if (acp->flags & AAC_CMD_BUF_READ) {
56755678Spl196000 		acp->fib_size = sizeof (struct aac_fib_header) + \
56765678Spl196000 		    sizeof (struct aac_blockread) + (acp->left_cookien - 1) * \
56775678Spl196000 		    sizeof (struct aac_sg_entry);
56785678Spl196000 
56795678Spl196000 		ddi_put32(acc, &br->Command, VM_CtBlockRead);
56805678Spl196000 		ddi_put32(acc, &br->SgMap.SgCount, acp->left_cookien);
56815678Spl196000 		sgp = &br->SgMap.SgEntry[0];
56825678Spl196000 	} else {
56835678Spl196000 		struct aac_blockwrite *bw = (struct aac_blockwrite *)br;
56845678Spl196000 
56855678Spl196000 		acp->fib_size = sizeof (struct aac_fib_header) + \
56865678Spl196000 		    sizeof (struct aac_blockwrite) + (acp->left_cookien - 1) * \
56875678Spl196000 		    sizeof (struct aac_sg_entry);
56885678Spl196000 
56895678Spl196000 		ddi_put32(acc, &bw->Command, VM_CtBlockWrite);
56905678Spl196000 		ddi_put32(acc, &bw->Stable, CUNSTABLE);
56915678Spl196000 		ddi_put32(acc, &bw->SgMap.SgCount, acp->left_cookien);
56925678Spl196000 		sgp = &bw->SgMap.SgEntry[0];
56935678Spl196000 	}
569411348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ContainerCommand);
56955678Spl196000 
56965678Spl196000 	/*
56975678Spl196000 	 * aac_blockread and aac_blockwrite have the similar
56985678Spl196000 	 * structure head, so use br for bw here
56995678Spl196000 	 */
57005678Spl196000 	ddi_put32(acc, &br->BlockNumber, (uint32_t)acp->blkno);
57015678Spl196000 	ddi_put32(acc, &br->ContainerId,
57025678Spl196000 	    ((struct aac_container *)acp->dvp)->cid);
57035678Spl196000 	ddi_put32(acc, &br->ByteCount, acp->bcount);
57045678Spl196000 
57055678Spl196000 	/* Fill SG table */
57065678Spl196000 	for (sge = &acp->sgt[0];
57075678Spl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
57085678Spl196000 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
57095678Spl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
57105678Spl196000 	}
57115678Spl196000 }
57125678Spl196000 
57135678Spl196000 /*ARGSUSED*/
57145678Spl196000 void
aac_cmd_fib_copy(struct aac_softstate * softs,struct aac_cmd * acp)57155678Spl196000 aac_cmd_fib_copy(struct aac_softstate *softs, struct aac_cmd *acp)
57165678Spl196000 {
57175678Spl196000 	struct aac_slot *slotp = acp->slotp;
57185678Spl196000 	struct aac_fib *fibp = slotp->fibp;
57195678Spl196000 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
57205678Spl196000 
57215678Spl196000 	ddi_rep_put8(acc, (uint8_t *)acp->fibp, (uint8_t *)fibp,
57225678Spl196000 	    acp->fib_size,   /* only copy data of needed length */
57235678Spl196000 	    DDI_DEV_AUTOINCR);
57245678Spl196000 	ddi_put32(acc, &fibp->Header.ReceiverFibAddress, slotp->fib_phyaddr);
57255678Spl196000 	ddi_put32(acc, &fibp->Header.SenderFibAddress, slotp->index << 2);
57265678Spl196000 }
57275678Spl196000 
57285678Spl196000 static void
aac_cmd_fib_sync(struct aac_softstate * softs,struct aac_cmd * acp)57295678Spl196000 aac_cmd_fib_sync(struct aac_softstate *softs, struct aac_cmd *acp)
57305678Spl196000 {
573111348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
57325678Spl196000 	struct aac_synchronize_command *sync =
573311348SZhongyan.Gu@Sun.COM 	    (struct aac_synchronize_command *)&acp->slotp->fibp->data[0];
573411348SZhongyan.Gu@Sun.COM 
573511348SZhongyan.Gu@Sun.COM 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_synchronize_command);
573611348SZhongyan.Gu@Sun.COM 
573711348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ContainerCommand);
57385678Spl196000 	ddi_put32(acc, &sync->Command, VM_ContainerConfig);
57395678Spl196000 	ddi_put32(acc, &sync->Type, (uint32_t)CT_FLUSH_CACHE);
57405678Spl196000 	ddi_put32(acc, &sync->Cid, ((struct aac_container *)acp->dvp)->cid);
57415678Spl196000 	ddi_put32(acc, &sync->Count,
57425678Spl196000 	    sizeof (((struct aac_synchronize_reply *)0)->Data));
57435678Spl196000 }
57445678Spl196000 
57455678Spl196000 /*
574610976SZhongyan.Gu@Sun.COM  * Start/Stop unit (Power Management)
574710976SZhongyan.Gu@Sun.COM  */
574810976SZhongyan.Gu@Sun.COM static void
aac_cmd_fib_startstop(struct aac_softstate * softs,struct aac_cmd * acp)574910976SZhongyan.Gu@Sun.COM aac_cmd_fib_startstop(struct aac_softstate *softs, struct aac_cmd *acp)
575010976SZhongyan.Gu@Sun.COM {
575111348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
575210976SZhongyan.Gu@Sun.COM 	struct aac_Container *cmd =
575311348SZhongyan.Gu@Sun.COM 	    (struct aac_Container *)&acp->slotp->fibp->data[0];
575410976SZhongyan.Gu@Sun.COM 	union scsi_cdb *cdbp = (void *)acp->pkt->pkt_cdbp;
575510976SZhongyan.Gu@Sun.COM 
575610976SZhongyan.Gu@Sun.COM 	acp->fib_size = AAC_FIB_SIZEOF(struct aac_Container);
575710976SZhongyan.Gu@Sun.COM 
575811348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ContainerCommand);
575910976SZhongyan.Gu@Sun.COM 	bzero(cmd, sizeof (*cmd) - CT_PACKET_SIZE);
576010976SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &cmd->Command, VM_ContainerConfig);
576110976SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &cmd->CTCommand.command, CT_PM_DRIVER_SUPPORT);
576210976SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &cmd->CTCommand.param[0], cdbp->cdb_opaque[4] & 1 ? \
576310976SZhongyan.Gu@Sun.COM 	    AAC_PM_DRIVERSUP_START_UNIT : AAC_PM_DRIVERSUP_STOP_UNIT);
576410976SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &cmd->CTCommand.param[1],
576510976SZhongyan.Gu@Sun.COM 	    ((struct aac_container *)acp->dvp)->cid);
576610976SZhongyan.Gu@Sun.COM 	ddi_put32(acc, &cmd->CTCommand.param[2], cdbp->cdb_opaque[1] & 1);
576710976SZhongyan.Gu@Sun.COM }
576810976SZhongyan.Gu@Sun.COM 
576910976SZhongyan.Gu@Sun.COM /*
57705678Spl196000  * Init FIB for pass-through SCMD
57715678Spl196000  */
57725678Spl196000 static void
aac_cmd_fib_srb(struct aac_cmd * acp)57735678Spl196000 aac_cmd_fib_srb(struct aac_cmd *acp)
57745678Spl196000 {
577511348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
577611348SZhongyan.Gu@Sun.COM 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
57777567SXin.Chen@Sun.COM 	uint8_t *cdb;
57785678Spl196000 
57795678Spl196000 	ddi_put32(acc, &srb->function, SRBF_ExecuteScsi);
57805678Spl196000 	ddi_put32(acc, &srb->retry_limit, 0);
57815678Spl196000 	ddi_put32(acc, &srb->cdb_size, acp->cmdlen);
57825678Spl196000 	ddi_put32(acc, &srb->timeout, 0); /* use driver timeout */
57837567SXin.Chen@Sun.COM 	if (acp->fibp == NULL) {
57847567SXin.Chen@Sun.COM 		if (acp->flags & AAC_CMD_BUF_READ)
57857567SXin.Chen@Sun.COM 			ddi_put32(acc, &srb->flags, SRB_DataIn);
57867567SXin.Chen@Sun.COM 		else if (acp->flags & AAC_CMD_BUF_WRITE)
57877567SXin.Chen@Sun.COM 			ddi_put32(acc, &srb->flags, SRB_DataOut);
57887567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->channel,
57897567SXin.Chen@Sun.COM 		    ((struct aac_nondasd *)acp->dvp)->bus);
57907567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->id, ((struct aac_nondasd *)acp->dvp)->tid);
57917567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->lun, 0);
57927567SXin.Chen@Sun.COM 		cdb = acp->pkt->pkt_cdbp;
57937567SXin.Chen@Sun.COM 	} else {
57947567SXin.Chen@Sun.COM 		struct aac_srb *srb0 = (struct aac_srb *)&acp->fibp->data[0];
57957567SXin.Chen@Sun.COM 
57967567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->flags, srb0->flags);
57977567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->channel, srb0->channel);
57987567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->id, srb0->id);
57997567SXin.Chen@Sun.COM 		ddi_put32(acc, &srb->lun, srb0->lun);
58007567SXin.Chen@Sun.COM 		cdb = srb0->cdb;
58017567SXin.Chen@Sun.COM 	}
58027567SXin.Chen@Sun.COM 	ddi_rep_put8(acc, cdb, srb->cdb, acp->cmdlen, DDI_DEV_AUTOINCR);
58035678Spl196000 }
58045678Spl196000 
58055678Spl196000 static void
aac_cmd_fib_scsi32(struct aac_softstate * softs,struct aac_cmd * acp)58065678Spl196000 aac_cmd_fib_scsi32(struct aac_softstate *softs, struct aac_cmd *acp)
58075678Spl196000 {
58085678Spl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
58095678Spl196000 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
58105678Spl196000 	struct aac_sg_entry *sgp;
58115678Spl196000 	struct aac_sge *sge;
58125678Spl196000 
58135678Spl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
58145678Spl196000 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
58155678Spl196000 	    acp->left_cookien * sizeof (struct aac_sg_entry);
58165678Spl196000 
58175678Spl196000 	/* Fill FIB and SRB headers, and copy cdb */
581811348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ScsiPortCommand);
58195678Spl196000 	aac_cmd_fib_srb(acp);
58205678Spl196000 
58215678Spl196000 	/* Fill SG table */
58225678Spl196000 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
58235678Spl196000 	ddi_put32(acc, &srb->count, acp->bcount);
58245678Spl196000 
58255678Spl196000 	for (sge = &acp->sgt[0], sgp = &srb->sg.SgEntry[0];
58265678Spl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
58275678Spl196000 		ddi_put32(acc, &sgp->SgAddress, sge->addr.ad32);
58285678Spl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
58295678Spl196000 	}
58305678Spl196000 }
58315678Spl196000 
58325678Spl196000 static void
aac_cmd_fib_scsi64(struct aac_softstate * softs,struct aac_cmd * acp)58335678Spl196000 aac_cmd_fib_scsi64(struct aac_softstate *softs, struct aac_cmd *acp)
58345678Spl196000 {
58355678Spl196000 	ddi_acc_handle_t acc = acp->slotp->fib_acc_handle;
58365678Spl196000 	struct aac_srb *srb = (struct aac_srb *)&acp->slotp->fibp->data[0];
58375678Spl196000 	struct aac_sg_entry64 *sgp;
58385678Spl196000 	struct aac_sge *sge;
58395678Spl196000 
58405678Spl196000 	acp->fib_size = sizeof (struct aac_fib_header) + \
58415678Spl196000 	    sizeof (struct aac_srb) - sizeof (struct aac_sg_entry) + \
58425678Spl196000 	    acp->left_cookien * sizeof (struct aac_sg_entry64);
58435678Spl196000 
58445678Spl196000 	/* Fill FIB and SRB headers, and copy cdb */
584511348SZhongyan.Gu@Sun.COM 	aac_cmd_fib_header(softs, acp, ScsiPortCommandU64);
58465678Spl196000 	aac_cmd_fib_srb(acp);
58475678Spl196000 
58485678Spl196000 	/* Fill SG table */
58495678Spl196000 	ddi_put32(acc, &srb->sg.SgCount, acp->left_cookien);
58505678Spl196000 	ddi_put32(acc, &srb->count, acp->bcount);
58515678Spl196000 
58525678Spl196000 	for (sge = &acp->sgt[0],
58535678Spl196000 	    sgp = &((struct aac_sg_table64 *)&srb->sg)->SgEntry64[0];
58545678Spl196000 	    sge < &acp->sgt[acp->left_cookien]; sge++, sgp++) {
58555678Spl196000 		ddi_put32(acc, AAC_LO32(&sgp->SgAddress), sge->addr.ad64.lo);
58565678Spl196000 		ddi_put32(acc, AAC_HI32(&sgp->SgAddress), sge->addr.ad64.hi);
58575678Spl196000 		ddi_put32(acc, &sgp->SgByteCount, sge->bcount);
58585678Spl196000 	}
58595678Spl196000 }
58605678Spl196000 
58615678Spl196000 static int
aac_cmd_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)58625678Spl196000 aac_cmd_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
58635678Spl196000 {
58645678Spl196000 	struct aac_slot *slotp;
58655678Spl196000 
58665678Spl196000 	if (slotp = aac_get_slot(softs)) {
58675678Spl196000 		acp->slotp = slotp;
58685678Spl196000 		slotp->acp = acp;
58695678Spl196000 		acp->aac_cmd_fib(softs, acp);
58705678Spl196000 		(void) ddi_dma_sync(slotp->fib_dma_handle, 0, 0,
58715678Spl196000 		    DDI_DMA_SYNC_FORDEV);
58725678Spl196000 		return (AACOK);
58735678Spl196000 	}
58745678Spl196000 	return (AACERR);
58755678Spl196000 }
58765678Spl196000 
58775678Spl196000 static int
aac_bind_io(struct aac_softstate * softs,struct aac_cmd * acp)58785678Spl196000 aac_bind_io(struct aac_softstate *softs, struct aac_cmd *acp)
58795678Spl196000 {
58807567SXin.Chen@Sun.COM 	struct aac_device *dvp = acp->dvp;
58815678Spl196000 	int q = AAC_CMDQ(acp);
58825678Spl196000 
588311636SXin.Chen@Sun.COM 	if (softs->bus_ncmds[q] < softs->bus_throttle[q]) {
588411636SXin.Chen@Sun.COM 		if (dvp) {
588511636SXin.Chen@Sun.COM 			if (dvp->ncmds[q] < dvp->throttle[q]) {
588611636SXin.Chen@Sun.COM 				if (!(acp->flags & AAC_CMD_NTAG) ||
588711636SXin.Chen@Sun.COM 				    dvp->ncmds[q] == 0) {
588811636SXin.Chen@Sun.COM 					return (aac_cmd_slot_bind(softs, acp));
588911636SXin.Chen@Sun.COM 				}
589011636SXin.Chen@Sun.COM 				ASSERT(q == AAC_CMDQ_ASYNC);
589111636SXin.Chen@Sun.COM 				aac_set_throttle(softs, dvp, AAC_CMDQ_ASYNC,
589211636SXin.Chen@Sun.COM 				    AAC_THROTTLE_DRAIN);
58935678Spl196000 			}
589411636SXin.Chen@Sun.COM 		} else {
589511636SXin.Chen@Sun.COM 			return (aac_cmd_slot_bind(softs, acp));
58965678Spl196000 		}
58975678Spl196000 	}
58985678Spl196000 	return (AACERR);
58995678Spl196000 }
59005678Spl196000 
590111348SZhongyan.Gu@Sun.COM static int
aac_sync_fib_slot_bind(struct aac_softstate * softs,struct aac_cmd * acp)590211348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_bind(struct aac_softstate *softs, struct aac_cmd *acp)
590311348SZhongyan.Gu@Sun.COM {
590411348SZhongyan.Gu@Sun.COM 	struct aac_slot *slotp;
590511348SZhongyan.Gu@Sun.COM 
590611636SXin.Chen@Sun.COM 	while (softs->sync_ac.slotp)
590711636SXin.Chen@Sun.COM 		cv_wait(&softs->sync_fib_cv, &softs->io_lock);
590811636SXin.Chen@Sun.COM 
590911348SZhongyan.Gu@Sun.COM 	if (slotp = aac_get_slot(softs)) {
591011348SZhongyan.Gu@Sun.COM 		ASSERT(acp->slotp == NULL);
591111348SZhongyan.Gu@Sun.COM 
591211348SZhongyan.Gu@Sun.COM 		acp->slotp = slotp;
591311348SZhongyan.Gu@Sun.COM 		slotp->acp = acp;
591411348SZhongyan.Gu@Sun.COM 		return (AACOK);
591511348SZhongyan.Gu@Sun.COM 	}
591611348SZhongyan.Gu@Sun.COM 	return (AACERR);
591711348SZhongyan.Gu@Sun.COM }
591811348SZhongyan.Gu@Sun.COM 
591911348SZhongyan.Gu@Sun.COM static void
aac_sync_fib_slot_release(struct aac_softstate * softs,struct aac_cmd * acp)592011348SZhongyan.Gu@Sun.COM aac_sync_fib_slot_release(struct aac_softstate *softs, struct aac_cmd *acp)
592111348SZhongyan.Gu@Sun.COM {
592211348SZhongyan.Gu@Sun.COM 	ASSERT(acp->slotp);
592311348SZhongyan.Gu@Sun.COM 
592411348SZhongyan.Gu@Sun.COM 	aac_release_slot(softs, acp->slotp);
592511348SZhongyan.Gu@Sun.COM 	acp->slotp->acp = NULL;
592611348SZhongyan.Gu@Sun.COM 	acp->slotp = NULL;
592711636SXin.Chen@Sun.COM 
592811636SXin.Chen@Sun.COM 	cv_signal(&softs->sync_fib_cv);
592911348SZhongyan.Gu@Sun.COM }
593011348SZhongyan.Gu@Sun.COM 
59315678Spl196000 static void
aac_start_io(struct aac_softstate * softs,struct aac_cmd * acp)59325678Spl196000 aac_start_io(struct aac_softstate *softs, struct aac_cmd *acp)
59335678Spl196000 {
59345678Spl196000 	struct aac_slot *slotp = acp->slotp;
59355678Spl196000 	int q = AAC_CMDQ(acp);
59365678Spl196000 	int rval;
59375678Spl196000 
59385678Spl196000 	/* Set ac and pkt */
59395678Spl196000 	if (acp->pkt) { /* ac from ioctl has no pkt */
59405678Spl196000 		acp->pkt->pkt_state |=
59415678Spl196000 		    STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
59425678Spl196000 	}
59435678Spl196000 	if (acp->timeout) /* 0 indicates no timeout */
59445678Spl196000 		acp->timeout += aac_timebase + aac_tick;
59455678Spl196000 
59465678Spl196000 	if (acp->dvp)
59475678Spl196000 		acp->dvp->ncmds[q]++;
59485678Spl196000 	softs->bus_ncmds[q]++;
59495678Spl196000 	aac_cmd_enqueue(&softs->q_busy, acp);
59505678Spl196000 
59517567SXin.Chen@Sun.COM 	AACDB_PRINT_FIB(softs, slotp);
59527567SXin.Chen@Sun.COM 
59535678Spl196000 	if (softs->flags & AAC_FLAGS_NEW_COMM) {
59545678Spl196000 		rval = aac_send_command(softs, slotp);
59555678Spl196000 	} else {
59565678Spl196000 		/*
59575678Spl196000 		 * If fib can not be enqueued, the adapter is in an abnormal
59585678Spl196000 		 * state, there will be no interrupt to us.
59595678Spl196000 		 */
59605678Spl196000 		rval = aac_fib_enqueue(softs, AAC_ADAP_NORM_CMD_Q,
59615678Spl196000 		    slotp->fib_phyaddr, acp->fib_size);
59625678Spl196000 	}
59635678Spl196000 
59645678Spl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS)
59655678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_UNAFFECTED);
59665678Spl196000 
59675678Spl196000 	/*
59685678Spl196000 	 * NOTE: We send command only when slots availabe, so should never
59695678Spl196000 	 * reach here.
59705678Spl196000 	 */
59715678Spl196000 	if (rval != AACOK) {
59725678Spl196000 		AACDB_PRINT(softs, CE_NOTE, "SCMD send failed");
59735678Spl196000 		if (acp->pkt) {
59745678Spl196000 			acp->pkt->pkt_state &= ~STATE_SENT_CMD;
59755678Spl196000 			aac_set_pkt_reason(softs, acp, CMD_INCOMPLETE, 0);
59765678Spl196000 		}
59775678Spl196000 		aac_end_io(softs, acp);
59785678Spl196000 		if (!(acp->flags & (AAC_CMD_NO_INTR | AAC_CMD_NO_CB)))
59795678Spl196000 			ddi_trigger_softintr(softs->softint_id);
59805678Spl196000 	}
59815678Spl196000 }
59825678Spl196000 
59835678Spl196000 static void
aac_start_waitq(struct aac_softstate * softs,struct aac_cmd_queue * q)59845678Spl196000 aac_start_waitq(struct aac_softstate *softs, struct aac_cmd_queue *q)
59855678Spl196000 {
59865678Spl196000 	struct aac_cmd *acp, *next_acp;
59875678Spl196000 
59885678Spl196000 	/* Serve as many waiting io's as possible */
59895678Spl196000 	for (acp = q->q_head; acp; acp = next_acp) {
59905678Spl196000 		next_acp = acp->next;
59915678Spl196000 		if (aac_bind_io(softs, acp) == AACOK) {
59925678Spl196000 			aac_cmd_delete(q, acp);
59935678Spl196000 			aac_start_io(softs, acp);
59945678Spl196000 		}
59955678Spl196000 		if (softs->free_io_slot_head == NULL)
59965678Spl196000 			break;
59975678Spl196000 	}
59985678Spl196000 }
59995678Spl196000 
60005678Spl196000 static void
aac_start_waiting_io(struct aac_softstate * softs)60015678Spl196000 aac_start_waiting_io(struct aac_softstate *softs)
60025678Spl196000 {
60035678Spl196000 	/*
60045678Spl196000 	 * Sync FIB io is served before async FIB io so that io requests
60055678Spl196000 	 * sent by interactive userland commands get responded asap.
60065678Spl196000 	 */
60075678Spl196000 	if (softs->q_wait[AAC_CMDQ_SYNC].q_head)
60085678Spl196000 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_SYNC]);
60095678Spl196000 	if (softs->q_wait[AAC_CMDQ_ASYNC].q_head)
60105678Spl196000 		aac_start_waitq(softs, &softs->q_wait[AAC_CMDQ_ASYNC]);
60115678Spl196000 }
60125678Spl196000 
60135678Spl196000 static void
aac_drain_comp_q(struct aac_softstate * softs)60145678Spl196000 aac_drain_comp_q(struct aac_softstate *softs)
60155678Spl196000 {
60165678Spl196000 	struct aac_cmd *acp;
60175678Spl196000 	struct scsi_pkt *pkt;
60185678Spl196000 
60195678Spl196000 	/*CONSTCOND*/
60205678Spl196000 	while (1) {
60215678Spl196000 		mutex_enter(&softs->q_comp_mutex);
60225678Spl196000 		acp = aac_cmd_dequeue(&softs->q_comp);
60235678Spl196000 		mutex_exit(&softs->q_comp_mutex);
60245678Spl196000 		if (acp != NULL) {
60255678Spl196000 			ASSERT(acp->pkt != NULL);
60265678Spl196000 			pkt = acp->pkt;
60275678Spl196000 
60285678Spl196000 			if (pkt->pkt_reason == CMD_CMPLT) {
60295678Spl196000 				/*
60305678Spl196000 				 * Consistent packets need to be sync'ed first
60315678Spl196000 				 */
60325678Spl196000 				if ((acp->flags & AAC_CMD_CONSISTENT) &&
60335678Spl196000 				    (acp->flags & AAC_CMD_BUF_READ)) {
60345678Spl196000 					if (aac_dma_sync_ac(acp) != AACOK) {
60355678Spl196000 						ddi_fm_service_impact(
60365678Spl196000 						    softs->devinfo_p,
60375678Spl196000 						    DDI_SERVICE_UNAFFECTED);
60385678Spl196000 						pkt->pkt_reason = CMD_TRAN_ERR;
60395678Spl196000 						pkt->pkt_statistics = 0;
60405678Spl196000 					}
60415678Spl196000 				}
60425678Spl196000 				if ((aac_check_acc_handle(softs-> \
60435678Spl196000 				    comm_space_acc_handle) != DDI_SUCCESS) ||
60445678Spl196000 				    (aac_check_acc_handle(softs-> \
60455678Spl196000 				    pci_mem_handle) != DDI_SUCCESS)) {
60465678Spl196000 					ddi_fm_service_impact(softs->devinfo_p,
60475678Spl196000 					    DDI_SERVICE_UNAFFECTED);
60485678Spl196000 					ddi_fm_acc_err_clear(softs-> \
60495678Spl196000 					    pci_mem_handle, DDI_FME_VER0);
60505678Spl196000 					pkt->pkt_reason = CMD_TRAN_ERR;
60515678Spl196000 					pkt->pkt_statistics = 0;
60525678Spl196000 				}
60535678Spl196000 				if (aac_check_dma_handle(softs-> \
60545678Spl196000 				    comm_space_dma_handle) != DDI_SUCCESS) {
60555678Spl196000 					ddi_fm_service_impact(softs->devinfo_p,
60565678Spl196000 					    DDI_SERVICE_UNAFFECTED);
60575678Spl196000 					pkt->pkt_reason = CMD_TRAN_ERR;
60585678Spl196000 					pkt->pkt_statistics = 0;
60595678Spl196000 				}
60605678Spl196000 			}
60619106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
60625678Spl196000 		} else {
60635678Spl196000 			break;
60645678Spl196000 		}
60655678Spl196000 	}
60665678Spl196000 }
60675678Spl196000 
60685678Spl196000 static int
aac_alloc_fib(struct aac_softstate * softs,struct aac_slot * slotp)60695678Spl196000 aac_alloc_fib(struct aac_softstate *softs, struct aac_slot *slotp)
60705678Spl196000 {
60715678Spl196000 	size_t rlen;
60725678Spl196000 	ddi_dma_cookie_t cookie;
60735678Spl196000 	uint_t cookien;
60745678Spl196000 
60755678Spl196000 	/* Allocate FIB dma resource */
60765678Spl196000 	if (ddi_dma_alloc_handle(
60775678Spl196000 	    softs->devinfo_p,
60785678Spl196000 	    &softs->addr_dma_attr,
60795678Spl196000 	    DDI_DMA_SLEEP,
60805678Spl196000 	    NULL,
60815678Spl196000 	    &slotp->fib_dma_handle) != DDI_SUCCESS) {
60825678Spl196000 		AACDB_PRINT(softs, CE_WARN,
60835678Spl196000 		    "Cannot alloc dma handle for slot fib area");
60845678Spl196000 		goto error;
60855678Spl196000 	}
60865678Spl196000 	if (ddi_dma_mem_alloc(
60875678Spl196000 	    slotp->fib_dma_handle,
60885678Spl196000 	    softs->aac_max_fib_size,
60897567SXin.Chen@Sun.COM 	    &softs->acc_attr,
60905678Spl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
60915678Spl196000 	    DDI_DMA_SLEEP,
60925678Spl196000 	    NULL,
60935678Spl196000 	    (caddr_t *)&slotp->fibp,
60945678Spl196000 	    &rlen,
60955678Spl196000 	    &slotp->fib_acc_handle) != DDI_SUCCESS) {
60965678Spl196000 		AACDB_PRINT(softs, CE_WARN,
60975678Spl196000 		    "Cannot alloc mem for slot fib area");
60985678Spl196000 		goto error;
60995678Spl196000 	}
61005678Spl196000 	if (ddi_dma_addr_bind_handle(
61015678Spl196000 	    slotp->fib_dma_handle,
61025678Spl196000 	    NULL,
61035678Spl196000 	    (caddr_t)slotp->fibp,
61045678Spl196000 	    softs->aac_max_fib_size,
61055678Spl196000 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
61065678Spl196000 	    DDI_DMA_SLEEP,
61075678Spl196000 	    NULL,
61085678Spl196000 	    &cookie,
61095678Spl196000 	    &cookien) != DDI_DMA_MAPPED) {
61105678Spl196000 		AACDB_PRINT(softs, CE_WARN,
61115678Spl196000 		    "dma bind failed for slot fib area");
61125678Spl196000 		goto error;
61135678Spl196000 	}
61145678Spl196000 
61155678Spl196000 	/* Check dma handles allocated in fib attach */
61165678Spl196000 	if (aac_check_dma_handle(slotp->fib_dma_handle) != DDI_SUCCESS) {
61175678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61185678Spl196000 		goto error;
61195678Spl196000 	}
61205678Spl196000 
61215678Spl196000 	/* Check acc handles allocated in fib attach */
61225678Spl196000 	if (aac_check_acc_handle(slotp->fib_acc_handle) != DDI_SUCCESS) {
61235678Spl196000 		ddi_fm_service_impact(softs->devinfo_p, DDI_SERVICE_LOST);
61245678Spl196000 		goto error;
61255678Spl196000 	}
61265678Spl196000 
61275678Spl196000 	slotp->fib_phyaddr = cookie.dmac_laddress;
61285678Spl196000 	return (AACOK);
61295678Spl196000 
61305678Spl196000 error:
61315678Spl196000 	if (slotp->fib_acc_handle) {
61325678Spl196000 		ddi_dma_mem_free(&slotp->fib_acc_handle);
61335678Spl196000 		slotp->fib_acc_handle = NULL;
61345678Spl196000 	}
61355678Spl196000 	if (slotp->fib_dma_handle) {
61365678Spl196000 		ddi_dma_free_handle(&slotp->fib_dma_handle);
61375678Spl196000 		slotp->fib_dma_handle = NULL;
61385678Spl196000 	}
61395678Spl196000 	return (AACERR);
61405678Spl196000 }
61415678Spl196000 
61425678Spl196000 static void
aac_free_fib(struct aac_slot * slotp)61435678Spl196000 aac_free_fib(struct aac_slot *slotp)
61445678Spl196000 {
61455678Spl196000 	(void) ddi_dma_unbind_handle(slotp->fib_dma_handle);
61465678Spl196000 	ddi_dma_mem_free(&slotp->fib_acc_handle);
61475678Spl196000 	slotp->fib_acc_handle = NULL;
61485678Spl196000 	ddi_dma_free_handle(&slotp->fib_dma_handle);
61495678Spl196000 	slotp->fib_dma_handle = NULL;
61505678Spl196000 	slotp->fib_phyaddr = 0;
61515678Spl196000 }
61525678Spl196000 
61535678Spl196000 static void
aac_alloc_fibs(struct aac_softstate * softs)61545678Spl196000 aac_alloc_fibs(struct aac_softstate *softs)
61555678Spl196000 {
61565678Spl196000 	int i;
61575678Spl196000 	struct aac_slot *slotp;
61585678Spl196000 
61595678Spl196000 	for (i = 0; i < softs->total_slots &&
61605678Spl196000 	    softs->total_fibs < softs->total_slots; i++) {
61615678Spl196000 		slotp = &(softs->io_slot[i]);
61625678Spl196000 		if (slotp->fib_phyaddr)
61635678Spl196000 			continue;
61645678Spl196000 		if (aac_alloc_fib(softs, slotp) != AACOK)
61655678Spl196000 			break;
61665678Spl196000 
61675678Spl196000 		/* Insert the slot to the free slot list */
61685678Spl196000 		aac_release_slot(softs, slotp);
61695678Spl196000 		softs->total_fibs++;
61705678Spl196000 	}
61715678Spl196000 }
61725678Spl196000 
61735678Spl196000 static void
aac_destroy_fibs(struct aac_softstate * softs)61745678Spl196000 aac_destroy_fibs(struct aac_softstate *softs)
61755678Spl196000 {
61765678Spl196000 	struct aac_slot *slotp;
61775678Spl196000 
61785678Spl196000 	while ((slotp = softs->free_io_slot_head) != NULL) {
61795678Spl196000 		ASSERT(slotp->fib_phyaddr);
61805678Spl196000 		softs->free_io_slot_head = slotp->next;
61815678Spl196000 		aac_free_fib(slotp);
61825678Spl196000 		ASSERT(slotp->index == (slotp - softs->io_slot));
61835678Spl196000 		softs->total_fibs--;
61845678Spl196000 	}
61855678Spl196000 	ASSERT(softs->total_fibs == 0);
61865678Spl196000 }
61875678Spl196000 
61885678Spl196000 static int
aac_create_slots(struct aac_softstate * softs)61895678Spl196000 aac_create_slots(struct aac_softstate *softs)
61905678Spl196000 {
61915678Spl196000 	int i;
61925678Spl196000 
61935678Spl196000 	softs->total_slots = softs->aac_max_fibs;
61945678Spl196000 	softs->io_slot = kmem_zalloc(sizeof (struct aac_slot) * \
61955678Spl196000 	    softs->total_slots, KM_SLEEP);
61965678Spl196000 	if (softs->io_slot == NULL) {
61975678Spl196000 		AACDB_PRINT(softs, CE_WARN, "Cannot allocate slot");
61985678Spl196000 		return (AACERR);
61995678Spl196000 	}
62005678Spl196000 	for (i = 0; i < softs->total_slots; i++)
62015678Spl196000 		softs->io_slot[i].index = i;
62025678Spl196000 	softs->free_io_slot_head = NULL;
62035678Spl196000 	softs->total_fibs = 0;
62045678Spl196000 	return (AACOK);
62055678Spl196000 }
62065678Spl196000 
62075678Spl196000 static void
aac_destroy_slots(struct aac_softstate * softs)62085678Spl196000 aac_destroy_slots(struct aac_softstate *softs)
62095678Spl196000 {
62105678Spl196000 	ASSERT(softs->free_io_slot_head == NULL);
62115678Spl196000 
62125678Spl196000 	kmem_free(softs->io_slot, sizeof (struct aac_slot) * \
62135678Spl196000 	    softs->total_slots);
62145678Spl196000 	softs->io_slot = NULL;
62155678Spl196000 	softs->total_slots = 0;
62165678Spl196000 }
62175678Spl196000 
62185678Spl196000 struct aac_slot *
aac_get_slot(struct aac_softstate * softs)62195678Spl196000 aac_get_slot(struct aac_softstate *softs)
62205678Spl196000 {
62215678Spl196000 	struct aac_slot *slotp;
62225678Spl196000 
62235678Spl196000 	if ((slotp = softs->free_io_slot_head) != NULL) {
62245678Spl196000 		softs->free_io_slot_head = slotp->next;
62255678Spl196000 		slotp->next = NULL;
62265678Spl196000 	}
62275678Spl196000 	return (slotp);
62285678Spl196000 }
62295678Spl196000 
62305678Spl196000 static void
aac_release_slot(struct aac_softstate * softs,struct aac_slot * slotp)62315678Spl196000 aac_release_slot(struct aac_softstate *softs, struct aac_slot *slotp)
62325678Spl196000 {
62335678Spl196000 	ASSERT((slotp->index >= 0) && (slotp->index < softs->total_slots));
62345678Spl196000 	ASSERT(slotp == &softs->io_slot[slotp->index]);
62355678Spl196000 
62365678Spl196000 	slotp->acp = NULL;
62375678Spl196000 	slotp->next = softs->free_io_slot_head;
62385678Spl196000 	softs->free_io_slot_head = slotp;
62395678Spl196000 }
62405678Spl196000 
62415678Spl196000 int
aac_do_io(struct aac_softstate * softs,struct aac_cmd * acp)62425678Spl196000 aac_do_io(struct aac_softstate *softs, struct aac_cmd *acp)
62435678Spl196000 {
62445678Spl196000 	if (aac_bind_io(softs, acp) == AACOK)
62455678Spl196000 		aac_start_io(softs, acp);
62465678Spl196000 	else
62475678Spl196000 		aac_cmd_enqueue(&softs->q_wait[AAC_CMDQ(acp)], acp);
62485678Spl196000 
62495678Spl196000 	if (!(acp->flags & (AAC_CMD_NO_CB | AAC_CMD_NO_INTR)))
62505678Spl196000 		return (TRAN_ACCEPT);
62515678Spl196000 	/*
62525678Spl196000 	 * Because sync FIB is always 512 bytes and used for critical
62535678Spl196000 	 * functions, async FIB is used for poll IO.
62545678Spl196000 	 */
62555678Spl196000 	if (acp->flags & AAC_CMD_NO_INTR) {
62565678Spl196000 		if (aac_do_poll_io(softs, acp) == AACOK)
62575678Spl196000 			return (TRAN_ACCEPT);
62585678Spl196000 	} else {
62595678Spl196000 		if (aac_do_sync_io(softs, acp) == AACOK)
62605678Spl196000 			return (TRAN_ACCEPT);
62615678Spl196000 	}
62625678Spl196000 	return (TRAN_BADPKT);
62635678Spl196000 }
62645678Spl196000 
62655678Spl196000 static int
aac_do_poll_io(struct aac_softstate * softs,struct aac_cmd * acp)62665678Spl196000 aac_do_poll_io(struct aac_softstate *softs, struct aac_cmd *acp)
62675678Spl196000 {
62685678Spl196000 	int (*intr_handler)(struct aac_softstate *);
62695678Spl196000 
62705678Spl196000 	/*
62715678Spl196000 	 * Interrupt is disabled, we have to poll the adapter by ourselves.
62725678Spl196000 	 */
62735678Spl196000 	intr_handler = (softs->flags & AAC_FLAGS_NEW_COMM) ?
62745678Spl196000 	    aac_process_intr_new : aac_process_intr_old;
62755678Spl196000 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT))) {
62765678Spl196000 		int i = AAC_POLL_TIME * 1000;
62775678Spl196000 
62785678Spl196000 		AAC_BUSYWAIT((intr_handler(softs) != AAC_DB_RESPONSE_READY), i);
62795678Spl196000 		if (i == 0)
62807567SXin.Chen@Sun.COM 			aac_cmd_timeout(softs, acp);
62815678Spl196000 	}
62825678Spl196000 
62835678Spl196000 	ddi_trigger_softintr(softs->softint_id);
62845678Spl196000 
62855678Spl196000 	if ((acp->flags & AAC_CMD_CMPLT) && !(acp->flags & AAC_CMD_ERR))
62865678Spl196000 		return (AACOK);
62875678Spl196000 	return (AACERR);
62885678Spl196000 }
62895678Spl196000 
62905678Spl196000 static int
aac_do_sync_io(struct aac_softstate * softs,struct aac_cmd * acp)62915678Spl196000 aac_do_sync_io(struct aac_softstate *softs, struct aac_cmd *acp)
62925678Spl196000 {
62935678Spl196000 	ASSERT(softs && acp);
62945678Spl196000 
62955678Spl196000 	while (!(acp->flags & (AAC_CMD_CMPLT | AAC_CMD_ABORT)))
62965678Spl196000 		cv_wait(&softs->event, &softs->io_lock);
62975678Spl196000 
62985678Spl196000 	if (acp->flags & AAC_CMD_CMPLT)
62995678Spl196000 		return (AACOK);
63005678Spl196000 	return (AACERR);
63015678Spl196000 }
63025678Spl196000 
63035678Spl196000 static int
aac_dma_sync_ac(struct aac_cmd * acp)63045678Spl196000 aac_dma_sync_ac(struct aac_cmd *acp)
63055678Spl196000 {
63065678Spl196000 	if (acp->buf_dma_handle) {
63075678Spl196000 		if (acp->flags & AAC_CMD_BUF_WRITE) {
63085678Spl196000 			if (acp->abp != NULL)
63095678Spl196000 				ddi_rep_put8(acp->abh,
63105678Spl196000 				    (uint8_t *)acp->bp->b_un.b_addr,
63115678Spl196000 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
63125678Spl196000 				    DDI_DEV_AUTOINCR);
63135678Spl196000 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
63145678Spl196000 			    DDI_DMA_SYNC_FORDEV);
63155678Spl196000 		} else {
63165678Spl196000 			(void) ddi_dma_sync(acp->buf_dma_handle, 0, 0,
63175678Spl196000 			    DDI_DMA_SYNC_FORCPU);
63185678Spl196000 			if (aac_check_dma_handle(acp->buf_dma_handle) !=
63195678Spl196000 			    DDI_SUCCESS)
63205678Spl196000 				return (AACERR);
63215678Spl196000 			if (acp->abp != NULL)
63225678Spl196000 				ddi_rep_get8(acp->abh,
63235678Spl196000 				    (uint8_t *)acp->bp->b_un.b_addr,
63245678Spl196000 				    (uint8_t *)acp->abp, acp->bp->b_bcount,
63255678Spl196000 				    DDI_DEV_AUTOINCR);
63265678Spl196000 		}
63275678Spl196000 	}
63285678Spl196000 	return (AACOK);
63295678Spl196000 }
63305678Spl196000 
63315678Spl196000 /*
633211964SXin.Chen@Sun.COM  * Copy AIF from adapter to the empty AIF slot and inform AIF threads
633311964SXin.Chen@Sun.COM  */
633411964SXin.Chen@Sun.COM static void
aac_save_aif(struct aac_softstate * softs,ddi_acc_handle_t acc,struct aac_fib * fibp0,int fib_size0)633511964SXin.Chen@Sun.COM aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
633611964SXin.Chen@Sun.COM     struct aac_fib *fibp0, int fib_size0)
633711964SXin.Chen@Sun.COM {
633811964SXin.Chen@Sun.COM 	struct aac_fib *fibp;	/* FIB in AIF queue */
633911964SXin.Chen@Sun.COM 	int fib_size;
634011964SXin.Chen@Sun.COM 	uint16_t fib_command;
634111964SXin.Chen@Sun.COM 	int current, next;
634211964SXin.Chen@Sun.COM 
634311964SXin.Chen@Sun.COM 	/* Ignore non AIF messages */
634411964SXin.Chen@Sun.COM 	fib_command = ddi_get16(acc, &fibp0->Header.Command);
634511964SXin.Chen@Sun.COM 	if (fib_command != AifRequest) {
634611964SXin.Chen@Sun.COM 		cmn_err(CE_WARN, "!Unknown command from controller");
634711964SXin.Chen@Sun.COM 		return;
634811964SXin.Chen@Sun.COM 	}
634911964SXin.Chen@Sun.COM 
635011964SXin.Chen@Sun.COM 	mutex_enter(&softs->aifq_mutex);
635111964SXin.Chen@Sun.COM 
635211964SXin.Chen@Sun.COM 	/* Save AIF */
635311964SXin.Chen@Sun.COM 	fibp = &softs->aifq[softs->aifq_idx].d;
635411964SXin.Chen@Sun.COM 	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
635511964SXin.Chen@Sun.COM 	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
635611964SXin.Chen@Sun.COM 	    DDI_DEV_AUTOINCR);
635711964SXin.Chen@Sun.COM 
635811964SXin.Chen@Sun.COM 	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
635911964SXin.Chen@Sun.COM 		ddi_fm_service_impact(softs->devinfo_p,
636011964SXin.Chen@Sun.COM 		    DDI_SERVICE_UNAFFECTED);
636111964SXin.Chen@Sun.COM 		mutex_exit(&softs->aifq_mutex);
636211964SXin.Chen@Sun.COM 		return;
636311964SXin.Chen@Sun.COM 	}
636411964SXin.Chen@Sun.COM 
636511964SXin.Chen@Sun.COM 	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
636611964SXin.Chen@Sun.COM 
636711964SXin.Chen@Sun.COM 	/* Modify AIF contexts */
636811964SXin.Chen@Sun.COM 	current = softs->aifq_idx;
636911964SXin.Chen@Sun.COM 	next = (current + 1) % AAC_AIFQ_LENGTH;
637011964SXin.Chen@Sun.COM 	if (next == 0) {
637111964SXin.Chen@Sun.COM 		struct aac_fib_context *ctx_p;
637211964SXin.Chen@Sun.COM 
637311964SXin.Chen@Sun.COM 		softs->aifq_wrap = 1;
637411964SXin.Chen@Sun.COM 		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
637511964SXin.Chen@Sun.COM 			if (next == ctx_p->ctx_idx) {
637611964SXin.Chen@Sun.COM 				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
637711964SXin.Chen@Sun.COM 			} else if (current == ctx_p->ctx_idx &&
637811964SXin.Chen@Sun.COM 			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
637911964SXin.Chen@Sun.COM 				ctx_p->ctx_idx = next;
638011964SXin.Chen@Sun.COM 				ctx_p->ctx_overrun++;
638111964SXin.Chen@Sun.COM 			}
638211964SXin.Chen@Sun.COM 		}
638311964SXin.Chen@Sun.COM 	}
638411964SXin.Chen@Sun.COM 	softs->aifq_idx = next;
638511964SXin.Chen@Sun.COM 
638611964SXin.Chen@Sun.COM 	/* Wakeup AIF threads */
638711964SXin.Chen@Sun.COM 	cv_broadcast(&softs->aifq_cv);
638811964SXin.Chen@Sun.COM 	mutex_exit(&softs->aifq_mutex);
638911964SXin.Chen@Sun.COM 
639011964SXin.Chen@Sun.COM 	/* Wakeup event thread to handle aif */
639111964SXin.Chen@Sun.COM 	aac_event_disp(softs, AAC_EVENT_AIF);
639211964SXin.Chen@Sun.COM }
639311964SXin.Chen@Sun.COM 
639411964SXin.Chen@Sun.COM static int
aac_return_aif_common(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)639511964SXin.Chen@Sun.COM aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
639611964SXin.Chen@Sun.COM     struct aac_fib **fibpp)
639711964SXin.Chen@Sun.COM {
639811964SXin.Chen@Sun.COM 	int current;
639911964SXin.Chen@Sun.COM 
640011964SXin.Chen@Sun.COM 	current = ctx->ctx_idx;
640111964SXin.Chen@Sun.COM 	if (current == softs->aifq_idx &&
640211964SXin.Chen@Sun.COM 	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
640311964SXin.Chen@Sun.COM 		return (EAGAIN); /* Empty */
640411964SXin.Chen@Sun.COM 
640511964SXin.Chen@Sun.COM 	*fibpp = &softs->aifq[current].d;
640611964SXin.Chen@Sun.COM 
640711964SXin.Chen@Sun.COM 	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
640811964SXin.Chen@Sun.COM 	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
640911964SXin.Chen@Sun.COM 	return (0);
641011964SXin.Chen@Sun.COM }
641111964SXin.Chen@Sun.COM 
641211964SXin.Chen@Sun.COM int
aac_return_aif(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)641311964SXin.Chen@Sun.COM aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
641411964SXin.Chen@Sun.COM     struct aac_fib **fibpp)
641511964SXin.Chen@Sun.COM {
641611964SXin.Chen@Sun.COM 	int rval;
641711964SXin.Chen@Sun.COM 
641811964SXin.Chen@Sun.COM 	mutex_enter(&softs->aifq_mutex);
641911964SXin.Chen@Sun.COM 	rval = aac_return_aif_common(softs, ctx, fibpp);
642011964SXin.Chen@Sun.COM 	mutex_exit(&softs->aifq_mutex);
642111964SXin.Chen@Sun.COM 	return (rval);
642211964SXin.Chen@Sun.COM }
642311964SXin.Chen@Sun.COM 
642411964SXin.Chen@Sun.COM int
aac_return_aif_wait(struct aac_softstate * softs,struct aac_fib_context * ctx,struct aac_fib ** fibpp)642511964SXin.Chen@Sun.COM aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
642611964SXin.Chen@Sun.COM     struct aac_fib **fibpp)
642711964SXin.Chen@Sun.COM {
642811964SXin.Chen@Sun.COM 	int rval;
642911964SXin.Chen@Sun.COM 
643011964SXin.Chen@Sun.COM 	mutex_enter(&softs->aifq_mutex);
643111964SXin.Chen@Sun.COM 	rval = aac_return_aif_common(softs, ctx, fibpp);
643211964SXin.Chen@Sun.COM 	if (rval == EAGAIN) {
643311964SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
643411964SXin.Chen@Sun.COM 		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
643511964SXin.Chen@Sun.COM 	}
643611964SXin.Chen@Sun.COM 	mutex_exit(&softs->aifq_mutex);
643711964SXin.Chen@Sun.COM 	return ((rval > 0) ? 0 : EINTR);
643811964SXin.Chen@Sun.COM }
643911964SXin.Chen@Sun.COM 
644011964SXin.Chen@Sun.COM /*
64415678Spl196000  * The following function comes from Adaptec:
64425678Spl196000  *
64435678Spl196000  * When driver sees a particular event that means containers are changed, it
64445678Spl196000  * will rescan containers. However a change may not be complete until some
64455678Spl196000  * other event is received. For example, creating or deleting an array will
64465678Spl196000  * incur as many as six AifEnConfigChange events which would generate six
64475678Spl196000  * container rescans. To diminish rescans, driver set a flag to wait for
64485678Spl196000  * another particular event. When sees that events come in, it will do rescan.
64495678Spl196000  */
64505678Spl196000 static int
aac_handle_aif(struct aac_softstate * softs,struct aac_aif_command * aif)645111964SXin.Chen@Sun.COM aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
64525678Spl196000 {
64535678Spl196000 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
64545678Spl196000 	int en_type;
64555678Spl196000 	int devcfg_needed;
6456*12408SZhongyan.Gu@Sun.COM 	int cid;
6457*12408SZhongyan.Gu@Sun.COM 	uint32_t bus_id, tgt_id;
6458*12408SZhongyan.Gu@Sun.COM 	enum aac_cfg_event event = AAC_CFG_NULL_EXIST;
645911964SXin.Chen@Sun.COM 
64605678Spl196000 	devcfg_needed = 0;
64615678Spl196000 	en_type = LE_32((uint32_t)aif->data.EN.type);
64625678Spl196000 
64635678Spl196000 	switch (LE_32((uint32_t)aif->command)) {
64645678Spl196000 	case AifCmdDriverNotify: {
6465*12408SZhongyan.Gu@Sun.COM 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
64665678Spl196000 
64675678Spl196000 		switch (en_type) {
64685678Spl196000 		case AifDenMorphComplete:
64695678Spl196000 		case AifDenVolumeExtendComplete:
64707567SXin.Chen@Sun.COM 			if (AAC_DEV_IS_VALID(&softs->containers[cid].dev))
64715678Spl196000 				softs->devcfg_wait_on = AifEnConfigChange;
64725678Spl196000 			break;
64735678Spl196000 		}
64745678Spl196000 		if (softs->devcfg_wait_on == en_type)
64755678Spl196000 			devcfg_needed = 1;
64765678Spl196000 		break;
64775678Spl196000 	}
64785678Spl196000 
64795678Spl196000 	case AifCmdEventNotify:
6480*12408SZhongyan.Gu@Sun.COM 		cid = LE_32(aif->data.EN.data.ECC.container[0]);
64815678Spl196000 		switch (en_type) {
64825678Spl196000 		case AifEnAddContainer:
64835678Spl196000 		case AifEnDeleteContainer:
64845678Spl196000 			softs->devcfg_wait_on = AifEnConfigChange;
64855678Spl196000 			break;
64865678Spl196000 		case AifEnContainerChange:
64875678Spl196000 			if (!softs->devcfg_wait_on)
64885678Spl196000 				softs->devcfg_wait_on = AifEnConfigChange;
64895678Spl196000 			break;
64905678Spl196000 		case AifEnContainerEvent:
64915678Spl196000 			if (ddi_get32(acc, &aif-> \
64925678Spl196000 			    data.EN.data.ECE.eventType) == CT_PUP_MISSING_DRIVE)
64935678Spl196000 				devcfg_needed = 1;
64945678Spl196000 			break;
6495*12408SZhongyan.Gu@Sun.COM 		case AifEnAddJBOD:
6496*12408SZhongyan.Gu@Sun.COM 			if (!(softs->flags & AAC_FLAGS_JBOD))
6497*12408SZhongyan.Gu@Sun.COM 				return (AACERR);
6498*12408SZhongyan.Gu@Sun.COM 			event = AAC_CFG_ADD;
6499*12408SZhongyan.Gu@Sun.COM 			bus_id = (cid >> 24) & 0xf;
6500*12408SZhongyan.Gu@Sun.COM 			tgt_id = cid & 0xffff;
6501*12408SZhongyan.Gu@Sun.COM 			break;
6502*12408SZhongyan.Gu@Sun.COM 		case AifEnDeleteJBOD:
6503*12408SZhongyan.Gu@Sun.COM 			if (!(softs->flags & AAC_FLAGS_JBOD))
6504*12408SZhongyan.Gu@Sun.COM 				return (AACERR);
6505*12408SZhongyan.Gu@Sun.COM 			event = AAC_CFG_DELETE;
6506*12408SZhongyan.Gu@Sun.COM 			bus_id = (cid >> 24) & 0xf;
6507*12408SZhongyan.Gu@Sun.COM 			tgt_id = cid & 0xffff;
6508*12408SZhongyan.Gu@Sun.COM 			break;
65095678Spl196000 		}
65105678Spl196000 		if (softs->devcfg_wait_on == en_type)
65115678Spl196000 			devcfg_needed = 1;
65125678Spl196000 		break;
65135678Spl196000 
65145678Spl196000 	case AifCmdJobProgress:
65155678Spl196000 		if (LE_32((uint32_t)aif->data.PR[0].jd.type) == AifJobCtrZero) {
65165678Spl196000 			int pr_status;
65175678Spl196000 			uint32_t pr_ftick, pr_ctick;
65185678Spl196000 
65195678Spl196000 			pr_status = LE_32((uint32_t)aif->data.PR[0].status);
65205678Spl196000 			pr_ctick = LE_32(aif->data.PR[0].currentTick);
65215678Spl196000 			pr_ftick = LE_32(aif->data.PR[0].finalTick);
65225678Spl196000 
65235678Spl196000 			if ((pr_ctick == pr_ftick) ||
65245678Spl196000 			    (pr_status == AifJobStsSuccess))
65255678Spl196000 				softs->devcfg_wait_on = AifEnContainerChange;
65265678Spl196000 			else if ((pr_ctick == 0) &&
65275678Spl196000 			    (pr_status == AifJobStsRunning))
65285678Spl196000 				softs->devcfg_wait_on = AifEnContainerChange;
65295678Spl196000 		}
65305678Spl196000 		break;
65315678Spl196000 	}
65325678Spl196000 
65337567SXin.Chen@Sun.COM 	if (devcfg_needed) {
65347567SXin.Chen@Sun.COM 		softs->devcfg_wait_on = 0;
65355678Spl196000 		(void) aac_probe_containers(softs);
65367567SXin.Chen@Sun.COM 	}
653711964SXin.Chen@Sun.COM 
6538*12408SZhongyan.Gu@Sun.COM 	if (event != AAC_CFG_NULL_EXIST) {
6539*12408SZhongyan.Gu@Sun.COM 		ASSERT(en_type == AifEnAddJBOD || en_type == AifEnDeleteJBOD);
6540*12408SZhongyan.Gu@Sun.COM 		(void) aac_probe_jbod(softs,
6541*12408SZhongyan.Gu@Sun.COM 		    AAC_P2VTGT(softs, bus_id, tgt_id), event);
6542*12408SZhongyan.Gu@Sun.COM 	}
65435678Spl196000 	return (AACOK);
65445678Spl196000 }
65455678Spl196000 
654611964SXin.Chen@Sun.COM 
654711964SXin.Chen@Sun.COM /*
654811964SXin.Chen@Sun.COM  * Check and handle AIF events
654911964SXin.Chen@Sun.COM  */
655011964SXin.Chen@Sun.COM static void
aac_aif_event(struct aac_softstate * softs)655111964SXin.Chen@Sun.COM aac_aif_event(struct aac_softstate *softs)
655211964SXin.Chen@Sun.COM {
655311964SXin.Chen@Sun.COM 	struct aac_fib *fibp;
655411964SXin.Chen@Sun.COM 
655511964SXin.Chen@Sun.COM 	/*CONSTCOND*/
655611964SXin.Chen@Sun.COM 	while (1) {
655711964SXin.Chen@Sun.COM 		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
655811964SXin.Chen@Sun.COM 			break; /* No more AIFs to handle, end loop */
655911964SXin.Chen@Sun.COM 
656011964SXin.Chen@Sun.COM 		/* AIF overrun, array create/delete may missed. */
656111964SXin.Chen@Sun.COM 		if (softs->aifctx.ctx_overrun) {
656211964SXin.Chen@Sun.COM 			softs->aifctx.ctx_overrun = 0;
656311964SXin.Chen@Sun.COM 		}
656411964SXin.Chen@Sun.COM 
656511964SXin.Chen@Sun.COM 		/* AIF received, handle it */
656611964SXin.Chen@Sun.COM 		struct aac_aif_command *aifp =
656711964SXin.Chen@Sun.COM 		    (struct aac_aif_command *)&fibp->data[0];
656811964SXin.Chen@Sun.COM 		uint32_t aif_command = LE_32((uint32_t)aifp->command);
656911964SXin.Chen@Sun.COM 
657011964SXin.Chen@Sun.COM 		if (aif_command == AifCmdDriverNotify ||
657111964SXin.Chen@Sun.COM 		    aif_command == AifCmdEventNotify ||
657211964SXin.Chen@Sun.COM 		    aif_command == AifCmdJobProgress)
657311964SXin.Chen@Sun.COM 			(void) aac_handle_aif(softs, aifp);
657411964SXin.Chen@Sun.COM 	}
657511964SXin.Chen@Sun.COM }
657611964SXin.Chen@Sun.COM 
65775678Spl196000 /*
65785678Spl196000  * Timeout recovery
65795678Spl196000  */
65807567SXin.Chen@Sun.COM /*ARGSUSED*/
65815678Spl196000 static void
aac_cmd_timeout(struct aac_softstate * softs,struct aac_cmd * acp)65827567SXin.Chen@Sun.COM aac_cmd_timeout(struct aac_softstate *softs, struct aac_cmd *acp)
65837567SXin.Chen@Sun.COM {
65847567SXin.Chen@Sun.COM #ifdef DEBUG
65857567SXin.Chen@Sun.COM 	acp->fib_flags |= AACDB_FLAGS_FIB_TIMEOUT;
65867567SXin.Chen@Sun.COM 	AACDB_PRINT(softs, CE_WARN, "acp %p timed out", acp);
65877567SXin.Chen@Sun.COM 	AACDB_PRINT_FIB(softs, acp->slotp);
65887567SXin.Chen@Sun.COM #endif
65897567SXin.Chen@Sun.COM 
65905678Spl196000 	/*
65915678Spl196000 	 * Besides the firmware in unhealthy state, an overloaded
65925678Spl196000 	 * adapter may also incur pkt timeout.
65935678Spl196000 	 * There is a chance for an adapter with a slower IOP to take
65945678Spl196000 	 * longer than 60 seconds to process the commands, such as when
65955678Spl196000 	 * to perform IOs. So the adapter is doing a build on a RAID-5
65965678Spl196000 	 * while being required longer completion times should be
65975678Spl196000 	 * tolerated.
65985678Spl196000 	 */
65997567SXin.Chen@Sun.COM 	switch (aac_do_reset(softs)) {
66007567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_SUCCEED:
66017567SXin.Chen@Sun.COM 		aac_abort_iocmds(softs, AAC_IOCMD_OUTSTANDING, NULL, CMD_RESET);
66025678Spl196000 		aac_start_waiting_io(softs);
66037567SXin.Chen@Sun.COM 		break;
66047567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_FAILED:
66055678Spl196000 		/* Abort all waiting cmds when adapter is dead */
66067567SXin.Chen@Sun.COM 		aac_abort_iocmds(softs, AAC_IOCMD_ALL, NULL, CMD_TIMEOUT);
66077567SXin.Chen@Sun.COM 		break;
66087567SXin.Chen@Sun.COM 	case AAC_IOP_RESET_ABNORMAL:
66097567SXin.Chen@Sun.COM 		aac_start_waiting_io(softs);
66105678Spl196000 	}
66115678Spl196000 }
66125678Spl196000 
66135678Spl196000 /*
66145678Spl196000  * The following function comes from Adaptec:
66155678Spl196000  *
66165678Spl196000  * Time sync. command added to synchronize time with firmware every 30
66175678Spl196000  * minutes (required for correct AIF timestamps etc.)
66185678Spl196000  */
661911964SXin.Chen@Sun.COM static void
aac_sync_tick(struct aac_softstate * softs)66205678Spl196000 aac_sync_tick(struct aac_softstate *softs)
66215678Spl196000 {
662211348SZhongyan.Gu@Sun.COM 	ddi_acc_handle_t acc;
662311348SZhongyan.Gu@Sun.COM 	int rval;
662411348SZhongyan.Gu@Sun.COM 
662511964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
662611964SXin.Chen@Sun.COM 	ASSERT(softs->time_sync <= softs->timebase);
662711964SXin.Chen@Sun.COM 	softs->time_sync = 0;
662811964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
662911964SXin.Chen@Sun.COM 
663011348SZhongyan.Gu@Sun.COM 	/* Time sync. with firmware every AAC_SYNC_TICK */
663111348SZhongyan.Gu@Sun.COM 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
663211348SZhongyan.Gu@Sun.COM 	acc = softs->sync_ac.slotp->fib_acc_handle;
663311348SZhongyan.Gu@Sun.COM 
663411348SZhongyan.Gu@Sun.COM 	ddi_put32(acc, (void *)&softs->sync_ac.slotp->fibp->data[0],
663511348SZhongyan.Gu@Sun.COM 	    ddi_get_time());
663611348SZhongyan.Gu@Sun.COM 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
663711348SZhongyan.Gu@Sun.COM 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
663811964SXin.Chen@Sun.COM 
663911964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
664011964SXin.Chen@Sun.COM 	softs->time_sync = softs->timebase;
664111964SXin.Chen@Sun.COM 	if (rval != AACOK)
664211964SXin.Chen@Sun.COM 		/* retry shortly */
664311964SXin.Chen@Sun.COM 		softs->time_sync += aac_tick << 1;
664411964SXin.Chen@Sun.COM 	else
664511964SXin.Chen@Sun.COM 		softs->time_sync += AAC_SYNC_TICK;
664611964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
664711964SXin.Chen@Sun.COM }
664811964SXin.Chen@Sun.COM 
664911964SXin.Chen@Sun.COM /*
665011964SXin.Chen@Sun.COM  * Timeout checking and handling
665111964SXin.Chen@Sun.COM  */
66525678Spl196000 static void
aac_daemon(struct aac_softstate * softs)665311964SXin.Chen@Sun.COM aac_daemon(struct aac_softstate *softs)
665411964SXin.Chen@Sun.COM {
665511964SXin.Chen@Sun.COM 	int time_out; /* set if timeout happened */
665611964SXin.Chen@Sun.COM 	int time_adjust;
665711964SXin.Chen@Sun.COM 	uint32_t softs_timebase;
665811964SXin.Chen@Sun.COM 
665911964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
666011964SXin.Chen@Sun.COM 	ASSERT(softs->time_out <= softs->timebase);
666111964SXin.Chen@Sun.COM 	softs->time_out = 0;
666211964SXin.Chen@Sun.COM 	softs_timebase = softs->timebase;
666311964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
666411964SXin.Chen@Sun.COM 
666511964SXin.Chen@Sun.COM 	/* Check slots for timeout pkts */
666611964SXin.Chen@Sun.COM 	time_adjust = 0;
666711964SXin.Chen@Sun.COM 	do {
666811964SXin.Chen@Sun.COM 		struct aac_cmd *acp;
666911964SXin.Chen@Sun.COM 
667011964SXin.Chen@Sun.COM 		time_out = 0;
667111964SXin.Chen@Sun.COM 		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
667211964SXin.Chen@Sun.COM 			if (acp->timeout == 0)
667311964SXin.Chen@Sun.COM 				continue;
667411964SXin.Chen@Sun.COM 
667511964SXin.Chen@Sun.COM 			/*
667611964SXin.Chen@Sun.COM 			 * If timeout happened, update outstanding cmds
667711964SXin.Chen@Sun.COM 			 * to be checked later again.
667811964SXin.Chen@Sun.COM 			 */
667911964SXin.Chen@Sun.COM 			if (time_adjust) {
668011964SXin.Chen@Sun.COM 				acp->timeout += time_adjust;
668111964SXin.Chen@Sun.COM 				continue;
668211964SXin.Chen@Sun.COM 			}
668311964SXin.Chen@Sun.COM 
668411964SXin.Chen@Sun.COM 			if (acp->timeout <= softs_timebase) {
66857567SXin.Chen@Sun.COM 				aac_cmd_timeout(softs, acp);
668611964SXin.Chen@Sun.COM 				time_out = 1;
668711964SXin.Chen@Sun.COM 				time_adjust = aac_tick * drv_usectohz(1000000);
668811964SXin.Chen@Sun.COM 				break; /* timeout happened */
668911964SXin.Chen@Sun.COM 			} else {
669011964SXin.Chen@Sun.COM 				break; /* no timeout */
66915678Spl196000 			}
669211964SXin.Chen@Sun.COM 		}
669311964SXin.Chen@Sun.COM 	} while (time_out);
669411964SXin.Chen@Sun.COM 
669511964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
669611964SXin.Chen@Sun.COM 	softs->time_out = softs->timebase + aac_tick;
669711964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
669811964SXin.Chen@Sun.COM }
669911964SXin.Chen@Sun.COM 
670011964SXin.Chen@Sun.COM /*
670111964SXin.Chen@Sun.COM  * The event thread handles various tasks serially for the other parts of
670211964SXin.Chen@Sun.COM  * the driver, so that they can run fast.
670311964SXin.Chen@Sun.COM  */
670411964SXin.Chen@Sun.COM static void
aac_event_thread(struct aac_softstate * softs)670511964SXin.Chen@Sun.COM aac_event_thread(struct aac_softstate *softs)
670611964SXin.Chen@Sun.COM {
670711964SXin.Chen@Sun.COM 	int run = 1;
670811964SXin.Chen@Sun.COM 
670911964SXin.Chen@Sun.COM 	DBCALLED(softs, 1);
671011964SXin.Chen@Sun.COM 
671111964SXin.Chen@Sun.COM 	mutex_enter(&softs->ev_lock);
671211964SXin.Chen@Sun.COM 	while (run) {
671311964SXin.Chen@Sun.COM 		int events;
671411964SXin.Chen@Sun.COM 
671511964SXin.Chen@Sun.COM 		if ((events = softs->events) == 0) {
671611964SXin.Chen@Sun.COM 			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
671711964SXin.Chen@Sun.COM 			events = softs->events;
671811964SXin.Chen@Sun.COM 		}
671911964SXin.Chen@Sun.COM 		softs->events = 0;
672011964SXin.Chen@Sun.COM 		mutex_exit(&softs->ev_lock);
672111964SXin.Chen@Sun.COM 
672211964SXin.Chen@Sun.COM 		mutex_enter(&softs->io_lock);
672311964SXin.Chen@Sun.COM 		if ((softs->state & AAC_STATE_RUN) &&
672411964SXin.Chen@Sun.COM 		    (softs->state & AAC_STATE_DEAD) == 0) {
672511964SXin.Chen@Sun.COM 			if (events & AAC_EVENT_TIMEOUT)
672611964SXin.Chen@Sun.COM 				aac_daemon(softs);
672711964SXin.Chen@Sun.COM 			if (events & AAC_EVENT_SYNCTICK)
672811964SXin.Chen@Sun.COM 				aac_sync_tick(softs);
672911964SXin.Chen@Sun.COM 			if (events & AAC_EVENT_AIF)
673011964SXin.Chen@Sun.COM 				aac_aif_event(softs);
673111964SXin.Chen@Sun.COM 		} else {
673211964SXin.Chen@Sun.COM 			run = 0;
673311964SXin.Chen@Sun.COM 		}
673411964SXin.Chen@Sun.COM 		mutex_exit(&softs->io_lock);
673511964SXin.Chen@Sun.COM 
673611964SXin.Chen@Sun.COM 		mutex_enter(&softs->ev_lock);
673711964SXin.Chen@Sun.COM 	}
673811964SXin.Chen@Sun.COM 
673911964SXin.Chen@Sun.COM 	cv_signal(&softs->event_wait_cv);
674011964SXin.Chen@Sun.COM 	mutex_exit(&softs->ev_lock);
674111964SXin.Chen@Sun.COM }
674211964SXin.Chen@Sun.COM 
674311964SXin.Chen@Sun.COM /*
674411964SXin.Chen@Sun.COM  * Internal timer. It is only responsbile for time counting and report time
674511964SXin.Chen@Sun.COM  * related events. Events handling is done by aac_event_thread(), so that
674611964SXin.Chen@Sun.COM  * the timer itself could be as precise as possible.
674711964SXin.Chen@Sun.COM  */
674811964SXin.Chen@Sun.COM static void
aac_timer(void * arg)674911964SXin.Chen@Sun.COM aac_timer(void *arg)
675011964SXin.Chen@Sun.COM {
675111964SXin.Chen@Sun.COM 	struct aac_softstate *softs = arg;
675211964SXin.Chen@Sun.COM 	int events = 0;
675311964SXin.Chen@Sun.COM 
675411964SXin.Chen@Sun.COM 	mutex_enter(&softs->time_mutex);
675511964SXin.Chen@Sun.COM 
675611964SXin.Chen@Sun.COM 	/* If timer is being stopped, exit */
675711964SXin.Chen@Sun.COM 	if (softs->timeout_id) {
675811964SXin.Chen@Sun.COM 		softs->timeout_id = timeout(aac_timer, (void *)softs,
67595678Spl196000 		    (aac_tick * drv_usectohz(1000000)));
676011964SXin.Chen@Sun.COM 	} else {
676111964SXin.Chen@Sun.COM 		mutex_exit(&softs->time_mutex);
676211964SXin.Chen@Sun.COM 		return;
676311964SXin.Chen@Sun.COM 	}
676411964SXin.Chen@Sun.COM 
676511964SXin.Chen@Sun.COM 	/* Time counting */
676611964SXin.Chen@Sun.COM 	softs->timebase += aac_tick;
676711964SXin.Chen@Sun.COM 
676811964SXin.Chen@Sun.COM 	/* Check time related events */
676911964SXin.Chen@Sun.COM 	if (softs->time_out && softs->time_out <= softs->timebase)
677011964SXin.Chen@Sun.COM 		events |= AAC_EVENT_TIMEOUT;
677111964SXin.Chen@Sun.COM 	if (softs->time_sync && softs->time_sync <= softs->timebase)
677211964SXin.Chen@Sun.COM 		events |= AAC_EVENT_SYNCTICK;
677311964SXin.Chen@Sun.COM 
677411964SXin.Chen@Sun.COM 	mutex_exit(&softs->time_mutex);
677511964SXin.Chen@Sun.COM 
677611964SXin.Chen@Sun.COM 	if (events)
677711964SXin.Chen@Sun.COM 		aac_event_disp(softs, events);
677811964SXin.Chen@Sun.COM }
677911964SXin.Chen@Sun.COM 
678011964SXin.Chen@Sun.COM /*
678111964SXin.Chen@Sun.COM  * Dispatch events to daemon thread for handling
678211964SXin.Chen@Sun.COM  */
678311964SXin.Chen@Sun.COM static void
aac_event_disp(struct aac_softstate * softs,int events)678411964SXin.Chen@Sun.COM aac_event_disp(struct aac_softstate *softs, int events)
678511964SXin.Chen@Sun.COM {
678611964SXin.Chen@Sun.COM 	mutex_enter(&softs->ev_lock);
678711964SXin.Chen@Sun.COM 	softs->events |= events;
678811964SXin.Chen@Sun.COM 	cv_broadcast(&softs->event_disp_cv);
678911964SXin.Chen@Sun.COM 	mutex_exit(&softs->ev_lock);
67905678Spl196000 }
67915678Spl196000 
67925678Spl196000 /*
67935678Spl196000  * Architecture dependent functions
67945678Spl196000  */
67955678Spl196000 static int
aac_rx_get_fwstatus(struct aac_softstate * softs)67965678Spl196000 aac_rx_get_fwstatus(struct aac_softstate *softs)
67975678Spl196000 {
67985678Spl196000 	return (PCI_MEM_GET32(softs, AAC_OMR0));
67995678Spl196000 }
68005678Spl196000 
68015678Spl196000 static int
aac_rx_get_mailbox(struct aac_softstate * softs,int mb)68025678Spl196000 aac_rx_get_mailbox(struct aac_softstate *softs, int mb)
68035678Spl196000 {
68045678Spl196000 	return (PCI_MEM_GET32(softs, AAC_RX_MAILBOX + mb * 4));
68055678Spl196000 }
68065678Spl196000 
68075678Spl196000 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)68085678Spl196000 aac_rx_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
68095678Spl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
68105678Spl196000 {
68115678Spl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX, cmd);
68125678Spl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 4, arg0);
68135678Spl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 8, arg1);
68145678Spl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 12, arg2);
68155678Spl196000 	PCI_MEM_PUT32(softs, AAC_RX_MAILBOX + 16, arg3);
68165678Spl196000 }
68175678Spl196000 
68185678Spl196000 static int
aac_rkt_get_fwstatus(struct aac_softstate * softs)68195678Spl196000 aac_rkt_get_fwstatus(struct aac_softstate *softs)
68205678Spl196000 {
68215678Spl196000 	return (PCI_MEM_GET32(softs, AAC_OMR0));
68225678Spl196000 }
68235678Spl196000 
68245678Spl196000 static int
aac_rkt_get_mailbox(struct aac_softstate * softs,int mb)68255678Spl196000 aac_rkt_get_mailbox(struct aac_softstate *softs, int mb)
68265678Spl196000 {
68275678Spl196000 	return (PCI_MEM_GET32(softs, AAC_RKT_MAILBOX + mb *4));
68285678Spl196000 }
68295678Spl196000 
68305678Spl196000 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)68315678Spl196000 aac_rkt_set_mailbox(struct aac_softstate *softs, uint32_t cmd,
68325678Spl196000     uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3)
68335678Spl196000 {
68345678Spl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX, cmd);
68355678Spl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 4, arg0);
68365678Spl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 8, arg1);
68375678Spl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 12, arg2);
68385678Spl196000 	PCI_MEM_PUT32(softs, AAC_RKT_MAILBOX + 16, arg3);
68395678Spl196000 }
68405678Spl196000 
68415678Spl196000 /*
68425678Spl196000  * cb_ops functions
68435678Spl196000  */
68445678Spl196000 static int
aac_open(dev_t * devp,int flag,int otyp,cred_t * cred)68455678Spl196000 aac_open(dev_t *devp, int flag, int otyp, cred_t *cred)
68465678Spl196000 {
68475678Spl196000 	struct aac_softstate *softs;
68485678Spl196000 	int minor0, minor;
68495678Spl196000 	int instance;
68505678Spl196000 
68515678Spl196000 	DBCALLED(NULL, 2);
68525678Spl196000 
68535678Spl196000 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
68545678Spl196000 		return (EINVAL);
68555678Spl196000 
68565678Spl196000 	minor0 = getminor(*devp);
68575678Spl196000 	minor = AAC_SCSA_MINOR(minor0);
68585678Spl196000 
68595678Spl196000 	if (AAC_IS_SCSA_NODE(minor))
68605678Spl196000 		return (scsi_hba_open(devp, flag, otyp, cred));
68615678Spl196000 
68625678Spl196000 	instance = MINOR2INST(minor0);
68635678Spl196000 	if (instance >= AAC_MAX_ADAPTERS)
68645678Spl196000 		return (ENXIO);
68655678Spl196000 
68665678Spl196000 	softs = ddi_get_soft_state(aac_softstatep, instance);
68675678Spl196000 	if (softs == NULL)
68685678Spl196000 		return (ENXIO);
68695678Spl196000 
68705678Spl196000 	return (0);
68715678Spl196000 }
68725678Spl196000 
68735678Spl196000 /*ARGSUSED*/
68745678Spl196000 static int
aac_close(dev_t dev,int flag,int otyp,cred_t * cred)68755678Spl196000 aac_close(dev_t dev, int flag, int otyp, cred_t *cred)
68765678Spl196000 {
68775678Spl196000 	int minor0, minor;
68785678Spl196000 	int instance;
68795678Spl196000 
68805678Spl196000 	DBCALLED(NULL, 2);
68815678Spl196000 
68825678Spl196000 	if (otyp != OTYP_BLK && otyp != OTYP_CHR)
68835678Spl196000 		return (EINVAL);
68845678Spl196000 
68855678Spl196000 	minor0 = getminor(dev);
68865678Spl196000 	minor = AAC_SCSA_MINOR(minor0);
68875678Spl196000 
68885678Spl196000 	if (AAC_IS_SCSA_NODE(minor))
68895678Spl196000 		return (scsi_hba_close(dev, flag, otyp, cred));
68905678Spl196000 
68915678Spl196000 	instance = MINOR2INST(minor0);
68925678Spl196000 	if (instance >= AAC_MAX_ADAPTERS)
68935678Spl196000 		return (ENXIO);
68945678Spl196000 
68955678Spl196000 	return (0);
68965678Spl196000 }
68975678Spl196000 
68985678Spl196000 static int
aac_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)68995678Spl196000 aac_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
69005678Spl196000     int *rval_p)
69015678Spl196000 {
69025678Spl196000 	struct aac_softstate *softs;
69035678Spl196000 	int minor0, minor;
69045678Spl196000 	int instance;
69055678Spl196000 
69065678Spl196000 	DBCALLED(NULL, 2);
69075678Spl196000 
69085678Spl196000 	if (drv_priv(cred_p) != 0)
69095678Spl196000 		return (EPERM);
69105678Spl196000 
69115678Spl196000 	minor0 = getminor(dev);
69125678Spl196000 	minor = AAC_SCSA_MINOR(minor0);
69135678Spl196000 
69145678Spl196000 	if (AAC_IS_SCSA_NODE(minor))
69155678Spl196000 		return (scsi_hba_ioctl(dev, cmd, arg, flag, cred_p, rval_p));
69165678Spl196000 
69175678Spl196000 	instance = MINOR2INST(minor0);
69185678Spl196000 	if (instance < AAC_MAX_ADAPTERS) {
69195678Spl196000 		softs = ddi_get_soft_state(aac_softstatep, instance);
69205678Spl196000 		return (aac_do_ioctl(softs, dev, cmd, arg, flag));
69215678Spl196000 	}
69225678Spl196000 	return (ENXIO);
69235678Spl196000 }
69245678Spl196000 
69255678Spl196000 /*
69265678Spl196000  * The IO fault service error handling callback function
69275678Spl196000  */
69285678Spl196000 /*ARGSUSED*/
69295678Spl196000 static int
aac_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)69305678Spl196000 aac_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
69315678Spl196000 {
69325678Spl196000 	/*
69335678Spl196000 	 * as the driver can always deal with an error in any dma or
69345678Spl196000 	 * access handle, we can just return the fme_status value.
69355678Spl196000 	 */
69365678Spl196000 	pci_ereport_post(dip, err, NULL);
69375678Spl196000 	return (err->fme_status);
69385678Spl196000 }
69395678Spl196000 
69405678Spl196000 /*
69415678Spl196000  * aac_fm_init - initialize fma capabilities and register with IO
69425678Spl196000  *               fault services.
69435678Spl196000  */
69445678Spl196000 static void
aac_fm_init(struct aac_softstate * softs)69455678Spl196000 aac_fm_init(struct aac_softstate *softs)
69465678Spl196000 {
69475678Spl196000 	/*
69485678Spl196000 	 * Need to change iblock to priority for new MSI intr
69495678Spl196000 	 */
69505678Spl196000 	ddi_iblock_cookie_t fm_ibc;
69515678Spl196000 
69527567SXin.Chen@Sun.COM 	softs->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, softs->devinfo_p,
69537567SXin.Chen@Sun.COM 	    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
69547567SXin.Chen@Sun.COM 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
69557567SXin.Chen@Sun.COM 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
69567567SXin.Chen@Sun.COM 
69575678Spl196000 	/* Only register with IO Fault Services if we have some capability */
69585678Spl196000 	if (softs->fm_capabilities) {
69595678Spl196000 		/* Adjust access and dma attributes for FMA */
696011236SStephen.Hanson@Sun.COM 		softs->reg_attr.devacc_attr_access = DDI_FLAGERR_ACC;
69617567SXin.Chen@Sun.COM 		softs->addr_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
69627567SXin.Chen@Sun.COM 		softs->buf_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
69635678Spl196000 
69645678Spl196000 		/*
69655678Spl196000 		 * Register capabilities with IO Fault Services.
69665678Spl196000 		 * fm_capabilities will be updated to indicate
69675678Spl196000 		 * capabilities actually supported (not requested.)
69685678Spl196000 		 */
69695678Spl196000 		ddi_fm_init(softs->devinfo_p, &softs->fm_capabilities, &fm_ibc);
69705678Spl196000 
69715678Spl196000 		/*
69725678Spl196000 		 * Initialize pci ereport capabilities if ereport
69735678Spl196000 		 * capable (should always be.)
69745678Spl196000 		 */
69755678Spl196000 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
69765678Spl196000 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69775678Spl196000 			pci_ereport_setup(softs->devinfo_p);
69785678Spl196000 		}
69795678Spl196000 
69805678Spl196000 		/*
69815678Spl196000 		 * Register error callback if error callback capable.
69825678Spl196000 		 */
69835678Spl196000 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
69845678Spl196000 			ddi_fm_handler_register(softs->devinfo_p,
69855678Spl196000 			    aac_fm_error_cb, (void *) softs);
69865678Spl196000 		}
69875678Spl196000 	}
69885678Spl196000 }
69895678Spl196000 
69905678Spl196000 /*
69915678Spl196000  * aac_fm_fini - Releases fma capabilities and un-registers with IO
69925678Spl196000  *               fault services.
69935678Spl196000  */
69945678Spl196000 static void
aac_fm_fini(struct aac_softstate * softs)69955678Spl196000 aac_fm_fini(struct aac_softstate *softs)
69965678Spl196000 {
69975678Spl196000 	/* Only unregister FMA capabilities if registered */
69985678Spl196000 	if (softs->fm_capabilities) {
69995678Spl196000 		/*
70005678Spl196000 		 * Un-register error callback if error callback capable.
70015678Spl196000 		 */
70025678Spl196000 		if (DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70035678Spl196000 			ddi_fm_handler_unregister(softs->devinfo_p);
70045678Spl196000 		}
70055678Spl196000 
70065678Spl196000 		/*
70075678Spl196000 		 * Release any resources allocated by pci_ereport_setup()
70085678Spl196000 		 */
70095678Spl196000 		if (DDI_FM_EREPORT_CAP(softs->fm_capabilities) ||
70105678Spl196000 		    DDI_FM_ERRCB_CAP(softs->fm_capabilities)) {
70115678Spl196000 			pci_ereport_teardown(softs->devinfo_p);
70125678Spl196000 		}
70135678Spl196000 
70145678Spl196000 		/* Unregister from IO Fault Services */
70155678Spl196000 		ddi_fm_fini(softs->devinfo_p);
70167567SXin.Chen@Sun.COM 
70177567SXin.Chen@Sun.COM 		/* Adjust access and dma attributes for FMA */
701811236SStephen.Hanson@Sun.COM 		softs->reg_attr.devacc_attr_access = DDI_DEFAULT_ACC;
70197567SXin.Chen@Sun.COM 		softs->addr_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
70207567SXin.Chen@Sun.COM 		softs->buf_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
70215678Spl196000 	}
70225678Spl196000 }
70235678Spl196000 
70245678Spl196000 int
aac_check_acc_handle(ddi_acc_handle_t handle)70255678Spl196000 aac_check_acc_handle(ddi_acc_handle_t handle)
70265678Spl196000 {
70275678Spl196000 	ddi_fm_error_t de;
70285678Spl196000 
70295678Spl196000 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
70305678Spl196000 	return (de.fme_status);
70315678Spl196000 }
70325678Spl196000 
70335678Spl196000 int
aac_check_dma_handle(ddi_dma_handle_t handle)70345678Spl196000 aac_check_dma_handle(ddi_dma_handle_t handle)
70355678Spl196000 {
70365678Spl196000 	ddi_fm_error_t de;
70375678Spl196000 
70385678Spl196000 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
70395678Spl196000 	return (de.fme_status);
70405678Spl196000 }
70415678Spl196000 
70425678Spl196000 void
aac_fm_ereport(struct aac_softstate * softs,char * detail)70435678Spl196000 aac_fm_ereport(struct aac_softstate *softs, char *detail)
70445678Spl196000 {
70455678Spl196000 	uint64_t ena;
70465678Spl196000 	char buf[FM_MAX_CLASS];
70475678Spl196000 
70485678Spl196000 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
70495678Spl196000 	ena = fm_ena_generate(0, FM_ENA_FMT1);
70505678Spl196000 	if (DDI_FM_EREPORT_CAP(softs->fm_capabilities)) {
70515678Spl196000 		ddi_fm_ereport_post(softs->devinfo_p, buf, ena, DDI_NOSLEEP,
70525678Spl196000 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
70535678Spl196000 	}
70545678Spl196000 }
70555678Spl196000 
70567567SXin.Chen@Sun.COM /*
70577567SXin.Chen@Sun.COM  * Autoconfiguration support
70587567SXin.Chen@Sun.COM  */
70597567SXin.Chen@Sun.COM static int
aac_parse_devname(char * devnm,int * tgt,int * lun)70607567SXin.Chen@Sun.COM aac_parse_devname(char *devnm, int *tgt, int *lun)
70617567SXin.Chen@Sun.COM {
70627567SXin.Chen@Sun.COM 	char devbuf[SCSI_MAXNAMELEN];
70637567SXin.Chen@Sun.COM 	char *addr;
70647567SXin.Chen@Sun.COM 	char *p,  *tp, *lp;
70657567SXin.Chen@Sun.COM 	long num;
70667567SXin.Chen@Sun.COM 
70677567SXin.Chen@Sun.COM 	/* Parse dev name and address */
70687567SXin.Chen@Sun.COM 	(void) strcpy(devbuf, devnm);
70697567SXin.Chen@Sun.COM 	addr = "";
70707567SXin.Chen@Sun.COM 	for (p = devbuf; *p != '\0'; p++) {
70717567SXin.Chen@Sun.COM 		if (*p == '@') {
70727567SXin.Chen@Sun.COM 			addr = p + 1;
70737567SXin.Chen@Sun.COM 			*p = '\0';
70747567SXin.Chen@Sun.COM 		} else if (*p == ':') {
70757567SXin.Chen@Sun.COM 			*p = '\0';
70767567SXin.Chen@Sun.COM 			break;
70777567SXin.Chen@Sun.COM 		}
70787567SXin.Chen@Sun.COM 	}
70797567SXin.Chen@Sun.COM 
70807567SXin.Chen@Sun.COM 	/* Parse taget and lun */
70817567SXin.Chen@Sun.COM 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
70827567SXin.Chen@Sun.COM 		if (*p == ',') {
70837567SXin.Chen@Sun.COM 			lp = p + 1;
70847567SXin.Chen@Sun.COM 			*p = '\0';
70857567SXin.Chen@Sun.COM 			break;
70867567SXin.Chen@Sun.COM 		}
70877567SXin.Chen@Sun.COM 	}
70887567SXin.Chen@Sun.COM 	if (tgt && tp) {
70897567SXin.Chen@Sun.COM 		if (ddi_strtol(tp, NULL, 0x10, &num))
70907567SXin.Chen@Sun.COM 			return (AACERR);
70917567SXin.Chen@Sun.COM 		*tgt = (int)num;
70927567SXin.Chen@Sun.COM 	}
70937567SXin.Chen@Sun.COM 	if (lun && lp) {
70947567SXin.Chen@Sun.COM 		if (ddi_strtol(lp, NULL, 0x10, &num))
70957567SXin.Chen@Sun.COM 			return (AACERR);
70967567SXin.Chen@Sun.COM 		*lun = (int)num;
70977567SXin.Chen@Sun.COM 	}
70987567SXin.Chen@Sun.COM 	return (AACOK);
70997567SXin.Chen@Sun.COM }
71007567SXin.Chen@Sun.COM 
71017567SXin.Chen@Sun.COM static dev_info_t *
aac_find_child(struct aac_softstate * softs,uint16_t tgt,uint8_t lun)71027567SXin.Chen@Sun.COM aac_find_child(struct aac_softstate *softs, uint16_t tgt, uint8_t lun)
71037567SXin.Chen@Sun.COM {
71047567SXin.Chen@Sun.COM 	dev_info_t *child = NULL;
71057567SXin.Chen@Sun.COM 	char addr[SCSI_MAXNAMELEN];
71067567SXin.Chen@Sun.COM 	char tmp[MAXNAMELEN];
71077567SXin.Chen@Sun.COM 
71087567SXin.Chen@Sun.COM 	if (tgt < AAC_MAX_LD) {
71097567SXin.Chen@Sun.COM 		if (lun == 0) {
71107567SXin.Chen@Sun.COM 			struct aac_device *dvp = &softs->containers[tgt].dev;
71117567SXin.Chen@Sun.COM 
71127567SXin.Chen@Sun.COM 			child = dvp->dip;
71137567SXin.Chen@Sun.COM 		}
71147567SXin.Chen@Sun.COM 	} else {
71157567SXin.Chen@Sun.COM 		(void) sprintf(addr, "%x,%x", tgt, lun);
71167567SXin.Chen@Sun.COM 		for (child = ddi_get_child(softs->devinfo_p);
71177567SXin.Chen@Sun.COM 		    child; child = ddi_get_next_sibling(child)) {
71187567SXin.Chen@Sun.COM 			/* We don't care about non-persistent node */
71197567SXin.Chen@Sun.COM 			if (ndi_dev_is_persistent_node(child) == 0)
71207567SXin.Chen@Sun.COM 				continue;
71217567SXin.Chen@Sun.COM 
71227567SXin.Chen@Sun.COM 			if (aac_name_node(child, tmp, MAXNAMELEN) !=
71237567SXin.Chen@Sun.COM 			    DDI_SUCCESS)
71247567SXin.Chen@Sun.COM 				continue;
71257567SXin.Chen@Sun.COM 			if (strcmp(addr, tmp) == 0)
71267567SXin.Chen@Sun.COM 				break;
71277567SXin.Chen@Sun.COM 		}
71287567SXin.Chen@Sun.COM 	}
71297567SXin.Chen@Sun.COM 	return (child);
71307567SXin.Chen@Sun.COM }
71317567SXin.Chen@Sun.COM 
71327567SXin.Chen@Sun.COM static int
aac_config_child(struct aac_softstate * softs,struct scsi_device * sd,dev_info_t ** dipp)71337567SXin.Chen@Sun.COM aac_config_child(struct aac_softstate *softs, struct scsi_device *sd,
71347567SXin.Chen@Sun.COM     dev_info_t **dipp)
71357567SXin.Chen@Sun.COM {
71367567SXin.Chen@Sun.COM 	char *nodename = NULL;
71377567SXin.Chen@Sun.COM 	char **compatible = NULL;
71387567SXin.Chen@Sun.COM 	int ncompatible = 0;
71397567SXin.Chen@Sun.COM 	char *childname;
71407567SXin.Chen@Sun.COM 	dev_info_t *ldip = NULL;
71417567SXin.Chen@Sun.COM 	int tgt = sd->sd_address.a_target;
71427567SXin.Chen@Sun.COM 	int lun = sd->sd_address.a_lun;
71437567SXin.Chen@Sun.COM 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
71447567SXin.Chen@Sun.COM 	int rval;
71457567SXin.Chen@Sun.COM 
71467567SXin.Chen@Sun.COM 	DBCALLED(softs, 2);
71477567SXin.Chen@Sun.COM 
71487567SXin.Chen@Sun.COM 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
71497567SXin.Chen@Sun.COM 	    NULL, &nodename, &compatible, &ncompatible);
71507567SXin.Chen@Sun.COM 	if (nodename == NULL) {
71517567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_WARN,
71527567SXin.Chen@Sun.COM 		    "found no comptible driver for t%dL%d", tgt, lun);
71537567SXin.Chen@Sun.COM 		rval = NDI_FAILURE;
71547567SXin.Chen@Sun.COM 		goto finish;
71557567SXin.Chen@Sun.COM 	}
71567567SXin.Chen@Sun.COM 	childname = (softs->legacy && dtype == DTYPE_DIRECT) ? "sd" : nodename;
71577567SXin.Chen@Sun.COM 
71587567SXin.Chen@Sun.COM 	/* Create dev node */
71597567SXin.Chen@Sun.COM 	rval = ndi_devi_alloc(softs->devinfo_p, childname, DEVI_SID_NODEID,
71607567SXin.Chen@Sun.COM 	    &ldip);
71617567SXin.Chen@Sun.COM 	if (rval == NDI_SUCCESS) {
71627567SXin.Chen@Sun.COM 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
71637567SXin.Chen@Sun.COM 		    != DDI_PROP_SUCCESS) {
71647567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN, "unable to create "
71657567SXin.Chen@Sun.COM 			    "property for t%dL%d (target)", tgt, lun);
71667567SXin.Chen@Sun.COM 			rval = NDI_FAILURE;
71677567SXin.Chen@Sun.COM 			goto finish;
71687567SXin.Chen@Sun.COM 		}
71697567SXin.Chen@Sun.COM 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
71707567SXin.Chen@Sun.COM 		    != DDI_PROP_SUCCESS) {
71717567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN, "unable to create "
71727567SXin.Chen@Sun.COM 			    "property for t%dL%d (lun)", tgt, lun);
71737567SXin.Chen@Sun.COM 			rval = NDI_FAILURE;
71747567SXin.Chen@Sun.COM 			goto finish;
71757567SXin.Chen@Sun.COM 		}
71767567SXin.Chen@Sun.COM 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
71777567SXin.Chen@Sun.COM 		    "compatible", compatible, ncompatible)
71787567SXin.Chen@Sun.COM 		    != DDI_PROP_SUCCESS) {
71797567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN, "unable to create "
71807567SXin.Chen@Sun.COM 			    "property for t%dL%d (compatible)", tgt, lun);
71817567SXin.Chen@Sun.COM 			rval = NDI_FAILURE;
71827567SXin.Chen@Sun.COM 			goto finish;
71837567SXin.Chen@Sun.COM 		}
71847567SXin.Chen@Sun.COM 
71857567SXin.Chen@Sun.COM 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
71867567SXin.Chen@Sun.COM 		if (rval != NDI_SUCCESS) {
71877567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_WARN, "unable to online t%dL%d",
71887567SXin.Chen@Sun.COM 			    tgt, lun);
71897567SXin.Chen@Sun.COM 			ndi_prop_remove_all(ldip);
71907567SXin.Chen@Sun.COM 			(void) ndi_devi_free(ldip);
71917567SXin.Chen@Sun.COM 		}
71927567SXin.Chen@Sun.COM 	}
71937567SXin.Chen@Sun.COM finish:
71947567SXin.Chen@Sun.COM 	if (dipp)
71957567SXin.Chen@Sun.COM 		*dipp = ldip;
71967567SXin.Chen@Sun.COM 
71977567SXin.Chen@Sun.COM 	scsi_hba_nodename_compatible_free(nodename, compatible);
71987567SXin.Chen@Sun.COM 	return (rval);
71997567SXin.Chen@Sun.COM }
72007567SXin.Chen@Sun.COM 
72017567SXin.Chen@Sun.COM /*ARGSUSED*/
72027567SXin.Chen@Sun.COM static int
aac_probe_lun(struct aac_softstate * softs,struct scsi_device * sd)72037567SXin.Chen@Sun.COM aac_probe_lun(struct aac_softstate *softs, struct scsi_device *sd)
72047567SXin.Chen@Sun.COM {
72057567SXin.Chen@Sun.COM 	int tgt = sd->sd_address.a_target;
72067567SXin.Chen@Sun.COM 	int lun = sd->sd_address.a_lun;
72077567SXin.Chen@Sun.COM 
72087567SXin.Chen@Sun.COM 	DBCALLED(softs, 2);
72097567SXin.Chen@Sun.COM 
72107567SXin.Chen@Sun.COM 	if (tgt < AAC_MAX_LD) {
721111964SXin.Chen@Sun.COM 		enum aac_cfg_event event;
72127567SXin.Chen@Sun.COM 
72137567SXin.Chen@Sun.COM 		if (lun == 0) {
72147567SXin.Chen@Sun.COM 			mutex_enter(&softs->io_lock);
721511964SXin.Chen@Sun.COM 			event = aac_probe_container(softs, tgt);
72167567SXin.Chen@Sun.COM 			mutex_exit(&softs->io_lock);
721711964SXin.Chen@Sun.COM 			if ((event != AAC_CFG_NULL_NOEXIST) &&
721811964SXin.Chen@Sun.COM 			    (event != AAC_CFG_DELETE)) {
72197567SXin.Chen@Sun.COM 				if (scsi_hba_probe(sd, NULL) ==
72207567SXin.Chen@Sun.COM 				    SCSIPROBE_EXISTS)
72217567SXin.Chen@Sun.COM 					return (NDI_SUCCESS);
72227567SXin.Chen@Sun.COM 			}
72237567SXin.Chen@Sun.COM 		}
72247567SXin.Chen@Sun.COM 		return (NDI_FAILURE);
72257567SXin.Chen@Sun.COM 	} else {
72267567SXin.Chen@Sun.COM 		int dtype;
7227*12408SZhongyan.Gu@Sun.COM 		int qual; /* device qualifier */
72287567SXin.Chen@Sun.COM 
72297567SXin.Chen@Sun.COM 		if (scsi_hba_probe(sd, NULL) != SCSIPROBE_EXISTS)
72307567SXin.Chen@Sun.COM 			return (NDI_FAILURE);
72317567SXin.Chen@Sun.COM 
72327567SXin.Chen@Sun.COM 		dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
7233*12408SZhongyan.Gu@Sun.COM 		qual = dtype >> 5;
72347567SXin.Chen@Sun.COM 
72357567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_NOTE,
72367567SXin.Chen@Sun.COM 		    "Phys. device found: tgt %d dtype %d: %s",
72377567SXin.Chen@Sun.COM 		    tgt, dtype, sd->sd_inq->inq_vid);
72387567SXin.Chen@Sun.COM 
7239*12408SZhongyan.Gu@Sun.COM 		/* Only non-DASD and JBOD mode DASD are allowed exposed */
7240*12408SZhongyan.Gu@Sun.COM 		if (dtype == DTYPE_RODIRECT /* CDROM */ ||
7241*12408SZhongyan.Gu@Sun.COM 		    dtype == DTYPE_SEQUENTIAL /* TAPE */ ||
7242*12408SZhongyan.Gu@Sun.COM 		    dtype == DTYPE_ESI /* SES */) {
7243*12408SZhongyan.Gu@Sun.COM 			if (!(softs->flags & AAC_FLAGS_NONDASD))
7244*12408SZhongyan.Gu@Sun.COM 				return (NDI_FAILURE);
7245*12408SZhongyan.Gu@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "non-DASD %d found", tgt);
7246*12408SZhongyan.Gu@Sun.COM 
7247*12408SZhongyan.Gu@Sun.COM 		} else if (dtype == DTYPE_DIRECT) {
7248*12408SZhongyan.Gu@Sun.COM 			if (!(softs->flags & AAC_FLAGS_JBOD) || qual != 0)
7249*12408SZhongyan.Gu@Sun.COM 				return (NDI_FAILURE);
7250*12408SZhongyan.Gu@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "JBOD DASD %d found", tgt);
7251*12408SZhongyan.Gu@Sun.COM 		}
7252*12408SZhongyan.Gu@Sun.COM 
72537567SXin.Chen@Sun.COM 		mutex_enter(&softs->io_lock);
72547567SXin.Chen@Sun.COM 		softs->nondasds[AAC_PD(tgt)].dev.flags |= AAC_DFLAG_VALID;
72557567SXin.Chen@Sun.COM 		mutex_exit(&softs->io_lock);
72567567SXin.Chen@Sun.COM 		return (NDI_SUCCESS);
72577567SXin.Chen@Sun.COM 	}
72587567SXin.Chen@Sun.COM }
72597567SXin.Chen@Sun.COM 
72607567SXin.Chen@Sun.COM static int
aac_config_lun(struct aac_softstate * softs,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)72617567SXin.Chen@Sun.COM aac_config_lun(struct aac_softstate *softs, uint16_t tgt, uint8_t lun,
72627567SXin.Chen@Sun.COM     dev_info_t **ldip)
72637567SXin.Chen@Sun.COM {
72647567SXin.Chen@Sun.COM 	struct scsi_device sd;
72657567SXin.Chen@Sun.COM 	dev_info_t *child;
72667567SXin.Chen@Sun.COM 	int rval;
72677567SXin.Chen@Sun.COM 
72687567SXin.Chen@Sun.COM 	DBCALLED(softs, 2);
72697567SXin.Chen@Sun.COM 
72707567SXin.Chen@Sun.COM 	if ((child = aac_find_child(softs, tgt, lun)) != NULL) {
72717567SXin.Chen@Sun.COM 		if (ldip)
72727567SXin.Chen@Sun.COM 			*ldip = child;
72737567SXin.Chen@Sun.COM 		return (NDI_SUCCESS);
72747567SXin.Chen@Sun.COM 	}
72757567SXin.Chen@Sun.COM 
72767567SXin.Chen@Sun.COM 	bzero(&sd, sizeof (struct scsi_device));
72777567SXin.Chen@Sun.COM 	sd.sd_address.a_hba_tran = softs->hba_tran;
72787567SXin.Chen@Sun.COM 	sd.sd_address.a_target = (uint16_t)tgt;
72797567SXin.Chen@Sun.COM 	sd.sd_address.a_lun = (uint8_t)lun;
72807567SXin.Chen@Sun.COM 	if ((rval = aac_probe_lun(softs, &sd)) == NDI_SUCCESS)
72817567SXin.Chen@Sun.COM 		rval = aac_config_child(softs, &sd, ldip);
728211348SZhongyan.Gu@Sun.COM 	/* scsi_unprobe is blank now. Free buffer manually */
728311348SZhongyan.Gu@Sun.COM 	if (sd.sd_inq) {
728411348SZhongyan.Gu@Sun.COM 		kmem_free(sd.sd_inq, SUN_INQSIZE);
728511348SZhongyan.Gu@Sun.COM 		sd.sd_inq = (struct scsi_inquiry *)NULL;
728611348SZhongyan.Gu@Sun.COM 	}
72877567SXin.Chen@Sun.COM 	return (rval);
72887567SXin.Chen@Sun.COM }
72897567SXin.Chen@Sun.COM 
72907567SXin.Chen@Sun.COM static int
aac_config_tgt(struct aac_softstate * softs,int tgt)72917567SXin.Chen@Sun.COM aac_config_tgt(struct aac_softstate *softs, int tgt)
72927567SXin.Chen@Sun.COM {
72937567SXin.Chen@Sun.COM 	struct scsi_address ap;
72947567SXin.Chen@Sun.COM 	struct buf *bp = NULL;
72957567SXin.Chen@Sun.COM 	int buf_len = AAC_SCSI_RPTLUNS_HEAD_SIZE + AAC_SCSI_RPTLUNS_ADDR_SIZE;
72967567SXin.Chen@Sun.COM 	int list_len = 0;
72977567SXin.Chen@Sun.COM 	int lun_total = 0;
72987567SXin.Chen@Sun.COM 	dev_info_t *ldip;
72997567SXin.Chen@Sun.COM 	int i;
73007567SXin.Chen@Sun.COM 
73017567SXin.Chen@Sun.COM 	ap.a_hba_tran = softs->hba_tran;
73027567SXin.Chen@Sun.COM 	ap.a_target = (uint16_t)tgt;
73037567SXin.Chen@Sun.COM 	ap.a_lun = 0;
73047567SXin.Chen@Sun.COM 
73057567SXin.Chen@Sun.COM 	for (i = 0; i < 2; i++) {
73067567SXin.Chen@Sun.COM 		struct scsi_pkt *pkt;
73077567SXin.Chen@Sun.COM 		uchar_t *cdb;
73087567SXin.Chen@Sun.COM 		uchar_t *p;
73097567SXin.Chen@Sun.COM 		uint32_t data;
73107567SXin.Chen@Sun.COM 
73117567SXin.Chen@Sun.COM 		if (bp == NULL) {
73127567SXin.Chen@Sun.COM 			if ((bp = scsi_alloc_consistent_buf(&ap, NULL,
73137567SXin.Chen@Sun.COM 			    buf_len, B_READ, NULL_FUNC, NULL)) == NULL)
73147567SXin.Chen@Sun.COM 			return (AACERR);
73157567SXin.Chen@Sun.COM 		}
73167567SXin.Chen@Sun.COM 		if ((pkt = scsi_init_pkt(&ap, NULL, bp, CDB_GROUP5,
73177567SXin.Chen@Sun.COM 		    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT,
73187567SXin.Chen@Sun.COM 		    NULL, NULL)) == NULL) {
73197567SXin.Chen@Sun.COM 			scsi_free_consistent_buf(bp);
73207567SXin.Chen@Sun.COM 			return (AACERR);
73217567SXin.Chen@Sun.COM 		}
73227567SXin.Chen@Sun.COM 		cdb = pkt->pkt_cdbp;
73237567SXin.Chen@Sun.COM 		bzero(cdb, CDB_GROUP5);
73247567SXin.Chen@Sun.COM 		cdb[0] = SCMD_REPORT_LUNS;
73257567SXin.Chen@Sun.COM 
73267567SXin.Chen@Sun.COM 		/* Convert buffer len from local to LE_32 */
73277567SXin.Chen@Sun.COM 		data = buf_len;
73287567SXin.Chen@Sun.COM 		for (p = &cdb[9]; p > &cdb[5]; p--) {
73297567SXin.Chen@Sun.COM 			*p = data & 0xff;
73307567SXin.Chen@Sun.COM 			data >>= 8;
73317567SXin.Chen@Sun.COM 		}
73327567SXin.Chen@Sun.COM 
73337567SXin.Chen@Sun.COM 		if (scsi_poll(pkt) < 0 ||
73347567SXin.Chen@Sun.COM 		    ((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
73357567SXin.Chen@Sun.COM 			scsi_destroy_pkt(pkt);
73367567SXin.Chen@Sun.COM 			break;
73377567SXin.Chen@Sun.COM 		}
73387567SXin.Chen@Sun.COM 
73397567SXin.Chen@Sun.COM 		/* Convert list_len from LE_32 to local */
73407567SXin.Chen@Sun.COM 		for (p = (uchar_t *)bp->b_un.b_addr;
73417567SXin.Chen@Sun.COM 		    p < (uchar_t *)bp->b_un.b_addr + 4; p++) {
73427567SXin.Chen@Sun.COM 			data <<= 8;
73437567SXin.Chen@Sun.COM 			data |= *p;
73447567SXin.Chen@Sun.COM 		}
73457567SXin.Chen@Sun.COM 		list_len = data;
73467567SXin.Chen@Sun.COM 		if (buf_len < list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE) {
73477567SXin.Chen@Sun.COM 			scsi_free_consistent_buf(bp);
73487567SXin.Chen@Sun.COM 			bp = NULL;
73497567SXin.Chen@Sun.COM 			buf_len = list_len + AAC_SCSI_RPTLUNS_HEAD_SIZE;
73507567SXin.Chen@Sun.COM 		}
73517567SXin.Chen@Sun.COM 		scsi_destroy_pkt(pkt);
73527567SXin.Chen@Sun.COM 	}
73537567SXin.Chen@Sun.COM 	if (i >= 2) {
73547567SXin.Chen@Sun.COM 		uint8_t *buf = (uint8_t *)(bp->b_un.b_addr +
73557567SXin.Chen@Sun.COM 		    AAC_SCSI_RPTLUNS_HEAD_SIZE);
73567567SXin.Chen@Sun.COM 
73577567SXin.Chen@Sun.COM 		for (i = 0; i < (list_len / AAC_SCSI_RPTLUNS_ADDR_SIZE); i++) {
73587567SXin.Chen@Sun.COM 			uint16_t lun;
73597567SXin.Chen@Sun.COM 
73607567SXin.Chen@Sun.COM 			/* Determine report luns addressing type */
73617567SXin.Chen@Sun.COM 			switch (buf[0] & AAC_SCSI_RPTLUNS_ADDR_MASK) {
73627567SXin.Chen@Sun.COM 			/*
73637567SXin.Chen@Sun.COM 			 * Vendors in the field have been found to be
73647567SXin.Chen@Sun.COM 			 * concatenating bus/target/lun to equal the
73657567SXin.Chen@Sun.COM 			 * complete lun value instead of switching to
73667567SXin.Chen@Sun.COM 			 * flat space addressing
73677567SXin.Chen@Sun.COM 			 */
73687567SXin.Chen@Sun.COM 			case AAC_SCSI_RPTLUNS_ADDR_PERIPHERAL:
73697567SXin.Chen@Sun.COM 			case AAC_SCSI_RPTLUNS_ADDR_LOGICAL_UNIT:
73707567SXin.Chen@Sun.COM 			case AAC_SCSI_RPTLUNS_ADDR_FLAT_SPACE:
73717567SXin.Chen@Sun.COM 				lun = ((buf[0] & 0x3f) << 8) | buf[1];
73727567SXin.Chen@Sun.COM 				if (lun > UINT8_MAX) {
73737567SXin.Chen@Sun.COM 					AACDB_PRINT(softs, CE_WARN,
73747567SXin.Chen@Sun.COM 					    "abnormal lun number: %d", lun);
73757567SXin.Chen@Sun.COM 					break;
73767567SXin.Chen@Sun.COM 				}
73777567SXin.Chen@Sun.COM 				if (aac_config_lun(softs, tgt, lun, &ldip) ==
73787567SXin.Chen@Sun.COM 				    NDI_SUCCESS)
73797567SXin.Chen@Sun.COM 					lun_total++;
73807567SXin.Chen@Sun.COM 				break;
73817567SXin.Chen@Sun.COM 			}
73827567SXin.Chen@Sun.COM 
73837567SXin.Chen@Sun.COM 			buf += AAC_SCSI_RPTLUNS_ADDR_SIZE;
73847567SXin.Chen@Sun.COM 		}
73857567SXin.Chen@Sun.COM 	} else {
73867567SXin.Chen@Sun.COM 		/* The target may do not support SCMD_REPORT_LUNS. */
73877567SXin.Chen@Sun.COM 		if (aac_config_lun(softs, tgt, 0, &ldip) == NDI_SUCCESS)
73887567SXin.Chen@Sun.COM 			lun_total++;
73897567SXin.Chen@Sun.COM 	}
73907567SXin.Chen@Sun.COM 	scsi_free_consistent_buf(bp);
73917567SXin.Chen@Sun.COM 	return (lun_total);
73927567SXin.Chen@Sun.COM }
73937567SXin.Chen@Sun.COM 
73947567SXin.Chen@Sun.COM static void
aac_devcfg(struct aac_softstate * softs,int tgt,int en)73957567SXin.Chen@Sun.COM aac_devcfg(struct aac_softstate *softs, int tgt, int en)
73967567SXin.Chen@Sun.COM {
73977567SXin.Chen@Sun.COM 	struct aac_device *dvp;
73987567SXin.Chen@Sun.COM 
73997567SXin.Chen@Sun.COM 	mutex_enter(&softs->io_lock);
74007567SXin.Chen@Sun.COM 	dvp = AAC_DEV(softs, tgt);
74017567SXin.Chen@Sun.COM 	if (en)
74027567SXin.Chen@Sun.COM 		dvp->flags |= AAC_DFLAG_CONFIGURING;
74037567SXin.Chen@Sun.COM 	else
74047567SXin.Chen@Sun.COM 		dvp->flags &= ~AAC_DFLAG_CONFIGURING;
74057567SXin.Chen@Sun.COM 	mutex_exit(&softs->io_lock);
74067567SXin.Chen@Sun.COM }
74077567SXin.Chen@Sun.COM 
74087567SXin.Chen@Sun.COM 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)74097567SXin.Chen@Sun.COM aac_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
74107567SXin.Chen@Sun.COM     void *arg, dev_info_t **childp)
74117567SXin.Chen@Sun.COM {
74127567SXin.Chen@Sun.COM 	struct aac_softstate *softs;
74137567SXin.Chen@Sun.COM 	int circ = 0;
74147567SXin.Chen@Sun.COM 	int rval;
74157567SXin.Chen@Sun.COM 
74167567SXin.Chen@Sun.COM 	if ((softs = ddi_get_soft_state(aac_softstatep,
74177567SXin.Chen@Sun.COM 	    ddi_get_instance(parent))) == NULL)
74187567SXin.Chen@Sun.COM 		return (NDI_FAILURE);
74197567SXin.Chen@Sun.COM 
74207567SXin.Chen@Sun.COM 	/* Commands for bus config should be blocked as the bus is quiesced */
74217567SXin.Chen@Sun.COM 	mutex_enter(&softs->io_lock);
74227567SXin.Chen@Sun.COM 	if (softs->state & AAC_STATE_QUIESCED) {
74237567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_NOTE,
74247567SXin.Chen@Sun.COM 		    "bus_config abroted because bus is quiesced");
74257567SXin.Chen@Sun.COM 		mutex_exit(&softs->io_lock);
74267567SXin.Chen@Sun.COM 		return (NDI_FAILURE);
74277567SXin.Chen@Sun.COM 	}
74287567SXin.Chen@Sun.COM 	mutex_exit(&softs->io_lock);
74297567SXin.Chen@Sun.COM 
74307567SXin.Chen@Sun.COM 	DBCALLED(softs, 1);
74317567SXin.Chen@Sun.COM 
74327567SXin.Chen@Sun.COM 	/* Hold the nexus across the bus_config */
74337567SXin.Chen@Sun.COM 	ndi_devi_enter(parent, &circ);
74347567SXin.Chen@Sun.COM 	switch (op) {
74357567SXin.Chen@Sun.COM 	case BUS_CONFIG_ONE: {
74367567SXin.Chen@Sun.COM 		int tgt, lun;
74377567SXin.Chen@Sun.COM 
74387567SXin.Chen@Sun.COM 		if (aac_parse_devname(arg, &tgt, &lun) != AACOK) {
74397567SXin.Chen@Sun.COM 			rval = NDI_FAILURE;
74407567SXin.Chen@Sun.COM 			break;
74417567SXin.Chen@Sun.COM 		}
7442*12408SZhongyan.Gu@Sun.COM 		if (tgt >= AAC_MAX_LD) {
7443*12408SZhongyan.Gu@Sun.COM 			if (tgt >= AAC_MAX_DEV(softs)) {
7444*12408SZhongyan.Gu@Sun.COM 				rval = NDI_FAILURE;
7445*12408SZhongyan.Gu@Sun.COM 				break;
7446*12408SZhongyan.Gu@Sun.COM 			}
7447*12408SZhongyan.Gu@Sun.COM 		}
74487567SXin.Chen@Sun.COM 
74497567SXin.Chen@Sun.COM 		AAC_DEVCFG_BEGIN(softs, tgt);
74507567SXin.Chen@Sun.COM 		rval = aac_config_lun(softs, tgt, lun, childp);
74517567SXin.Chen@Sun.COM 		AAC_DEVCFG_END(softs, tgt);
74527567SXin.Chen@Sun.COM 		break;
74537567SXin.Chen@Sun.COM 	}
74547567SXin.Chen@Sun.COM 
74557567SXin.Chen@Sun.COM 	case BUS_CONFIG_DRIVER:
74567567SXin.Chen@Sun.COM 	case BUS_CONFIG_ALL: {
74577567SXin.Chen@Sun.COM 		uint32_t bus, tgt;
74587567SXin.Chen@Sun.COM 		int index, total;
74597567SXin.Chen@Sun.COM 
74607567SXin.Chen@Sun.COM 		for (tgt = 0; tgt < AAC_MAX_LD; tgt++) {
74617567SXin.Chen@Sun.COM 			AAC_DEVCFG_BEGIN(softs, tgt);
74627567SXin.Chen@Sun.COM 			(void) aac_config_lun(softs, tgt, 0, NULL);
74637567SXin.Chen@Sun.COM 			AAC_DEVCFG_END(softs, tgt);
74647567SXin.Chen@Sun.COM 		}
74657567SXin.Chen@Sun.COM 
74667567SXin.Chen@Sun.COM 		/* Config the non-DASD devices connected to the card */
74677567SXin.Chen@Sun.COM 		total = 0;
74687567SXin.Chen@Sun.COM 		index = AAC_MAX_LD;
74697567SXin.Chen@Sun.COM 		for (bus = 0; bus < softs->bus_max; bus++) {
74707567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "bus %d:", bus);
74717567SXin.Chen@Sun.COM 			for (tgt = 0; tgt < softs->tgt_max; tgt++, index++) {
74727567SXin.Chen@Sun.COM 				AAC_DEVCFG_BEGIN(softs, index);
74737567SXin.Chen@Sun.COM 				if (aac_config_tgt(softs, index))
74747567SXin.Chen@Sun.COM 					total++;
74757567SXin.Chen@Sun.COM 				AAC_DEVCFG_END(softs, index);
74767567SXin.Chen@Sun.COM 			}
74777567SXin.Chen@Sun.COM 		}
74787567SXin.Chen@Sun.COM 		AACDB_PRINT(softs, CE_CONT,
74797567SXin.Chen@Sun.COM 		    "?Total %d phys. device(s) found", total);
74807567SXin.Chen@Sun.COM 		rval = NDI_SUCCESS;
74817567SXin.Chen@Sun.COM 		break;
74827567SXin.Chen@Sun.COM 	}
74837567SXin.Chen@Sun.COM 	}
74847567SXin.Chen@Sun.COM 
74857567SXin.Chen@Sun.COM 	if (rval == NDI_SUCCESS)
74867567SXin.Chen@Sun.COM 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
74877567SXin.Chen@Sun.COM 	ndi_devi_exit(parent, circ);
74887567SXin.Chen@Sun.COM 	return (rval);
74897567SXin.Chen@Sun.COM }
74907567SXin.Chen@Sun.COM 
749111964SXin.Chen@Sun.COM /*ARGSUSED*/
749211964SXin.Chen@Sun.COM static int
aac_handle_dr(struct aac_softstate * softs,int tgt,int lun,int event)749311964SXin.Chen@Sun.COM aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
749411964SXin.Chen@Sun.COM {
74957567SXin.Chen@Sun.COM 	struct aac_device *dvp;
74967567SXin.Chen@Sun.COM 	dev_info_t *dip;
74977567SXin.Chen@Sun.COM 	int valid;
74987567SXin.Chen@Sun.COM 	int circ1 = 0;
74997567SXin.Chen@Sun.COM 
75007567SXin.Chen@Sun.COM 	DBCALLED(softs, 1);
75017567SXin.Chen@Sun.COM 
75027567SXin.Chen@Sun.COM 	/* Hold the nexus across the bus_config */
750311964SXin.Chen@Sun.COM 	dvp = AAC_DEV(softs, tgt);
75047567SXin.Chen@Sun.COM 	valid = AAC_DEV_IS_VALID(dvp);
75057567SXin.Chen@Sun.COM 	dip = dvp->dip;
750611964SXin.Chen@Sun.COM 	if (!(softs->state & AAC_STATE_RUN))
750711964SXin.Chen@Sun.COM 		return (AACERR);
75087567SXin.Chen@Sun.COM 	mutex_exit(&softs->io_lock);
75097567SXin.Chen@Sun.COM 
751011964SXin.Chen@Sun.COM 	switch (event) {
751111964SXin.Chen@Sun.COM 	case AAC_CFG_ADD:
751211964SXin.Chen@Sun.COM 	case AAC_CFG_DELETE:
75137567SXin.Chen@Sun.COM 		/* Device onlined */
75147567SXin.Chen@Sun.COM 		if (dip == NULL && valid) {
75157567SXin.Chen@Sun.COM 			ndi_devi_enter(softs->devinfo_p, &circ1);
751611964SXin.Chen@Sun.COM 			(void) aac_config_lun(softs, tgt, 0, NULL);
75177567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
751811964SXin.Chen@Sun.COM 			    softs->instance, tgt, lun);
75197567SXin.Chen@Sun.COM 			ndi_devi_exit(softs->devinfo_p, circ1);
75207567SXin.Chen@Sun.COM 		}
75217567SXin.Chen@Sun.COM 		/* Device offlined */
75227567SXin.Chen@Sun.COM 		if (dip && !valid) {
75237567SXin.Chen@Sun.COM 			mutex_enter(&softs->io_lock);
75247567SXin.Chen@Sun.COM 			(void) aac_do_reset(softs);
75257567SXin.Chen@Sun.COM 			mutex_exit(&softs->io_lock);
75267567SXin.Chen@Sun.COM 
75277567SXin.Chen@Sun.COM 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
75287567SXin.Chen@Sun.COM 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
752911964SXin.Chen@Sun.COM 			    softs->instance, tgt, lun);
75307567SXin.Chen@Sun.COM 		}
75317567SXin.Chen@Sun.COM 		break;
75327567SXin.Chen@Sun.COM 	}
753311964SXin.Chen@Sun.COM 
753411964SXin.Chen@Sun.COM 	mutex_enter(&softs->io_lock);
75357567SXin.Chen@Sun.COM 	return (AACOK);
75367567SXin.Chen@Sun.COM }
75377567SXin.Chen@Sun.COM 
75385678Spl196000 #ifdef DEBUG
75395678Spl196000 
75405678Spl196000 /* -------------------------debug aid functions-------------------------- */
75415678Spl196000 
75425678Spl196000 #define	AAC_FIB_CMD_KEY_STRINGS \
75435678Spl196000 	TestCommandResponse, "TestCommandResponse", \
75445678Spl196000 	TestAdapterCommand, "TestAdapterCommand", \
75455678Spl196000 	LastTestCommand, "LastTestCommand", \
75465678Spl196000 	ReinitHostNormCommandQueue, "ReinitHostNormCommandQueue", \
75475678Spl196000 	ReinitHostHighCommandQueue, "ReinitHostHighCommandQueue", \
75485678Spl196000 	ReinitHostHighRespQueue, "ReinitHostHighRespQueue", \
75495678Spl196000 	ReinitHostNormRespQueue, "ReinitHostNormRespQueue", \
75505678Spl196000 	ReinitAdapNormCommandQueue, "ReinitAdapNormCommandQueue", \
75515678Spl196000 	ReinitAdapHighCommandQueue, "ReinitAdapHighCommandQueue", \
75525678Spl196000 	ReinitAdapHighRespQueue, "ReinitAdapHighRespQueue", \
75535678Spl196000 	ReinitAdapNormRespQueue, "ReinitAdapNormRespQueue", \
75545678Spl196000 	InterfaceShutdown, "InterfaceShutdown", \
75555678Spl196000 	DmaCommandFib, "DmaCommandFib", \
75565678Spl196000 	StartProfile, "StartProfile", \
75575678Spl196000 	TermProfile, "TermProfile", \
75585678Spl196000 	SpeedTest, "SpeedTest", \
75595678Spl196000 	TakeABreakPt, "TakeABreakPt", \
75605678Spl196000 	RequestPerfData, "RequestPerfData", \
75615678Spl196000 	SetInterruptDefTimer, "SetInterruptDefTimer", \
75625678Spl196000 	SetInterruptDefCount, "SetInterruptDefCount", \
75635678Spl196000 	GetInterruptDefStatus, "GetInterruptDefStatus", \
75645678Spl196000 	LastCommCommand, "LastCommCommand", \
75655678Spl196000 	NuFileSystem, "NuFileSystem", \
75665678Spl196000 	UFS, "UFS", \
75675678Spl196000 	HostFileSystem, "HostFileSystem", \
75685678Spl196000 	LastFileSystemCommand, "LastFileSystemCommand", \
75695678Spl196000 	ContainerCommand, "ContainerCommand", \
75705678Spl196000 	ContainerCommand64, "ContainerCommand64", \
75715678Spl196000 	ClusterCommand, "ClusterCommand", \
75725678Spl196000 	ScsiPortCommand, "ScsiPortCommand", \
75735678Spl196000 	ScsiPortCommandU64, "ScsiPortCommandU64", \
75745678Spl196000 	AifRequest, "AifRequest", \
75755678Spl196000 	CheckRevision, "CheckRevision", \
75765678Spl196000 	FsaHostShutdown, "FsaHostShutdown", \
75775678Spl196000 	RequestAdapterInfo, "RequestAdapterInfo", \
75785678Spl196000 	IsAdapterPaused, "IsAdapterPaused", \
75795678Spl196000 	SendHostTime, "SendHostTime", \
75805678Spl196000 	LastMiscCommand, "LastMiscCommand"
75815678Spl196000 
75825678Spl196000 #define	AAC_CTVM_SUBCMD_KEY_STRINGS \
75835678Spl196000 	VM_Null, "VM_Null", \
75845678Spl196000 	VM_NameServe, "VM_NameServe", \
75855678Spl196000 	VM_ContainerConfig, "VM_ContainerConfig", \
75865678Spl196000 	VM_Ioctl, "VM_Ioctl", \
75875678Spl196000 	VM_FilesystemIoctl, "VM_FilesystemIoctl", \
75885678Spl196000 	VM_CloseAll, "VM_CloseAll", \
75895678Spl196000 	VM_CtBlockRead, "VM_CtBlockRead", \
75905678Spl196000 	VM_CtBlockWrite, "VM_CtBlockWrite", \
75915678Spl196000 	VM_SliceBlockRead, "VM_SliceBlockRead", \
75925678Spl196000 	VM_SliceBlockWrite, "VM_SliceBlockWrite", \
75935678Spl196000 	VM_DriveBlockRead, "VM_DriveBlockRead", \
75945678Spl196000 	VM_DriveBlockWrite, "VM_DriveBlockWrite", \
75955678Spl196000 	VM_EnclosureMgt, "VM_EnclosureMgt", \
75965678Spl196000 	VM_Unused, "VM_Unused", \
75975678Spl196000 	VM_CtBlockVerify, "VM_CtBlockVerify", \
75985678Spl196000 	VM_CtPerf, "VM_CtPerf", \
75995678Spl196000 	VM_CtBlockRead64, "VM_CtBlockRead64", \
76005678Spl196000 	VM_CtBlockWrite64, "VM_CtBlockWrite64", \
76015678Spl196000 	VM_CtBlockVerify64, "VM_CtBlockVerify64", \
76025678Spl196000 	VM_CtHostRead64, "VM_CtHostRead64", \
76035678Spl196000 	VM_CtHostWrite64, "VM_CtHostWrite64", \
76045678Spl196000 	VM_NameServe64, "VM_NameServe64"
76055678Spl196000 
76065678Spl196000 #define	AAC_CT_SUBCMD_KEY_STRINGS \
76075678Spl196000 	CT_Null, "CT_Null", \
76085678Spl196000 	CT_GET_SLICE_COUNT, "CT_GET_SLICE_COUNT", \
76095678Spl196000 	CT_GET_PARTITION_COUNT, "CT_GET_PARTITION_COUNT", \
76105678Spl196000 	CT_GET_PARTITION_INFO, "CT_GET_PARTITION_INFO", \
76115678Spl196000 	CT_GET_CONTAINER_COUNT, "CT_GET_CONTAINER_COUNT", \
76125678Spl196000 	CT_GET_CONTAINER_INFO_OLD, "CT_GET_CONTAINER_INFO_OLD", \
76135678Spl196000 	CT_WRITE_MBR, "CT_WRITE_MBR", \
76145678Spl196000 	CT_WRITE_PARTITION, "CT_WRITE_PARTITION", \
76155678Spl196000 	CT_UPDATE_PARTITION, "CT_UPDATE_PARTITION", \
76165678Spl196000 	CT_UNLOAD_CONTAINER, "CT_UNLOAD_CONTAINER", \
76175678Spl196000 	CT_CONFIG_SINGLE_PRIMARY, "CT_CONFIG_SINGLE_PRIMARY", \
76185678Spl196000 	CT_READ_CONFIG_AGE, "CT_READ_CONFIG_AGE", \
76195678Spl196000 	CT_WRITE_CONFIG_AGE, "CT_WRITE_CONFIG_AGE", \
76205678Spl196000 	CT_READ_SERIAL_NUMBER, "CT_READ_SERIAL_NUMBER", \
76215678Spl196000 	CT_ZERO_PAR_ENTRY, "CT_ZERO_PAR_ENTRY", \
76225678Spl196000 	CT_READ_MBR, "CT_READ_MBR", \
76235678Spl196000 	CT_READ_PARTITION, "CT_READ_PARTITION", \
76245678Spl196000 	CT_DESTROY_CONTAINER, "CT_DESTROY_CONTAINER", \
76255678Spl196000 	CT_DESTROY2_CONTAINER, "CT_DESTROY2_CONTAINER", \
76265678Spl196000 	CT_SLICE_SIZE, "CT_SLICE_SIZE", \
76275678Spl196000 	CT_CHECK_CONFLICTS, "CT_CHECK_CONFLICTS", \
76285678Spl196000 	CT_MOVE_CONTAINER, "CT_MOVE_CONTAINER", \
76295678Spl196000 	CT_READ_LAST_DRIVE, "CT_READ_LAST_DRIVE", \
76305678Spl196000 	CT_WRITE_LAST_DRIVE, "CT_WRITE_LAST_DRIVE", \
76315678Spl196000 	CT_UNMIRROR, "CT_UNMIRROR", \
76325678Spl196000 	CT_MIRROR_DELAY, "CT_MIRROR_DELAY", \
76335678Spl196000 	CT_GEN_MIRROR, "CT_GEN_MIRROR", \
76345678Spl196000 	CT_GEN_MIRROR2, "CT_GEN_MIRROR2", \
76355678Spl196000 	CT_TEST_CONTAINER, "CT_TEST_CONTAINER", \
76365678Spl196000 	CT_MOVE2, "CT_MOVE2", \
76375678Spl196000 	CT_SPLIT, "CT_SPLIT", \
76385678Spl196000 	CT_SPLIT2, "CT_SPLIT2", \
76395678Spl196000 	CT_SPLIT_BROKEN, "CT_SPLIT_BROKEN", \
76405678Spl196000 	CT_SPLIT_BROKEN2, "CT_SPLIT_BROKEN2", \
76415678Spl196000 	CT_RECONFIG, "CT_RECONFIG", \
76425678Spl196000 	CT_BREAK2, "CT_BREAK2", \
76435678Spl196000 	CT_BREAK, "CT_BREAK", \
76445678Spl196000 	CT_MERGE2, "CT_MERGE2", \
76455678Spl196000 	CT_MERGE, "CT_MERGE", \
76465678Spl196000 	CT_FORCE_ERROR, "CT_FORCE_ERROR", \
76475678Spl196000 	CT_CLEAR_ERROR, "CT_CLEAR_ERROR", \
76485678Spl196000 	CT_ASSIGN_FAILOVER, "CT_ASSIGN_FAILOVER", \
76495678Spl196000 	CT_CLEAR_FAILOVER, "CT_CLEAR_FAILOVER", \
76505678Spl196000 	CT_GET_FAILOVER_DATA, "CT_GET_FAILOVER_DATA", \
76515678Spl196000 	CT_VOLUME_ADD, "CT_VOLUME_ADD", \
76525678Spl196000 	CT_VOLUME_ADD2, "CT_VOLUME_ADD2", \
76535678Spl196000 	CT_MIRROR_STATUS, "CT_MIRROR_STATUS", \
76545678Spl196000 	CT_COPY_STATUS, "CT_COPY_STATUS", \
76555678Spl196000 	CT_COPY, "CT_COPY", \
76565678Spl196000 	CT_UNLOCK_CONTAINER, "CT_UNLOCK_CONTAINER", \
76575678Spl196000 	CT_LOCK_CONTAINER, "CT_LOCK_CONTAINER", \
76585678Spl196000 	CT_MAKE_READ_ONLY, "CT_MAKE_READ_ONLY", \
76595678Spl196000 	CT_MAKE_READ_WRITE, "CT_MAKE_READ_WRITE", \
76605678Spl196000 	CT_CLEAN_DEAD, "CT_CLEAN_DEAD", \
76615678Spl196000 	CT_ABORT_MIRROR_COMMAND, "CT_ABORT_MIRROR_COMMAND", \
76625678Spl196000 	CT_SET, "CT_SET", \
76635678Spl196000 	CT_GET, "CT_GET", \
76645678Spl196000 	CT_GET_NVLOG_ENTRY, "CT_GET_NVLOG_ENTRY", \
76655678Spl196000 	CT_GET_DELAY, "CT_GET_DELAY", \
76665678Spl196000 	CT_ZERO_CONTAINER_SPACE, "CT_ZERO_CONTAINER_SPACE", \
76675678Spl196000 	CT_GET_ZERO_STATUS, "CT_GET_ZERO_STATUS", \
76685678Spl196000 	CT_SCRUB, "CT_SCRUB", \
76695678Spl196000 	CT_GET_SCRUB_STATUS, "CT_GET_SCRUB_STATUS", \
76705678Spl196000 	CT_GET_SLICE_INFO, "CT_GET_SLICE_INFO", \
76715678Spl196000 	CT_GET_SCSI_METHOD, "CT_GET_SCSI_METHOD", \
76725678Spl196000 	CT_PAUSE_IO, "CT_PAUSE_IO", \
76735678Spl196000 	CT_RELEASE_IO, "CT_RELEASE_IO", \
76745678Spl196000 	CT_SCRUB2, "CT_SCRUB2", \
76755678Spl196000 	CT_MCHECK, "CT_MCHECK", \
76765678Spl196000 	CT_CORRUPT, "CT_CORRUPT", \
76775678Spl196000 	CT_GET_TASK_COUNT, "CT_GET_TASK_COUNT", \
76785678Spl196000 	CT_PROMOTE, "CT_PROMOTE", \
76795678Spl196000 	CT_SET_DEAD, "CT_SET_DEAD", \
76805678Spl196000 	CT_CONTAINER_OPTIONS, "CT_CONTAINER_OPTIONS", \
76815678Spl196000 	CT_GET_NV_PARAM, "CT_GET_NV_PARAM", \
76825678Spl196000 	CT_GET_PARAM, "CT_GET_PARAM", \
76835678Spl196000 	CT_NV_PARAM_SIZE, "CT_NV_PARAM_SIZE", \
76845678Spl196000 	CT_COMMON_PARAM_SIZE, "CT_COMMON_PARAM_SIZE", \
76855678Spl196000 	CT_PLATFORM_PARAM_SIZE, "CT_PLATFORM_PARAM_SIZE", \
76865678Spl196000 	CT_SET_NV_PARAM, "CT_SET_NV_PARAM", \
76875678Spl196000 	CT_ABORT_SCRUB, "CT_ABORT_SCRUB", \
76885678Spl196000 	CT_GET_SCRUB_ERROR, "CT_GET_SCRUB_ERROR", \
76895678Spl196000 	CT_LABEL_CONTAINER, "CT_LABEL_CONTAINER", \
76905678Spl196000 	CT_CONTINUE_DATA, "CT_CONTINUE_DATA", \
76915678Spl196000 	CT_STOP_DATA, "CT_STOP_DATA", \
76925678Spl196000 	CT_GET_PARTITION_TABLE, "CT_GET_PARTITION_TABLE", \
76935678Spl196000 	CT_GET_DISK_PARTITIONS, "CT_GET_DISK_PARTITIONS", \
76945678Spl196000 	CT_GET_MISC_STATUS, "CT_GET_MISC_STATUS", \
76955678Spl196000 	CT_GET_CONTAINER_PERF_INFO, "CT_GET_CONTAINER_PERF_INFO", \
76965678Spl196000 	CT_GET_TIME, "CT_GET_TIME", \
76975678Spl196000 	CT_READ_DATA, "CT_READ_DATA", \
76985678Spl196000 	CT_CTR, "CT_CTR", \
76995678Spl196000 	CT_CTL, "CT_CTL", \
77005678Spl196000 	CT_DRAINIO, "CT_DRAINIO", \
77015678Spl196000 	CT_RELEASEIO, "CT_RELEASEIO", \
77025678Spl196000 	CT_GET_NVRAM, "CT_GET_NVRAM", \
77035678Spl196000 	CT_GET_MEMORY, "CT_GET_MEMORY", \
77045678Spl196000 	CT_PRINT_CT_LOG, "CT_PRINT_CT_LOG", \
77055678Spl196000 	CT_ADD_LEVEL, "CT_ADD_LEVEL", \
77065678Spl196000 	CT_NV_ZERO, "CT_NV_ZERO", \
77075678Spl196000 	CT_READ_SIGNATURE, "CT_READ_SIGNATURE", \
77085678Spl196000 	CT_THROTTLE_ON, "CT_THROTTLE_ON", \
77095678Spl196000 	CT_THROTTLE_OFF, "CT_THROTTLE_OFF", \
77105678Spl196000 	CT_GET_THROTTLE_STATS, "CT_GET_THROTTLE_STATS", \
77115678Spl196000 	CT_MAKE_SNAPSHOT, "CT_MAKE_SNAPSHOT", \
77125678Spl196000 	CT_REMOVE_SNAPSHOT, "CT_REMOVE_SNAPSHOT", \
77135678Spl196000 	CT_WRITE_USER_FLAGS, "CT_WRITE_USER_FLAGS", \
77145678Spl196000 	CT_READ_USER_FLAGS, "CT_READ_USER_FLAGS", \
77155678Spl196000 	CT_MONITOR, "CT_MONITOR", \
77165678Spl196000 	CT_GEN_MORPH, "CT_GEN_MORPH", \
77175678Spl196000 	CT_GET_SNAPSHOT_INFO, "CT_GET_SNAPSHOT_INFO", \
77185678Spl196000 	CT_CACHE_SET, "CT_CACHE_SET", \
77195678Spl196000 	CT_CACHE_STAT, "CT_CACHE_STAT", \
77205678Spl196000 	CT_TRACE_START, "CT_TRACE_START", \
77215678Spl196000 	CT_TRACE_STOP, "CT_TRACE_STOP", \
77225678Spl196000 	CT_TRACE_ENABLE, "CT_TRACE_ENABLE", \
77235678Spl196000 	CT_TRACE_DISABLE, "CT_TRACE_DISABLE", \
77245678Spl196000 	CT_FORCE_CORE_DUMP, "CT_FORCE_CORE_DUMP", \
77255678Spl196000 	CT_SET_SERIAL_NUMBER, "CT_SET_SERIAL_NUMBER", \
77265678Spl196000 	CT_RESET_SERIAL_NUMBER, "CT_RESET_SERIAL_NUMBER", \
77275678Spl196000 	CT_ENABLE_RAID5, "CT_ENABLE_RAID5", \
77285678Spl196000 	CT_CLEAR_VALID_DUMP_FLAG, "CT_CLEAR_VALID_DUMP_FLAG", \
77295678Spl196000 	CT_GET_MEM_STATS, "CT_GET_MEM_STATS", \
77305678Spl196000 	CT_GET_CORE_SIZE, "CT_GET_CORE_SIZE", \
77315678Spl196000 	CT_CREATE_CONTAINER_OLD, "CT_CREATE_CONTAINER_OLD", \
77325678Spl196000 	CT_STOP_DUMPS, "CT_STOP_DUMPS", \
77335678Spl196000 	CT_PANIC_ON_TAKE_A_BREAK, "CT_PANIC_ON_TAKE_A_BREAK", \
77345678Spl196000 	CT_GET_CACHE_STATS, "CT_GET_CACHE_STATS", \
77355678Spl196000 	CT_MOVE_PARTITION, "CT_MOVE_PARTITION", \
77365678Spl196000 	CT_FLUSH_CACHE, "CT_FLUSH_CACHE", \
77375678Spl196000 	CT_READ_NAME, "CT_READ_NAME", \
77385678Spl196000 	CT_WRITE_NAME, "CT_WRITE_NAME", \
77395678Spl196000 	CT_TOSS_CACHE, "CT_TOSS_CACHE", \
77405678Spl196000 	CT_LOCK_DRAINIO, "CT_LOCK_DRAINIO", \
77415678Spl196000 	CT_CONTAINER_OFFLINE, "CT_CONTAINER_OFFLINE", \
77425678Spl196000 	CT_SET_CACHE_SIZE, "CT_SET_CACHE_SIZE", \
77435678Spl196000 	CT_CLEAN_SHUTDOWN_STATUS, "CT_CLEAN_SHUTDOWN_STATUS", \
77445678Spl196000 	CT_CLEAR_DISKLOG_ON_DISK, "CT_CLEAR_DISKLOG_ON_DISK", \
77455678Spl196000 	CT_CLEAR_ALL_DISKLOG, "CT_CLEAR_ALL_DISKLOG", \
77465678Spl196000 	CT_CACHE_FAVOR, "CT_CACHE_FAVOR", \
77475678Spl196000 	CT_READ_PASSTHRU_MBR, "CT_READ_PASSTHRU_MBR", \
77485678Spl196000 	CT_SCRUB_NOFIX, "CT_SCRUB_NOFIX", \
77495678Spl196000 	CT_SCRUB2_NOFIX, "CT_SCRUB2_NOFIX", \
77505678Spl196000 	CT_FLUSH, "CT_FLUSH", \
77515678Spl196000 	CT_REBUILD, "CT_REBUILD", \
77525678Spl196000 	CT_FLUSH_CONTAINER, "CT_FLUSH_CONTAINER", \
77535678Spl196000 	CT_RESTART, "CT_RESTART", \
77545678Spl196000 	CT_GET_CONFIG_STATUS, "CT_GET_CONFIG_STATUS", \
77555678Spl196000 	CT_TRACE_FLAG, "CT_TRACE_FLAG", \
77565678Spl196000 	CT_RESTART_MORPH, "CT_RESTART_MORPH", \
77575678Spl196000 	CT_GET_TRACE_INFO, "CT_GET_TRACE_INFO", \
77585678Spl196000 	CT_GET_TRACE_ITEM, "CT_GET_TRACE_ITEM", \
77595678Spl196000 	CT_COMMIT_CONFIG, "CT_COMMIT_CONFIG", \
77605678Spl196000 	CT_CONTAINER_EXISTS, "CT_CONTAINER_EXISTS", \
77615678Spl196000 	CT_GET_SLICE_FROM_DEVT, "CT_GET_SLICE_FROM_DEVT", \
77625678Spl196000 	CT_OPEN_READ_WRITE, "CT_OPEN_READ_WRITE", \
77635678Spl196000 	CT_WRITE_MEMORY_BLOCK, "CT_WRITE_MEMORY_BLOCK", \
77645678Spl196000 	CT_GET_CACHE_PARAMS, "CT_GET_CACHE_PARAMS", \
77655678Spl196000 	CT_CRAZY_CACHE, "CT_CRAZY_CACHE", \
77665678Spl196000 	CT_GET_PROFILE_STRUCT, "CT_GET_PROFILE_STRUCT", \
77675678Spl196000 	CT_SET_IO_TRACE_FLAG, "CT_SET_IO_TRACE_FLAG", \
77685678Spl196000 	CT_GET_IO_TRACE_STRUCT, "CT_GET_IO_TRACE_STRUCT", \
77695678Spl196000 	CT_CID_TO_64BITS_UID, "CT_CID_TO_64BITS_UID", \
77705678Spl196000 	CT_64BITS_UID_TO_CID, "CT_64BITS_UID_TO_CID", \
77715678Spl196000 	CT_PAR_TO_64BITS_UID, "CT_PAR_TO_64BITS_UID", \
77725678Spl196000 	CT_CID_TO_32BITS_UID, "CT_CID_TO_32BITS_UID", \
77735678Spl196000 	CT_32BITS_UID_TO_CID, "CT_32BITS_UID_TO_CID", \
77745678Spl196000 	CT_PAR_TO_32BITS_UID, "CT_PAR_TO_32BITS_UID", \
77755678Spl196000 	CT_SET_FAILOVER_OPTION, "CT_SET_FAILOVER_OPTION", \
77765678Spl196000 	CT_GET_FAILOVER_OPTION, "CT_GET_FAILOVER_OPTION", \
77775678Spl196000 	CT_STRIPE_ADD2, "CT_STRIPE_ADD2", \
77785678Spl196000 	CT_CREATE_VOLUME_SET, "CT_CREATE_VOLUME_SET", \
77795678Spl196000 	CT_CREATE_STRIPE_SET, "CT_CREATE_STRIPE_SET", \
77805678Spl196000 	CT_VERIFY_CONTAINER, "CT_VERIFY_CONTAINER", \
77815678Spl196000 	CT_IS_CONTAINER_DEAD, "CT_IS_CONTAINER_DEAD", \
77825678Spl196000 	CT_GET_CONTAINER_OPTION, "CT_GET_CONTAINER_OPTION", \
77835678Spl196000 	CT_GET_SNAPSHOT_UNUSED_STRUCT, "CT_GET_SNAPSHOT_UNUSED_STRUCT", \
77845678Spl196000 	CT_CLEAR_SNAPSHOT_UNUSED_STRUCT, "CT_CLEAR_SNAPSHOT_UNUSED_STRUCT", \
77855678Spl196000 	CT_GET_CONTAINER_INFO, "CT_GET_CONTAINER_INFO", \
77865678Spl196000 	CT_CREATE_CONTAINER, "CT_CREATE_CONTAINER", \
77875678Spl196000 	CT_CHANGE_CREATIONINFO, "CT_CHANGE_CREATIONINFO", \
77885678Spl196000 	CT_CHECK_CONFLICT_UID, "CT_CHECK_CONFLICT_UID", \
77895678Spl196000 	CT_CONTAINER_UID_CHECK, "CT_CONTAINER_UID_CHECK", \
77905678Spl196000 	CT_IS_CONTAINER_MEATADATA_STANDARD, \
77915678Spl196000 	    "CT_IS_CONTAINER_MEATADATA_STANDARD", \
77925678Spl196000 	CT_IS_SLICE_METADATA_STANDARD, "CT_IS_SLICE_METADATA_STANDARD", \
77935678Spl196000 	CT_GET_IMPORT_COUNT, "CT_GET_IMPORT_COUNT", \
77945678Spl196000 	CT_CANCEL_ALL_IMPORTS, "CT_CANCEL_ALL_IMPORTS", \
77955678Spl196000 	CT_GET_IMPORT_INFO, "CT_GET_IMPORT_INFO", \
77965678Spl196000 	CT_IMPORT_ARRAY, "CT_IMPORT_ARRAY", \
77975678Spl196000 	CT_GET_LOG_SIZE, "CT_GET_LOG_SIZE", \
77985678Spl196000 	CT_ALARM_GET_STATE, "CT_ALARM_GET_STATE", \
77995678Spl196000 	CT_ALARM_SET_STATE, "CT_ALARM_SET_STATE", \
78005678Spl196000 	CT_ALARM_ON_OFF, "CT_ALARM_ON_OFF", \
78015678Spl196000 	CT_GET_EE_OEM_ID, "CT_GET_EE_OEM_ID", \
78025678Spl196000 	CT_GET_PPI_HEADERS, "CT_GET_PPI_HEADERS", \
78035678Spl196000 	CT_GET_PPI_DATA, "CT_GET_PPI_DATA", \
78045678Spl196000 	CT_GET_PPI_ENTRIES, "CT_GET_PPI_ENTRIES", \
78055678Spl196000 	CT_DELETE_PPI_BUNDLE, "CT_DELETE_PPI_BUNDLE", \
78065678Spl196000 	CT_GET_PARTITION_TABLE_2, "CT_GET_PARTITION_TABLE_2", \
78075678Spl196000 	CT_GET_PARTITION_INFO_2, "CT_GET_PARTITION_INFO_2", \
78085678Spl196000 	CT_GET_DISK_PARTITIONS_2, "CT_GET_DISK_PARTITIONS_2", \
78095678Spl196000 	CT_QUIESCE_ADAPTER, "CT_QUIESCE_ADAPTER", \
78105678Spl196000 	CT_CLEAR_PPI_TABLE, "CT_CLEAR_PPI_TABLE"
78115678Spl196000 
78125678Spl196000 #define	AAC_CL_SUBCMD_KEY_STRINGS \
78135678Spl196000 	CL_NULL, "CL_NULL", \
78145678Spl196000 	DS_INIT, "DS_INIT", \
78155678Spl196000 	DS_RESCAN, "DS_RESCAN", \
78165678Spl196000 	DS_CREATE, "DS_CREATE", \
78175678Spl196000 	DS_DELETE, "DS_DELETE", \
78185678Spl196000 	DS_ADD_DISK, "DS_ADD_DISK", \
78195678Spl196000 	DS_REMOVE_DISK, "DS_REMOVE_DISK", \
78205678Spl196000 	DS_MOVE_DISK, "DS_MOVE_DISK", \
78215678Spl196000 	DS_TAKE_OWNERSHIP, "DS_TAKE_OWNERSHIP", \
78225678Spl196000 	DS_RELEASE_OWNERSHIP, "DS_RELEASE_OWNERSHIP", \
78235678Spl196000 	DS_FORCE_OWNERSHIP, "DS_FORCE_OWNERSHIP", \
78245678Spl196000 	DS_GET_DISK_SET_PARAM, "DS_GET_DISK_SET_PARAM", \
78255678Spl196000 	DS_GET_DRIVE_PARAM, "DS_GET_DRIVE_PARAM", \
78265678Spl196000 	DS_GET_SLICE_PARAM, "DS_GET_SLICE_PARAM", \
78275678Spl196000 	DS_GET_DISK_SETS, "DS_GET_DISK_SETS", \
78285678Spl196000 	DS_GET_DRIVES, "DS_GET_DRIVES", \
78295678Spl196000 	DS_SET_DISK_SET_PARAM, "DS_SET_DISK_SET_PARAM", \
78305678Spl196000 	DS_ONLINE, "DS_ONLINE", \
78315678Spl196000 	DS_OFFLINE, "DS_OFFLINE", \
78325678Spl196000 	DS_ONLINE_CONTAINERS, "DS_ONLINE_CONTAINERS", \
78335678Spl196000 	DS_FSAPRINT, "DS_FSAPRINT", \
78345678Spl196000 	CL_CFG_SET_HOST_IDS, "CL_CFG_SET_HOST_IDS", \
78355678Spl196000 	CL_CFG_SET_PARTNER_HOST_IDS, "CL_CFG_SET_PARTNER_HOST_IDS", \
78365678Spl196000 	CL_CFG_GET_CLUSTER_CONFIG, "CL_CFG_GET_CLUSTER_CONFIG", \
78375678Spl196000 	CC_CLI_CLEAR_MESSAGE_BUFFER, "CC_CLI_CLEAR_MESSAGE_BUFFER", \
78385678Spl196000 	CC_SRV_CLEAR_MESSAGE_BUFFER, "CC_SRV_CLEAR_MESSAGE_BUFFER", \
78395678Spl196000 	CC_CLI_SHOW_MESSAGE_BUFFER, "CC_CLI_SHOW_MESSAGE_BUFFER", \
78405678Spl196000 	CC_SRV_SHOW_MESSAGE_BUFFER, "CC_SRV_SHOW_MESSAGE_BUFFER", \
78415678Spl196000 	CC_CLI_SEND_MESSAGE, "CC_CLI_SEND_MESSAGE", \
78425678Spl196000 	CC_SRV_SEND_MESSAGE, "CC_SRV_SEND_MESSAGE", \
78435678Spl196000 	CC_CLI_GET_MESSAGE, "CC_CLI_GET_MESSAGE", \
78445678Spl196000 	CC_SRV_GET_MESSAGE, "CC_SRV_GET_MESSAGE", \
78455678Spl196000 	CC_SEND_TEST_MESSAGE, "CC_SEND_TEST_MESSAGE", \
78465678Spl196000 	CC_GET_BUSINFO, "CC_GET_BUSINFO", \
78475678Spl196000 	CC_GET_PORTINFO, "CC_GET_PORTINFO", \
78485678Spl196000 	CC_GET_NAMEINFO, "CC_GET_NAMEINFO", \
78495678Spl196000 	CC_GET_CONFIGINFO, "CC_GET_CONFIGINFO", \
78505678Spl196000 	CQ_QUORUM_OP, "CQ_QUORUM_OP"
78515678Spl196000 
78525678Spl196000 #define	AAC_AIF_SUBCMD_KEY_STRINGS \
78535678Spl196000 	AifCmdEventNotify, "AifCmdEventNotify", \
78545678Spl196000 	AifCmdJobProgress, "AifCmdJobProgress", \
78555678Spl196000 	AifCmdAPIReport, "AifCmdAPIReport", \
78565678Spl196000 	AifCmdDriverNotify, "AifCmdDriverNotify", \
78575678Spl196000 	AifReqJobList, "AifReqJobList", \
78585678Spl196000 	AifReqJobsForCtr, "AifReqJobsForCtr", \
78595678Spl196000 	AifReqJobsForScsi, "AifReqJobsForScsi", \
78605678Spl196000 	AifReqJobReport, "AifReqJobReport", \
78615678Spl196000 	AifReqTerminateJob, "AifReqTerminateJob", \
78625678Spl196000 	AifReqSuspendJob, "AifReqSuspendJob", \
78635678Spl196000 	AifReqResumeJob, "AifReqResumeJob", \
78645678Spl196000 	AifReqSendAPIReport, "AifReqSendAPIReport", \
78655678Spl196000 	AifReqAPIJobStart, "AifReqAPIJobStart", \
78665678Spl196000 	AifReqAPIJobUpdate, "AifReqAPIJobUpdate", \
78675678Spl196000 	AifReqAPIJobFinish, "AifReqAPIJobFinish"
78685678Spl196000 
78695678Spl196000 #define	AAC_IOCTL_SUBCMD_KEY_STRINGS \
78705678Spl196000 	Reserved_IOCTL, "Reserved_IOCTL", \
78715678Spl196000 	GetDeviceHandle, "GetDeviceHandle", \
78725678Spl196000 	BusTargetLun_to_DeviceHandle, "BusTargetLun_to_DeviceHandle", \
78735678Spl196000 	DeviceHandle_to_BusTargetLun, "DeviceHandle_to_BusTargetLun", \
78745678Spl196000 	RescanBus, "RescanBus", \
78755678Spl196000 	GetDeviceProbeInfo, "GetDeviceProbeInfo", \
78765678Spl196000 	GetDeviceCapacity, "GetDeviceCapacity", \
78775678Spl196000 	GetContainerProbeInfo, "GetContainerProbeInfo", \
78785678Spl196000 	GetRequestedMemorySize, "GetRequestedMemorySize", \
78795678Spl196000 	GetBusInfo, "GetBusInfo", \
78805678Spl196000 	GetVendorSpecific, "GetVendorSpecific", \
78815678Spl196000 	EnhancedGetDeviceProbeInfo, "EnhancedGetDeviceProbeInfo", \
78825678Spl196000 	EnhancedGetBusInfo, "EnhancedGetBusInfo", \
78835678Spl196000 	SetupExtendedCounters, "SetupExtendedCounters", \
78845678Spl196000 	GetPerformanceCounters, "GetPerformanceCounters", \
78855678Spl196000 	ResetPerformanceCounters, "ResetPerformanceCounters", \
78865678Spl196000 	ReadModePage, "ReadModePage", \
78875678Spl196000 	WriteModePage, "WriteModePage", \
78885678Spl196000 	ReadDriveParameter, "ReadDriveParameter", \
78895678Spl196000 	WriteDriveParameter, "WriteDriveParameter", \
78905678Spl196000 	ResetAdapter, "ResetAdapter", \
78915678Spl196000 	ResetBus, "ResetBus", \
78925678Spl196000 	ResetBusDevice, "ResetBusDevice", \
78935678Spl196000 	ExecuteSrb, "ExecuteSrb", \
78945678Spl196000 	Create_IO_Task, "Create_IO_Task", \
78955678Spl196000 	Delete_IO_Task, "Delete_IO_Task", \
78965678Spl196000 	Get_IO_Task_Info, "Get_IO_Task_Info", \
78975678Spl196000 	Check_Task_Progress, "Check_Task_Progress", \
78985678Spl196000 	InjectError, "InjectError", \
78995678Spl196000 	GetDeviceDefectCounts, "GetDeviceDefectCounts", \
79005678Spl196000 	GetDeviceDefectInfo, "GetDeviceDefectInfo", \
79015678Spl196000 	GetDeviceStatus, "GetDeviceStatus", \
79025678Spl196000 	ClearDeviceStatus, "ClearDeviceStatus", \
79035678Spl196000 	DiskSpinControl, "DiskSpinControl", \
79045678Spl196000 	DiskSmartControl, "DiskSmartControl", \
79055678Spl196000 	WriteSame, "WriteSame", \
79065678Spl196000 	ReadWriteLong, "ReadWriteLong", \
79075678Spl196000 	FormatUnit, "FormatUnit", \
79085678Spl196000 	TargetDeviceControl, "TargetDeviceControl", \
79095678Spl196000 	TargetChannelControl, "TargetChannelControl", \
79105678Spl196000 	FlashNewCode, "FlashNewCode", \
79115678Spl196000 	DiskCheck, "DiskCheck", \
79125678Spl196000 	RequestSense, "RequestSense", \
79135678Spl196000 	DiskPERControl, "DiskPERControl", \
79145678Spl196000 	Read10, "Read10", \
79155678Spl196000 	Write10, "Write10"
79165678Spl196000 
79175678Spl196000 #define	AAC_AIFEN_KEY_STRINGS \
79185678Spl196000 	AifEnGeneric, "Generic", \
79195678Spl196000 	AifEnTaskComplete, "TaskComplete", \
79205678Spl196000 	AifEnConfigChange, "Config change", \
79215678Spl196000 	AifEnContainerChange, "Container change", \
79225678Spl196000 	AifEnDeviceFailure, "device failed", \
79235678Spl196000 	AifEnMirrorFailover, "Mirror failover", \
79245678Spl196000 	AifEnContainerEvent, "container event", \
79255678Spl196000 	AifEnFileSystemChange, "File system changed", \
79265678Spl196000 	AifEnConfigPause, "Container pause event", \
79275678Spl196000 	AifEnConfigResume, "Container resume event", \
79285678Spl196000 	AifEnFailoverChange, "Failover space assignment changed", \
79295678Spl196000 	AifEnRAID5RebuildDone, "RAID5 rebuild finished", \
79305678Spl196000 	AifEnEnclosureManagement, "Enclosure management event", \
79315678Spl196000 	AifEnBatteryEvent, "battery event", \
79325678Spl196000 	AifEnAddContainer, "Add container", \
79335678Spl196000 	AifEnDeleteContainer, "Delete container", \
79345678Spl196000 	AifEnSMARTEvent, "SMART Event", \
79355678Spl196000 	AifEnBatteryNeedsRecond, "battery needs reconditioning", \
79365678Spl196000 	AifEnClusterEvent, "cluster event", \
79375678Spl196000 	AifEnDiskSetEvent, "disk set event occured", \
79385678Spl196000 	AifDenMorphComplete, "morph operation completed", \
79395678Spl196000 	AifDenVolumeExtendComplete, "VolumeExtendComplete"
79405678Spl196000 
79415678Spl196000 struct aac_key_strings {
79425678Spl196000 	int key;
79435678Spl196000 	char *message;
79445678Spl196000 };
79455678Spl196000 
79465678Spl196000 extern struct scsi_key_strings scsi_cmds[];
79475678Spl196000 
79485678Spl196000 static struct aac_key_strings aac_fib_cmds[] = {
79495678Spl196000 	AAC_FIB_CMD_KEY_STRINGS,
79505678Spl196000 	-1,			NULL
79515678Spl196000 };
79525678Spl196000 
79535678Spl196000 static struct aac_key_strings aac_ctvm_subcmds[] = {
79545678Spl196000 	AAC_CTVM_SUBCMD_KEY_STRINGS,
79555678Spl196000 	-1,			NULL
79565678Spl196000 };
79575678Spl196000 
79585678Spl196000 static struct aac_key_strings aac_ct_subcmds[] = {
79595678Spl196000 	AAC_CT_SUBCMD_KEY_STRINGS,
79605678Spl196000 	-1,			NULL
79615678Spl196000 };
79625678Spl196000 
79635678Spl196000 static struct aac_key_strings aac_cl_subcmds[] = {
79645678Spl196000 	AAC_CL_SUBCMD_KEY_STRINGS,
79655678Spl196000 	-1,			NULL
79665678Spl196000 };
79675678Spl196000 
79685678Spl196000 static struct aac_key_strings aac_aif_subcmds[] = {
79695678Spl196000 	AAC_AIF_SUBCMD_KEY_STRINGS,
79705678Spl196000 	-1,			NULL
79715678Spl196000 };
79725678Spl196000 
79735678Spl196000 static struct aac_key_strings aac_ioctl_subcmds[] = {
79745678Spl196000 	AAC_IOCTL_SUBCMD_KEY_STRINGS,
79755678Spl196000 	-1,			NULL
79765678Spl196000 };
79775678Spl196000 
79785678Spl196000 static struct aac_key_strings aac_aifens[] = {
79795678Spl196000 	AAC_AIFEN_KEY_STRINGS,
79805678Spl196000 	-1,			NULL
79815678Spl196000 };
79825678Spl196000 
79835678Spl196000 /*
79845678Spl196000  * The following function comes from Adaptec:
79855678Spl196000  *
79865678Spl196000  * Get the firmware print buffer parameters from the firmware,
79875678Spl196000  * if the command was successful map in the address.
79885678Spl196000  */
79895678Spl196000 static int
aac_get_fw_debug_buffer(struct aac_softstate * softs)79905678Spl196000 aac_get_fw_debug_buffer(struct aac_softstate *softs)
79915678Spl196000 {
79925678Spl196000 	if (aac_sync_mbcommand(softs, AAC_MONKER_GETDRVPROP,
79935678Spl196000 	    0, 0, 0, 0, NULL) == AACOK) {
79945678Spl196000 		uint32_t mondrv_buf_paddrl = AAC_MAILBOX_GET(softs, 1);
79955678Spl196000 		uint32_t mondrv_buf_paddrh = AAC_MAILBOX_GET(softs, 2);
79965678Spl196000 		uint32_t mondrv_buf_size = AAC_MAILBOX_GET(softs, 3);
79975678Spl196000 		uint32_t mondrv_hdr_size = AAC_MAILBOX_GET(softs, 4);
79985678Spl196000 
79995678Spl196000 		if (mondrv_buf_size) {
80005678Spl196000 			uint32_t offset = mondrv_buf_paddrl - \
80015678Spl196000 			    softs->pci_mem_base_paddr;
80025678Spl196000 
80035678Spl196000 			/*
80045678Spl196000 			 * See if the address is already mapped in, and
80055678Spl196000 			 * if so set it up from the base address
80065678Spl196000 			 */
80075678Spl196000 			if ((mondrv_buf_paddrh == 0) &&
80085678Spl196000 			    (offset + mondrv_buf_size < softs->map_size)) {
80095678Spl196000 				mutex_enter(&aac_prt_mutex);
80105678Spl196000 				softs->debug_buf_offset = offset;
80115678Spl196000 				softs->debug_header_size = mondrv_hdr_size;
80125678Spl196000 				softs->debug_buf_size = mondrv_buf_size;
80135678Spl196000 				softs->debug_fw_flags = 0;
80145678Spl196000 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
80155678Spl196000 				mutex_exit(&aac_prt_mutex);
80165678Spl196000 
80175678Spl196000 				return (AACOK);
80185678Spl196000 			}
80195678Spl196000 		}
80205678Spl196000 	}
80215678Spl196000 	return (AACERR);
80225678Spl196000 }
80235678Spl196000 
80245678Spl196000 int
aac_dbflag_on(struct aac_softstate * softs,int flag)80255678Spl196000 aac_dbflag_on(struct aac_softstate *softs, int flag)
80265678Spl196000 {
80275678Spl196000 	int debug_flags = softs ? softs->debug_flags : aac_debug_flags;
80285678Spl196000 
80295678Spl196000 	return ((debug_flags & (AACDB_FLAGS_FW_PRINT | \
80305678Spl196000 	    AACDB_FLAGS_KERNEL_PRINT)) && (debug_flags & flag));
80315678Spl196000 }
80325678Spl196000 
80335678Spl196000 static void
aac_cmn_err(struct aac_softstate * softs,uint_t lev,char sl,int noheader)80345678Spl196000 aac_cmn_err(struct aac_softstate *softs, uint_t lev, char sl, int noheader)
80355678Spl196000 {
80365678Spl196000 	if (noheader) {
80375678Spl196000 		if (sl) {
80385678Spl196000 			aac_fmt[0] = sl;
80395678Spl196000 			cmn_err(lev, aac_fmt, aac_prt_buf);
80405678Spl196000 		} else {
80415678Spl196000 			cmn_err(lev, &aac_fmt[1], aac_prt_buf);
80425678Spl196000 		}
80435678Spl196000 	} else {
80445678Spl196000 		if (sl) {
80455678Spl196000 			aac_fmt_header[0] = sl;
80465678Spl196000 			cmn_err(lev, aac_fmt_header,
80475678Spl196000 			    softs->vendor_name, softs->instance,
80485678Spl196000 			    aac_prt_buf);
80495678Spl196000 		} else {
80505678Spl196000 			cmn_err(lev, &aac_fmt_header[1],
80515678Spl196000 			    softs->vendor_name, softs->instance,
80525678Spl196000 			    aac_prt_buf);
80535678Spl196000 		}
80545678Spl196000 	}
80555678Spl196000 }
80565678Spl196000 
80575678Spl196000 /*
80585678Spl196000  * The following function comes from Adaptec:
80595678Spl196000  *
80605678Spl196000  * Format and print out the data passed in to UART or console
80615678Spl196000  * as specified by debug flags.
80625678Spl196000  */
80635678Spl196000 void
aac_printf(struct aac_softstate * softs,uint_t lev,const char * fmt,...)80645678Spl196000 aac_printf(struct aac_softstate *softs, uint_t lev, const char *fmt, ...)
80655678Spl196000 {
80665678Spl196000 	va_list args;
80675678Spl196000 	char sl; /* system log character */
80685678Spl196000 
80695678Spl196000 	mutex_enter(&aac_prt_mutex);
80705678Spl196000 	/* Set up parameters and call sprintf function to format the data */
80715678Spl196000 	if (strchr("^!?", fmt[0]) == NULL) {
80725678Spl196000 		sl = 0;
80735678Spl196000 	} else {
80745678Spl196000 		sl = fmt[0];
80755678Spl196000 		fmt++;
80765678Spl196000 	}
80775678Spl196000 	va_start(args, fmt);
80785678Spl196000 	(void) vsprintf(aac_prt_buf, fmt, args);
80795678Spl196000 	va_end(args);
80805678Spl196000 
80815678Spl196000 	/* Make sure the softs structure has been passed in for this section */
80825678Spl196000 	if (softs) {
80835678Spl196000 		if ((softs->debug_flags & AACDB_FLAGS_FW_PRINT) &&
80845678Spl196000 		    /* If we are set up for a Firmware print */
80855678Spl196000 		    (softs->debug_buf_size)) {
80865678Spl196000 			uint32_t count, i;
80875678Spl196000 
80885678Spl196000 			/* Make sure the string size is within boundaries */
80895678Spl196000 			count = strlen(aac_prt_buf);
80905678Spl196000 			if (count > softs->debug_buf_size)
80915678Spl196000 				count = (uint16_t)softs->debug_buf_size;
80925678Spl196000 
80935678Spl196000 			/*
80945678Spl196000 			 * Wait for no more than AAC_PRINT_TIMEOUT for the
80955678Spl196000 			 * previous message length to clear (the handshake).
80965678Spl196000 			 */
80975678Spl196000 			for (i = 0; i < AAC_PRINT_TIMEOUT; i++) {
80985678Spl196000 				if (!PCI_MEM_GET32(softs,
80995678Spl196000 				    softs->debug_buf_offset + \
81005678Spl196000 				    AAC_FW_DBG_STRLEN_OFFSET))
81015678Spl196000 					break;
81025678Spl196000 
81035678Spl196000 				drv_usecwait(1000);
81045678Spl196000 			}
81055678Spl196000 
81065678Spl196000 			/*
81075678Spl196000 			 * If the length is clear, copy over the message, the
81085678Spl196000 			 * flags, and the length. Make sure the length is the
81095678Spl196000 			 * last because that is the signal for the Firmware to
81105678Spl196000 			 * pick it up.
81115678Spl196000 			 */
81125678Spl196000 			if (!PCI_MEM_GET32(softs, softs->debug_buf_offset + \
81135678Spl196000 			    AAC_FW_DBG_STRLEN_OFFSET)) {
81145678Spl196000 				PCI_MEM_REP_PUT8(softs,
81155678Spl196000 				    softs->debug_buf_offset + \
81165678Spl196000 				    softs->debug_header_size,
81175678Spl196000 				    aac_prt_buf, count);
81185678Spl196000 				PCI_MEM_PUT32(softs,
81195678Spl196000 				    softs->debug_buf_offset + \
81205678Spl196000 				    AAC_FW_DBG_FLAGS_OFFSET,
81215678Spl196000 				    softs->debug_fw_flags);
81225678Spl196000 				PCI_MEM_PUT32(softs,
81235678Spl196000 				    softs->debug_buf_offset + \
81245678Spl196000 				    AAC_FW_DBG_STRLEN_OFFSET, count);
81255678Spl196000 			} else {
81265678Spl196000 				cmn_err(CE_WARN, "UART output fail");
81275678Spl196000 				softs->debug_flags &= ~AACDB_FLAGS_FW_PRINT;
81285678Spl196000 			}
81295678Spl196000 		}
81305678Spl196000 
81315678Spl196000 		/*
81325678Spl196000 		 * If the Kernel Debug Print flag is set, send it off
81335678Spl196000 		 * to the Kernel Debugger
81345678Spl196000 		 */
81355678Spl196000 		if (softs->debug_flags & AACDB_FLAGS_KERNEL_PRINT)
81365678Spl196000 			aac_cmn_err(softs, lev, sl,
81375678Spl196000 			    (softs->debug_flags & AACDB_FLAGS_NO_HEADERS));
81385678Spl196000 	} else {
81395678Spl196000 		/* Driver not initialized yet, no firmware or header output */
81405678Spl196000 		if (aac_debug_flags & AACDB_FLAGS_KERNEL_PRINT)
81415678Spl196000 			aac_cmn_err(softs, lev, sl, 1);
81425678Spl196000 	}
81435678Spl196000 	mutex_exit(&aac_prt_mutex);
81445678Spl196000 }
81455678Spl196000 
81465678Spl196000 /*
81475678Spl196000  * Translate command number to description string
81485678Spl196000  */
81495678Spl196000 static char *
aac_cmd_name(int cmd,struct aac_key_strings * cmdlist)81505678Spl196000 aac_cmd_name(int cmd, struct aac_key_strings *cmdlist)
81515678Spl196000 {
81525678Spl196000 	int i;
81535678Spl196000 
81545678Spl196000 	for (i = 0; cmdlist[i].key != -1; i++) {
81555678Spl196000 		if (cmd == cmdlist[i].key)
81565678Spl196000 			return (cmdlist[i].message);
81575678Spl196000 	}
81585678Spl196000 	return (NULL);
81595678Spl196000 }
81605678Spl196000 
81615678Spl196000 static void
aac_print_scmd(struct aac_softstate * softs,struct aac_cmd * acp)81625678Spl196000 aac_print_scmd(struct aac_softstate *softs, struct aac_cmd *acp)
81635678Spl196000 {
81645678Spl196000 	struct scsi_pkt *pkt = acp->pkt;
81655678Spl196000 	struct scsi_address *ap = &pkt->pkt_address;
81667567SXin.Chen@Sun.COM 	int is_pd = 0;
81675678Spl196000 	int ctl = ddi_get_instance(softs->devinfo_p);
81685678Spl196000 	int tgt = ap->a_target;
81695678Spl196000 	int lun = ap->a_lun;
81707100Spl196000 	union scsi_cdb *cdbp = (void *)pkt->pkt_cdbp;
81715678Spl196000 	uchar_t cmd = cdbp->scc_cmd;
81725678Spl196000 	char *desc;
81735678Spl196000 
81747567SXin.Chen@Sun.COM 	if (tgt >= AAC_MAX_LD) {
81757567SXin.Chen@Sun.COM 		is_pd = 1;
81767567SXin.Chen@Sun.COM 		ctl = ((struct aac_nondasd *)acp->dvp)->bus;
81777567SXin.Chen@Sun.COM 		tgt = ((struct aac_nondasd *)acp->dvp)->tid;
81787567SXin.Chen@Sun.COM 		lun = 0;
81797567SXin.Chen@Sun.COM 	}
81807567SXin.Chen@Sun.COM 
81815678Spl196000 	if ((desc = aac_cmd_name(cmd,
81825678Spl196000 	    (struct aac_key_strings *)scsi_cmds)) == NULL) {
81835678Spl196000 		aac_printf(softs, CE_NOTE,
81847567SXin.Chen@Sun.COM 		    "SCMD> Unknown(0x%2x) --> c%dt%dL%d %s",
81857567SXin.Chen@Sun.COM 		    cmd, ctl, tgt, lun, is_pd ? "(pd)" : "");
81865678Spl196000 		return;
81875678Spl196000 	}
81885678Spl196000 
81895678Spl196000 	switch (cmd) {
81905678Spl196000 	case SCMD_READ:
81915678Spl196000 	case SCMD_WRITE:
81925678Spl196000 		aac_printf(softs, CE_NOTE,
81937567SXin.Chen@Sun.COM 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
81945678Spl196000 		    desc, GETG0ADDR(cdbp), GETG0COUNT(cdbp),
81955678Spl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
81967567SXin.Chen@Sun.COM 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
81975678Spl196000 		break;
81985678Spl196000 	case SCMD_READ_G1:
81995678Spl196000 	case SCMD_WRITE_G1:
82005678Spl196000 		aac_printf(softs, CE_NOTE,
82017567SXin.Chen@Sun.COM 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
82025678Spl196000 		    desc, GETG1ADDR(cdbp), GETG1COUNT(cdbp),
82035678Spl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82047567SXin.Chen@Sun.COM 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
82055678Spl196000 		break;
82065678Spl196000 	case SCMD_READ_G4:
82075678Spl196000 	case SCMD_WRITE_G4:
82085678Spl196000 		aac_printf(softs, CE_NOTE,
82097567SXin.Chen@Sun.COM 		    "SCMD> %s 0x%x.%08x[%d] %s --> c%dt%dL%d %s",
82105678Spl196000 		    desc, GETG4ADDR(cdbp), GETG4ADDRTL(cdbp),
82115678Spl196000 		    GETG4COUNT(cdbp),
82125678Spl196000 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82137567SXin.Chen@Sun.COM 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
82147567SXin.Chen@Sun.COM 		break;
82157567SXin.Chen@Sun.COM 	case SCMD_READ_G5:
82167567SXin.Chen@Sun.COM 	case SCMD_WRITE_G5:
82177567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE,
82187567SXin.Chen@Sun.COM 		    "SCMD> %s 0x%x[%d] %s --> c%dt%dL%d %s",
82197567SXin.Chen@Sun.COM 		    desc, GETG5ADDR(cdbp), GETG5COUNT(cdbp),
82207567SXin.Chen@Sun.COM 		    (acp->flags & AAC_CMD_NO_INTR) ? "poll" : "intr",
82217567SXin.Chen@Sun.COM 		    ctl, tgt, lun, is_pd ? "(pd)" : "");
82225678Spl196000 		break;
82235678Spl196000 	default:
82247567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "SCMD> %s --> c%dt%dL%d %s",
82257567SXin.Chen@Sun.COM 		    desc, ctl, tgt, lun, is_pd ? "(pd)" : "");
82265678Spl196000 	}
82275678Spl196000 }
82285678Spl196000 
82295678Spl196000 void
aac_print_fib(struct aac_softstate * softs,struct aac_slot * slotp)82307567SXin.Chen@Sun.COM aac_print_fib(struct aac_softstate *softs, struct aac_slot *slotp)
82317567SXin.Chen@Sun.COM {
82327567SXin.Chen@Sun.COM 	struct aac_cmd *acp = slotp->acp;
82337567SXin.Chen@Sun.COM 	struct aac_fib *fibp = slotp->fibp;
82347567SXin.Chen@Sun.COM 	ddi_acc_handle_t acc = slotp->fib_acc_handle;
82355678Spl196000 	uint16_t fib_size;
82367567SXin.Chen@Sun.COM 	uint32_t fib_cmd, sub_cmd;
82375678Spl196000 	char *cmdstr, *subcmdstr;
82387567SXin.Chen@Sun.COM 	char *caller;
82397567SXin.Chen@Sun.COM 	int i;
82407567SXin.Chen@Sun.COM 
82417567SXin.Chen@Sun.COM 	if (acp) {
82427567SXin.Chen@Sun.COM 		if (!(softs->debug_fib_flags & acp->fib_flags))
82437567SXin.Chen@Sun.COM 			return;
82447567SXin.Chen@Sun.COM 		if (acp->fib_flags & AACDB_FLAGS_FIB_SCMD)
82457567SXin.Chen@Sun.COM 			caller = "SCMD";
82467567SXin.Chen@Sun.COM 		else if (acp->fib_flags & AACDB_FLAGS_FIB_IOCTL)
82477567SXin.Chen@Sun.COM 			caller = "IOCTL";
82487567SXin.Chen@Sun.COM 		else if (acp->fib_flags & AACDB_FLAGS_FIB_SRB)
82497567SXin.Chen@Sun.COM 			caller = "SRB";
82507567SXin.Chen@Sun.COM 		else
82517567SXin.Chen@Sun.COM 			return;
82527567SXin.Chen@Sun.COM 	} else {
82537567SXin.Chen@Sun.COM 		if (!(softs->debug_fib_flags & AACDB_FLAGS_FIB_SYNC))
82547567SXin.Chen@Sun.COM 			return;
82557567SXin.Chen@Sun.COM 		caller = "SYNC";
82567567SXin.Chen@Sun.COM 	}
82577567SXin.Chen@Sun.COM 
82587567SXin.Chen@Sun.COM 	fib_cmd = ddi_get16(acc, &fibp->Header.Command);
82595678Spl196000 	cmdstr = aac_cmd_name(fib_cmd, aac_fib_cmds);
82607567SXin.Chen@Sun.COM 	sub_cmd = (uint32_t)-1;
82615678Spl196000 	subcmdstr = NULL;
82625678Spl196000 
82637567SXin.Chen@Sun.COM 	/* Print FIB header */
82647567SXin.Chen@Sun.COM 	if (softs->debug_fib_flags & AACDB_FLAGS_FIB_HEADER) {
82657567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "FIB> from %s", caller);
82667567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     XferState  %d",
82677567SXin.Chen@Sun.COM 		    ddi_get32(acc, &fibp->Header.XferState));
82687567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     Command    %d",
82697567SXin.Chen@Sun.COM 		    ddi_get16(acc, &fibp->Header.Command));
82707567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     StructType %d",
82717567SXin.Chen@Sun.COM 		    ddi_get8(acc, &fibp->Header.StructType));
82727567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     Flags      0x%x",
82737567SXin.Chen@Sun.COM 		    ddi_get8(acc, &fibp->Header.Flags));
82747567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     Size       %d",
82757567SXin.Chen@Sun.COM 		    ddi_get16(acc, &fibp->Header.Size));
82767567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     SenderSize %d",
82777567SXin.Chen@Sun.COM 		    ddi_get16(acc, &fibp->Header.SenderSize));
82787567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     SenderAddr 0x%x",
82797567SXin.Chen@Sun.COM 		    ddi_get32(acc, &fibp->Header.SenderFibAddress));
82807567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     RcvrAddr   0x%x",
82817567SXin.Chen@Sun.COM 		    ddi_get32(acc, &fibp->Header.ReceiverFibAddress));
82827567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE, "     SenderData 0x%x",
82837567SXin.Chen@Sun.COM 		    ddi_get32(acc, &fibp->Header.SenderData));
82847567SXin.Chen@Sun.COM 	}
82857567SXin.Chen@Sun.COM 
82867567SXin.Chen@Sun.COM 	/* Print FIB data */
82875678Spl196000 	switch (fib_cmd) {
82885678Spl196000 	case ContainerCommand:
82897567SXin.Chen@Sun.COM 		sub_cmd = ddi_get32(acc,
82907567SXin.Chen@Sun.COM 		    (void *)&(((uint32_t *)(void *)&fibp->data[0])[0]));
82915678Spl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_ctvm_subcmds);
82925678Spl196000 		if (subcmdstr == NULL)
82935678Spl196000 			break;
82947567SXin.Chen@Sun.COM 
82957567SXin.Chen@Sun.COM 		switch (sub_cmd) {
82967567SXin.Chen@Sun.COM 		case VM_ContainerConfig: {
82977567SXin.Chen@Sun.COM 			struct aac_Container *pContainer =
82987567SXin.Chen@Sun.COM 			    (struct aac_Container *)fibp->data;
82997567SXin.Chen@Sun.COM 
83007567SXin.Chen@Sun.COM 			fib_cmd = sub_cmd;
83017567SXin.Chen@Sun.COM 			cmdstr = subcmdstr;
83027567SXin.Chen@Sun.COM 			sub_cmd = (uint32_t)-1;
83037567SXin.Chen@Sun.COM 			subcmdstr = NULL;
83047567SXin.Chen@Sun.COM 
83057567SXin.Chen@Sun.COM 			sub_cmd = ddi_get32(acc,
83067567SXin.Chen@Sun.COM 			    &pContainer->CTCommand.command);
83075678Spl196000 			subcmdstr = aac_cmd_name(sub_cmd, aac_ct_subcmds);
83085678Spl196000 			if (subcmdstr == NULL)
83095678Spl196000 				break;
83105678Spl196000 			aac_printf(softs, CE_NOTE, "FIB> %s (0x%x, 0x%x, 0x%x)",
83115678Spl196000 			    subcmdstr,
83127567SXin.Chen@Sun.COM 			    ddi_get32(acc, &pContainer->CTCommand.param[0]),
83137567SXin.Chen@Sun.COM 			    ddi_get32(acc, &pContainer->CTCommand.param[1]),
83147567SXin.Chen@Sun.COM 			    ddi_get32(acc, &pContainer->CTCommand.param[2]));
83155678Spl196000 			return;
83167567SXin.Chen@Sun.COM 		}
83177567SXin.Chen@Sun.COM 
83185678Spl196000 		case VM_Ioctl:
83197567SXin.Chen@Sun.COM 			fib_cmd = sub_cmd;
83207567SXin.Chen@Sun.COM 			cmdstr = subcmdstr;
83217567SXin.Chen@Sun.COM 			sub_cmd = (uint32_t)-1;
83227567SXin.Chen@Sun.COM 			subcmdstr = NULL;
83237567SXin.Chen@Sun.COM 
83247567SXin.Chen@Sun.COM 			sub_cmd = ddi_get32(acc,
83257567SXin.Chen@Sun.COM 			    (void *)&(((uint32_t *)(void *)&fibp->data[0])[4]));
83265678Spl196000 			subcmdstr = aac_cmd_name(sub_cmd, aac_ioctl_subcmds);
83275678Spl196000 			break;
83287567SXin.Chen@Sun.COM 
83297567SXin.Chen@Sun.COM 		case VM_CtBlockRead:
83307567SXin.Chen@Sun.COM 		case VM_CtBlockWrite: {
83317567SXin.Chen@Sun.COM 			struct aac_blockread *br =
83327567SXin.Chen@Sun.COM 			    (struct aac_blockread *)fibp->data;
83337567SXin.Chen@Sun.COM 			struct aac_sg_table *sg = &br->SgMap;
83347567SXin.Chen@Sun.COM 			uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83357567SXin.Chen@Sun.COM 
83367567SXin.Chen@Sun.COM 			aac_printf(softs, CE_NOTE,
83377567SXin.Chen@Sun.COM 			    "FIB> %s Container %d  0x%x/%d", subcmdstr,
83387567SXin.Chen@Sun.COM 			    ddi_get32(acc, &br->ContainerId),
83397567SXin.Chen@Sun.COM 			    ddi_get32(acc, &br->BlockNumber),
83407567SXin.Chen@Sun.COM 			    ddi_get32(acc, &br->ByteCount));
83417567SXin.Chen@Sun.COM 			for (i = 0; i < sgcount; i++)
83427567SXin.Chen@Sun.COM 				aac_printf(softs, CE_NOTE,
83437567SXin.Chen@Sun.COM 				    "     %d: 0x%08x/%d", i,
83447567SXin.Chen@Sun.COM 				    ddi_get32(acc, &sg->SgEntry[i].SgAddress),
83457567SXin.Chen@Sun.COM 				    ddi_get32(acc, &sg->SgEntry[i]. \
83467567SXin.Chen@Sun.COM 				    SgByteCount));
83477567SXin.Chen@Sun.COM 			return;
83487567SXin.Chen@Sun.COM 		}
83495678Spl196000 		}
83505678Spl196000 		break;
83515678Spl196000 
83527567SXin.Chen@Sun.COM 	case ContainerCommand64: {
83537567SXin.Chen@Sun.COM 		struct aac_blockread64 *br =
83547567SXin.Chen@Sun.COM 		    (struct aac_blockread64 *)fibp->data;
83557567SXin.Chen@Sun.COM 		struct aac_sg_table64 *sg = &br->SgMap64;
83567567SXin.Chen@Sun.COM 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83577567SXin.Chen@Sun.COM 		uint64_t sgaddr;
83587567SXin.Chen@Sun.COM 
83597567SXin.Chen@Sun.COM 		sub_cmd = br->Command;
83607567SXin.Chen@Sun.COM 		subcmdstr = NULL;
83617567SXin.Chen@Sun.COM 		if (sub_cmd == VM_CtHostRead64)
83627567SXin.Chen@Sun.COM 			subcmdstr = "VM_CtHostRead64";
83637567SXin.Chen@Sun.COM 		else if (sub_cmd == VM_CtHostWrite64)
83647567SXin.Chen@Sun.COM 			subcmdstr = "VM_CtHostWrite64";
83657567SXin.Chen@Sun.COM 		else
83667567SXin.Chen@Sun.COM 			break;
83677567SXin.Chen@Sun.COM 
83687567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE,
83697567SXin.Chen@Sun.COM 		    "FIB> %s Container %d  0x%x/%d", subcmdstr,
83707567SXin.Chen@Sun.COM 		    ddi_get16(acc, &br->ContainerId),
83717567SXin.Chen@Sun.COM 		    ddi_get32(acc, &br->BlockNumber),
83727567SXin.Chen@Sun.COM 		    ddi_get16(acc, &br->SectorCount));
83737567SXin.Chen@Sun.COM 		for (i = 0; i < sgcount; i++) {
83747567SXin.Chen@Sun.COM 			sgaddr = ddi_get64(acc,
83757567SXin.Chen@Sun.COM 			    &sg->SgEntry64[i].SgAddress);
83767567SXin.Chen@Sun.COM 			aac_printf(softs, CE_NOTE,
83777567SXin.Chen@Sun.COM 			    "     %d: 0x%08x.%08x/%d", i,
83787567SXin.Chen@Sun.COM 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
83797567SXin.Chen@Sun.COM 			    ddi_get32(acc, &sg->SgEntry64[i]. \
83807567SXin.Chen@Sun.COM 			    SgByteCount));
83817567SXin.Chen@Sun.COM 		}
83827567SXin.Chen@Sun.COM 		return;
83837567SXin.Chen@Sun.COM 	}
83847567SXin.Chen@Sun.COM 
83857567SXin.Chen@Sun.COM 	case RawIo: {
83867567SXin.Chen@Sun.COM 		struct aac_raw_io *io = (struct aac_raw_io *)fibp->data;
83877567SXin.Chen@Sun.COM 		struct aac_sg_tableraw *sg = &io->SgMapRaw;
83887567SXin.Chen@Sun.COM 		uint32_t sgcount = ddi_get32(acc, &sg->SgCount);
83897567SXin.Chen@Sun.COM 		uint64_t sgaddr;
83907567SXin.Chen@Sun.COM 
83917567SXin.Chen@Sun.COM 		aac_printf(softs, CE_NOTE,
83927567SXin.Chen@Sun.COM 		    "FIB> RawIo Container %d  0x%llx/%d 0x%x",
83937567SXin.Chen@Sun.COM 		    ddi_get16(acc, &io->ContainerId),
83947567SXin.Chen@Sun.COM 		    ddi_get64(acc, &io->BlockNumber),
83957567SXin.Chen@Sun.COM 		    ddi_get32(acc, &io->ByteCount),
83967567SXin.Chen@Sun.COM 		    ddi_get16(acc, &io->Flags));
83977567SXin.Chen@Sun.COM 		for (i = 0; i < sgcount; i++) {
83987567SXin.Chen@Sun.COM 			sgaddr = ddi_get64(acc, &sg->SgEntryRaw[i].SgAddress);
83997567SXin.Chen@Sun.COM 			aac_printf(softs, CE_NOTE, "     %d: 0x%08x.%08x/%d", i,
84007567SXin.Chen@Sun.COM 			    AAC_MS32(sgaddr), AAC_LS32(sgaddr),
84017567SXin.Chen@Sun.COM 			    ddi_get32(acc, &sg->SgEntryRaw[i].SgByteCount));
84027567SXin.Chen@Sun.COM 		}
84037567SXin.Chen@Sun.COM 		return;
84047567SXin.Chen@Sun.COM 	}
84057567SXin.Chen@Sun.COM 
84065678Spl196000 	case ClusterCommand:
84077567SXin.Chen@Sun.COM 		sub_cmd = ddi_get32(acc,
84087567SXin.Chen@Sun.COM 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
84095678Spl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_cl_subcmds);
84105678Spl196000 		break;
84115678Spl196000 
84125678Spl196000 	case AifRequest:
84137567SXin.Chen@Sun.COM 		sub_cmd = ddi_get32(acc,
84147567SXin.Chen@Sun.COM 		    (void *)&(((uint32_t *)(void *)fibp->data)[0]));
84155678Spl196000 		subcmdstr = aac_cmd_name(sub_cmd, aac_aif_subcmds);
84165678Spl196000 		break;
84175678Spl196000 
84185678Spl196000 	default:
84195678Spl196000 		break;
84205678Spl196000 	}
84215678Spl196000 
84227567SXin.Chen@Sun.COM 	fib_size = ddi_get16(acc, &(fibp->Header.Size));
84235678Spl196000 	if (subcmdstr)
84245678Spl196000 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
84255678Spl196000 		    subcmdstr, fib_size);
84267567SXin.Chen@Sun.COM 	else if (cmdstr && sub_cmd == (uint32_t)-1)
84275678Spl196000 		aac_printf(softs, CE_NOTE, "FIB> %s, sz=%d",
84285678Spl196000 		    cmdstr, fib_size);
84295678Spl196000 	else if (cmdstr)
84305678Spl196000 		aac_printf(softs, CE_NOTE, "FIB> %s: Unknown(0x%x), sz=%d",
84315678Spl196000 		    cmdstr, sub_cmd, fib_size);
84325678Spl196000 	else
84335678Spl196000 		aac_printf(softs, CE_NOTE, "FIB> Unknown(0x%x), sz=%d",
84345678Spl196000 		    fib_cmd, fib_size);
84355678Spl196000 }
84365678Spl196000 
84375678Spl196000 static void
aac_print_aif(struct aac_softstate * softs,struct aac_aif_command * aif)84385678Spl196000 aac_print_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
84395678Spl196000 {
84405678Spl196000 	int aif_command;
84415678Spl196000 	uint32_t aif_seqnumber;
84425678Spl196000 	int aif_en_type;
84435678Spl196000 	char *str;
84445678Spl196000 
84455678Spl196000 	aif_command = LE_32(aif->command);
84465678Spl196000 	aif_seqnumber = LE_32(aif->seqNumber);
84475678Spl196000 	aif_en_type = LE_32(aif->data.EN.type);
84485678Spl196000 
84495678Spl196000 	switch (aif_command) {
84505678Spl196000 	case AifCmdEventNotify:
84515678Spl196000 		str = aac_cmd_name(aif_en_type, aac_aifens);
84525678Spl196000 		if (str)
84535678Spl196000 			aac_printf(softs, CE_NOTE, "AIF! %s", str);
84545678Spl196000 		else
84555678Spl196000 			aac_printf(softs, CE_NOTE, "AIF! Unknown(0x%x)",
84565678Spl196000 			    aif_en_type);
84575678Spl196000 		break;
84585678Spl196000 
84595678Spl196000 	case AifCmdJobProgress:
84605678Spl196000 		switch (LE_32(aif->data.PR[0].status)) {
84615678Spl196000 		case AifJobStsSuccess:
84625678Spl196000 			str = "success"; break;
84635678Spl196000 		case AifJobStsFinished:
84645678Spl196000 			str = "finished"; break;
84655678Spl196000 		case AifJobStsAborted:
84665678Spl196000 			str = "aborted"; break;
84675678Spl196000 		case AifJobStsFailed:
84685678Spl196000 			str = "failed"; break;
84695678Spl196000 		case AifJobStsSuspended:
84705678Spl196000 			str = "suspended"; break;
84715678Spl196000 		case AifJobStsRunning:
84725678Spl196000 			str = "running"; break;
84735678Spl196000 		default:
84745678Spl196000 			str = "unknown"; break;
84755678Spl196000 		}
84765678Spl196000 		aac_printf(softs, CE_NOTE,
84775678Spl196000 		    "AIF! JobProgress (%d) - %s (%d, %d)",
84785678Spl196000 		    aif_seqnumber, str,
84795678Spl196000 		    LE_32(aif->data.PR[0].currentTick),
84805678Spl196000 		    LE_32(aif->data.PR[0].finalTick));
84815678Spl196000 		break;
84825678Spl196000 
84835678Spl196000 	case AifCmdAPIReport:
84845678Spl196000 		aac_printf(softs, CE_NOTE, "AIF! APIReport (%d)",
84855678Spl196000 		    aif_seqnumber);
84865678Spl196000 		break;
84875678Spl196000 
84885678Spl196000 	case AifCmdDriverNotify:
84895678Spl196000 		aac_printf(softs, CE_NOTE, "AIF! DriverNotify (%d)",
84905678Spl196000 		    aif_seqnumber);
84915678Spl196000 		break;
84925678Spl196000 
84935678Spl196000 	default:
84945678Spl196000 		aac_printf(softs, CE_NOTE, "AIF! AIF %d (%d)",
84955678Spl196000 		    aif_command, aif_seqnumber);
84965678Spl196000 		break;
84975678Spl196000 	}
84985678Spl196000 }
84995678Spl196000 
85005678Spl196000 #endif /* DEBUG */
8501