1508aff1aSJames C. McPherson /*
2508aff1aSJames C. McPherson  *       O.S   : Solaris
3508aff1aSJames C. McPherson  *  FILE NAME  : arcmsr.c
482beb602SGarrett D'Amore  *       BY    : Erich Chen, C.L. Huang
5508aff1aSJames C. McPherson  *  Description: SCSI RAID Device Driver for
6508aff1aSJames C. McPherson  *               ARECA RAID Host adapter
7508aff1aSJames C. McPherson  *
882beb602SGarrett D'Amore  *  Copyright (C) 2002,2010 Areca Technology Corporation All rights reserved.
982beb602SGarrett D'Amore  *  Copyright (C) 2002,2010 Erich Chen
10508aff1aSJames C. McPherson  *	    Web site: www.areca.com.tw
1182beb602SGarrett D'Amore  *	      E-mail: erich@areca.com.tw; ching2048@areca.com.tw
12508aff1aSJames C. McPherson  *
13508aff1aSJames C. McPherson  *	Redistribution and use in source and binary forms, with or without
14508aff1aSJames C. McPherson  *	modification, are permitted provided that the following conditions
15508aff1aSJames C. McPherson  *	are met:
16508aff1aSJames C. McPherson  *	1. Redistributions of source code must retain the above copyright
17508aff1aSJames C. McPherson  *	   notice, this list of conditions and the following disclaimer.
18508aff1aSJames C. McPherson  *	2. Redistributions in binary form must reproduce the above copyright
19508aff1aSJames C. McPherson  *	   notice, this list of conditions and the following disclaimer in the
20508aff1aSJames C. McPherson  *	   documentation and/or other materials provided with the distribution.
21508aff1aSJames C. McPherson  *  3. The party using or redistributing the source code and binary forms
22508aff1aSJames C. McPherson  *     agrees to the disclaimer below and the terms and conditions set forth
23508aff1aSJames C. McPherson  *     herein.
24508aff1aSJames C. McPherson  *
25508aff1aSJames C. McPherson  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26508aff1aSJames C. McPherson  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27508aff1aSJames C. McPherson  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28508aff1aSJames C. McPherson  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29508aff1aSJames C. McPherson  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30508aff1aSJames C. McPherson  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31508aff1aSJames C. McPherson  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32508aff1aSJames C. McPherson  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33508aff1aSJames C. McPherson  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34508aff1aSJames C. McPherson  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35508aff1aSJames C. McPherson  *  SUCH DAMAGE.
3682beb602SGarrett D'Amore  *
37ed632624SColin Yi  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
38508aff1aSJames C. McPherson  * Use is subject to license terms.
3982beb602SGarrett D'Amore  *
4082beb602SGarrett D'Amore  */
4182beb602SGarrett D'Amore /*
4282beb602SGarrett D'Amore  * This file and its contents are supplied under the terms of the
4382beb602SGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4482beb602SGarrett D'Amore  * You may only use this file in accordance with the terms of version
4582beb602SGarrett D'Amore  * 1.0 of the CDDL.
4682beb602SGarrett D'Amore  *
4782beb602SGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
4882beb602SGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
4982beb602SGarrett D'Amore  * http://www.illumos.org/license/CDDL.
5082beb602SGarrett D'Amore  */
5182beb602SGarrett D'Amore /*
5282beb602SGarrett D'Amore  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
533fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
54508aff1aSJames C. McPherson  */
55508aff1aSJames C. McPherson #include <sys/types.h>
56508aff1aSJames C. McPherson #include <sys/ddidmareq.h>
57508aff1aSJames C. McPherson #include <sys/scsi/scsi.h>
58508aff1aSJames C. McPherson #include <sys/ddi.h>
59508aff1aSJames C. McPherson #include <sys/sunddi.h>
60508aff1aSJames C. McPherson #include <sys/file.h>
61508aff1aSJames C. McPherson #include <sys/disp.h>
62508aff1aSJames C. McPherson #include <sys/signal.h>
63508aff1aSJames C. McPherson #include <sys/debug.h>
64508aff1aSJames C. McPherson #include <sys/pci.h>
65508aff1aSJames C. McPherson #include <sys/policy.h>
66ed632624SColin Yi #include <sys/atomic.h>
67508aff1aSJames C. McPherson #include "arcmsr.h"
68508aff1aSJames C. McPherson 
69508aff1aSJames C. McPherson static int arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
70508aff1aSJames C. McPherson static int arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg,
71508aff1aSJames C. McPherson     int mode, cred_t *credp, int *rvalp);
72508aff1aSJames C. McPherson static int arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
73508aff1aSJames C. McPherson static int arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd);
74508aff1aSJames C. McPherson static int arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
75508aff1aSJames C. McPherson static int arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
76508aff1aSJames C. McPherson static int arcmsr_tran_reset(struct scsi_address *ap, int level);
77508aff1aSJames C. McPherson static int arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom);
78508aff1aSJames C. McPherson static int arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value,
79508aff1aSJames C. McPherson     int whom);
80508aff1aSJames C. McPherson static int arcmsr_tran_tgt_init(dev_info_t *host_dev_info,
81508aff1aSJames C. McPherson     dev_info_t *target_dev_info, scsi_hba_tran_t *hosttran,
82508aff1aSJames C. McPherson     struct scsi_device *sd);
83508aff1aSJames C. McPherson static void arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt);
84508aff1aSJames C. McPherson static void arcmsr_tran_destroy_pkt(struct scsi_address *ap,
85508aff1aSJames C. McPherson     struct scsi_pkt *pkt);
86508aff1aSJames C. McPherson static void arcmsr_tran_sync_pkt(struct scsi_address *ap,
87508aff1aSJames C. McPherson     struct scsi_pkt *pkt);
88508aff1aSJames C. McPherson static struct scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap,
89508aff1aSJames C. McPherson     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
90508aff1aSJames C. McPherson     int tgtlen, int flags, int (*callback)(), caddr_t arg);
9182beb602SGarrett D'Amore static int arcmsr_config_child(struct ACB *acb, struct scsi_device *sd,
9282beb602SGarrett D'Amore     dev_info_t **dipp);
93508aff1aSJames C. McPherson 
94ed632624SColin Yi static int arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun,
95ed632624SColin Yi     dev_info_t **ldip);
9682beb602SGarrett D'Amore static uint8_t arcmsr_abort_host_command(struct ACB *acb);
9782beb602SGarrett D'Amore static uint8_t arcmsr_get_echo_from_iop(struct ACB *acb);
9882beb602SGarrett D'Amore static uint_t arcmsr_intr_handler(caddr_t arg, caddr_t arg2);
99508aff1aSJames C. McPherson static int arcmsr_initialize(struct ACB *acb);
100508aff1aSJames C. McPherson static int arcmsr_dma_alloc(struct ACB *acb,
101508aff1aSJames C. McPherson     struct scsi_pkt *pkt, struct buf *bp, int flags, int (*callback)());
102508aff1aSJames C. McPherson static int arcmsr_dma_move(struct ACB *acb,
103508aff1aSJames C. McPherson     struct scsi_pkt *pkt, struct buf *bp);
10482beb602SGarrett D'Amore static void arcmsr_handle_iop_bus_hold(struct ACB *acb);
10582beb602SGarrett D'Amore static void arcmsr_hbc_message_isr(struct ACB *acb);
106508aff1aSJames C. McPherson static void arcmsr_pcidev_disattach(struct ACB *acb);
107508aff1aSJames C. McPherson static void arcmsr_ccb_complete(struct CCB *ccb, int flag);
108508aff1aSJames C. McPherson static void arcmsr_iop_init(struct ACB *acb);
109508aff1aSJames C. McPherson static void arcmsr_iop_parking(struct ACB *acb);
11082beb602SGarrett D'Amore /*PRINTFLIKE3*/
111508aff1aSJames C. McPherson static void arcmsr_log(struct ACB *acb, int level, char *fmt, ...);
11282beb602SGarrett D'Amore /*PRINTFLIKE2*/
11382beb602SGarrett D'Amore static void arcmsr_warn(struct ACB *acb, char *fmt, ...);
11482beb602SGarrett D'Amore static void arcmsr_mutex_init(struct ACB *acb);
11582beb602SGarrett D'Amore static void arcmsr_remove_intr(struct ACB *acb);
11682beb602SGarrett D'Amore static void arcmsr_ccbs_timeout(void* arg);
11782beb602SGarrett D'Amore static void arcmsr_devMap_monitor(void* arg);
11882beb602SGarrett D'Amore static void arcmsr_pcidev_disattach(struct ACB *acb);
11982beb602SGarrett D'Amore static void arcmsr_iop_message_read(struct ACB *acb);
12082beb602SGarrett D'Amore static void arcmsr_free_ccb(struct CCB *ccb);
12182beb602SGarrett D'Amore static void arcmsr_post_ioctldata2iop(struct ACB *acb);
12282beb602SGarrett D'Amore static void arcmsr_report_sense_info(struct CCB *ccb);
12382beb602SGarrett D'Amore static void arcmsr_init_list_head(struct list_head *list);
12482beb602SGarrett D'Amore static void arcmsr_enable_allintr(struct ACB *acb, uint32_t intmask_org);
12582beb602SGarrett D'Amore static void arcmsr_done4abort_postqueue(struct ACB *acb);
12682beb602SGarrett D'Amore static void arcmsr_list_add_tail(kmutex_t *list_lock,
12782beb602SGarrett D'Amore     struct list_head *new_one, struct list_head *head);
12882beb602SGarrett D'Amore static int arcmsr_name_node(dev_info_t *dip, char *name, int len);
12982beb602SGarrett D'Amore static int arcmsr_seek_cmd2abort(struct ACB *acb, struct scsi_pkt *abortpkt);
13082beb602SGarrett D'Amore static int arcmsr_iop_message_xfer(struct ACB *acb, struct scsi_pkt *pkt);
13182beb602SGarrett D'Amore static int arcmsr_post_ccb(struct ACB *acb, struct CCB *ccb);
13282beb602SGarrett D'Amore static int arcmsr_parse_devname(char *devnm, int *tgt, int *lun);
13382beb602SGarrett D'Amore static int arcmsr_do_ddi_attach(dev_info_t *dev_info, int instance);
13482beb602SGarrett D'Amore static uint8_t arcmsr_iop_reset(struct ACB *acb);
13582beb602SGarrett D'Amore static uint32_t arcmsr_disable_allintr(struct ACB *acb);
13682beb602SGarrett D'Amore static uint32_t arcmsr_iop_confirm(struct ACB *acb);
137508aff1aSJames C. McPherson static struct CCB *arcmsr_get_freeccb(struct ACB *acb);
138508aff1aSJames C. McPherson static void arcmsr_flush_hba_cache(struct ACB *acb);
139508aff1aSJames C. McPherson static void arcmsr_flush_hbb_cache(struct ACB *acb);
14082beb602SGarrett D'Amore static void arcmsr_flush_hbc_cache(struct ACB *acb);
141508aff1aSJames C. McPherson static void arcmsr_stop_hba_bgrb(struct ACB *acb);
142508aff1aSJames C. McPherson static void arcmsr_stop_hbb_bgrb(struct ACB *acb);
14382beb602SGarrett D'Amore static void arcmsr_stop_hbc_bgrb(struct ACB *acb);
144508aff1aSJames C. McPherson static void arcmsr_start_hba_bgrb(struct ACB *acb);
14582beb602SGarrett D'Amore static void arcmsr_start_hbb_bgrb(struct ACB *acb);
14682beb602SGarrett D'Amore static void arcmsr_start_hbc_bgrb(struct ACB *acb);
14782beb602SGarrett D'Amore static void arcmsr_mutex_destroy(struct ACB *acb);
148508aff1aSJames C. McPherson static void arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb);
149508aff1aSJames C. McPherson static void arcmsr_polling_hbb_ccbdone(struct ACB *acb, struct CCB *poll_ccb);
15082beb602SGarrett D'Amore static void arcmsr_polling_hbc_ccbdone(struct ACB *acb, struct CCB *poll_ccb);
151508aff1aSJames C. McPherson static void arcmsr_build_ccb(struct CCB *ccb);
152ed632624SColin Yi static int arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags,
153ed632624SColin Yi     ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
154ed632624SColin Yi static int arcmsr_name_node(dev_info_t *dip, char *name, int len);
155ed632624SColin Yi static dev_info_t *arcmsr_find_child(struct ACB *acb, uint16_t tgt,
156ed632624SColin Yi     uint8_t lun);
15782beb602SGarrett D'Amore static struct QBUFFER *arcmsr_get_iop_rqbuffer(struct ACB *acb);
158508aff1aSJames C. McPherson 
15982beb602SGarrett D'Amore static int arcmsr_add_intr(struct ACB *, int);
160508aff1aSJames C. McPherson 
16182beb602SGarrett D'Amore static void *arcmsr_soft_state = NULL;
162ed632624SColin Yi 
163508aff1aSJames C. McPherson static ddi_dma_attr_t arcmsr_dma_attr = {
164508aff1aSJames C. McPherson 	DMA_ATTR_V0,		/* ddi_dma_attr version */
165508aff1aSJames C. McPherson 	0,			/* low DMA address range */
16682beb602SGarrett D'Amore 	0xffffffffffffffffull,	/* high DMA address range */
167508aff1aSJames C. McPherson 	0x00ffffff,		/* DMA counter counter upper bound */
168508aff1aSJames C. McPherson 	1,			/* DMA address alignment requirements */
169508aff1aSJames C. McPherson 	DEFAULT_BURSTSIZE | BURST32 | BURST64,	/* burst sizes */
170508aff1aSJames C. McPherson 	1,			/* minimum effective DMA size */
171508aff1aSJames C. McPherson 	ARCMSR_MAX_XFER_LEN,	/* maximum DMA xfer size */
172508aff1aSJames C. McPherson 	/*
173508aff1aSJames C. McPherson 	 * The dma_attr_seg field supplies the limit of each Scatter/Gather
174508aff1aSJames C. McPherson 	 * list element's "address+length". The Intel IOP331 can not use
175508aff1aSJames C. McPherson 	 * segments over the 4G boundary due to segment boundary restrictions
176508aff1aSJames C. McPherson 	 */
17782beb602SGarrett D'Amore 	0xffffffff,
178508aff1aSJames C. McPherson 	ARCMSR_MAX_SG_ENTRIES,	/* scatter/gather list count */
17982beb602SGarrett D'Amore 	1,			/* device granularity */
180508aff1aSJames C. McPherson 	DDI_DMA_FORCE_PHYSICAL	/* Bus specific DMA flags */
181508aff1aSJames C. McPherson };
182508aff1aSJames C. McPherson 
18382beb602SGarrett D'Amore 
184508aff1aSJames C. McPherson static ddi_dma_attr_t arcmsr_ccb_attr = {
185508aff1aSJames C. McPherson 	DMA_ATTR_V0,	/* ddi_dma_attr version */
186508aff1aSJames C. McPherson 	0,		/* low DMA address range */
187508aff1aSJames C. McPherson 	0xffffffff,	/* high DMA address range */
188508aff1aSJames C. McPherson 	0x00ffffff,	/* DMA counter counter upper bound */
189508aff1aSJames C. McPherson 	1,		/* default byte alignment */
190508aff1aSJames C. McPherson 	DEFAULT_BURSTSIZE | BURST32 | BURST64,   /* burst sizes */
191508aff1aSJames C. McPherson 	1,		/* minimum effective DMA size */
192508aff1aSJames C. McPherson 	0xffffffff,	/* maximum DMA xfer size */
193508aff1aSJames C. McPherson 	0x00ffffff,	/* max segment size, segment boundary restrictions */
194508aff1aSJames C. McPherson 	1,		/* scatter/gather list count */
195508aff1aSJames C. McPherson 	1,		/* device granularity */
196508aff1aSJames C. McPherson 	DDI_DMA_FORCE_PHYSICAL	/* Bus specific DMA flags */
197508aff1aSJames C. McPherson };
198508aff1aSJames C. McPherson 
19982beb602SGarrett D'Amore 
200508aff1aSJames C. McPherson static struct cb_ops arcmsr_cb_ops = {
201508aff1aSJames C. McPherson 	scsi_hba_open,		/* open(9E) */
202508aff1aSJames C. McPherson 	scsi_hba_close,		/* close(9E) */
203508aff1aSJames C. McPherson 	nodev,			/* strategy(9E), returns ENXIO */
204508aff1aSJames C. McPherson 	nodev,			/* print(9E) */
205508aff1aSJames C. McPherson 	nodev,			/* dump(9E) Cannot be used as a dump device */
206508aff1aSJames C. McPherson 	nodev,			/* read(9E) */
207508aff1aSJames C. McPherson 	nodev,			/* write(9E) */
208508aff1aSJames C. McPherson 	arcmsr_cb_ioctl,	/* ioctl(9E) */
209508aff1aSJames C. McPherson 	nodev,			/* devmap(9E) */
210508aff1aSJames C. McPherson 	nodev,			/* mmap(9E) */
211508aff1aSJames C. McPherson 	nodev,			/* segmap(9E) */
212508aff1aSJames C. McPherson 	NULL,			/* chpoll(9E) returns ENXIO */
213508aff1aSJames C. McPherson 	nodev,			/* prop_op(9E) */
214508aff1aSJames C. McPherson 	NULL,			/* streamtab(9S) */
21582beb602SGarrett D'Amore 	D_MP,
216508aff1aSJames C. McPherson 	CB_REV,
217508aff1aSJames C. McPherson 	nodev,			/* aread(9E) */
218508aff1aSJames C. McPherson 	nodev			/* awrite(9E) */
219508aff1aSJames C. McPherson };
220508aff1aSJames C. McPherson 
221508aff1aSJames C. McPherson static struct dev_ops arcmsr_ops = {
222508aff1aSJames C. McPherson 	DEVO_REV,		/* devo_rev */
223508aff1aSJames C. McPherson 	0,			/* reference count */
224508aff1aSJames C. McPherson 	nodev,			/* getinfo */
225508aff1aSJames C. McPherson 	nulldev,		/* identify */
226508aff1aSJames C. McPherson 	nulldev,		/* probe */
227508aff1aSJames C. McPherson 	arcmsr_attach,		/* attach */
228508aff1aSJames C. McPherson 	arcmsr_detach,		/* detach */
229508aff1aSJames C. McPherson 	arcmsr_reset,		/* reset, shutdown, reboot notify */
230508aff1aSJames C. McPherson 	&arcmsr_cb_ops,		/* driver operations */
231508aff1aSJames C. McPherson 	NULL,			/* bus operations */
23282beb602SGarrett D'Amore 	NULL			/* power */
233508aff1aSJames C. McPherson };
234508aff1aSJames C. McPherson 
235508aff1aSJames C. McPherson static struct modldrv arcmsr_modldrv = {
23682beb602SGarrett D'Amore 	&mod_driverops,			/* Type of module. This is a driver. */
23782beb602SGarrett D'Amore 	"ARECA RAID Controller",	/* module name, from arcmsr.h */
23882beb602SGarrett D'Amore 	&arcmsr_ops,			/* driver ops */
239508aff1aSJames C. McPherson };
240508aff1aSJames C. McPherson 
241508aff1aSJames C. McPherson static struct modlinkage arcmsr_modlinkage = {
242508aff1aSJames C. McPherson 	MODREV_1,
243508aff1aSJames C. McPherson 	&arcmsr_modldrv,
244508aff1aSJames C. McPherson 	NULL
245508aff1aSJames C. McPherson };
246508aff1aSJames C. McPherson 
247508aff1aSJames C. McPherson 
248508aff1aSJames C. McPherson int
_init(void)24982beb602SGarrett D'Amore _init(void)
25082beb602SGarrett D'Amore {
251508aff1aSJames C. McPherson 	int ret;
252508aff1aSJames C. McPherson 
25382beb602SGarrett D'Amore 	ret = ddi_soft_state_init(&arcmsr_soft_state, sizeof (struct ACB), 1);
254508aff1aSJames C. McPherson 	if (ret != 0) {
255508aff1aSJames C. McPherson 		return (ret);
256508aff1aSJames C. McPherson 	}
257508aff1aSJames C. McPherson 	if ((ret = scsi_hba_init(&arcmsr_modlinkage)) != 0) {
258508aff1aSJames C. McPherson 		ddi_soft_state_fini(&arcmsr_soft_state);
259508aff1aSJames C. McPherson 		return (ret);
260508aff1aSJames C. McPherson 	}
261508aff1aSJames C. McPherson 
262508aff1aSJames C. McPherson 	if ((ret = mod_install(&arcmsr_modlinkage)) != 0) {
263508aff1aSJames C. McPherson 		scsi_hba_fini(&arcmsr_modlinkage);
264508aff1aSJames C. McPherson 		if (arcmsr_soft_state != NULL) {
265508aff1aSJames C. McPherson 			ddi_soft_state_fini(&arcmsr_soft_state);
266508aff1aSJames C. McPherson 		}
267508aff1aSJames C. McPherson 	}
268508aff1aSJames C. McPherson 	return (ret);
269508aff1aSJames C. McPherson }
270508aff1aSJames C. McPherson 
271508aff1aSJames C. McPherson 
272508aff1aSJames C. McPherson int
_fini(void)27382beb602SGarrett D'Amore _fini(void)
27482beb602SGarrett D'Amore {
275508aff1aSJames C. McPherson 	int ret;
276508aff1aSJames C. McPherson 
277508aff1aSJames C. McPherson 	ret = mod_remove(&arcmsr_modlinkage);
278508aff1aSJames C. McPherson 	if (ret == 0) {
279508aff1aSJames C. McPherson 		/* if ret = 0 , said driver can remove */
280508aff1aSJames C. McPherson 		scsi_hba_fini(&arcmsr_modlinkage);
281508aff1aSJames C. McPherson 		if (arcmsr_soft_state != NULL) {
282508aff1aSJames C. McPherson 			ddi_soft_state_fini(&arcmsr_soft_state);
283508aff1aSJames C. McPherson 		}
284508aff1aSJames C. McPherson 	}
285508aff1aSJames C. McPherson 	return (ret);
286508aff1aSJames C. McPherson }
287508aff1aSJames C. McPherson 
288508aff1aSJames C. McPherson 
289508aff1aSJames C. McPherson int
_info(struct modinfo * modinfop)29082beb602SGarrett D'Amore _info(struct modinfo *modinfop)
29182beb602SGarrett D'Amore {
292508aff1aSJames C. McPherson 	return (mod_info(&arcmsr_modlinkage, modinfop));
293508aff1aSJames C. McPherson }
294508aff1aSJames C. McPherson 
295508aff1aSJames C. McPherson 
29682beb602SGarrett D'Amore /*
29782beb602SGarrett D'Amore  *      Function: arcmsr_attach(9E)
29882beb602SGarrett D'Amore  *   Description: Set up all device state and allocate data structures,
29982beb602SGarrett D'Amore  *		  mutexes, condition variables, etc. for device operation.
30082beb602SGarrett D'Amore  *		  Set mt_attr property for driver to indicate MT-safety.
30182beb602SGarrett D'Amore  *		  Add interrupts needed.
30282beb602SGarrett D'Amore  *         Input: dev_info_t *dev_info, ddi_attach_cmd_t cmd
30382beb602SGarrett D'Amore  *        Output: Return DDI_SUCCESS if device is ready,
30482beb602SGarrett D'Amore  *		          else return DDI_FAILURE
30582beb602SGarrett D'Amore  */
30682beb602SGarrett D'Amore static int
arcmsr_attach(dev_info_t * dev_info,ddi_attach_cmd_t cmd)30782beb602SGarrett D'Amore arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
30882beb602SGarrett D'Amore {
30982beb602SGarrett D'Amore 	scsi_hba_tran_t *hba_trans;
31082beb602SGarrett D'Amore 	struct ACB *acb;
311508aff1aSJames C. McPherson 
31282beb602SGarrett D'Amore 	switch (cmd) {
31382beb602SGarrett D'Amore 	case DDI_ATTACH:
31482beb602SGarrett D'Amore 		return (arcmsr_do_ddi_attach(dev_info,
31582beb602SGarrett D'Amore 		    ddi_get_instance(dev_info)));
31682beb602SGarrett D'Amore 	case DDI_RESUME:
31782beb602SGarrett D'Amore 		/*
31882beb602SGarrett D'Amore 		 * There is no hardware state to restart and no
31982beb602SGarrett D'Amore 		 * timeouts to restart since we didn't DDI_SUSPEND with
32082beb602SGarrett D'Amore 		 * active cmds or active timeouts We just need to
32182beb602SGarrett D'Amore 		 * unblock waiting threads and restart I/O the code
32282beb602SGarrett D'Amore 		 */
32382beb602SGarrett D'Amore 		hba_trans = ddi_get_driver_private(dev_info);
32482beb602SGarrett D'Amore 		if (hba_trans == NULL) {
32582beb602SGarrett D'Amore 			return (DDI_FAILURE);
326508aff1aSJames C. McPherson 		}
32782beb602SGarrett D'Amore 		acb = hba_trans->tran_hba_private;
32882beb602SGarrett D'Amore 		mutex_enter(&acb->acb_mutex);
32982beb602SGarrett D'Amore 		arcmsr_iop_init(acb);
33082beb602SGarrett D'Amore 
33182beb602SGarrett D'Amore 		/* restart ccbs "timeout" watchdog */
33282beb602SGarrett D'Amore 		acb->timeout_count = 0;
33382beb602SGarrett D'Amore 		acb->timeout_id = timeout(arcmsr_ccbs_timeout, (caddr_t)acb,
33482beb602SGarrett D'Amore 		    (ARCMSR_TIMEOUT_WATCH * drv_usectohz(1000000)));
33582beb602SGarrett D'Amore 		acb->timeout_sc_id = timeout(arcmsr_devMap_monitor,
33682beb602SGarrett D'Amore 		    (caddr_t)acb,
33782beb602SGarrett D'Amore 		    (ARCMSR_DEV_MAP_WATCH * drv_usectohz(1000000)));
33882beb602SGarrett D'Amore 		mutex_exit(&acb->acb_mutex);
33982beb602SGarrett D'Amore 		return (DDI_SUCCESS);
340ed632624SColin Yi 
34182beb602SGarrett D'Amore 	default:
34282beb602SGarrett D'Amore 		return (DDI_FAILURE);
343ed632624SColin Yi 	}
344ed632624SColin Yi }
345ed632624SColin Yi 
34682beb602SGarrett D'Amore /*
34782beb602SGarrett D'Amore  *    Function:	arcmsr_detach(9E)
34882beb602SGarrett D'Amore  * Description: Remove all device allocation and system resources, disable
34982beb602SGarrett D'Amore  *		        device interrupt.
35082beb602SGarrett D'Amore  *       Input: dev_info_t *dev_info
35182beb602SGarrett D'Amore  *		        ddi_detach_cmd_t cmd
35282beb602SGarrett D'Amore  *      Output:	Return DDI_SUCCESS if done,
35382beb602SGarrett D'Amore  *		        else returnDDI_FAILURE
35482beb602SGarrett D'Amore  */
35582beb602SGarrett D'Amore static int
arcmsr_detach(dev_info_t * dev_info,ddi_detach_cmd_t cmd)356d5ebc493SDan Cross arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
357d5ebc493SDan Cross {
35882beb602SGarrett D'Amore 	int instance;
35982beb602SGarrett D'Amore 	struct ACB *acb;
360508aff1aSJames C. McPherson 
36182beb602SGarrett D'Amore 	instance = ddi_get_instance(dev_info);
36282beb602SGarrett D'Amore 	acb = ddi_get_soft_state(arcmsr_soft_state, instance);
36382beb602SGarrett D'Amore 	if (acb == NULL)
36482beb602SGarrett D'Amore 		return (DDI_FAILURE);
365508aff1aSJames C. McPherson 
36682beb602SGarrett D'Amore 	switch (cmd) {
36782beb602SGarrett D'Amore 	case DDI_DETACH:
36882beb602SGarrett D'Amore 		mutex_enter(&acb->acb_mutex);
36982beb602SGarrett D'Amore 		if (acb->timeout_id != 0) {
37082beb602SGarrett D'Amore 			mutex_exit(&acb->acb_mutex);
37182beb602SGarrett D'Amore 			(void) untimeout(acb->timeout_id);
37282beb602SGarrett D'Amore 			mutex_enter(&acb->acb_mutex);
37382beb602SGarrett D'Amore 			acb->timeout_id = 0;
37482beb602SGarrett D'Amore 		}
37582beb602SGarrett D'Amore 		if (acb->timeout_sc_id != 0) {
37682beb602SGarrett D'Amore 			mutex_exit(&acb->acb_mutex);
37782beb602SGarrett D'Amore 			(void) untimeout(acb->timeout_sc_id);
37882beb602SGarrett D'Amore 			mutex_enter(&acb->acb_mutex);
37982beb602SGarrett D'Amore 			acb->timeout_sc_id = 0;
38082beb602SGarrett D'Amore 		}
38182beb602SGarrett D'Amore 		arcmsr_pcidev_disattach(acb);
38282beb602SGarrett D'Amore 		/* Remove interrupt set up by ddi_add_intr */
38382beb602SGarrett D'Amore 		arcmsr_remove_intr(acb);
38482beb602SGarrett D'Amore 		/* unbind mapping object to handle */
38582beb602SGarrett D'Amore 		(void) ddi_dma_unbind_handle(acb->ccbs_pool_handle);
38682beb602SGarrett D'Amore 		/* Free ccb pool memory */
38782beb602SGarrett D'Amore 		ddi_dma_mem_free(&acb->ccbs_acc_handle);
38882beb602SGarrett D'Amore 		/* Free DMA handle */
38982beb602SGarrett D'Amore 		ddi_dma_free_handle(&acb->ccbs_pool_handle);
39082beb602SGarrett D'Amore 		ddi_regs_map_free(&acb->reg_mu_acc_handle0);
39182beb602SGarrett D'Amore 		if (scsi_hba_detach(dev_info) != DDI_SUCCESS)
39282beb602SGarrett D'Amore 			arcmsr_warn(acb, "Unable to detach instance cleanly "
39382beb602SGarrett D'Amore 			    "(should not happen)");
39482beb602SGarrett D'Amore 		/* free scsi_hba_transport from scsi_hba_tran_alloc */
39582beb602SGarrett D'Amore 		scsi_hba_tran_free(acb->scsi_hba_transport);
39682beb602SGarrett D'Amore 		ddi_taskq_destroy(acb->taskq);
39782beb602SGarrett D'Amore 		ddi_prop_remove_all(dev_info);
39882beb602SGarrett D'Amore 		mutex_exit(&acb->acb_mutex);
39982beb602SGarrett D'Amore 		arcmsr_mutex_destroy(acb);
40082beb602SGarrett D'Amore 		pci_config_teardown(&acb->pci_acc_handle);
40182beb602SGarrett D'Amore 		ddi_set_driver_private(dev_info, NULL);
40282beb602SGarrett D'Amore 		ddi_soft_state_free(arcmsr_soft_state, instance);
40382beb602SGarrett D'Amore 		return (DDI_SUCCESS);
40482beb602SGarrett D'Amore 	case DDI_SUSPEND:
40582beb602SGarrett D'Amore 		mutex_enter(&acb->acb_mutex);
40682beb602SGarrett D'Amore 		if (acb->timeout_id != 0) {
40782beb602SGarrett D'Amore 			acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
40882beb602SGarrett D'Amore 			mutex_exit(&acb->acb_mutex);
40982beb602SGarrett D'Amore 			(void) untimeout(acb->timeout_id);
41082beb602SGarrett D'Amore 			(void) untimeout(acb->timeout_sc_id);
41182beb602SGarrett D'Amore 			mutex_enter(&acb->acb_mutex);
41282beb602SGarrett D'Amore 			acb->timeout_id = 0;
413508aff1aSJames C. McPherson 		}
414508aff1aSJames C. McPherson 
41582beb602SGarrett D'Amore 		if (acb->timeout_sc_id != 0) {
41682beb602SGarrett D'Amore 			acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
41782beb602SGarrett D'Amore 			mutex_exit(&acb->acb_mutex);
41882beb602SGarrett D'Amore 			(void) untimeout(acb->timeout_sc_id);
41982beb602SGarrett D'Amore 			mutex_enter(&acb->acb_mutex);
42082beb602SGarrett D'Amore 			acb->timeout_sc_id = 0;
42182beb602SGarrett D'Amore 		}
422508aff1aSJames C. McPherson 
42382beb602SGarrett D'Amore 		/* disable all outbound interrupt */
42482beb602SGarrett D'Amore 		(void) arcmsr_disable_allintr(acb);
42582beb602SGarrett D'Amore 		/* stop adapter background rebuild */
42682beb602SGarrett D'Amore 		switch (acb->adapter_type) {
42782beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_A:
42882beb602SGarrett D'Amore 			arcmsr_stop_hba_bgrb(acb);
42982beb602SGarrett D'Amore 			arcmsr_flush_hba_cache(acb);
43082beb602SGarrett D'Amore 			break;
43182beb602SGarrett D'Amore 
43282beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_B:
43382beb602SGarrett D'Amore 			arcmsr_stop_hbb_bgrb(acb);
43482beb602SGarrett D'Amore 			arcmsr_flush_hbb_cache(acb);
43582beb602SGarrett D'Amore 			break;
43682beb602SGarrett D'Amore 
43782beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_C:
43882beb602SGarrett D'Amore 			arcmsr_stop_hbc_bgrb(acb);
43982beb602SGarrett D'Amore 			arcmsr_flush_hbc_cache(acb);
44082beb602SGarrett D'Amore 			break;
441508aff1aSJames C. McPherson 		}
44282beb602SGarrett D'Amore 		mutex_exit(&acb->acb_mutex);
44382beb602SGarrett D'Amore 		return (DDI_SUCCESS);
44482beb602SGarrett D'Amore 	default:
44582beb602SGarrett D'Amore 		return (DDI_FAILURE);
446508aff1aSJames C. McPherson 	}
447508aff1aSJames C. McPherson }
448508aff1aSJames C. McPherson 
44982beb602SGarrett D'Amore static int
arcmsr_reset(dev_info_t * resetdev,ddi_reset_cmd_t cmd)45082beb602SGarrett D'Amore arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd)
45182beb602SGarrett D'Amore {
45282beb602SGarrett D'Amore 	struct ACB *acb;
45382beb602SGarrett D'Amore 	scsi_hba_tran_t *scsi_hba_transport;
45482beb602SGarrett D'Amore 	_NOTE(ARGUNUSED(cmd));
455508aff1aSJames C. McPherson 
45682beb602SGarrett D'Amore 	scsi_hba_transport = ddi_get_driver_private(resetdev);
45782beb602SGarrett D'Amore 	if (scsi_hba_transport == NULL)
45882beb602SGarrett D'Amore 		return (DDI_FAILURE);
459508aff1aSJames C. McPherson 
46082beb602SGarrett D'Amore 	acb = (struct ACB *)scsi_hba_transport->tran_hba_private;
46182beb602SGarrett D'Amore 	if (!acb)
46282beb602SGarrett D'Amore 		return (DDI_FAILURE);
463508aff1aSJames C. McPherson 
46482beb602SGarrett D'Amore 	arcmsr_pcidev_disattach(acb);
465508aff1aSJames C. McPherson 
46682beb602SGarrett D'Amore 	return (DDI_SUCCESS);
467508aff1aSJames C. McPherson }
468508aff1aSJames C. McPherson 
46982beb602SGarrett D'Amore static int
arcmsr_cb_ioctl(dev_t dev,int ioctl_cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)47082beb602SGarrett D'Amore arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg, int mode,
47182beb602SGarrett D'Amore     cred_t *credp, int *rvalp)
47282beb602SGarrett D'Amore {
47382beb602SGarrett D'Amore 	struct ACB *acb;
47482beb602SGarrett D'Amore 	struct CMD_MESSAGE_FIELD *pktioctlfld;
47582beb602SGarrett D'Amore 	int retvalue = 0;
47682beb602SGarrett D'Amore 	int instance = MINOR2INST(getminor(dev));
477508aff1aSJames C. McPherson 
47882beb602SGarrett D'Amore 	if (instance < 0)
47982beb602SGarrett D'Amore 		return (ENXIO);
480508aff1aSJames C. McPherson 
48182beb602SGarrett D'Amore 	if (secpolicy_sys_config(credp, B_FALSE) != 0)
48282beb602SGarrett D'Amore 		return (EPERM);
483508aff1aSJames C. McPherson 
48482beb602SGarrett D'Amore 	acb = ddi_get_soft_state(arcmsr_soft_state, instance);
48582beb602SGarrett D'Amore 	if (acb == NULL)
48682beb602SGarrett D'Amore 		return (ENXIO);
487508aff1aSJames C. McPherson 
48882beb602SGarrett D'Amore 	pktioctlfld = kmem_zalloc(sizeof (struct CMD_MESSAGE_FIELD), KM_SLEEP);
48982beb602SGarrett D'Amore 
49082beb602SGarrett D'Amore 	mutex_enter(&acb->ioctl_mutex);
49182beb602SGarrett D'Amore 	if (ddi_copyin((void *)arg, pktioctlfld,
49282beb602SGarrett D'Amore 	    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) {
49382beb602SGarrett D'Amore 		retvalue = ENXIO;
49482beb602SGarrett D'Amore 		goto ioctl_out;
49582beb602SGarrett D'Amore 	}
49682beb602SGarrett D'Amore 
49782beb602SGarrett D'Amore 	if (memcmp(pktioctlfld->cmdmessage.Signature, "ARCMSR", 6) != 0) {
49882beb602SGarrett D'Amore 		/* validity check */
49982beb602SGarrett D'Amore 		retvalue = ENXIO;
50082beb602SGarrett D'Amore 		goto ioctl_out;
50182beb602SGarrett D'Amore 	}
50282beb602SGarrett D'Amore 
50382beb602SGarrett D'Amore 	switch ((unsigned int)ioctl_cmd) {
50482beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_READ_RQBUFFER:
50582beb602SGarrett D'Amore 	{
50682beb602SGarrett D'Amore 		uint8_t *ver_addr;
50782beb602SGarrett D'Amore 		uint8_t *pQbuffer, *ptmpQbuffer;
50882beb602SGarrett D'Amore 		int32_t allxfer_len = 0;
50982beb602SGarrett D'Amore 
51082beb602SGarrett D'Amore 		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
51182beb602SGarrett D'Amore 		ptmpQbuffer = ver_addr;
51282beb602SGarrett D'Amore 		while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) &&
51382beb602SGarrett D'Amore 		    (allxfer_len < (MSGDATABUFLEN - 1))) {
51482beb602SGarrett D'Amore 			/* copy READ QBUFFER to srb */
51582beb602SGarrett D'Amore 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx];
51682beb602SGarrett D'Amore 			(void) memcpy(ptmpQbuffer, pQbuffer, 1);
51782beb602SGarrett D'Amore 			acb->rqbuf_firstidx++;
51882beb602SGarrett D'Amore 			/* if last index number set it to 0 */
51982beb602SGarrett D'Amore 			acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
52082beb602SGarrett D'Amore 			ptmpQbuffer++;
52182beb602SGarrett D'Amore 			allxfer_len++;
522508aff1aSJames C. McPherson 		}
523508aff1aSJames C. McPherson 
52482beb602SGarrett D'Amore 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
52582beb602SGarrett D'Amore 			struct QBUFFER *prbuffer;
52682beb602SGarrett D'Amore 			uint8_t *pQbuffer;
52782beb602SGarrett D'Amore 			uint8_t *iop_data;
52882beb602SGarrett D'Amore 			int32_t iop_len;
52982beb602SGarrett D'Amore 
53082beb602SGarrett D'Amore 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
53182beb602SGarrett D'Amore 			prbuffer = arcmsr_get_iop_rqbuffer(acb);
53282beb602SGarrett D'Amore 			iop_data = (uint8_t *)prbuffer->data;
53382beb602SGarrett D'Amore 			iop_len = (int32_t)prbuffer->data_len;
53482beb602SGarrett D'Amore 			/*
53582beb602SGarrett D'Amore 			 * this iop data does no chance to make me overflow
53682beb602SGarrett D'Amore 			 * again here, so just do it
53782beb602SGarrett D'Amore 			 */
53882beb602SGarrett D'Amore 			while (iop_len > 0) {
53982beb602SGarrett D'Amore 				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx];
54082beb602SGarrett D'Amore 				(void) memcpy(pQbuffer, iop_data, 1);
54182beb602SGarrett D'Amore 				acb->rqbuf_lastidx++;
54282beb602SGarrett D'Amore 				/* if last index number set it to 0 */
54382beb602SGarrett D'Amore 				acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
54482beb602SGarrett D'Amore 				iop_data++;
54582beb602SGarrett D'Amore 				iop_len--;
54682beb602SGarrett D'Amore 			}
54782beb602SGarrett D'Amore 			/* let IOP know data has been read */
54882beb602SGarrett D'Amore 			arcmsr_iop_message_read(acb);
549508aff1aSJames C. McPherson 		}
55082beb602SGarrett D'Amore 		(void) memcpy(pktioctlfld->messagedatabuffer,
55182beb602SGarrett D'Amore 		    ver_addr, allxfer_len);
55282beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.Length = allxfer_len;
55382beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.ReturnCode =
55482beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_RETURNCODE_OK;
55582beb602SGarrett D'Amore 
55682beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
55782beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
55882beb602SGarrett D'Amore 			retvalue = ENXIO;
55982beb602SGarrett D'Amore 
56082beb602SGarrett D'Amore 		kmem_free(ver_addr, MSGDATABUFLEN);
561508aff1aSJames C. McPherson 		break;
562508aff1aSJames C. McPherson 	}
563508aff1aSJames C. McPherson 
56482beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_WRITE_WQBUFFER:
56582beb602SGarrett D'Amore 	{
56682beb602SGarrett D'Amore 		uint8_t *ver_addr;
56782beb602SGarrett D'Amore 		int32_t my_empty_len, user_len;
56882beb602SGarrett D'Amore 		int32_t wqbuf_firstidx, wqbuf_lastidx;
56982beb602SGarrett D'Amore 		uint8_t *pQbuffer, *ptmpuserbuffer;
570508aff1aSJames C. McPherson 
57182beb602SGarrett D'Amore 		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
572508aff1aSJames C. McPherson 
57382beb602SGarrett D'Amore 		ptmpuserbuffer = ver_addr;
57482beb602SGarrett D'Amore 		user_len = min(pktioctlfld->cmdmessage.Length,
57582beb602SGarrett D'Amore 		    MSGDATABUFLEN);
57682beb602SGarrett D'Amore 		(void) memcpy(ptmpuserbuffer,
57782beb602SGarrett D'Amore 		    pktioctlfld->messagedatabuffer, user_len);
57882beb602SGarrett D'Amore 		/*
57982beb602SGarrett D'Amore 		 * check ifdata xfer length of this request will overflow
58082beb602SGarrett D'Amore 		 * my array qbuffer
58182beb602SGarrett D'Amore 		 */
58282beb602SGarrett D'Amore 		wqbuf_lastidx = acb->wqbuf_lastidx;
58382beb602SGarrett D'Amore 		wqbuf_firstidx = acb->wqbuf_firstidx;
58482beb602SGarrett D'Amore 		if (wqbuf_lastidx != wqbuf_firstidx) {
58582beb602SGarrett D'Amore 			arcmsr_post_ioctldata2iop(acb);
58682beb602SGarrett D'Amore 			pktioctlfld->cmdmessage.ReturnCode =
58782beb602SGarrett D'Amore 			    ARCMSR_MESSAGE_RETURNCODE_ERROR;
58882beb602SGarrett D'Amore 		} else {
58982beb602SGarrett D'Amore 			my_empty_len = (wqbuf_firstidx - wqbuf_lastidx - 1)
59082beb602SGarrett D'Amore 			    & (ARCMSR_MAX_QBUFFER - 1);
59182beb602SGarrett D'Amore 			if (my_empty_len >= user_len) {
59282beb602SGarrett D'Amore 				while (user_len > 0) {
59382beb602SGarrett D'Amore 					/* copy srb data to wqbuffer */
59482beb602SGarrett D'Amore 					pQbuffer =
59582beb602SGarrett D'Amore 					    &acb->wqbuffer[acb->wqbuf_lastidx];
59682beb602SGarrett D'Amore 					(void) memcpy(pQbuffer,
59782beb602SGarrett D'Amore 					    ptmpuserbuffer, 1);
59882beb602SGarrett D'Amore 					acb->wqbuf_lastidx++;
59982beb602SGarrett D'Amore 					/* iflast index number set it to 0 */
60082beb602SGarrett D'Amore 					acb->wqbuf_lastidx %=
60182beb602SGarrett D'Amore 					    ARCMSR_MAX_QBUFFER;
60282beb602SGarrett D'Amore 					ptmpuserbuffer++;
60382beb602SGarrett D'Amore 					user_len--;
60482beb602SGarrett D'Amore 				}
60582beb602SGarrett D'Amore 				/* post first Qbuffer */
60682beb602SGarrett D'Amore 				if (acb->acb_flags &
60782beb602SGarrett D'Amore 				    ACB_F_MESSAGE_WQBUFFER_CLEARED) {
60882beb602SGarrett D'Amore 					acb->acb_flags &=
60982beb602SGarrett D'Amore 					    ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
61082beb602SGarrett D'Amore 					arcmsr_post_ioctldata2iop(acb);
61182beb602SGarrett D'Amore 				}
61282beb602SGarrett D'Amore 				pktioctlfld->cmdmessage.ReturnCode =
61382beb602SGarrett D'Amore 				    ARCMSR_MESSAGE_RETURNCODE_OK;
614508aff1aSJames C. McPherson 			} else {
61582beb602SGarrett D'Amore 				pktioctlfld->cmdmessage.ReturnCode =
61682beb602SGarrett D'Amore 				    ARCMSR_MESSAGE_RETURNCODE_ERROR;
617508aff1aSJames C. McPherson 			}
618508aff1aSJames C. McPherson 		}
61982beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
62082beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
62182beb602SGarrett D'Amore 			retvalue = ENXIO;
62282beb602SGarrett D'Amore 
62382beb602SGarrett D'Amore 		kmem_free(ver_addr, MSGDATABUFLEN);
62482beb602SGarrett D'Amore 		break;
625508aff1aSJames C. McPherson 	}
626508aff1aSJames C. McPherson 
62782beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER:
62882beb602SGarrett D'Amore 	{
62982beb602SGarrett D'Amore 		uint8_t *pQbuffer = acb->rqbuffer;
630508aff1aSJames C. McPherson 
63182beb602SGarrett D'Amore 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
63282beb602SGarrett D'Amore 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
63382beb602SGarrett D'Amore 			arcmsr_iop_message_read(acb);
63482beb602SGarrett D'Amore 		}
63582beb602SGarrett D'Amore 		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
63682beb602SGarrett D'Amore 		acb->rqbuf_firstidx = 0;
63782beb602SGarrett D'Amore 		acb->rqbuf_lastidx = 0;
63882beb602SGarrett D'Amore 		bzero(pQbuffer, ARCMSR_MAX_QBUFFER);
63982beb602SGarrett D'Amore 		/* report success */
64082beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.ReturnCode =
64182beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_RETURNCODE_OK;
642508aff1aSJames C. McPherson 
64382beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
64482beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
64582beb602SGarrett D'Amore 			retvalue = ENXIO;
64682beb602SGarrett D'Amore 		break;
64782beb602SGarrett D'Amore 	}
648508aff1aSJames C. McPherson 
64982beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER:
65082beb602SGarrett D'Amore 	{
65182beb602SGarrett D'Amore 		uint8_t *pQbuffer = acb->wqbuffer;
652508aff1aSJames C. McPherson 
65382beb602SGarrett D'Amore 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
65482beb602SGarrett D'Amore 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
65582beb602SGarrett D'Amore 			arcmsr_iop_message_read(acb);
65682beb602SGarrett D'Amore 		}
65782beb602SGarrett D'Amore 		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
65882beb602SGarrett D'Amore 		    ACB_F_MESSAGE_WQBUFFER_READ);
65982beb602SGarrett D'Amore 		acb->wqbuf_firstidx = 0;
66082beb602SGarrett D'Amore 		acb->wqbuf_lastidx = 0;
66182beb602SGarrett D'Amore 		bzero(pQbuffer, ARCMSR_MAX_QBUFFER);
66282beb602SGarrett D'Amore 		/* report success */
66382beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.ReturnCode =
66482beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_RETURNCODE_OK;
665508aff1aSJames C. McPherson 
66682beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
66782beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
66882beb602SGarrett D'Amore 			retvalue = ENXIO;
66982beb602SGarrett D'Amore 		break;
67082beb602SGarrett D'Amore 	}
671508aff1aSJames C. McPherson 
67282beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER:
67382beb602SGarrett D'Amore 	{
67482beb602SGarrett D'Amore 		uint8_t *pQbuffer;
675508aff1aSJames C. McPherson 
67682beb602SGarrett D'Amore 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
67782beb602SGarrett D'Amore 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
67882beb602SGarrett D'Amore 			arcmsr_iop_message_read(acb);
67982beb602SGarrett D'Amore 		}
68082beb602SGarrett D'Amore 		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
68182beb602SGarrett D'Amore 		    ACB_F_MESSAGE_RQBUFFER_CLEARED |
68282beb602SGarrett D'Amore 		    ACB_F_MESSAGE_WQBUFFER_READ);
68382beb602SGarrett D'Amore 		acb->rqbuf_firstidx = 0;
68482beb602SGarrett D'Amore 		acb->rqbuf_lastidx = 0;
68582beb602SGarrett D'Amore 		acb->wqbuf_firstidx = 0;
68682beb602SGarrett D'Amore 		acb->wqbuf_lastidx = 0;
68782beb602SGarrett D'Amore 		pQbuffer = acb->rqbuffer;
68882beb602SGarrett D'Amore 		bzero(pQbuffer, sizeof (struct QBUFFER));
68982beb602SGarrett D'Amore 		pQbuffer = acb->wqbuffer;
69082beb602SGarrett D'Amore 		bzero(pQbuffer, sizeof (struct QBUFFER));
69182beb602SGarrett D'Amore 		/* report success */
69282beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.ReturnCode =
69382beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_RETURNCODE_OK;
69482beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
69582beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
69682beb602SGarrett D'Amore 			retvalue = ENXIO;
69782beb602SGarrett D'Amore 		break;
69882beb602SGarrett D'Amore 	}
699508aff1aSJames C. McPherson 
70082beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F:
70182beb602SGarrett D'Amore 		pktioctlfld->cmdmessage.ReturnCode =
70282beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_RETURNCODE_3F;
70382beb602SGarrett D'Amore 		if (ddi_copyout(pktioctlfld, (void *)arg,
70482beb602SGarrett D'Amore 		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
70582beb602SGarrett D'Amore 			retvalue = ENXIO;
70682beb602SGarrett D'Amore 		break;
707508aff1aSJames C. McPherson 
70882beb602SGarrett D'Amore 	/* Not supported: ARCMSR_MESSAGE_SAY_HELLO */
70982beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_SAY_GOODBYE:
71082beb602SGarrett D'Amore 		arcmsr_iop_parking(acb);
71182beb602SGarrett D'Amore 		break;
712508aff1aSJames C. McPherson 
71382beb602SGarrett D'Amore 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
71482beb602SGarrett D'Amore 		switch (acb->adapter_type) {
71582beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_A:
71682beb602SGarrett D'Amore 			arcmsr_flush_hba_cache(acb);
71782beb602SGarrett D'Amore 			break;
71882beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_B:
71982beb602SGarrett D'Amore 			arcmsr_flush_hbb_cache(acb);
72082beb602SGarrett D'Amore 			break;
72182beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_C:
72282beb602SGarrett D'Amore 			arcmsr_flush_hbc_cache(acb);
72382beb602SGarrett D'Amore 			break;
72482beb602SGarrett D'Amore 		}
72582beb602SGarrett D'Amore 		break;
726508aff1aSJames C. McPherson 
72782beb602SGarrett D'Amore 	default:
72882beb602SGarrett D'Amore 		mutex_exit(&acb->ioctl_mutex);
72982beb602SGarrett D'Amore 		kmem_free(pktioctlfld, sizeof (struct CMD_MESSAGE_FIELD));
73082beb602SGarrett D'Amore 		return (scsi_hba_ioctl(dev, ioctl_cmd, arg, mode, credp,
73182beb602SGarrett D'Amore 		    rvalp));
73282beb602SGarrett D'Amore 	}
733508aff1aSJames C. McPherson 
73482beb602SGarrett D'Amore ioctl_out:
73582beb602SGarrett D'Amore 	kmem_free(pktioctlfld, sizeof (struct CMD_MESSAGE_FIELD));
73682beb602SGarrett D'Amore 	mutex_exit(&acb->ioctl_mutex);
737508aff1aSJames C. McPherson 
73882beb602SGarrett D'Amore 	return (retvalue);
73982beb602SGarrett D'Amore }
740508aff1aSJames C. McPherson 
741508aff1aSJames C. McPherson 
74282beb602SGarrett D'Amore /*
74382beb602SGarrett D'Amore  *    Function:	arcmsr_tran_tgt_init
74482beb602SGarrett D'Amore  * Description: Called when initializing a target device instance. If
74582beb602SGarrett D'Amore  *		        no per-target initialization is required, the HBA
74682beb602SGarrett D'Amore  *		        may leave tran_tgt_init to NULL
74782beb602SGarrett D'Amore  *       Input:
74882beb602SGarrett D'Amore  *		        dev_info_t *host_dev_info,
74982beb602SGarrett D'Amore  *		        dev_info_t *target_dev_info,
75082beb602SGarrett D'Amore  *		        scsi_hba_tran_t *tran,
75182beb602SGarrett D'Amore  *		        struct scsi_device *sd
75282beb602SGarrett D'Amore  *
75382beb602SGarrett D'Amore  *      Return: DDI_SUCCESS if success, else return DDI_FAILURE
75482beb602SGarrett D'Amore  *
75582beb602SGarrett D'Amore  *  entry point enables the HBA to allocate and/or initialize any per-
75682beb602SGarrett D'Amore  *  target resources.
75782beb602SGarrett D'Amore  *  It also enables the HBA to qualify the device's address as valid and
75882beb602SGarrett D'Amore  *  supportable for that particular HBA.
75982beb602SGarrett D'Amore  *  By returning DDI_FAILURE, the instance of the target driver for that
76082beb602SGarrett D'Amore  *  device will not be probed or attached.
761d5ebc493SDan Cross  *	This entry point is not required, and if none is supplied,
76282beb602SGarrett D'Amore  *  the framework will attempt to probe and attach all possible instances
76382beb602SGarrett D'Amore  *  of the appropriate target drivers.
76482beb602SGarrett D'Amore  */
76582beb602SGarrett D'Amore static int
arcmsr_tran_tgt_init(dev_info_t * host_dev_info,dev_info_t * target_dev_info,scsi_hba_tran_t * tran,struct scsi_device * sd)76682beb602SGarrett D'Amore arcmsr_tran_tgt_init(dev_info_t *host_dev_info, dev_info_t *target_dev_info,
76782beb602SGarrett D'Amore     scsi_hba_tran_t *tran, struct scsi_device *sd)
76882beb602SGarrett D'Amore {
76982beb602SGarrett D'Amore 	uint16_t  target;
77082beb602SGarrett D'Amore 	uint8_t  lun;
77182beb602SGarrett D'Amore 	struct ACB *acb = tran->tran_hba_private;
772508aff1aSJames C. McPherson 
77382beb602SGarrett D'Amore 	_NOTE(ARGUNUSED(tran, target_dev_info, host_dev_info))
774508aff1aSJames C. McPherson 
77582beb602SGarrett D'Amore 	target = sd->sd_address.a_target;
77682beb602SGarrett D'Amore 	lun = sd->sd_address.a_lun;
77782beb602SGarrett D'Amore 	if ((target >= ARCMSR_MAX_TARGETID) || (lun >= ARCMSR_MAX_TARGETLUN)) {
77882beb602SGarrett D'Amore 		return (DDI_FAILURE);
779508aff1aSJames C. McPherson 	}
780508aff1aSJames C. McPherson 
78182beb602SGarrett D'Amore 
78282beb602SGarrett D'Amore 	if (ndi_dev_is_persistent_node(target_dev_info) == 0) {
78382beb602SGarrett D'Amore 		/*
78482beb602SGarrett D'Amore 		 * If no persistent node exist, we don't allow .conf node
78582beb602SGarrett D'Amore 		 * to be created.
78682beb602SGarrett D'Amore 		 */
78782beb602SGarrett D'Amore 		if (arcmsr_find_child(acb, target, lun) != NULL) {
78882beb602SGarrett D'Amore 			if ((ndi_merge_node(target_dev_info,
78982beb602SGarrett D'Amore 			    arcmsr_name_node) != DDI_SUCCESS)) {
79082beb602SGarrett D'Amore 				return (DDI_SUCCESS);
79182beb602SGarrett D'Amore 			}
79282beb602SGarrett D'Amore 		}
79382beb602SGarrett D'Amore 		return (DDI_FAILURE);
794508aff1aSJames C. McPherson 	}
795508aff1aSJames C. McPherson 
79682beb602SGarrett D'Amore 	return (DDI_SUCCESS);
79782beb602SGarrett D'Amore }
79882beb602SGarrett D'Amore 
79982beb602SGarrett D'Amore /*
80082beb602SGarrett D'Amore  *         Function: arcmsr_tran_getcap(9E)
80182beb602SGarrett D'Amore  *      Description: Get the capability named, and returnits value.
80282beb602SGarrett D'Amore  *    Return Values: current value of capability, ifdefined
80382beb602SGarrett D'Amore  *		             -1 ifcapability is not defined
80482beb602SGarrett D'Amore  * ------------------------------------------------------
80582beb602SGarrett D'Amore  *         Common Capability Strings Array
80682beb602SGarrett D'Amore  * ------------------------------------------------------
80782beb602SGarrett D'Amore  *	#define	SCSI_CAP_DMA_MAX		0
80882beb602SGarrett D'Amore  *	#define	SCSI_CAP_MSG_OUT		1
80982beb602SGarrett D'Amore  *	#define	SCSI_CAP_DISCONNECT		2
81082beb602SGarrett D'Amore  *	#define	SCSI_CAP_SYNCHRONOUS		3
81182beb602SGarrett D'Amore  *	#define	SCSI_CAP_WIDE_XFER		4
81282beb602SGarrett D'Amore  *	#define	SCSI_CAP_PARITY			5
81382beb602SGarrett D'Amore  *	#define	SCSI_CAP_INITIATOR_ID		6
81482beb602SGarrett D'Amore  *	#define	SCSI_CAP_UNTAGGED_QING		7
81582beb602SGarrett D'Amore  *	#define	SCSI_CAP_TAGGED_QING		8
81682beb602SGarrett D'Amore  *	#define	SCSI_CAP_ARQ			9
81782beb602SGarrett D'Amore  *	#define	SCSI_CAP_LINKED_CMDS		10 a
81882beb602SGarrett D'Amore  *	#define	SCSI_CAP_SECTOR_SIZE		11 b
81982beb602SGarrett D'Amore  *	#define	SCSI_CAP_TOTAL_SECTORS		12 c
82082beb602SGarrett D'Amore  *	#define	SCSI_CAP_GEOMETRY		13 d
82182beb602SGarrett D'Amore  *	#define	SCSI_CAP_RESET_NOTIFICATION	14 e
82282beb602SGarrett D'Amore  *	#define	SCSI_CAP_QFULL_RETRIES		15 f
82382beb602SGarrett D'Amore  *	#define	SCSI_CAP_QFULL_RETRY_INTERVAL	16 10
82482beb602SGarrett D'Amore  *	#define	SCSI_CAP_SCSI_VERSION		17 11
82582beb602SGarrett D'Amore  *	#define	SCSI_CAP_INTERCONNECT_TYPE	18 12
82682beb602SGarrett D'Amore  *	#define	SCSI_CAP_LUN_RESET		19 13
82782beb602SGarrett D'Amore  */
82882beb602SGarrett D'Amore static int
arcmsr_tran_getcap(struct scsi_address * ap,char * cap,int whom)82982beb602SGarrett D'Amore arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom)
83082beb602SGarrett D'Amore {
83182beb602SGarrett D'Amore 	int capability = 0;
83282beb602SGarrett D'Amore 	struct ACB *acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
83382beb602SGarrett D'Amore 
83482beb602SGarrett D'Amore 	if (cap == NULL || whom == 0) {
83582beb602SGarrett D'Amore 		return (DDI_FAILURE);
836508aff1aSJames C. McPherson 	}
837508aff1aSJames C. McPherson 
83882beb602SGarrett D'Amore 	mutex_enter(&acb->acb_mutex);
83982beb602SGarrett D'Amore 	if (acb->devstate[ap->a_target][ap->a_lun] == ARECA_RAID_GONE) {
84082beb602SGarrett D'Amore 		mutex_exit(&acb->acb_mutex);
84182beb602SGarrett D'Amore 		return (-1);
84282beb602SGarrett D'Amore 	}
84382beb602SGarrett D'Amore 	switch (scsi_hba_lookup_capstr(cap)) {
84482beb602SGarrett D'Amore 	case SCSI_CAP_MSG_OUT:
84582beb602SGarrett D'Amore 	case SCSI_CAP_DISCONNECT:
84682beb602SGarrett D'Amore 	case SCSI_CAP_WIDE_XFER:
84782beb602SGarrett D'Amore 	case SCSI_CAP_TAGGED_QING:
84882beb602SGarrett D'Amore 	case SCSI_CAP_UNTAGGED_QING:
84982beb602SGarrett D'Amore 	case SCSI_CAP_PARITY:
85082beb602SGarrett D'Amore 	case SCSI_CAP_ARQ:
85182beb602SGarrett D'Amore 		capability = 1;
852508aff1aSJames C. McPherson 		break;
85382beb602SGarrett D'Amore 	case SCSI_CAP_SECTOR_SIZE:
85482beb602SGarrett D'Amore 		capability = ARCMSR_DEV_SECTOR_SIZE;
85582beb602SGarrett D'Amore 		break;
85682beb602SGarrett D'Amore 	case SCSI_CAP_DMA_MAX:
85782beb602SGarrett D'Amore 		/* Limit to 16MB max transfer */
85882beb602SGarrett D'Amore 		capability = ARCMSR_MAX_XFER_LEN;
85982beb602SGarrett D'Amore 		break;
86082beb602SGarrett D'Amore 	case SCSI_CAP_INITIATOR_ID:
86182beb602SGarrett D'Amore 		capability = ARCMSR_SCSI_INITIATOR_ID;
86282beb602SGarrett D'Amore 		break;
86382beb602SGarrett D'Amore 	case SCSI_CAP_GEOMETRY:
86482beb602SGarrett D'Amore 		/* head , track , cylinder */
86582beb602SGarrett D'Amore 		capability = (255 << 16) | 63;
866508aff1aSJames C. McPherson 		break;
867508aff1aSJames C. McPherson 	default:
86882beb602SGarrett D'Amore 		capability = -1;
869508aff1aSJames C. McPherson 		break;
870508aff1aSJames C. McPherson 	}
87182beb602SGarrett D'Amore 	mutex_exit(&acb->acb_mutex);
87282beb602SGarrett D'Amore 	return (capability);
87382beb602SGarrett D'Amore }
874508aff1aSJames C. McPherson 
87582beb602SGarrett D'Amore /*
87682beb602SGarrett D'Amore  *      Function: arcmsr_tran_setcap(9E)
87782beb602SGarrett D'Amore  *   Description: Set the specific capability.
87882beb602SGarrett D'Amore  * Return Values: 1 - capability exists and can be set to new value
87982beb602SGarrett D'Amore  *		          0 - capability could not be set to new value
88082beb602SGarrett D'Amore  *		         -1 - no such capability
88182beb602SGarrett D'Amore  */
88282beb602SGarrett D'Amore static int
arcmsr_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)88382beb602SGarrett D'Amore arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
88482beb602SGarrett D'Amore {
88582beb602SGarrett D'Amore 	_NOTE(ARGUNUSED(value))
886508aff1aSJames C. McPherson 
88782beb602SGarrett D'Amore 	int supported = 0;
88882beb602SGarrett D'Amore 	struct ACB *acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
889508aff1aSJames C. McPherson 
89082beb602SGarrett D'Amore 	if (cap == NULL || whom == 0) {
89182beb602SGarrett D'Amore 		return (-1);
892508aff1aSJames C. McPherson 	}
893508aff1aSJames C. McPherson 
89482beb602SGarrett D'Amore 	mutex_enter(&acb->acb_mutex);
89582beb602SGarrett D'Amore 	if (acb->devstate[ap->a_target][ap->a_lun] == ARECA_RAID_GONE) {
89682beb602SGarrett D'Amore 		mutex_exit(&acb->acb_mutex);
89782beb602SGarrett D'Amore 		return (-1);
898508aff1aSJames C. McPherson 	}
89982beb602SGarrett D'Amore 	switch (supported = scsi_hba_lookup_capstr(cap)) {
90082beb602SGarrett D'Amore 	case SCSI_CAP_ARQ:			/* 9 auto request sense */
901d5ebc493SDan Cross 	case SCSI_CAP_UNTAGGED_QING:		/* 7 */
90282beb602SGarrett D'Amore 	case SCSI_CAP_TAGGED_QING:		/* 8 */
90382beb602SGarrett D'Amore 		/* these are always on, and cannot be turned off */
90482beb602SGarrett D'Amore 		supported = (value == 1) ? 1 : 0;
90582beb602SGarrett D'Amore 		break;
90682beb602SGarrett D'Amore 	case SCSI_CAP_TOTAL_SECTORS:		/* c */
90782beb602SGarrett D'Amore 		supported = 1;
90882beb602SGarrett D'Amore 		break;
90982beb602SGarrett D'Amore 	case SCSI_CAP_DISCONNECT:		/* 2 */
91082beb602SGarrett D'Amore 	case SCSI_CAP_WIDE_XFER:		/* 4 */
91182beb602SGarrett D'Amore 	case SCSI_CAP_INITIATOR_ID:		/* 6 */
91282beb602SGarrett D'Amore 	case SCSI_CAP_DMA_MAX:			/* 0 */
91382beb602SGarrett D'Amore 	case SCSI_CAP_MSG_OUT:			/* 1 */
91482beb602SGarrett D'Amore 	case SCSI_CAP_PARITY:			/* 5 */
91582beb602SGarrett D'Amore 	case SCSI_CAP_LINKED_CMDS:		/* a */
91682beb602SGarrett D'Amore 	case SCSI_CAP_RESET_NOTIFICATION:	/* e */
91782beb602SGarrett D'Amore 	case SCSI_CAP_SECTOR_SIZE:		/* b */
91882beb602SGarrett D'Amore 		/* these are not settable */
91982beb602SGarrett D'Amore 		supported = 0;
92082beb602SGarrett D'Amore 		break;
92182beb602SGarrett D'Amore 	default:
92282beb602SGarrett D'Amore 		supported = -1;
92382beb602SGarrett D'Amore 		break;
924508aff1aSJames C. McPherson 	}
92582beb602SGarrett D'Amore 	mutex_exit(&acb->acb_mutex);
92682beb602SGarrett D'Amore 	return (supported);
92782beb602SGarrett D'Amore }
928508aff1aSJames C. McPherson 
929508aff1aSJames C. McPherson 
93082beb602SGarrett D'Amore /*
93182beb602SGarrett D'Amore  *      Function: arcmsr_tran_init_pkt
93282beb602SGarrett D'Amore  * Return Values: pointer to scsi_pkt, or NULL
93382beb602SGarrett D'Amore  *   Description: simultaneously allocate both a scsi_pkt(9S) structure and
93482beb602SGarrett D'Amore  *                DMA resources for that pkt.
93582beb602SGarrett D'Amore  *                Called by kernel on behalf of a target driver
93682beb602SGarrett D'Amore  *		          calling scsi_init_pkt(9F).
93782beb602SGarrett D'Amore  *		          Refer to tran_init_pkt(9E) man page
93882beb602SGarrett D'Amore  *       Context: Can be called from different kernel process threads.
93982beb602SGarrett D'Amore  *		          Can be called by interrupt thread.
94082beb602SGarrett D'Amore  * Allocates SCSI packet and DMA resources
94182beb602SGarrett D'Amore  */
94282beb602SGarrett D'Amore static struct
arcmsr_tran_init_pkt(struct scsi_address * ap,register struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)94382beb602SGarrett D'Amore scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap,
94482beb602SGarrett D'Amore     register struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
94582beb602SGarrett D'Amore     int tgtlen, int flags, int (*callback)(), caddr_t arg)
94682beb602SGarrett D'Amore {
94782beb602SGarrett D'Amore 	struct CCB *ccb;
94882beb602SGarrett D'Amore 	struct ARCMSR_CDB *arcmsr_cdb;
94982beb602SGarrett D'Amore 	struct ACB *acb;
95082beb602SGarrett D'Amore 	int old_pkt_flag;
951508aff1aSJames C. McPherson 
95282beb602SGarrett D'Amore 	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
95382beb602SGarrett D'Amore 
95482beb602SGarrett D'Amore 	if (acb->acb_flags & ACB_F_BUS_RESET) {
95582beb602SGarrett D'Amore 		return (NULL);
956508aff1aSJames C. McPherson 	}
95782beb602SGarrett D'Amore 	if (pkt == NULL) {
95882beb602SGarrett D'Amore 		/* get free CCB */
95982beb602SGarrett D'Amore 		(void) ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
96082beb602SGarrett D'Amore 		    DDI_DMA_SYNC_FORKERNEL);
96182beb602SGarrett D'Amore 		ccb = arcmsr_get_freeccb(acb);
96282beb602SGarrett D'Amore 		if (ccb == (struct CCB *)NULL) {
96382beb602SGarrett D'Amore 			return (NULL);
96482beb602SGarrett D'Amore 		}
965508aff1aSJames C. McPherson 
96682beb602SGarrett D'Amore 		if (statuslen < sizeof (struct scsi_arq_status)) {
96782beb602SGarrett D'Amore 			statuslen = sizeof (struct scsi_arq_status);
96882beb602SGarrett D'Amore 		}
96982beb602SGarrett D'Amore 		pkt = scsi_hba_pkt_alloc(acb->dev_info, ap, cmdlen,
97082beb602SGarrett D'Amore 		    statuslen, tgtlen, sizeof (void *), callback, arg);
97182beb602SGarrett D'Amore 		if (pkt == NULL) {
97282beb602SGarrett D'Amore 			arcmsr_warn(acb, "scsi pkt allocation failed");
97382beb602SGarrett D'Amore 			arcmsr_free_ccb(ccb);
97482beb602SGarrett D'Amore 			return (NULL);
97582beb602SGarrett D'Amore 		}
97682beb602SGarrett D'Amore 		/* Initialize CCB */
97782beb602SGarrett D'Amore 		ccb->pkt = pkt;
97882beb602SGarrett D'Amore 		ccb->pkt_dma_handle = NULL;
97982beb602SGarrett D'Amore 		/* record how many sg are needed to xfer on this pkt */
98082beb602SGarrett D'Amore 		ccb->pkt_ncookies = 0;
98182beb602SGarrett D'Amore 		/* record how many sg we got from this window */
98282beb602SGarrett D'Amore 		ccb->pkt_cookie = 0;
98382beb602SGarrett D'Amore 		/* record how many windows have partial dma map set */
98482beb602SGarrett D'Amore 		ccb->pkt_nwin = 0;
98582beb602SGarrett D'Amore 		/* record current sg window position */
98682beb602SGarrett D'Amore 		ccb->pkt_curwin	= 0;
98782beb602SGarrett D'Amore 		ccb->pkt_dma_len = 0;
98882beb602SGarrett D'Amore 		ccb->pkt_dma_offset = 0;
98982beb602SGarrett D'Amore 		ccb->resid_dmacookie.dmac_size = 0;
990ed632624SColin Yi 
99182beb602SGarrett D'Amore 		/*
99282beb602SGarrett D'Amore 		 * we will still use this point for we want to fake some
99382beb602SGarrett D'Amore 		 * information in tran_start
99482beb602SGarrett D'Amore 		 */
99582beb602SGarrett D'Amore 		ccb->bp = bp;
996508aff1aSJames C. McPherson 
99782beb602SGarrett D'Amore 		/* Initialize arcmsr_cdb */
99882beb602SGarrett D'Amore 		arcmsr_cdb = &ccb->arcmsr_cdb;
99982beb602SGarrett D'Amore 		bzero(arcmsr_cdb, sizeof (struct ARCMSR_CDB));
100082beb602SGarrett D'Amore 		arcmsr_cdb->Bus = 0;
100182beb602SGarrett D'Amore 		arcmsr_cdb->Function = 1;
100282beb602SGarrett D'Amore 		arcmsr_cdb->LUN = ap->a_lun;
100382beb602SGarrett D'Amore 		arcmsr_cdb->TargetID = ap->a_target;
100482beb602SGarrett D'Amore 		arcmsr_cdb->CdbLength = (uint8_t)cmdlen;
100582beb602SGarrett D'Amore 		arcmsr_cdb->Context = (uintptr_t)arcmsr_cdb;
100682beb602SGarrett D'Amore 
100782beb602SGarrett D'Amore 		/* Fill in the rest of the structure */
100882beb602SGarrett D'Amore 		pkt->pkt_ha_private = ccb;
100982beb602SGarrett D'Amore 		pkt->pkt_address = *ap;
101082beb602SGarrett D'Amore 		pkt->pkt_comp = NULL;
101182beb602SGarrett D'Amore 		pkt->pkt_flags = 0;
101282beb602SGarrett D'Amore 		pkt->pkt_time = 0;
101382beb602SGarrett D'Amore 		pkt->pkt_resid = 0;
101482beb602SGarrett D'Amore 		pkt->pkt_statistics = 0;
101582beb602SGarrett D'Amore 		pkt->pkt_reason = 0;
101682beb602SGarrett D'Amore 		old_pkt_flag = 0;
1017508aff1aSJames C. McPherson 	} else {
101882beb602SGarrett D'Amore 		ccb = pkt->pkt_ha_private;
101982beb602SGarrett D'Amore 		if (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
102082beb602SGarrett D'Amore 			if (!(ccb->ccb_state & ARCMSR_CCB_BACK)) {
102182beb602SGarrett D'Amore 				return (NULL);
102282beb602SGarrett D'Amore 			}
102382beb602SGarrett D'Amore 		}
1024508aff1aSJames C. McPherson 
102582beb602SGarrett D'Amore 		/*
102682beb602SGarrett D'Amore 		 * you cannot update CdbLength with cmdlen here, it would
102782beb602SGarrett D'Amore 		 * cause a data compare error
102882beb602SGarrett D'Amore 		 */
102982beb602SGarrett D'Amore 		ccb->ccb_state = ARCMSR_CCB_UNBUILD;
103082beb602SGarrett D'Amore 		old_pkt_flag = 1;
1031508aff1aSJames C. McPherson 	}
1032508aff1aSJames C. McPherson 
103382beb602SGarrett D'Amore 	/* Second step : dma allocation/move */
103482beb602SGarrett D'Amore 	if (bp && bp->b_bcount != 0) {
103582beb602SGarrett D'Amore 		/*
103682beb602SGarrett D'Amore 		 * system had a lot of data trunk need to xfer, from...20 byte
103782beb602SGarrett D'Amore 		 * to 819200 byte.
103882beb602SGarrett D'Amore 		 * arcmsr_dma_alloc will get pkt_dma_handle (not null) until
103982beb602SGarrett D'Amore 		 * this lot of data trunk xfer done this mission will be done
104082beb602SGarrett D'Amore 		 * by some of continue READ or WRITE scsi command, till this
104182beb602SGarrett D'Amore 		 * lot of data trunk xfer completed.
104282beb602SGarrett D'Amore 		 * arcmsr_dma_move do the action repeatedly, and use the same
104382beb602SGarrett D'Amore 		 * ccb till this lot of data trunk xfer complete notice.
104482beb602SGarrett D'Amore 		 * when after the arcmsr_tran_init_pkt returns the solaris
104582beb602SGarrett D'Amore 		 * kernel is by your pkt_resid and its b_bcount to give you
104682beb602SGarrett D'Amore 		 * which type of scsi command descriptor to implement the
104782beb602SGarrett D'Amore 		 * length of folowing arcmsr_tran_start scsi cdb (data length)
104882beb602SGarrett D'Amore 		 *
104982beb602SGarrett D'Amore 		 * Each transfer should be aligned on a 512 byte boundary
105082beb602SGarrett D'Amore 		 */
105182beb602SGarrett D'Amore 		if (ccb->pkt_dma_handle == NULL) {
105282beb602SGarrett D'Amore 			if (arcmsr_dma_alloc(acb, pkt, bp, flags, callback) ==
105382beb602SGarrett D'Amore 			    DDI_FAILURE) {
105482beb602SGarrett D'Amore 				/*
105582beb602SGarrett D'Amore 				 * the HBA driver is unable to allocate DMA
105682beb602SGarrett D'Amore 				 * resources, it must free the allocated
105782beb602SGarrett D'Amore 				 * scsi_pkt(9S) before returning
105882beb602SGarrett D'Amore 				 */
105982beb602SGarrett D'Amore 				arcmsr_warn(acb, "dma allocation failure");
106082beb602SGarrett D'Amore 				if (old_pkt_flag == 0) {
106182beb602SGarrett D'Amore 					arcmsr_warn(acb, "dma "
106282beb602SGarrett D'Amore 					    "allocation failed to free "
106382beb602SGarrett D'Amore 					    "scsi hba pkt");
106482beb602SGarrett D'Amore 					arcmsr_free_ccb(ccb);
106582beb602SGarrett D'Amore 					scsi_hba_pkt_free(ap, pkt);
106682beb602SGarrett D'Amore 				}
106782beb602SGarrett D'Amore 				return (NULL);
106882beb602SGarrett D'Amore 			}
106982beb602SGarrett D'Amore 		} else {
107082beb602SGarrett D'Amore 			/* DMA resources to next DMA window, for old pkt */
107182beb602SGarrett D'Amore 			if (arcmsr_dma_move(acb, pkt, bp) == DDI_FAILURE) {
107282beb602SGarrett D'Amore 				arcmsr_warn(acb, "dma move failed");
107382beb602SGarrett D'Amore 				return (NULL);
107482beb602SGarrett D'Amore 			}
107582beb602SGarrett D'Amore 		}
107682beb602SGarrett D'Amore 	} else {
107782beb602SGarrett D'Amore 		pkt->pkt_resid = 0;
1078ed632624SColin Yi 	}
107982beb602SGarrett D'Amore 	return (pkt);
108082beb602SGarrett D'Amore }
1081ed632624SColin Yi 
108282beb602SGarrett D'Amore /*
108382beb602SGarrett D'Amore  *    Function: arcmsr_tran_start(9E)
108482beb602SGarrett D'Amore  * Description: Transport the command in pktp to the target device.
108582beb602SGarrett D'Amore  *		The command is not finished when this returns, only
108682beb602SGarrett D'Amore  *		sent to the target; arcmsr_intr_handler will call
108782beb602SGarrett D'Amore  *		scsi_hba_pkt_comp(pktp) when the target device has done.
108882beb602SGarrett D'Amore  *
108982beb602SGarrett D'Amore  *       Input: struct scsi_address *ap, struct scsi_pkt *pktp
109082beb602SGarrett D'Amore  *      Output:	TRAN_ACCEPT if pkt is OK and not driver not busy
109182beb602SGarrett D'Amore  *		TRAN_BUSY if driver is
109282beb602SGarrett D'Amore  *		TRAN_BADPKT if pkt is invalid
109382beb602SGarrett D'Amore  */
109482beb602SGarrett D'Amore static int
arcmsr_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)109582beb602SGarrett D'Amore arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
109682beb602SGarrett D'Amore {
109782beb602SGarrett D'Amore 	struct ACB *acb;
109882beb602SGarrett D'Amore 	struct CCB *ccb;
109982beb602SGarrett D'Amore 	int target = ap->a_target;
110082beb602SGarrett D'Amore 	int lun = ap->a_lun;
1101ed632624SColin Yi 
110282beb602SGarrett D'Amore 	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
110382beb602SGarrett D'Amore 	ccb = pkt->pkt_ha_private;
110482beb602SGarrett D'Amore 	*pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
1105508aff1aSJames C. McPherson 
110682beb602SGarrett D'Amore 	if ((ccb->ccb_flags & CCB_FLAG_DMAVALID) &&
110782beb602SGarrett D'Amore 	    (ccb->ccb_flags & DDI_DMA_CONSISTENT))
110882beb602SGarrett D'Amore 		(void) ddi_dma_sync(ccb->pkt_dma_handle, 0, 0,
110982beb602SGarrett D'Amore 		    DDI_DMA_SYNC_FORDEV);
1110508aff1aSJames C. McPherson 
111182beb602SGarrett D'Amore 	if (ccb->ccb_state == ARCMSR_CCB_UNBUILD)
111282beb602SGarrett D'Amore 		arcmsr_build_ccb(ccb);
1113508aff1aSJames C. McPherson 
111482beb602SGarrett D'Amore 	if (acb->acb_flags & ACB_F_BUS_RESET) {
111582beb602SGarrett D'Amore 		pkt->pkt_reason = CMD_RESET;
111682beb602SGarrett D'Amore 		pkt->pkt_statistics |= STAT_BUS_RESET;
111782beb602SGarrett D'Amore 		pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
111882beb602SGarrett D'Amore 		    STATE_SENT_CMD | STATE_GOT_STATUS);
111982beb602SGarrett D'Amore 		if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
112082beb602SGarrett D'Amore 		    (pkt->pkt_state & STATE_XFERRED_DATA))
112182beb602SGarrett D'Amore 			(void) ddi_dma_sync(ccb->pkt_dma_handle,
112282beb602SGarrett D'Amore 			    0, 0, DDI_DMA_SYNC_FORCPU);
1123508aff1aSJames C. McPherson 
112482beb602SGarrett D'Amore 		scsi_hba_pkt_comp(pkt);
112582beb602SGarrett D'Amore 		return (TRAN_ACCEPT);
112682beb602SGarrett D'Amore 	}
1127508aff1aSJames C. McPherson 
112882beb602SGarrett D'Amore 	/* IMPORTANT: Target 16 is a virtual device for iop message transfer */
112982beb602SGarrett D'Amore 	if (target == 16) {
1130508aff1aSJames C. McPherson 
113182beb602SGarrett D'Amore 		struct buf *bp = ccb->bp;
113282beb602SGarrett D'Amore 		uint8_t scsicmd = pkt->pkt_cdbp[0];
1133508aff1aSJames C. McPherson 
113482beb602SGarrett D'Amore 		switch (scsicmd) {
113582beb602SGarrett D'Amore 		case SCMD_INQUIRY: {
113682beb602SGarrett D'Amore 			if (lun != 0) {
113782beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_TIMEOUT;
113882beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_TIMEOUT;
113982beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 0);
114082beb602SGarrett D'Amore 				return (TRAN_ACCEPT);
114182beb602SGarrett D'Amore 			}
1142508aff1aSJames C. McPherson 
114382beb602SGarrett D'Amore 			if (bp && bp->b_un.b_addr && bp->b_bcount) {
114482beb602SGarrett D'Amore 				uint8_t inqdata[36];
1145508aff1aSJames C. McPherson 
114682beb602SGarrett D'Amore 				/* The EVDP and pagecode is not supported */
114782beb602SGarrett D'Amore 				if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[2]) {
114882beb602SGarrett D'Amore 					inqdata[1] = 0xFF;
114982beb602SGarrett D'Amore 					inqdata[2] = 0x00;
115082beb602SGarrett D'Amore 				} else {
115182beb602SGarrett D'Amore 					/* Periph Qualifier & Periph Dev Type */
115282beb602SGarrett D'Amore 					inqdata[0] = DTYPE_PROCESSOR;
115382beb602SGarrett D'Amore 					/* rem media bit & Dev Type Modifier */
115482beb602SGarrett D'Amore 					inqdata[1] = 0;
115582beb602SGarrett D'Amore 					/* ISO, ECMA, & ANSI versions */
115682beb602SGarrett D'Amore 					inqdata[2] = 0;
115782beb602SGarrett D'Amore 					inqdata[3] = 0;
115882beb602SGarrett D'Amore 					/* length of additional data */
115982beb602SGarrett D'Amore 					inqdata[4] = 31;
116082beb602SGarrett D'Amore 					/* Vendor Identification */
116182beb602SGarrett D'Amore 					bcopy("Areca   ", &inqdata[8], VIDLEN);
116282beb602SGarrett D'Amore 					/* Product Identification */
116382beb602SGarrett D'Amore 					bcopy("RAID controller ", &inqdata[16],
116482beb602SGarrett D'Amore 					    PIDLEN);
116582beb602SGarrett D'Amore 					/* Product Revision */
116682beb602SGarrett D'Amore 					bcopy(&inqdata[32], "R001", REVLEN);
116782beb602SGarrett D'Amore 					if (bp->b_flags & (B_PHYS | B_PAGEIO))
116882beb602SGarrett D'Amore 						bp_mapin(bp);
1169508aff1aSJames C. McPherson 
117082beb602SGarrett D'Amore 					(void) memcpy(bp->b_un.b_addr,
117182beb602SGarrett D'Amore 					    inqdata, sizeof (inqdata));
117282beb602SGarrett D'Amore 				}
117382beb602SGarrett D'Amore 				ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
117482beb602SGarrett D'Amore 			}
117582beb602SGarrett D'Amore 			arcmsr_ccb_complete(ccb, 0);
117682beb602SGarrett D'Amore 			return (TRAN_ACCEPT);
117782beb602SGarrett D'Amore 		}
117882beb602SGarrett D'Amore 		case SCMD_WRITE_BUFFER:
117982beb602SGarrett D'Amore 		case SCMD_READ_BUFFER: {
118082beb602SGarrett D'Amore 			if (arcmsr_iop_message_xfer(acb, pkt)) {
118182beb602SGarrett D'Amore 				/* error just for retry */
118282beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_TRAN_ERR;
118382beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_TERMINATED;
118482beb602SGarrett D'Amore 			}
118582beb602SGarrett D'Amore 			ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
118682beb602SGarrett D'Amore 			arcmsr_ccb_complete(ccb, 0);
118782beb602SGarrett D'Amore 			return (TRAN_ACCEPT);
118882beb602SGarrett D'Amore 		}
118982beb602SGarrett D'Amore 		default:
119082beb602SGarrett D'Amore 			ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
119182beb602SGarrett D'Amore 			arcmsr_ccb_complete(ccb, 0);
119282beb602SGarrett D'Amore 			return (TRAN_ACCEPT);
119382beb602SGarrett D'Amore 		}
119482beb602SGarrett D'Amore 	}
1195508aff1aSJames C. McPherson 
119682beb602SGarrett D'Amore 	if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
119782beb602SGarrett D'Amore 		uint8_t block_cmd;
1198508aff1aSJames C. McPherson 
119982beb602SGarrett D'Amore 		block_cmd = pkt->pkt_cdbp[0] & 0x0f;
120082beb602SGarrett D'Amore 		if (block_cmd == 0x08 || block_cmd == 0x0a) {
120182beb602SGarrett D'Amore 			pkt->pkt_reason = CMD_TIMEOUT;
120282beb602SGarrett D'Amore 			pkt->pkt_statistics |= STAT_TIMEOUT;
120382beb602SGarrett D'Amore 			pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
120482beb602SGarrett D'Amore 			    STATE_SENT_CMD | STATE_GOT_STATUS);
120582beb602SGarrett D'Amore 			if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
120682beb602SGarrett D'Amore 			    (pkt->pkt_state & STATE_XFERRED_DATA)) {
120782beb602SGarrett D'Amore 				(void) ddi_dma_sync(ccb->pkt_dma_handle,
120882beb602SGarrett D'Amore 				    ccb->pkt_dma_offset,
120982beb602SGarrett D'Amore 				    ccb->pkt_dma_len, DDI_DMA_SYNC_FORCPU);
121082beb602SGarrett D'Amore 			}
121182beb602SGarrett D'Amore 			scsi_hba_pkt_comp(pkt);
121282beb602SGarrett D'Amore 			return (TRAN_ACCEPT);
121382beb602SGarrett D'Amore 		}
121482beb602SGarrett D'Amore 	}
121582beb602SGarrett D'Amore 	mutex_enter(&acb->postq_mutex);
121682beb602SGarrett D'Amore 	if (acb->ccboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) {
121782beb602SGarrett D'Amore 		ccb->ccb_state = ARCMSR_CCB_RETRY;
121882beb602SGarrett D'Amore 		mutex_exit(&acb->postq_mutex);
121982beb602SGarrett D'Amore 		return (TRAN_BUSY);
122082beb602SGarrett D'Amore 	} else if (arcmsr_post_ccb(acb, ccb) == DDI_FAILURE) {
122182beb602SGarrett D'Amore 		arcmsr_warn(acb, "post ccb failure, ccboutstandingcount = %d",
122282beb602SGarrett D'Amore 		    acb->ccboutstandingcount);
122382beb602SGarrett D'Amore 		mutex_exit(&acb->postq_mutex);
122482beb602SGarrett D'Amore 		return (TRAN_FATAL_ERROR);
122582beb602SGarrett D'Amore 	}
122682beb602SGarrett D'Amore 	mutex_exit(&acb->postq_mutex);
122782beb602SGarrett D'Amore 	return (TRAN_ACCEPT);
122882beb602SGarrett D'Amore }
1229508aff1aSJames C. McPherson 
1230508aff1aSJames C. McPherson /*
123182beb602SGarrett D'Amore  * Function name: arcmsr_tran_destroy_pkt
123282beb602SGarrett D'Amore  * Return Values: none
123382beb602SGarrett D'Amore  *   Description: Called by kernel on behalf of a target driver
123482beb602SGarrett D'Amore  *	          calling scsi_destroy_pkt(9F).
123582beb602SGarrett D'Amore  *	          Refer to tran_destroy_pkt(9E) man page
123682beb602SGarrett D'Amore  *       Context: Can be called from different kernel process threads.
123782beb602SGarrett D'Amore  *	          Can be called by interrupt thread.
1238508aff1aSJames C. McPherson  */
123982beb602SGarrett D'Amore static void
arcmsr_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)124082beb602SGarrett D'Amore arcmsr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
124182beb602SGarrett D'Amore {
124282beb602SGarrett D'Amore 	struct CCB *ccb = pkt->pkt_ha_private;
124382beb602SGarrett D'Amore 	ddi_dma_handle_t pkt_dma_handle = ccb->pkt_dma_handle;
1244508aff1aSJames C. McPherson 
124582beb602SGarrett D'Amore 	if (ccb == NULL) {
124682beb602SGarrett D'Amore 		return;
124782beb602SGarrett D'Amore 	}
124882beb602SGarrett D'Amore 	if (ccb->pkt != pkt) {
124982beb602SGarrett D'Amore 		return;
125082beb602SGarrett D'Amore 	}
125182beb602SGarrett D'Amore 	if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
125282beb602SGarrett D'Amore 		ccb->ccb_flags &= ~CCB_FLAG_DMAVALID;
125382beb602SGarrett D'Amore 		if (pkt_dma_handle) {
125482beb602SGarrett D'Amore 			(void) ddi_dma_unbind_handle(ccb->pkt_dma_handle);
125582beb602SGarrett D'Amore 		}
125682beb602SGarrett D'Amore 	}
125782beb602SGarrett D'Amore 	if (pkt_dma_handle) {
125882beb602SGarrett D'Amore 		(void) ddi_dma_free_handle(&pkt_dma_handle);
125982beb602SGarrett D'Amore 	}
126082beb602SGarrett D'Amore 	pkt->pkt_ha_private = NULL;
126182beb602SGarrett D'Amore 	if (ccb)	{
126282beb602SGarrett D'Amore 		if (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
126382beb602SGarrett D'Amore 			if (ccb->ccb_state & ARCMSR_CCB_BACK) {
126482beb602SGarrett D'Amore 				arcmsr_free_ccb(ccb);
126582beb602SGarrett D'Amore 			} else {
126682beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_WAIT4_FREE;
126782beb602SGarrett D'Amore 			}
126882beb602SGarrett D'Amore 		} else {
126982beb602SGarrett D'Amore 			arcmsr_free_ccb(ccb);
127082beb602SGarrett D'Amore 		}
1271508aff1aSJames C. McPherson 	}
127282beb602SGarrett D'Amore 	scsi_hba_pkt_free(ap, pkt);
1273508aff1aSJames C. McPherson }
1274508aff1aSJames C. McPherson 
1275508aff1aSJames C. McPherson /*
127682beb602SGarrett D'Amore  * Function name: arcmsr_tran_dmafree()
127782beb602SGarrett D'Amore  * Return Values: none
127882beb602SGarrett D'Amore  *   Description: free dvma resources
127982beb602SGarrett D'Amore  *       Context: Can be called from different kernel process threads.
128082beb602SGarrett D'Amore  *	          Can be called by interrupt thread.
1281508aff1aSJames C. McPherson  */
128282beb602SGarrett D'Amore static void
arcmsr_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)128382beb602SGarrett D'Amore arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
128482beb602SGarrett D'Amore {
128582beb602SGarrett D'Amore 	struct CCB *ccb = pkt->pkt_ha_private;
1286508aff1aSJames C. McPherson 
128782beb602SGarrett D'Amore 	if ((ccb == NULL) || (ccb->pkt != pkt)) {
128882beb602SGarrett D'Amore 		return;
1289508aff1aSJames C. McPherson 	}
129082beb602SGarrett D'Amore 	if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
129182beb602SGarrett D'Amore 		ccb->ccb_flags &= ~CCB_FLAG_DMAVALID;
129282beb602SGarrett D'Amore 		if (ddi_dma_unbind_handle(ccb->pkt_dma_handle) != DDI_SUCCESS) {
129382beb602SGarrett D'Amore 			arcmsr_warn(ccb->acb, "ddi_dma_unbind_handle() failed "
129482beb602SGarrett D'Amore 			    "(target %d lun %d)", ap->a_target, ap->a_lun);
1295508aff1aSJames C. McPherson 		}
129682beb602SGarrett D'Amore 		ddi_dma_free_handle(&ccb->pkt_dma_handle);
129782beb602SGarrett D'Amore 		ccb->pkt_dma_handle = NULL;
129882beb602SGarrett D'Amore 	}
129982beb602SGarrett D'Amore }
1300ed632624SColin Yi 
130182beb602SGarrett D'Amore /*
130282beb602SGarrett D'Amore  * Function name: arcmsr_tran_sync_pkt()
130382beb602SGarrett D'Amore  * Return Values: none
130482beb602SGarrett D'Amore  *   Description: sync dma
130582beb602SGarrett D'Amore  *       Context: Can be called from different kernel process threads.
130682beb602SGarrett D'Amore  *		  Can be called by interrupt thread.
130782beb602SGarrett D'Amore  */
130882beb602SGarrett D'Amore static void
arcmsr_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)130982beb602SGarrett D'Amore arcmsr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
131082beb602SGarrett D'Amore {
131182beb602SGarrett D'Amore 	struct CCB *ccb;
1312ed632624SColin Yi 
131382beb602SGarrett D'Amore 	ccb = pkt->pkt_ha_private;
131482beb602SGarrett D'Amore 	if ((ccb == NULL) || (ccb->pkt != pkt)) {
131582beb602SGarrett D'Amore 		return;
131682beb602SGarrett D'Amore 	}
131782beb602SGarrett D'Amore 	if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
131882beb602SGarrett D'Amore 		if (ddi_dma_sync(ccb->pkt_dma_handle, 0, 0,
131982beb602SGarrett D'Amore 		    (ccb->ccb_flags & CCB_FLAG_DMAWRITE) ?
132082beb602SGarrett D'Amore 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU) !=
132182beb602SGarrett D'Amore 		    DDI_SUCCESS) {
132282beb602SGarrett D'Amore 			arcmsr_warn(ccb->acb,
132382beb602SGarrett D'Amore 			    "sync pkt failed for target %d lun %d",
132482beb602SGarrett D'Amore 			    ap->a_target, ap->a_lun);
1325508aff1aSJames C. McPherson 		}
1326508aff1aSJames C. McPherson 	}
1327508aff1aSJames C. McPherson }
1328508aff1aSJames C. McPherson 
1329508aff1aSJames C. McPherson 
1330508aff1aSJames C. McPherson /*
133182beb602SGarrett D'Amore  * Function: arcmsr_tran_abort(9E)
1332d5ebc493SDan Cross  *		SCSA interface routine to abort pkt(s) in progress.
1333d5ebc493SDan Cross  *		Aborts the pkt specified.  If NULL pkt, aborts ALL pkts.
133482beb602SGarrett D'Amore  * Output:	Return 1 if success
133582beb602SGarrett D'Amore  *		Return 0 if failure
1336508aff1aSJames C. McPherson  */
1337508aff1aSJames C. McPherson static int
arcmsr_tran_abort(struct scsi_address * ap,struct scsi_pkt * abortpkt)133882beb602SGarrett D'Amore arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *abortpkt)
133982beb602SGarrett D'Amore {
134082beb602SGarrett D'Amore 	struct ACB *acb;
134182beb602SGarrett D'Amore 	int return_code;
1342508aff1aSJames C. McPherson 
134382beb602SGarrett D'Amore 	acb = ap->a_hba_tran->tran_hba_private;
134482beb602SGarrett D'Amore 
134582beb602SGarrett D'Amore 	while (acb->ccboutstandingcount != 0) {
134682beb602SGarrett D'Amore 		drv_usecwait(10000);
1347508aff1aSJames C. McPherson 	}
1348ed632624SColin Yi 
134982beb602SGarrett D'Amore 	mutex_enter(&acb->isr_mutex);
135082beb602SGarrett D'Amore 	return_code = arcmsr_seek_cmd2abort(acb, abortpkt);
135182beb602SGarrett D'Amore 	mutex_exit(&acb->isr_mutex);
1352ed632624SColin Yi 
135382beb602SGarrett D'Amore 	if (return_code != DDI_SUCCESS) {
135482beb602SGarrett D'Amore 		arcmsr_warn(acb, "abort command failed for target %d lun %d",
135582beb602SGarrett D'Amore 		    ap->a_target, ap->a_lun);
135682beb602SGarrett D'Amore 		return (0);
1357ed632624SColin Yi 	}
135882beb602SGarrett D'Amore 	return (1);
1359508aff1aSJames C. McPherson }
1360508aff1aSJames C. McPherson 
1361508aff1aSJames C. McPherson /*
136282beb602SGarrett D'Amore  * Function: arcmsr_tran_reset(9E)
136382beb602SGarrett D'Amore  *           SCSA interface routine to perform scsi resets on either
136482beb602SGarrett D'Amore  *           a specified target or the bus (default).
136582beb602SGarrett D'Amore  *   Output: Return 1 if success
136682beb602SGarrett D'Amore  *	     Return 0 if failure
1367508aff1aSJames C. McPherson  */
1368508aff1aSJames C. McPherson static int
arcmsr_tran_reset(struct scsi_address * ap,int level)1369d5ebc493SDan Cross arcmsr_tran_reset(struct scsi_address *ap, int level)
1370d5ebc493SDan Cross {
137182beb602SGarrett D'Amore 	struct ACB *acb;
137282beb602SGarrett D'Amore 	int return_code = 1;
137382beb602SGarrett D'Amore 	int target = ap->a_target;
137482beb602SGarrett D'Amore 	int lun = ap->a_lun;
1375508aff1aSJames C. McPherson 
137682beb602SGarrett D'Amore 	/* Are we in the middle of dumping core? */
137782beb602SGarrett D'Amore 	if (ddi_in_panic())
137882beb602SGarrett D'Amore 		return (return_code);
1379508aff1aSJames C. McPherson 
138082beb602SGarrett D'Amore 	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
138182beb602SGarrett D'Amore 	mutex_enter(&acb->isr_mutex);
138282beb602SGarrett D'Amore 	switch (level) {
138382beb602SGarrett D'Amore 	case RESET_ALL:		/* 0 */
138482beb602SGarrett D'Amore 		acb->num_resets++;
138582beb602SGarrett D'Amore 		acb->acb_flags |= ACB_F_BUS_RESET;
138682beb602SGarrett D'Amore 		if (acb->timeout_count) {
138782beb602SGarrett D'Amore 			if (arcmsr_iop_reset(acb) != 0) {
138882beb602SGarrett D'Amore 				arcmsr_handle_iop_bus_hold(acb);
138982beb602SGarrett D'Amore 				acb->acb_flags &= ~ACB_F_BUS_HANG_ON;
139082beb602SGarrett D'Amore 			}
139182beb602SGarrett D'Amore 		}
139282beb602SGarrett D'Amore 		acb->acb_flags &= ~ACB_F_BUS_RESET;
139382beb602SGarrett D'Amore 		break;
139482beb602SGarrett D'Amore 	case RESET_TARGET:	/* 1 */
139582beb602SGarrett D'Amore 		if (acb->devstate[target][lun] == ARECA_RAID_GONE)
139682beb602SGarrett D'Amore 			return_code = 0;
139782beb602SGarrett D'Amore 		break;
139882beb602SGarrett D'Amore 	case RESET_BUS:		/* 2 */
139982beb602SGarrett D'Amore 		return_code = 0;
140082beb602SGarrett D'Amore 		break;
140182beb602SGarrett D'Amore 	case RESET_LUN:		/* 3 */
140282beb602SGarrett D'Amore 		return_code = 0;
140382beb602SGarrett D'Amore 		break;
140482beb602SGarrett D'Amore 	default:
140582beb602SGarrett D'Amore 		return_code = 0;
1406508aff1aSJames C. McPherson 	}
140782beb602SGarrett D'Amore 	mutex_exit(&acb->isr_mutex);
140882beb602SGarrett D'Amore 	return (return_code);
1409508aff1aSJames C. McPherson }
1410508aff1aSJames C. McPherson 
1411508aff1aSJames C. McPherson static int
arcmsr_tran_bus_config(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** childp)141282beb602SGarrett D'Amore arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags,
141382beb602SGarrett D'Amore     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
141482beb602SGarrett D'Amore {
1415508aff1aSJames C. McPherson 	struct ACB *acb;
141682beb602SGarrett D'Amore 	int rval;
141782beb602SGarrett D'Amore 	int tgt, lun;
1418508aff1aSJames C. McPherson 
141982beb602SGarrett D'Amore 	if ((acb = ddi_get_soft_state(arcmsr_soft_state,
142082beb602SGarrett D'Amore 	    ddi_get_instance(parent))) == NULL)
142182beb602SGarrett D'Amore 		return (NDI_FAILURE);
1422508aff1aSJames C. McPherson 
14233fe80ca4SDan Cross 	ndi_devi_enter(parent);
142482beb602SGarrett D'Amore 	switch (op) {
142582beb602SGarrett D'Amore 	case BUS_CONFIG_ONE:
142682beb602SGarrett D'Amore 		if (arcmsr_parse_devname(arg, &tgt, &lun) != 0) {
142782beb602SGarrett D'Amore 			rval = NDI_FAILURE;
142882beb602SGarrett D'Amore 			break;
1429508aff1aSJames C. McPherson 		}
143082beb602SGarrett D'Amore 		if (acb->device_map[tgt] & 1 << lun) {
143182beb602SGarrett D'Amore 			acb->devstate[tgt][lun] = ARECA_RAID_GOOD;
143282beb602SGarrett D'Amore 			rval = arcmsr_config_lun(acb, tgt, lun, childp);
1433508aff1aSJames C. McPherson 		}
143482beb602SGarrett D'Amore 		break;
1435508aff1aSJames C. McPherson 
143682beb602SGarrett D'Amore 	case BUS_CONFIG_DRIVER:
143782beb602SGarrett D'Amore 	case BUS_CONFIG_ALL:
143882beb602SGarrett D'Amore 		for (tgt = 0; tgt < ARCMSR_MAX_TARGETID; tgt++)
143982beb602SGarrett D'Amore 			for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++)
144082beb602SGarrett D'Amore 				if (acb->device_map[tgt] & 1 << lun) {
144182beb602SGarrett D'Amore 					acb->devstate[tgt][lun] =
144282beb602SGarrett D'Amore 					    ARECA_RAID_GOOD;
144382beb602SGarrett D'Amore 					(void) arcmsr_config_lun(acb, tgt,
144482beb602SGarrett D'Amore 					    lun, NULL);
1445508aff1aSJames C. McPherson 				}
144682beb602SGarrett D'Amore 
144782beb602SGarrett D'Amore 		rval = NDI_SUCCESS;
144882beb602SGarrett D'Amore 		break;
1449508aff1aSJames C. McPherson 	}
145082beb602SGarrett D'Amore 	if (rval == NDI_SUCCESS)
145182beb602SGarrett D'Amore 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
14523fe80ca4SDan Cross 	ndi_devi_exit(parent);
145382beb602SGarrett D'Amore 	return (rval);
1454508aff1aSJames C. McPherson }
1455508aff1aSJames C. McPherson 
1456508aff1aSJames C. McPherson /*
1457508aff1aSJames C. McPherson  * Function name: arcmsr_dma_alloc
1458508aff1aSJames C. McPherson  * Return Values: 0 if successful, -1 if failure
1459508aff1aSJames C. McPherson  *   Description: allocate DMA resources
1460508aff1aSJames C. McPherson  *       Context: Can only be called from arcmsr_tran_init_pkt()
1461508aff1aSJames C. McPherson  *     register struct scsi_address	*ap = &((pkt)->pkt_address);
1462508aff1aSJames C. McPherson  */
1463508aff1aSJames C. McPherson static int
arcmsr_dma_alloc(struct ACB * acb,struct scsi_pkt * pkt,struct buf * bp,int flags,int (* callback)())1464508aff1aSJames C. McPherson arcmsr_dma_alloc(struct ACB *acb, struct scsi_pkt *pkt,
146582beb602SGarrett D'Amore     struct buf *bp, int flags, int (*callback)())
146682beb602SGarrett D'Amore {
1467508aff1aSJames C. McPherson 	struct CCB *ccb = pkt->pkt_ha_private;
1468508aff1aSJames C. McPherson 	int alloc_result, map_method, dma_flags;
1469508aff1aSJames C. McPherson 	int resid = 0;
1470508aff1aSJames C. McPherson 	int total_ccb_xferlen = 0;
1471508aff1aSJames C. McPherson 	int (*cb)(caddr_t);
1472508aff1aSJames C. McPherson 	uint8_t i;
1473508aff1aSJames C. McPherson 
1474508aff1aSJames C. McPherson 	/*
1475508aff1aSJames C. McPherson 	 * at this point the PKT SCSI CDB is empty, and dma xfer length
1476508aff1aSJames C. McPherson 	 * is bp->b_bcount
1477508aff1aSJames C. McPherson 	 */
1478508aff1aSJames C. McPherson 
1479508aff1aSJames C. McPherson 	if (bp->b_flags & B_READ) {
1480508aff1aSJames C. McPherson 		ccb->ccb_flags &= ~CCB_FLAG_DMAWRITE;
1481508aff1aSJames C. McPherson 		dma_flags = DDI_DMA_READ;
1482508aff1aSJames C. McPherson 	} else {
1483508aff1aSJames C. McPherson 		ccb->ccb_flags |= CCB_FLAG_DMAWRITE;
1484508aff1aSJames C. McPherson 		dma_flags = DDI_DMA_WRITE;
1485508aff1aSJames C. McPherson 	}
1486508aff1aSJames C. McPherson 
1487508aff1aSJames C. McPherson 	if (flags & PKT_CONSISTENT) {
1488508aff1aSJames C. McPherson 		ccb->ccb_flags |= CCB_FLAG_DMACONSISTENT;
1489508aff1aSJames C. McPherson 		dma_flags |= DDI_DMA_CONSISTENT;
1490508aff1aSJames C. McPherson 	}
1491508aff1aSJames C. McPherson 	if (flags & PKT_DMA_PARTIAL) {
1492508aff1aSJames C. McPherson 		dma_flags |= DDI_DMA_PARTIAL;
1493508aff1aSJames C. McPherson 	}
1494508aff1aSJames C. McPherson 
1495508aff1aSJames C. McPherson 	dma_flags |= DDI_DMA_REDZONE;
1496508aff1aSJames C. McPherson 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
1497508aff1aSJames C. McPherson 
149882beb602SGarrett D'Amore 	alloc_result = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_dma_attr,
149982beb602SGarrett D'Amore 	    cb, 0, &ccb->pkt_dma_handle);
150082beb602SGarrett D'Amore 	if (alloc_result != DDI_SUCCESS) {
150182beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma allocate failed (%x)", alloc_result);
150282beb602SGarrett D'Amore 		return (DDI_FAILURE);
1503508aff1aSJames C. McPherson 	}
1504508aff1aSJames C. McPherson 
150582beb602SGarrett D'Amore 	map_method = ddi_dma_buf_bind_handle(ccb->pkt_dma_handle,
150682beb602SGarrett D'Amore 	    bp, dma_flags, cb, 0,
1507508aff1aSJames C. McPherson 	    &ccb->pkt_dmacookies[0],	/* SG List pointer */
1508508aff1aSJames C. McPherson 	    &ccb->pkt_ncookies);	/* number of sgl cookies */
1509508aff1aSJames C. McPherson 
1510508aff1aSJames C. McPherson 	switch (map_method) {
1511508aff1aSJames C. McPherson 	case DDI_DMA_PARTIAL_MAP:
1512508aff1aSJames C. McPherson 		/*
1513508aff1aSJames C. McPherson 		 * When your main memory size larger then 4G
1514508aff1aSJames C. McPherson 		 * DDI_DMA_PARTIAL_MAP will be touched.
1515508aff1aSJames C. McPherson 		 *
1516508aff1aSJames C. McPherson 		 * We've already set DDI_DMA_PARTIAL in dma_flags,
1517508aff1aSJames C. McPherson 		 * so if it's now missing, there's something screwy
1518508aff1aSJames C. McPherson 		 * happening. We plow on....
1519508aff1aSJames C. McPherson 		 */
1520508aff1aSJames C. McPherson 
1521508aff1aSJames C. McPherson 		if ((dma_flags & DDI_DMA_PARTIAL) == 0) {
152282beb602SGarrett D'Amore 			arcmsr_warn(acb,
152382beb602SGarrett D'Amore 			    "dma partial mapping lost ...impossible case!");
1524508aff1aSJames C. McPherson 		}
1525508aff1aSJames C. McPherson 		if (ddi_dma_numwin(ccb->pkt_dma_handle, &ccb->pkt_nwin) ==
1526508aff1aSJames C. McPherson 		    DDI_FAILURE) {
152782beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_numwin() failed");
1528508aff1aSJames C. McPherson 		}
1529508aff1aSJames C. McPherson 
1530508aff1aSJames C. McPherson 		if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin,
1531508aff1aSJames C. McPherson 		    &ccb->pkt_dma_offset, &ccb->pkt_dma_len,
1532508aff1aSJames C. McPherson 		    &ccb->pkt_dmacookies[0], &ccb->pkt_ncookies) ==
1533508aff1aSJames C. McPherson 		    DDI_FAILURE) {
153482beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_getwin failed");
1535508aff1aSJames C. McPherson 		}
1536508aff1aSJames C. McPherson 
1537508aff1aSJames C. McPherson 		i = 0;
1538508aff1aSJames C. McPherson 		/* first cookie is accessed from ccb->pkt_dmacookies[0] */
1539508aff1aSJames C. McPherson 		total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size;
1540508aff1aSJames C. McPherson 		for (;;) {
1541508aff1aSJames C. McPherson 			i++;
154282beb602SGarrett D'Amore 			if ((i == ARCMSR_MAX_SG_ENTRIES) ||
154382beb602SGarrett D'Amore 			    (i == ccb->pkt_ncookies) ||
154482beb602SGarrett D'Amore 			    (total_ccb_xferlen == ARCMSR_MAX_XFER_LEN)) {
1545508aff1aSJames C. McPherson 				break;
1546508aff1aSJames C. McPherson 			}
1547508aff1aSJames C. McPherson 			/*
1548508aff1aSJames C. McPherson 			 * next cookie will be retrieved from
1549508aff1aSJames C. McPherson 			 * ccb->pkt_dmacookies[i]
1550508aff1aSJames C. McPherson 			 */
1551508aff1aSJames C. McPherson 			ddi_dma_nextcookie(ccb->pkt_dma_handle,
1552508aff1aSJames C. McPherson 			    &ccb->pkt_dmacookies[i]);
1553508aff1aSJames C. McPherson 			total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
1554508aff1aSJames C. McPherson 		}
1555508aff1aSJames C. McPherson 		ccb->pkt_cookie = i;
1556508aff1aSJames C. McPherson 		ccb->arcmsr_cdb.sgcount = i;
1557508aff1aSJames C. McPherson 		if (total_ccb_xferlen > 512) {
1558508aff1aSJames C. McPherson 			resid = total_ccb_xferlen % 512;
1559508aff1aSJames C. McPherson 			if (resid != 0) {
1560508aff1aSJames C. McPherson 				i--;
1561508aff1aSJames C. McPherson 				total_ccb_xferlen -= resid;
1562508aff1aSJames C. McPherson 				/* modify last sg length */
1563508aff1aSJames C. McPherson 				ccb->pkt_dmacookies[i].dmac_size =
1564508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_size - resid;
1565508aff1aSJames C. McPherson 				ccb->resid_dmacookie.dmac_size = resid;
1566508aff1aSJames C. McPherson 				ccb->resid_dmacookie.dmac_laddress =
1567508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_laddress +
1568508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_size;
1569508aff1aSJames C. McPherson 			}
1570508aff1aSJames C. McPherson 		}
1571508aff1aSJames C. McPherson 		ccb->total_dmac_size = total_ccb_xferlen;
1572508aff1aSJames C. McPherson 		ccb->ccb_flags |= CCB_FLAG_DMAVALID;
1573508aff1aSJames C. McPherson 		pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
1574508aff1aSJames C. McPherson 
1575508aff1aSJames C. McPherson 		return (DDI_SUCCESS);
1576508aff1aSJames C. McPherson 
1577508aff1aSJames C. McPherson 	case DDI_DMA_MAPPED:
1578508aff1aSJames C. McPherson 		ccb->pkt_nwin = 1; /* all mapped, so only one window */
1579508aff1aSJames C. McPherson 		ccb->pkt_dma_len = 0;
1580508aff1aSJames C. McPherson 		ccb->pkt_dma_offset = 0;
1581508aff1aSJames C. McPherson 		i = 0;
1582508aff1aSJames C. McPherson 		/* first cookie is accessed from ccb->pkt_dmacookies[0] */
1583508aff1aSJames C. McPherson 		total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size;
1584508aff1aSJames C. McPherson 		for (;;) {
1585508aff1aSJames C. McPherson 			i++;
158682beb602SGarrett D'Amore 			if ((i == ARCMSR_MAX_SG_ENTRIES) ||
158782beb602SGarrett D'Amore 			    (i == ccb->pkt_ncookies) ||
158882beb602SGarrett D'Amore 			    (total_ccb_xferlen == ARCMSR_MAX_XFER_LEN)) {
1589508aff1aSJames C. McPherson 				break;
1590508aff1aSJames C. McPherson 			}
1591508aff1aSJames C. McPherson 			/*
1592508aff1aSJames C. McPherson 			 * next cookie will be retrieved from
1593508aff1aSJames C. McPherson 			 * ccb->pkt_dmacookies[i]
1594508aff1aSJames C. McPherson 			 */
1595508aff1aSJames C. McPherson 			ddi_dma_nextcookie(ccb->pkt_dma_handle,
1596508aff1aSJames C. McPherson 			    &ccb->pkt_dmacookies[i]);
1597508aff1aSJames C. McPherson 			total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
1598508aff1aSJames C. McPherson 		}
1599508aff1aSJames C. McPherson 		ccb->pkt_cookie = i;
1600508aff1aSJames C. McPherson 		ccb->arcmsr_cdb.sgcount = i;
1601508aff1aSJames C. McPherson 		if (total_ccb_xferlen > 512) {
1602508aff1aSJames C. McPherson 			resid = total_ccb_xferlen % 512;
160382beb602SGarrett D'Amore 			if (resid != 0) {
1604508aff1aSJames C. McPherson 				i--;
1605508aff1aSJames C. McPherson 				total_ccb_xferlen -= resid;
1606508aff1aSJames C. McPherson 				/* modify last sg length */
1607508aff1aSJames C. McPherson 				ccb->pkt_dmacookies[i].dmac_size =
1608508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_size - resid;
1609508aff1aSJames C. McPherson 				ccb->resid_dmacookie.dmac_size = resid;
1610508aff1aSJames C. McPherson 				ccb->resid_dmacookie.dmac_laddress =
1611508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_laddress +
1612508aff1aSJames C. McPherson 				    ccb->pkt_dmacookies[i].dmac_size;
1613508aff1aSJames C. McPherson 			}
1614508aff1aSJames C. McPherson 		}
1615508aff1aSJames C. McPherson 		ccb->total_dmac_size = total_ccb_xferlen;
1616508aff1aSJames C. McPherson 		ccb->ccb_flags |= CCB_FLAG_DMAVALID;
1617508aff1aSJames C. McPherson 		pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
1618508aff1aSJames C. McPherson 		return (DDI_SUCCESS);
1619508aff1aSJames C. McPherson 
1620508aff1aSJames C. McPherson 	case DDI_DMA_NORESOURCES:
162182beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma map got 'no resources'");
1622508aff1aSJames C. McPherson 		bioerror(bp, ENOMEM);
1623508aff1aSJames C. McPherson 		break;
1624508aff1aSJames C. McPherson 
1625508aff1aSJames C. McPherson 	case DDI_DMA_NOMAPPING:
162682beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma map got 'no mapping'");
1627508aff1aSJames C. McPherson 		bioerror(bp, EFAULT);
1628508aff1aSJames C. McPherson 		break;
1629508aff1aSJames C. McPherson 
1630508aff1aSJames C. McPherson 	case DDI_DMA_TOOBIG:
163182beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma map got 'too big'");
1632508aff1aSJames C. McPherson 		bioerror(bp, EINVAL);
1633508aff1aSJames C. McPherson 		break;
1634508aff1aSJames C. McPherson 
1635508aff1aSJames C. McPherson 	case DDI_DMA_INUSE:
163682beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma map got 'in use' "
163782beb602SGarrett D'Amore 		    "(should not happen)");
1638508aff1aSJames C. McPherson 		break;
1639508aff1aSJames C. McPherson 	default:
164082beb602SGarrett D'Amore 		arcmsr_warn(acb, "dma map failed (0x%x)", i);
1641508aff1aSJames C. McPherson 		break;
1642508aff1aSJames C. McPherson 	}
1643508aff1aSJames C. McPherson 
1644508aff1aSJames C. McPherson 	ddi_dma_free_handle(&ccb->pkt_dma_handle);
1645508aff1aSJames C. McPherson 	ccb->pkt_dma_handle = NULL;
1646508aff1aSJames C. McPherson 	ccb->ccb_flags &= ~CCB_FLAG_DMAVALID;
1647508aff1aSJames C. McPherson 	return (DDI_FAILURE);
1648508aff1aSJames C. McPherson }
1649508aff1aSJames C. McPherson 
1650508aff1aSJames C. McPherson 
1651508aff1aSJames C. McPherson /*
1652508aff1aSJames C. McPherson  * Function name: arcmsr_dma_move
1653508aff1aSJames C. McPherson  * Return Values: 0 if successful, -1 if failure
1654508aff1aSJames C. McPherson  *   Description: move DMA resources to next DMA window
1655508aff1aSJames C. McPherson  *       Context: Can only be called from arcmsr_tran_init_pkt()
1656508aff1aSJames C. McPherson  */
1657508aff1aSJames C. McPherson static int
arcmsr_dma_move(struct ACB * acb,struct scsi_pkt * pkt,struct buf * bp)165882beb602SGarrett D'Amore arcmsr_dma_move(struct ACB *acb, struct scsi_pkt *pkt, struct buf *bp)
165982beb602SGarrett D'Amore {
1660508aff1aSJames C. McPherson 	struct CCB *ccb = pkt->pkt_ha_private;
1661508aff1aSJames C. McPherson 	uint8_t i = 0;
1662508aff1aSJames C. McPherson 	int resid = 0;
1663508aff1aSJames C. McPherson 	int total_ccb_xferlen = 0;
1664508aff1aSJames C. McPherson 
1665d5ebc493SDan Cross 	if (ccb->resid_dmacookie.dmac_size != 0) {
1666508aff1aSJames C. McPherson 		total_ccb_xferlen += ccb->resid_dmacookie.dmac_size;
1667508aff1aSJames C. McPherson 		ccb->pkt_dmacookies[i].dmac_size =
1668508aff1aSJames C. McPherson 		    ccb->resid_dmacookie.dmac_size;
1669508aff1aSJames C. McPherson 		ccb->pkt_dmacookies[i].dmac_laddress =
1670508aff1aSJames C. McPherson 		    ccb->resid_dmacookie.dmac_laddress;
1671508aff1aSJames C. McPherson 		i++;
1672508aff1aSJames C. McPherson 		ccb->resid_dmacookie.dmac_size = 0;
1673508aff1aSJames C. McPherson 	}
1674508aff1aSJames C. McPherson 	/*
1675508aff1aSJames C. McPherson 	 * If there are no more cookies remaining in this window,
1676508aff1aSJames C. McPherson 	 * move to the next window.
1677508aff1aSJames C. McPherson 	 */
1678508aff1aSJames C. McPherson 	if (ccb->pkt_cookie == ccb->pkt_ncookies) {
1679508aff1aSJames C. McPherson 		/*
1680508aff1aSJames C. McPherson 		 * only dma map "partial" arrive here
1681508aff1aSJames C. McPherson 		 */
1682508aff1aSJames C. McPherson 		if ((ccb->pkt_curwin == ccb->pkt_nwin) &&
1683508aff1aSJames C. McPherson 		    (ccb->pkt_nwin == 1)) {
1684508aff1aSJames C. McPherson 			return (DDI_SUCCESS);
1685508aff1aSJames C. McPherson 		}
1686508aff1aSJames C. McPherson 
1687508aff1aSJames C. McPherson 		/* At last window, cannot move */
1688508aff1aSJames C. McPherson 		if (++ccb->pkt_curwin >= ccb->pkt_nwin) {
168982beb602SGarrett D'Amore 			arcmsr_warn(acb, "dma partial set, numwin exceeded");
1690508aff1aSJames C. McPherson 			return (DDI_FAILURE);
1691508aff1aSJames C. McPherson 		}
1692508aff1aSJames C. McPherson 		if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin,
1693508aff1aSJames C. McPherson 		    &ccb->pkt_dma_offset, &ccb->pkt_dma_len,
1694508aff1aSJames C. McPherson 		    &ccb->pkt_dmacookies[i], &ccb->pkt_ncookies) ==
1695508aff1aSJames C. McPherson 		    DDI_FAILURE) {
169682beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_getwin failed");
1697508aff1aSJames C. McPherson 			return (DDI_FAILURE);
1698508aff1aSJames C. McPherson 		}
1699508aff1aSJames C. McPherson 		/* reset cookie pointer */
1700508aff1aSJames C. McPherson 		ccb->pkt_cookie = 0;
1701508aff1aSJames C. McPherson 	} else {
1702508aff1aSJames C. McPherson 		/*
1703508aff1aSJames C. McPherson 		 * only dma map "all" arrive here
1704508aff1aSJames C. McPherson 		 * We still have more cookies in this window,
1705508aff1aSJames C. McPherson 		 * get the next one
1706508aff1aSJames C. McPherson 		 * access the pkt_dma_handle remain cookie record at
1707508aff1aSJames C. McPherson 		 * ccb->pkt_dmacookies array
1708508aff1aSJames C. McPherson 		 */
1709508aff1aSJames C. McPherson 		ddi_dma_nextcookie(ccb->pkt_dma_handle,
1710508aff1aSJames C. McPherson 		    &ccb->pkt_dmacookies[i]);
1711508aff1aSJames C. McPherson 	}
1712508aff1aSJames C. McPherson 
171382beb602SGarrett D'Amore 	/* Get remaining cookies in this window, up to our maximum */
171482beb602SGarrett D'Amore 	total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
171582beb602SGarrett D'Amore 
171682beb602SGarrett D'Amore 	/* retrieve and store cookies, start at ccb->pkt_dmacookies[0] */
171782beb602SGarrett D'Amore 	for (;;) {
171882beb602SGarrett D'Amore 		i++;
171982beb602SGarrett D'Amore 		/* handled cookies count level indicator */
172082beb602SGarrett D'Amore 		ccb->pkt_cookie++;
172182beb602SGarrett D'Amore 		if ((i == ARCMSR_MAX_SG_ENTRIES) ||
172282beb602SGarrett D'Amore 		    (ccb->pkt_cookie == ccb->pkt_ncookies) ||
172382beb602SGarrett D'Amore 		    (total_ccb_xferlen == ARCMSR_MAX_XFER_LEN)) {
172482beb602SGarrett D'Amore 			break;
172582beb602SGarrett D'Amore 		}
172682beb602SGarrett D'Amore 		ddi_dma_nextcookie(ccb->pkt_dma_handle,
172782beb602SGarrett D'Amore 		    &ccb->pkt_dmacookies[i]);
172882beb602SGarrett D'Amore 		total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
172982beb602SGarrett D'Amore 	}
173082beb602SGarrett D'Amore 
173182beb602SGarrett D'Amore 	ccb->arcmsr_cdb.sgcount = i;
173282beb602SGarrett D'Amore 	if (total_ccb_xferlen > 512) {
173382beb602SGarrett D'Amore 		resid = total_ccb_xferlen % 512;
173482beb602SGarrett D'Amore 		if (resid != 0) {
173582beb602SGarrett D'Amore 			i--;
173682beb602SGarrett D'Amore 			total_ccb_xferlen -= resid;
173782beb602SGarrett D'Amore 			/* modify last sg length */
173882beb602SGarrett D'Amore 			ccb->pkt_dmacookies[i].dmac_size =
173982beb602SGarrett D'Amore 			    ccb->pkt_dmacookies[i].dmac_size - resid;
174082beb602SGarrett D'Amore 			ccb->resid_dmacookie.dmac_size = resid;
174182beb602SGarrett D'Amore 			ccb->resid_dmacookie.dmac_laddress =
174282beb602SGarrett D'Amore 			    ccb->pkt_dmacookies[i].dmac_laddress +
174382beb602SGarrett D'Amore 			    ccb->pkt_dmacookies[i].dmac_size;
174482beb602SGarrett D'Amore 		}
174582beb602SGarrett D'Amore 	}
174682beb602SGarrett D'Amore 	ccb->total_dmac_size += total_ccb_xferlen;
174782beb602SGarrett D'Amore 	pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
174882beb602SGarrett D'Amore 
174982beb602SGarrett D'Amore 	return (DDI_SUCCESS);
175082beb602SGarrett D'Amore }
175182beb602SGarrett D'Amore 
175282beb602SGarrett D'Amore 
175382beb602SGarrett D'Amore /*ARGSUSED*/
175482beb602SGarrett D'Amore static void
arcmsr_build_ccb(struct CCB * ccb)175582beb602SGarrett D'Amore arcmsr_build_ccb(struct CCB *ccb)
175682beb602SGarrett D'Amore {
175782beb602SGarrett D'Amore 	struct scsi_pkt *pkt = ccb->pkt;
175882beb602SGarrett D'Amore 	struct ARCMSR_CDB *arcmsr_cdb;
175982beb602SGarrett D'Amore 	char *psge;
176082beb602SGarrett D'Amore 	uint32_t address_lo, address_hi;
176182beb602SGarrett D'Amore 	int arccdbsize = 0x30;
176282beb602SGarrett D'Amore 	uint8_t sgcount;
176382beb602SGarrett D'Amore 
176482beb602SGarrett D'Amore 	arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
176582beb602SGarrett D'Amore 	psge = (char *)&arcmsr_cdb->sgu;
176682beb602SGarrett D'Amore 
176782beb602SGarrett D'Amore 	bcopy((caddr_t)pkt->pkt_cdbp, arcmsr_cdb->Cdb, arcmsr_cdb->CdbLength);
176882beb602SGarrett D'Amore 	sgcount = ccb->arcmsr_cdb.sgcount;
176982beb602SGarrett D'Amore 
177082beb602SGarrett D'Amore 	if (sgcount != 0) {
177182beb602SGarrett D'Amore 		int length, i;
177282beb602SGarrett D'Amore 		int cdb_sgcount = 0;
177382beb602SGarrett D'Amore 		int total_xfer_length = 0;
177482beb602SGarrett D'Amore 
177582beb602SGarrett D'Amore 		/* map stor port SG list to our iop SG List. */
177682beb602SGarrett D'Amore 		for (i = 0; i < sgcount; i++) {
177782beb602SGarrett D'Amore 			/* Get physaddr of the current data pointer */
177882beb602SGarrett D'Amore 			length = ccb->pkt_dmacookies[i].dmac_size;
177982beb602SGarrett D'Amore 			total_xfer_length += length;
178082beb602SGarrett D'Amore 			address_lo =
178182beb602SGarrett D'Amore 			    dma_addr_lo32(ccb->pkt_dmacookies[i].dmac_laddress);
178282beb602SGarrett D'Amore 			address_hi =
178382beb602SGarrett D'Amore 			    dma_addr_hi32(ccb->pkt_dmacookies[i].dmac_laddress);
178482beb602SGarrett D'Amore 
178582beb602SGarrett D'Amore 			if (address_hi == 0) {
178682beb602SGarrett D'Amore 				struct SG32ENTRY *dma_sg;
178782beb602SGarrett D'Amore 
178882beb602SGarrett D'Amore 				dma_sg = (struct SG32ENTRY *)(intptr_t)psge;
178982beb602SGarrett D'Amore 				dma_sg->address = address_lo;
179082beb602SGarrett D'Amore 				dma_sg->length = length;
179182beb602SGarrett D'Amore 				psge += sizeof (struct SG32ENTRY);
179282beb602SGarrett D'Amore 				arccdbsize += sizeof (struct SG32ENTRY);
179382beb602SGarrett D'Amore 			} else {
179482beb602SGarrett D'Amore 				struct SG64ENTRY *dma_sg;
179582beb602SGarrett D'Amore 
179682beb602SGarrett D'Amore 				dma_sg = (struct SG64ENTRY *)(intptr_t)psge;
179782beb602SGarrett D'Amore 				dma_sg->addresshigh = address_hi;
179882beb602SGarrett D'Amore 				dma_sg->address = address_lo;
179982beb602SGarrett D'Amore 				dma_sg->length = length | IS_SG64_ADDR;
180082beb602SGarrett D'Amore 				psge += sizeof (struct SG64ENTRY);
180182beb602SGarrett D'Amore 				arccdbsize += sizeof (struct SG64ENTRY);
180282beb602SGarrett D'Amore 			}
180382beb602SGarrett D'Amore 			cdb_sgcount++;
180482beb602SGarrett D'Amore 		}
180582beb602SGarrett D'Amore 		arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
180682beb602SGarrett D'Amore 		arcmsr_cdb->DataLength = total_xfer_length;
180782beb602SGarrett D'Amore 		if (arccdbsize > 256) {
180882beb602SGarrett D'Amore 			arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
180982beb602SGarrett D'Amore 		}
181082beb602SGarrett D'Amore 	} else {
181182beb602SGarrett D'Amore 		arcmsr_cdb->DataLength = 0;
181282beb602SGarrett D'Amore 	}
181382beb602SGarrett D'Amore 
181482beb602SGarrett D'Amore 	if (ccb->ccb_flags & CCB_FLAG_DMAWRITE)
181582beb602SGarrett D'Amore 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
181682beb602SGarrett D'Amore 	ccb->arc_cdb_size = arccdbsize;
181782beb602SGarrett D'Amore }
181882beb602SGarrett D'Amore 
181982beb602SGarrett D'Amore /*
182082beb602SGarrett D'Amore  * arcmsr_post_ccb - Send a protocol specific ARC send postcard to a AIOC.
182182beb602SGarrett D'Amore  *
182282beb602SGarrett D'Amore  * handle:		Handle of registered ARC protocol driver
182382beb602SGarrett D'Amore  * adapter_id:		AIOC unique identifier(integer)
182482beb602SGarrett D'Amore  * pPOSTCARD_SEND:	Pointer to ARC send postcard
182582beb602SGarrett D'Amore  *
182682beb602SGarrett D'Amore  * This routine posts a ARC send postcard to the request post FIFO of a
182782beb602SGarrett D'Amore  * specific ARC adapter.
182882beb602SGarrett D'Amore  */
182982beb602SGarrett D'Amore static int
arcmsr_post_ccb(struct ACB * acb,struct CCB * ccb)183082beb602SGarrett D'Amore arcmsr_post_ccb(struct ACB *acb, struct CCB *ccb)
183182beb602SGarrett D'Amore {
183282beb602SGarrett D'Amore 	uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
183382beb602SGarrett D'Amore 	struct scsi_pkt *pkt = ccb->pkt;
183482beb602SGarrett D'Amore 	struct ARCMSR_CDB *arcmsr_cdb;
183582beb602SGarrett D'Amore 	uint_t pkt_flags = pkt->pkt_flags;
183682beb602SGarrett D'Amore 
183782beb602SGarrett D'Amore 	arcmsr_cdb = &ccb->arcmsr_cdb;
183882beb602SGarrett D'Amore 
183982beb602SGarrett D'Amore 	/* TODO: Use correct offset and size for syncing? */
184082beb602SGarrett D'Amore 	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, 0, DDI_DMA_SYNC_FORDEV) ==
184182beb602SGarrett D'Amore 	    DDI_FAILURE)
184282beb602SGarrett D'Amore 		return (DDI_FAILURE);
184382beb602SGarrett D'Amore 
18441a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&acb->ccboutstandingcount);
184582beb602SGarrett D'Amore 	ccb->ccb_time = (time_t)(ddi_get_time() + pkt->pkt_time);
184682beb602SGarrett D'Amore 
184782beb602SGarrett D'Amore 	ccb->ccb_state = ARCMSR_CCB_START;
184882beb602SGarrett D'Amore 	switch (acb->adapter_type) {
184982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
185082beb602SGarrett D'Amore 	{
185182beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
185282beb602SGarrett D'Amore 
185382beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
185482beb602SGarrett D'Amore 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
185582beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
185682beb602SGarrett D'Amore 			    &phbamu->inbound_queueport,
185782beb602SGarrett D'Amore 			    cdb_phyaddr_pattern |
185882beb602SGarrett D'Amore 			    ARCMSR_CCBPOST_FLAG_SGL_BSIZE);
185982beb602SGarrett D'Amore 		} else {
186082beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
186182beb602SGarrett D'Amore 			    &phbamu->inbound_queueport, cdb_phyaddr_pattern);
186282beb602SGarrett D'Amore 		}
186382beb602SGarrett D'Amore 		if (pkt_flags & FLAG_NOINTR)
186482beb602SGarrett D'Amore 			arcmsr_polling_hba_ccbdone(acb, ccb);
186582beb602SGarrett D'Amore 		break;
186682beb602SGarrett D'Amore 	}
186782beb602SGarrett D'Amore 
186882beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
186982beb602SGarrett D'Amore 	{
187082beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
187182beb602SGarrett D'Amore 		int ending_index, index;
187282beb602SGarrett D'Amore 
187382beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
187482beb602SGarrett D'Amore 		index = phbbmu->postq_index;
187582beb602SGarrett D'Amore 		ending_index = ((index+1)%ARCMSR_MAX_HBB_POSTQUEUE);
187682beb602SGarrett D'Amore 		phbbmu->post_qbuffer[ending_index] = 0;
187782beb602SGarrett D'Amore 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
187882beb602SGarrett D'Amore 			phbbmu->post_qbuffer[index] =
187982beb602SGarrett D'Amore 			    (cdb_phyaddr_pattern|ARCMSR_CCBPOST_FLAG_SGL_BSIZE);
188082beb602SGarrett D'Amore 		} else {
188182beb602SGarrett D'Amore 			phbbmu->post_qbuffer[index] = cdb_phyaddr_pattern;
188282beb602SGarrett D'Amore 		}
188382beb602SGarrett D'Amore 		index++;
188482beb602SGarrett D'Amore 		/* if last index number set it to 0 */
188582beb602SGarrett D'Amore 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
188682beb602SGarrett D'Amore 		phbbmu->postq_index = index;
188782beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
188882beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
188982beb602SGarrett D'Amore 		    ARCMSR_DRV2IOP_CDB_POSTED);
189082beb602SGarrett D'Amore 
189182beb602SGarrett D'Amore 		if (pkt_flags & FLAG_NOINTR)
189282beb602SGarrett D'Amore 			arcmsr_polling_hbb_ccbdone(acb, ccb);
189382beb602SGarrett D'Amore 		break;
189482beb602SGarrett D'Amore 	}
189582beb602SGarrett D'Amore 
189682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
189782beb602SGarrett D'Amore 	{
189882beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
189982beb602SGarrett D'Amore 		uint32_t ccb_post_stamp, arc_cdb_size;
190082beb602SGarrett D'Amore 
190182beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
190282beb602SGarrett D'Amore 		arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 :
190382beb602SGarrett D'Amore 		    ccb->arc_cdb_size;
190482beb602SGarrett D'Amore 		ccb_post_stamp = (cdb_phyaddr_pattern |
190582beb602SGarrett D'Amore 		    ((arc_cdb_size-1) >> 6) |1);
190682beb602SGarrett D'Amore 		if (acb->cdb_phyaddr_hi32) {
190782beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
190882beb602SGarrett D'Amore 			    &phbcmu->inbound_queueport_high,
190982beb602SGarrett D'Amore 			    acb->cdb_phyaddr_hi32);
191082beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
191182beb602SGarrett D'Amore 			    &phbcmu->inbound_queueport_low, ccb_post_stamp);
191282beb602SGarrett D'Amore 		} else {
191382beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
191482beb602SGarrett D'Amore 			    &phbcmu->inbound_queueport_low, ccb_post_stamp);
191582beb602SGarrett D'Amore 		}
191682beb602SGarrett D'Amore 		if (pkt_flags & FLAG_NOINTR)
191782beb602SGarrett D'Amore 			arcmsr_polling_hbc_ccbdone(acb, ccb);
191882beb602SGarrett D'Amore 		break;
191982beb602SGarrett D'Amore 	}
192082beb602SGarrett D'Amore 
192182beb602SGarrett D'Amore 	}
192282beb602SGarrett D'Amore 	return (DDI_SUCCESS);
192382beb602SGarrett D'Amore }
192482beb602SGarrett D'Amore 
192582beb602SGarrett D'Amore 
192682beb602SGarrett D'Amore static void
arcmsr_ccb_complete(struct CCB * ccb,int flag)192782beb602SGarrett D'Amore arcmsr_ccb_complete(struct CCB *ccb, int flag)
192882beb602SGarrett D'Amore {
192982beb602SGarrett D'Amore 	struct ACB *acb = ccb->acb;
193082beb602SGarrett D'Amore 	struct scsi_pkt *pkt = ccb->pkt;
193182beb602SGarrett D'Amore 
193282beb602SGarrett D'Amore 	if (pkt == NULL) {
193382beb602SGarrett D'Amore 		return;
193482beb602SGarrett D'Amore 	}
193582beb602SGarrett D'Amore 	ccb->ccb_state |= ARCMSR_CCB_DONE;
193682beb602SGarrett D'Amore 	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
193782beb602SGarrett D'Amore 	    STATE_SENT_CMD | STATE_GOT_STATUS);
193882beb602SGarrett D'Amore 
193982beb602SGarrett D'Amore 	if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
194082beb602SGarrett D'Amore 	    (pkt->pkt_state & STATE_XFERRED_DATA)) {
194182beb602SGarrett D'Amore 		(void) ddi_dma_sync(ccb->pkt_dma_handle, 0, 0,
194282beb602SGarrett D'Amore 		    DDI_DMA_SYNC_FORCPU);
194382beb602SGarrett D'Amore 	}
194482beb602SGarrett D'Amore 	/*
194582beb602SGarrett D'Amore 	 * TODO: This represents a potential race condition, and is
194682beb602SGarrett D'Amore 	 * ultimately a poor design decision.  Revisit this code
194782beb602SGarrett D'Amore 	 * and solve the mutex ownership issue correctly.
194882beb602SGarrett D'Amore 	 */
194982beb602SGarrett D'Amore 	if (mutex_owned(&acb->isr_mutex)) {
195082beb602SGarrett D'Amore 		mutex_exit(&acb->isr_mutex);
195182beb602SGarrett D'Amore 		scsi_hba_pkt_comp(pkt);
195282beb602SGarrett D'Amore 		mutex_enter(&acb->isr_mutex);
195382beb602SGarrett D'Amore 	} else {
195482beb602SGarrett D'Amore 		scsi_hba_pkt_comp(pkt);
195582beb602SGarrett D'Amore 	}
195682beb602SGarrett D'Amore 	if (flag == 1) {
19571a5e258fSJosef 'Jeff' Sipek 		atomic_dec_32(&acb->ccboutstandingcount);
195882beb602SGarrett D'Amore 	}
195982beb602SGarrett D'Amore }
196082beb602SGarrett D'Amore 
196182beb602SGarrett D'Amore static void
arcmsr_report_ccb_state(struct ACB * acb,struct CCB * ccb,boolean_t error)196282beb602SGarrett D'Amore arcmsr_report_ccb_state(struct ACB *acb, struct CCB *ccb, boolean_t error)
196382beb602SGarrett D'Amore {
196482beb602SGarrett D'Amore 	int id, lun;
196582beb602SGarrett D'Amore 
196682beb602SGarrett D'Amore 	ccb->ccb_state |= ARCMSR_CCB_DONE;
196782beb602SGarrett D'Amore 	id = ccb->pkt->pkt_address.a_target;
196882beb602SGarrett D'Amore 	lun = ccb->pkt->pkt_address.a_lun;
196982beb602SGarrett D'Amore 
197082beb602SGarrett D'Amore 	if (!error) {
197182beb602SGarrett D'Amore 		if (acb->devstate[id][lun] == ARECA_RAID_GONE) {
197282beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
197382beb602SGarrett D'Amore 		}
197482beb602SGarrett D'Amore 		ccb->pkt->pkt_reason = CMD_CMPLT;
197582beb602SGarrett D'Amore 		ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
197682beb602SGarrett D'Amore 		arcmsr_list_add_tail(&acb->ccb_complete_list_mutex,
197782beb602SGarrett D'Amore 		    &ccb->complete_queue_pointer, &acb->ccb_complete_list);
197882beb602SGarrett D'Amore 
197982beb602SGarrett D'Amore 	} else {
198082beb602SGarrett D'Amore 		switch (ccb->arcmsr_cdb.DeviceStatus) {
198182beb602SGarrett D'Amore 		case ARCMSR_DEV_SELECT_TIMEOUT:
198282beb602SGarrett D'Amore 			if (acb->devstate[id][lun] == ARECA_RAID_GOOD) {
198382beb602SGarrett D'Amore 				arcmsr_warn(acb,
198482beb602SGarrett D'Amore 				    "target %d lun %d selection "
198582beb602SGarrett D'Amore 				    "timeout", id, lun);
198682beb602SGarrett D'Amore 			}
198782beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GONE;
198882beb602SGarrett D'Amore 			ccb->pkt->pkt_reason = CMD_TIMEOUT; /* CMD_DEV_GONE; */
198982beb602SGarrett D'Amore 			ccb->pkt->pkt_statistics |= STAT_TIMEOUT;
199082beb602SGarrett D'Amore 			arcmsr_list_add_tail(&acb->ccb_complete_list_mutex,
199182beb602SGarrett D'Amore 			    &ccb->complete_queue_pointer,
199282beb602SGarrett D'Amore 			    &acb->ccb_complete_list);
199382beb602SGarrett D'Amore 			break;
199482beb602SGarrett D'Amore 		case ARCMSR_DEV_ABORTED:
199582beb602SGarrett D'Amore 		case ARCMSR_DEV_INIT_FAIL:
199682beb602SGarrett D'Amore 			arcmsr_warn(acb, "isr got 'ARCMSR_DEV_ABORTED'"
199782beb602SGarrett D'Amore 			    " 'ARCMSR_DEV_INIT_FAIL'");
199882beb602SGarrett D'Amore 			arcmsr_log(acb, CE_NOTE, "raid volume was kicked out");
199982beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GONE;
200082beb602SGarrett D'Amore 			ccb->pkt->pkt_reason = CMD_DEV_GONE;
200182beb602SGarrett D'Amore 			ccb->pkt->pkt_statistics |= STAT_TERMINATED;
200282beb602SGarrett D'Amore 			arcmsr_list_add_tail(&acb->ccb_complete_list_mutex,
200382beb602SGarrett D'Amore 			    &ccb->complete_queue_pointer,
200482beb602SGarrett D'Amore 			    &acb->ccb_complete_list);
200582beb602SGarrett D'Amore 			break;
200682beb602SGarrett D'Amore 		case SCSISTAT_CHECK_CONDITION:
200782beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
200882beb602SGarrett D'Amore 			arcmsr_report_sense_info(ccb);
200982beb602SGarrett D'Amore 			arcmsr_list_add_tail(&acb->ccb_complete_list_mutex,
201082beb602SGarrett D'Amore 			    &ccb->complete_queue_pointer,
201182beb602SGarrett D'Amore 			    &acb->ccb_complete_list);
201282beb602SGarrett D'Amore 			break;
201382beb602SGarrett D'Amore 		default:
201482beb602SGarrett D'Amore 			arcmsr_warn(acb,
201582beb602SGarrett D'Amore 			    "target %d lun %d isr received CMD_DONE"
201682beb602SGarrett D'Amore 			    " with unknown DeviceStatus (0x%x)",
201782beb602SGarrett D'Amore 			    id, lun, ccb->arcmsr_cdb.DeviceStatus);
201882beb602SGarrett D'Amore 			arcmsr_log(acb, CE_NOTE, "raid volume was kicked out");
201982beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GONE;
202082beb602SGarrett D'Amore 			/* unknown error or crc error just for retry */
202182beb602SGarrett D'Amore 			ccb->pkt->pkt_reason = CMD_TRAN_ERR;
202282beb602SGarrett D'Amore 			ccb->pkt->pkt_statistics |= STAT_TERMINATED;
202382beb602SGarrett D'Amore 			arcmsr_list_add_tail(&acb->ccb_complete_list_mutex,
202482beb602SGarrett D'Amore 			    &ccb->complete_queue_pointer,
202582beb602SGarrett D'Amore 			    &acb->ccb_complete_list);
202682beb602SGarrett D'Amore 			break;
202782beb602SGarrett D'Amore 		}
202882beb602SGarrett D'Amore 	}
202982beb602SGarrett D'Amore }
203082beb602SGarrett D'Amore 
203182beb602SGarrett D'Amore 
203282beb602SGarrett D'Amore static void
arcmsr_drain_donequeue(struct ACB * acb,struct CCB * ccb,boolean_t error)203382beb602SGarrett D'Amore arcmsr_drain_donequeue(struct ACB *acb, struct CCB *ccb, boolean_t error)
203482beb602SGarrett D'Amore {
203582beb602SGarrett D'Amore 	uint16_t	ccb_state;
203682beb602SGarrett D'Amore 
203782beb602SGarrett D'Amore 	if (ccb->acb != acb) {
203882beb602SGarrett D'Amore 		return;
203982beb602SGarrett D'Amore 	}
204082beb602SGarrett D'Amore 	if (ccb->ccb_state != ARCMSR_CCB_START) {
204182beb602SGarrett D'Amore 		switch (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
204282beb602SGarrett D'Amore 		case ARCMSR_CCB_TIMEOUT:
204382beb602SGarrett D'Amore 			ccb_state = ccb->ccb_state;
204482beb602SGarrett D'Amore 			if (ccb_state & ARCMSR_CCB_WAIT4_FREE)
204582beb602SGarrett D'Amore 				arcmsr_free_ccb(ccb);
204682beb602SGarrett D'Amore 			else
204782beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
204882beb602SGarrett D'Amore 			return;
204982beb602SGarrett D'Amore 
205082beb602SGarrett D'Amore 		case ARCMSR_CCB_ABORTED:
205182beb602SGarrett D'Amore 			ccb_state = ccb->ccb_state;
205282beb602SGarrett D'Amore 			if (ccb_state & ARCMSR_CCB_WAIT4_FREE)
205382beb602SGarrett D'Amore 				arcmsr_free_ccb(ccb);
205482beb602SGarrett D'Amore 			else
205582beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
205682beb602SGarrett D'Amore 			return;
205782beb602SGarrett D'Amore 		case ARCMSR_CCB_RESET:
205882beb602SGarrett D'Amore 			ccb_state = ccb->ccb_state;
205982beb602SGarrett D'Amore 			if (ccb_state & ARCMSR_CCB_WAIT4_FREE)
206082beb602SGarrett D'Amore 				arcmsr_free_ccb(ccb);
206182beb602SGarrett D'Amore 			else
206282beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
206382beb602SGarrett D'Amore 			return;
206482beb602SGarrett D'Amore 		default:
206582beb602SGarrett D'Amore 			return;
206682beb602SGarrett D'Amore 		}
206782beb602SGarrett D'Amore 	}
206882beb602SGarrett D'Amore 	arcmsr_report_ccb_state(acb, ccb, error);
206982beb602SGarrett D'Amore }
207082beb602SGarrett D'Amore 
207182beb602SGarrett D'Amore static void
arcmsr_report_sense_info(struct CCB * ccb)207282beb602SGarrett D'Amore arcmsr_report_sense_info(struct CCB *ccb)
207382beb602SGarrett D'Amore {
207482beb602SGarrett D'Amore 	struct SENSE_DATA *cdb_sensedata;
207582beb602SGarrett D'Amore 	struct scsi_pkt *pkt = ccb->pkt;
207682beb602SGarrett D'Amore 	struct scsi_arq_status *arq_status;
207782beb602SGarrett D'Amore 	union scsi_cdb *cdbp;
207882beb602SGarrett D'Amore 	uint64_t err_blkno;
207982beb602SGarrett D'Amore 
208082beb602SGarrett D'Amore 	cdbp = (void *)pkt->pkt_cdbp;
208182beb602SGarrett D'Amore 	err_blkno = ARCMSR_GETGXADDR(ccb->arcmsr_cdb.CdbLength, cdbp);
208282beb602SGarrett D'Amore 
208382beb602SGarrett D'Amore 	arq_status = (struct scsi_arq_status *)(intptr_t)(pkt->pkt_scbp);
208482beb602SGarrett D'Amore 	bzero((caddr_t)arq_status, sizeof (struct scsi_arq_status));
208582beb602SGarrett D'Amore 	*pkt->pkt_scbp = STATUS_CHECK; /* CHECK CONDITION */
208682beb602SGarrett D'Amore 	arq_status->sts_rqpkt_reason = CMD_CMPLT;
208782beb602SGarrett D'Amore 	arq_status->sts_rqpkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET |
208882beb602SGarrett D'Amore 	    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS);
208982beb602SGarrett D'Amore 	arq_status->sts_rqpkt_statistics = 0;
209082beb602SGarrett D'Amore 	arq_status->sts_rqpkt_resid = 0;
209182beb602SGarrett D'Amore 
209282beb602SGarrett D'Amore 	pkt->pkt_reason = CMD_CMPLT;
209382beb602SGarrett D'Amore 	/* auto rqsense took place */
209482beb602SGarrett D'Amore 	pkt->pkt_state |= STATE_ARQ_DONE;
209582beb602SGarrett D'Amore 
209682beb602SGarrett D'Amore 	cdb_sensedata = (struct SENSE_DATA *)ccb->arcmsr_cdb.SenseData;
2097*2cbbfaaaSToomas Soome 	if (err_blkno <= 0xfffffffful) {
2098*2cbbfaaaSToomas Soome 		struct scsi_extended_sense *sts_sensedata;
2099*2cbbfaaaSToomas Soome 
2100*2cbbfaaaSToomas Soome 		sts_sensedata = &arq_status->sts_sensedata;
2101*2cbbfaaaSToomas Soome 		sts_sensedata->es_code = cdb_sensedata->ErrorCode;
2102*2cbbfaaaSToomas Soome 		/* must eq CLASS_EXTENDED_SENSE (0x07) */
2103*2cbbfaaaSToomas Soome 		sts_sensedata->es_class = cdb_sensedata->ErrorClass;
2104*2cbbfaaaSToomas Soome 		sts_sensedata->es_valid = cdb_sensedata->Valid;
2105*2cbbfaaaSToomas Soome 		sts_sensedata->es_segnum = cdb_sensedata->SegmentNumber;
2106*2cbbfaaaSToomas Soome 		sts_sensedata->es_key = cdb_sensedata->SenseKey;
2107*2cbbfaaaSToomas Soome 		sts_sensedata->es_ili = cdb_sensedata->IncorrectLength;
2108*2cbbfaaaSToomas Soome 		sts_sensedata->es_eom = cdb_sensedata->EndOfMedia;
2109*2cbbfaaaSToomas Soome 		sts_sensedata->es_filmk = cdb_sensedata->FileMark;
2110*2cbbfaaaSToomas Soome 		sts_sensedata->es_info_1 = (err_blkno >> 24) & 0xFF;
2111*2cbbfaaaSToomas Soome 		sts_sensedata->es_info_2 = (err_blkno >> 16) & 0xFF;
2112*2cbbfaaaSToomas Soome 		sts_sensedata->es_info_3 = (err_blkno >>  8) & 0xFF;
2113*2cbbfaaaSToomas Soome 		sts_sensedata->es_info_4 = err_blkno & 0xFF;
2114*2cbbfaaaSToomas Soome 		sts_sensedata->es_add_len =
2115*2cbbfaaaSToomas Soome 		    cdb_sensedata->AdditionalSenseLength;
2116*2cbbfaaaSToomas Soome 		sts_sensedata->es_cmd_info[0] =
2117*2cbbfaaaSToomas Soome 		    cdb_sensedata->CommandSpecificInformation[0];
2118*2cbbfaaaSToomas Soome 		sts_sensedata->es_cmd_info[1] =
2119*2cbbfaaaSToomas Soome 		    cdb_sensedata->CommandSpecificInformation[1];
2120*2cbbfaaaSToomas Soome 		sts_sensedata->es_cmd_info[2] =
2121*2cbbfaaaSToomas Soome 		    cdb_sensedata->CommandSpecificInformation[2];
2122*2cbbfaaaSToomas Soome 		sts_sensedata->es_cmd_info[3] =
2123*2cbbfaaaSToomas Soome 		    cdb_sensedata->CommandSpecificInformation[3];
2124*2cbbfaaaSToomas Soome 		sts_sensedata->es_add_code =
2125*2cbbfaaaSToomas Soome 		    cdb_sensedata->AdditionalSenseCode;
2126*2cbbfaaaSToomas Soome 		sts_sensedata->es_qual_code =
2127*2cbbfaaaSToomas Soome 		    cdb_sensedata->AdditionalSenseCodeQualifier;
2128*2cbbfaaaSToomas Soome 		sts_sensedata->es_fru_code =
2129*2cbbfaaaSToomas Soome 		    cdb_sensedata->FieldReplaceableUnitCode;
2130*2cbbfaaaSToomas Soome 	} else { /* 64-bit LBA */
2131*2cbbfaaaSToomas Soome 		struct scsi_descr_sense_hdr *dsp;
2132*2cbbfaaaSToomas Soome 		struct scsi_information_sense_descr *isd;
2133*2cbbfaaaSToomas Soome 
2134*2cbbfaaaSToomas Soome 		dsp = (struct scsi_descr_sense_hdr *)
2135*2cbbfaaaSToomas Soome 		    &arq_status->sts_sensedata;
2136*2cbbfaaaSToomas Soome 		dsp->ds_class = CLASS_EXTENDED_SENSE;
2137*2cbbfaaaSToomas Soome 		dsp->ds_code = CODE_FMT_DESCR_CURRENT;
2138*2cbbfaaaSToomas Soome 		dsp->ds_key = cdb_sensedata->SenseKey;
2139*2cbbfaaaSToomas Soome 		dsp->ds_add_code = cdb_sensedata->AdditionalSenseCode;
2140*2cbbfaaaSToomas Soome 		dsp->ds_qual_code =
2141*2cbbfaaaSToomas Soome 		    cdb_sensedata->AdditionalSenseCodeQualifier;
2142*2cbbfaaaSToomas Soome 		dsp->ds_addl_sense_length =
2143*2cbbfaaaSToomas Soome 		    sizeof (struct scsi_information_sense_descr);
2144*2cbbfaaaSToomas Soome 
2145*2cbbfaaaSToomas Soome 		isd = (struct scsi_information_sense_descr *)(dsp+1);
2146*2cbbfaaaSToomas Soome 		isd->isd_descr_type = DESCR_INFORMATION;
2147*2cbbfaaaSToomas Soome 		isd->isd_valid = 1;
2148*2cbbfaaaSToomas Soome 		isd->isd_information[0] = (err_blkno >> 56) & 0xFF;
2149*2cbbfaaaSToomas Soome 		isd->isd_information[1] = (err_blkno >> 48) & 0xFF;
2150*2cbbfaaaSToomas Soome 		isd->isd_information[2] = (err_blkno >> 40) & 0xFF;
2151*2cbbfaaaSToomas Soome 		isd->isd_information[3] = (err_blkno >> 32) & 0xFF;
2152*2cbbfaaaSToomas Soome 		isd->isd_information[4] = (err_blkno >> 24) & 0xFF;
2153*2cbbfaaaSToomas Soome 		isd->isd_information[5] = (err_blkno >> 16) & 0xFF;
2154*2cbbfaaaSToomas Soome 		isd->isd_information[6] = (err_blkno >>  8) & 0xFF;
2155*2cbbfaaaSToomas Soome 		isd->isd_information[7] = (err_blkno) & 0xFF;
215682beb602SGarrett D'Amore 	}
215782beb602SGarrett D'Amore }
215882beb602SGarrett D'Amore 
215982beb602SGarrett D'Amore 
216082beb602SGarrett D'Amore static int
arcmsr_seek_cmd2abort(struct ACB * acb,struct scsi_pkt * abortpkt)216182beb602SGarrett D'Amore arcmsr_seek_cmd2abort(struct ACB *acb, struct scsi_pkt *abortpkt)
216282beb602SGarrett D'Amore {
216382beb602SGarrett D'Amore 	struct CCB *ccb;
216482beb602SGarrett D'Amore 	uint32_t intmask_org = 0;
216582beb602SGarrett D'Amore 	int i = 0;
216682beb602SGarrett D'Amore 
216782beb602SGarrett D'Amore 	acb->num_aborts++;
216882beb602SGarrett D'Amore 
216982beb602SGarrett D'Amore 	if (abortpkt != NULL) {
217082beb602SGarrett D'Amore 		/*
217182beb602SGarrett D'Amore 		 * We don't support abort of a single packet.  All
217282beb602SGarrett D'Amore 		 * callers in our kernel always do a global abort, so
217382beb602SGarrett D'Amore 		 * there is no point in having code to support it
217482beb602SGarrett D'Amore 		 * here.
217582beb602SGarrett D'Amore 		 */
217682beb602SGarrett D'Amore 		return (DDI_FAILURE);
217782beb602SGarrett D'Amore 	}
217882beb602SGarrett D'Amore 
217982beb602SGarrett D'Amore 	/*
218082beb602SGarrett D'Amore 	 * if abortpkt is NULL, the upper layer needs us
218182beb602SGarrett D'Amore 	 * to abort all commands
218282beb602SGarrett D'Amore 	 */
218382beb602SGarrett D'Amore 	if (acb->ccboutstandingcount != 0) {
218482beb602SGarrett D'Amore 		/* disable all outbound interrupt */
218582beb602SGarrett D'Amore 		intmask_org = arcmsr_disable_allintr(acb);
218682beb602SGarrett D'Amore 		/* clear and abort all outbound posted Q */
218782beb602SGarrett D'Amore 		arcmsr_done4abort_postqueue(acb);
218882beb602SGarrett D'Amore 		/* talk to iop 331 outstanding command aborted */
218982beb602SGarrett D'Amore 		(void) arcmsr_abort_host_command(acb);
219082beb602SGarrett D'Amore 
219182beb602SGarrett D'Amore 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
219282beb602SGarrett D'Amore 			ccb = acb->pccb_pool[i];
219382beb602SGarrett D'Amore 			if (ccb->ccb_state == ARCMSR_CCB_START) {
219482beb602SGarrett D'Amore 				/*
219582beb602SGarrett D'Amore 				 * this ccb will complete at
219682beb602SGarrett D'Amore 				 * hwinterrupt
219782beb602SGarrett D'Amore 				 */
219882beb602SGarrett D'Amore 				/* ccb->ccb_state = ARCMSR_CCB_ABORTED; */
219982beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_ABORTED;
220082beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
220182beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 1);
220282beb602SGarrett D'Amore 			}
220382beb602SGarrett D'Amore 		}
220482beb602SGarrett D'Amore 		/*
220582beb602SGarrett D'Amore 		 * enable outbound Post Queue, outbound
220682beb602SGarrett D'Amore 		 * doorbell Interrupt
220782beb602SGarrett D'Amore 		 */
220882beb602SGarrett D'Amore 		arcmsr_enable_allintr(acb, intmask_org);
220982beb602SGarrett D'Amore 	}
221082beb602SGarrett D'Amore 	return (DDI_SUCCESS);
221182beb602SGarrett D'Amore }
221282beb602SGarrett D'Amore 
221382beb602SGarrett D'Amore 
221482beb602SGarrett D'Amore /*
221582beb602SGarrett D'Amore  * Autoconfiguration support
221682beb602SGarrett D'Amore  */
221782beb602SGarrett D'Amore static int
arcmsr_parse_devname(char * devnm,int * tgt,int * lun)2218d5ebc493SDan Cross arcmsr_parse_devname(char *devnm, int *tgt, int *lun)
2219d5ebc493SDan Cross {
222082beb602SGarrett D'Amore 	char devbuf[SCSI_MAXNAMELEN];
222182beb602SGarrett D'Amore 	char *addr;
222282beb602SGarrett D'Amore 	char *p,  *tp, *lp;
222382beb602SGarrett D'Amore 	long num;
222482beb602SGarrett D'Amore 
222582beb602SGarrett D'Amore 	/* Parse dev name and address */
222682beb602SGarrett D'Amore 	(void) strlcpy(devbuf, devnm, sizeof (devbuf));
222782beb602SGarrett D'Amore 	addr = "";
222882beb602SGarrett D'Amore 	for (p = devbuf; *p != '\0'; p++) {
222982beb602SGarrett D'Amore 		if (*p == '@') {
223082beb602SGarrett D'Amore 			addr = p + 1;
223182beb602SGarrett D'Amore 			*p = '\0';
223282beb602SGarrett D'Amore 		} else if (*p == ':') {
223382beb602SGarrett D'Amore 			*p = '\0';
223482beb602SGarrett D'Amore 			break;
223582beb602SGarrett D'Amore 		}
223682beb602SGarrett D'Amore 	}
223782beb602SGarrett D'Amore 
223882beb602SGarrett D'Amore 	/* Parse target and lun */
223982beb602SGarrett D'Amore 	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
224082beb602SGarrett D'Amore 		if (*p == ',') {
224182beb602SGarrett D'Amore 			lp = p + 1;
224282beb602SGarrett D'Amore 			*p = '\0';
224382beb602SGarrett D'Amore 			break;
224482beb602SGarrett D'Amore 		}
224582beb602SGarrett D'Amore 	}
224682beb602SGarrett D'Amore 	if ((tgt != NULL) && (tp != NULL)) {
224782beb602SGarrett D'Amore 		if (ddi_strtol(tp, NULL, 0x10, &num) != 0)
224882beb602SGarrett D'Amore 			return (-1);
224982beb602SGarrett D'Amore 		*tgt = (int)num;
225082beb602SGarrett D'Amore 	}
225182beb602SGarrett D'Amore 	if ((lun != NULL) && (lp != NULL)) {
225282beb602SGarrett D'Amore 		if (ddi_strtol(lp, NULL, 0x10, &num) != 0)
225382beb602SGarrett D'Amore 			return (-1);
225482beb602SGarrett D'Amore 		*lun = (int)num;
225582beb602SGarrett D'Amore 	}
225682beb602SGarrett D'Amore 	return (0);
225782beb602SGarrett D'Amore }
225882beb602SGarrett D'Amore 
225982beb602SGarrett D'Amore static int
arcmsr_name_node(dev_info_t * dip,char * name,int len)226082beb602SGarrett D'Amore arcmsr_name_node(dev_info_t *dip, char *name, int len)
226182beb602SGarrett D'Amore {
226282beb602SGarrett D'Amore 	int tgt, lun;
226382beb602SGarrett D'Amore 
226482beb602SGarrett D'Amore 	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "target",
226582beb602SGarrett D'Amore 	    -1);
226682beb602SGarrett D'Amore 	if (tgt == -1)
226782beb602SGarrett D'Amore 		return (DDI_FAILURE);
226882beb602SGarrett D'Amore 	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "lun",
226982beb602SGarrett D'Amore 	    -1);
227082beb602SGarrett D'Amore 	if (lun == -1)
227182beb602SGarrett D'Amore 		return (DDI_FAILURE);
227282beb602SGarrett D'Amore 	(void) snprintf(name, len, "%x,%x", tgt, lun);
227382beb602SGarrett D'Amore 	return (DDI_SUCCESS);
227482beb602SGarrett D'Amore }
227582beb602SGarrett D'Amore 
227682beb602SGarrett D'Amore static dev_info_t *
arcmsr_find_child(struct ACB * acb,uint16_t tgt,uint8_t lun)227782beb602SGarrett D'Amore arcmsr_find_child(struct ACB *acb, uint16_t tgt, uint8_t lun)
227882beb602SGarrett D'Amore {
227982beb602SGarrett D'Amore 	dev_info_t *child = NULL;
228082beb602SGarrett D'Amore 	char addr[SCSI_MAXNAMELEN];
228182beb602SGarrett D'Amore 	char tmp[SCSI_MAXNAMELEN];
228282beb602SGarrett D'Amore 
228382beb602SGarrett D'Amore 	(void) sprintf(addr, "%x,%x", tgt, lun);
228482beb602SGarrett D'Amore 
228582beb602SGarrett D'Amore 	for (child = ddi_get_child(acb->dev_info);
228682beb602SGarrett D'Amore 	    child;
228782beb602SGarrett D'Amore 	    child = ddi_get_next_sibling(child)) {
228882beb602SGarrett D'Amore 		/* We don't care about non-persistent node */
228982beb602SGarrett D'Amore 		if (ndi_dev_is_persistent_node(child) == 0)
229082beb602SGarrett D'Amore 			continue;
229182beb602SGarrett D'Amore 		if (arcmsr_name_node(child, tmp, SCSI_MAXNAMELEN) !=
229282beb602SGarrett D'Amore 		    DDI_SUCCESS)
229382beb602SGarrett D'Amore 			continue;
229482beb602SGarrett D'Amore 		if (strcmp(addr, tmp) == 0)
229582beb602SGarrett D'Amore 			break;
229682beb602SGarrett D'Amore 	}
229782beb602SGarrett D'Amore 	return (child);
229882beb602SGarrett D'Amore }
229982beb602SGarrett D'Amore 
230082beb602SGarrett D'Amore static int
arcmsr_config_child(struct ACB * acb,struct scsi_device * sd,dev_info_t ** dipp)230182beb602SGarrett D'Amore arcmsr_config_child(struct ACB *acb, struct scsi_device *sd, dev_info_t **dipp)
230282beb602SGarrett D'Amore {
230382beb602SGarrett D'Amore 	char *nodename = NULL;
230482beb602SGarrett D'Amore 	char **compatible = NULL;
230582beb602SGarrett D'Amore 	int ncompatible = 0;
230682beb602SGarrett D'Amore 	dev_info_t *ldip = NULL;
230782beb602SGarrett D'Amore 	int tgt = sd->sd_address.a_target;
230882beb602SGarrett D'Amore 	int lun = sd->sd_address.a_lun;
230982beb602SGarrett D'Amore 	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
231082beb602SGarrett D'Amore 	int rval;
231182beb602SGarrett D'Amore 
231282beb602SGarrett D'Amore 	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
231382beb602SGarrett D'Amore 	    NULL, &nodename, &compatible, &ncompatible);
231482beb602SGarrett D'Amore 	if (nodename == NULL) {
231582beb602SGarrett D'Amore 		arcmsr_warn(acb, "found no comptible driver for T%dL%d",
231682beb602SGarrett D'Amore 		    tgt, lun);
231782beb602SGarrett D'Amore 		rval = NDI_FAILURE;
231882beb602SGarrett D'Amore 		goto finish;
231982beb602SGarrett D'Amore 	}
232082beb602SGarrett D'Amore 	/* Create dev node */
232182beb602SGarrett D'Amore 	rval = ndi_devi_alloc(acb->dev_info, nodename, DEVI_SID_NODEID, &ldip);
232282beb602SGarrett D'Amore 	if (rval == NDI_SUCCESS) {
232382beb602SGarrett D'Amore 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt) !=
232482beb602SGarrett D'Amore 		    DDI_PROP_SUCCESS) {
232582beb602SGarrett D'Amore 			arcmsr_warn(acb,
232682beb602SGarrett D'Amore 			    "unable to create target property for T%dL%d",
232782beb602SGarrett D'Amore 			    tgt, lun);
232882beb602SGarrett D'Amore 			rval = NDI_FAILURE;
232982beb602SGarrett D'Amore 			goto finish;
233082beb602SGarrett D'Amore 		}
233182beb602SGarrett D'Amore 		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun) !=
233282beb602SGarrett D'Amore 		    DDI_PROP_SUCCESS) {
233382beb602SGarrett D'Amore 			arcmsr_warn(acb,
233482beb602SGarrett D'Amore 			    "unable to create lun property for T%dL%d",
233582beb602SGarrett D'Amore 			    tgt, lun);
233682beb602SGarrett D'Amore 			rval = NDI_FAILURE;
233782beb602SGarrett D'Amore 			goto finish;
233882beb602SGarrett D'Amore 		}
233982beb602SGarrett D'Amore 		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
234082beb602SGarrett D'Amore 		    "compatible", compatible, ncompatible) !=
234182beb602SGarrett D'Amore 		    DDI_PROP_SUCCESS) {
234282beb602SGarrett D'Amore 			arcmsr_warn(acb,
234382beb602SGarrett D'Amore 			    "unable to create compatible property for T%dL%d",
234482beb602SGarrett D'Amore 			    tgt, lun);
234582beb602SGarrett D'Amore 			rval = NDI_FAILURE;
234682beb602SGarrett D'Amore 			goto finish;
234782beb602SGarrett D'Amore 		}
234882beb602SGarrett D'Amore 		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
234982beb602SGarrett D'Amore 		if (rval != NDI_SUCCESS) {
235082beb602SGarrett D'Amore 			arcmsr_warn(acb, "unable to online T%dL%d", tgt, lun);
235182beb602SGarrett D'Amore 			ndi_prop_remove_all(ldip);
235282beb602SGarrett D'Amore 			(void) ndi_devi_free(ldip);
235382beb602SGarrett D'Amore 		} else {
235482beb602SGarrett D'Amore 			arcmsr_log(acb, CE_NOTE, "T%dL%d onlined", tgt, lun);
235582beb602SGarrett D'Amore 		}
235682beb602SGarrett D'Amore 	}
235782beb602SGarrett D'Amore finish:
235882beb602SGarrett D'Amore 	if (dipp)
235982beb602SGarrett D'Amore 		*dipp = ldip;
236082beb602SGarrett D'Amore 
236182beb602SGarrett D'Amore 	scsi_hba_nodename_compatible_free(nodename, compatible);
236282beb602SGarrett D'Amore 	return (rval);
236382beb602SGarrett D'Amore }
236482beb602SGarrett D'Amore 
236582beb602SGarrett D'Amore static int
arcmsr_config_lun(struct ACB * acb,uint16_t tgt,uint8_t lun,dev_info_t ** ldip)236682beb602SGarrett D'Amore arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun, dev_info_t **ldip)
236782beb602SGarrett D'Amore {
236882beb602SGarrett D'Amore 	struct scsi_device sd;
236982beb602SGarrett D'Amore 	dev_info_t *child;
237082beb602SGarrett D'Amore 	int rval;
237182beb602SGarrett D'Amore 
237282beb602SGarrett D'Amore 	if ((child = arcmsr_find_child(acb, tgt, lun)) != NULL) {
237382beb602SGarrett D'Amore 		if (ldip) {
237482beb602SGarrett D'Amore 			*ldip = child;
237582beb602SGarrett D'Amore 		}
237682beb602SGarrett D'Amore 		return (NDI_SUCCESS);
237782beb602SGarrett D'Amore 	}
237882beb602SGarrett D'Amore 	bzero(&sd, sizeof (struct scsi_device));
237982beb602SGarrett D'Amore 	sd.sd_address.a_hba_tran = acb->scsi_hba_transport;
238082beb602SGarrett D'Amore 	sd.sd_address.a_target = tgt;
238182beb602SGarrett D'Amore 	sd.sd_address.a_lun = lun;
238282beb602SGarrett D'Amore 
238382beb602SGarrett D'Amore 	rval = scsi_hba_probe(&sd, NULL);
238482beb602SGarrett D'Amore 	if (rval == SCSIPROBE_EXISTS)
238582beb602SGarrett D'Amore 		rval = arcmsr_config_child(acb, &sd, ldip);
238682beb602SGarrett D'Amore 	scsi_unprobe(&sd);
238782beb602SGarrett D'Amore 	return (rval);
238882beb602SGarrett D'Amore }
238982beb602SGarrett D'Amore 
239082beb602SGarrett D'Amore 
239182beb602SGarrett D'Amore static int
arcmsr_add_intr(struct ACB * acb,int intr_type)239282beb602SGarrett D'Amore arcmsr_add_intr(struct ACB *acb, int intr_type)
239382beb602SGarrett D'Amore {
239482beb602SGarrett D'Amore 	int	rc, count;
239582beb602SGarrett D'Amore 	dev_info_t *dev_info;
239682beb602SGarrett D'Amore 	const char *type_str;
239782beb602SGarrett D'Amore 
239882beb602SGarrett D'Amore 	switch (intr_type) {
239982beb602SGarrett D'Amore 	case DDI_INTR_TYPE_MSI:
240082beb602SGarrett D'Amore 		type_str = "MSI";
240182beb602SGarrett D'Amore 		break;
240282beb602SGarrett D'Amore 	case DDI_INTR_TYPE_MSIX:
240382beb602SGarrett D'Amore 		type_str = "MSIX";
240482beb602SGarrett D'Amore 		break;
240582beb602SGarrett D'Amore 	case DDI_INTR_TYPE_FIXED:
240682beb602SGarrett D'Amore 		type_str = "FIXED";
240782beb602SGarrett D'Amore 		break;
240882beb602SGarrett D'Amore 	default:
240982beb602SGarrett D'Amore 		type_str = "unknown";
241082beb602SGarrett D'Amore 		break;
241182beb602SGarrett D'Amore 	}
241282beb602SGarrett D'Amore 
241382beb602SGarrett D'Amore 	dev_info = acb->dev_info;
241482beb602SGarrett D'Amore 	/* Determine number of supported interrupts */
241582beb602SGarrett D'Amore 	rc = ddi_intr_get_nintrs(dev_info, intr_type, &count);
241682beb602SGarrett D'Amore 	if ((rc != DDI_SUCCESS) || (count == 0)) {
241782beb602SGarrett D'Amore 		arcmsr_warn(acb,
241882beb602SGarrett D'Amore 		    "no interrupts of type %s, rc=0x%x, count=%d",
241982beb602SGarrett D'Amore 		    type_str, rc, count);
242082beb602SGarrett D'Amore 		return (DDI_FAILURE);
242182beb602SGarrett D'Amore 	}
242282beb602SGarrett D'Amore 	acb->intr_size = sizeof (ddi_intr_handle_t) * count;
242382beb602SGarrett D'Amore 	acb->phandle = kmem_zalloc(acb->intr_size, KM_SLEEP);
242482beb602SGarrett D'Amore 	rc = ddi_intr_alloc(dev_info, acb->phandle, intr_type, 0,
242582beb602SGarrett D'Amore 	    count, &acb->intr_count, DDI_INTR_ALLOC_NORMAL);
242682beb602SGarrett D'Amore 	if ((rc != DDI_SUCCESS) || (acb->intr_count == 0)) {
242782beb602SGarrett D'Amore 		arcmsr_warn(acb, "ddi_intr_alloc(%s) failed 0x%x",
242882beb602SGarrett D'Amore 		    type_str, rc);
242982beb602SGarrett D'Amore 		return (DDI_FAILURE);
243082beb602SGarrett D'Amore 	}
243182beb602SGarrett D'Amore 	if (acb->intr_count < count) {
243282beb602SGarrett D'Amore 		arcmsr_log(acb, CE_NOTE, "Got %d interrupts, but requested %d",
243382beb602SGarrett D'Amore 		    acb->intr_count, count);
243482beb602SGarrett D'Amore 	}
243582beb602SGarrett D'Amore 	/*
243682beb602SGarrett D'Amore 	 * Get priority for first msi, assume remaining are all the same
243782beb602SGarrett D'Amore 	 */
243882beb602SGarrett D'Amore 	if (ddi_intr_get_pri(acb->phandle[0], &acb->intr_pri) != DDI_SUCCESS) {
243982beb602SGarrett D'Amore 		arcmsr_warn(acb, "ddi_intr_get_pri failed");
244082beb602SGarrett D'Amore 		return (DDI_FAILURE);
244182beb602SGarrett D'Amore 	}
244282beb602SGarrett D'Amore 	if (acb->intr_pri >= ddi_intr_get_hilevel_pri()) {
244382beb602SGarrett D'Amore 		arcmsr_warn(acb,  "high level interrupt not supported");
244482beb602SGarrett D'Amore 		return (DDI_FAILURE);
244582beb602SGarrett D'Amore 	}
244682beb602SGarrett D'Amore 
244782beb602SGarrett D'Amore 	for (int x = 0; x < acb->intr_count; x++) {
244882beb602SGarrett D'Amore 		if (ddi_intr_add_handler(acb->phandle[x], arcmsr_intr_handler,
244982beb602SGarrett D'Amore 		    (caddr_t)acb, NULL) != DDI_SUCCESS) {
245082beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_intr_add_handler(%s) failed",
245182beb602SGarrett D'Amore 			    type_str);
245282beb602SGarrett D'Amore 			return (DDI_FAILURE);
245382beb602SGarrett D'Amore 		}
245482beb602SGarrett D'Amore 	}
245582beb602SGarrett D'Amore 	(void) ddi_intr_get_cap(acb->phandle[0], &acb->intr_cap);
245682beb602SGarrett D'Amore 	if (acb->intr_cap & DDI_INTR_FLAG_BLOCK) {
245782beb602SGarrett D'Amore 		/* Call ddi_intr_block_enable() for MSI */
245882beb602SGarrett D'Amore 		(void) ddi_intr_block_enable(acb->phandle, acb->intr_count);
245982beb602SGarrett D'Amore 	} else {
246082beb602SGarrett D'Amore 		/* Call ddi_intr_enable() for MSI non block enable */
246182beb602SGarrett D'Amore 		for (int x = 0; x < acb->intr_count; x++) {
246282beb602SGarrett D'Amore 			(void) ddi_intr_enable(acb->phandle[x]);
246382beb602SGarrett D'Amore 		}
246482beb602SGarrett D'Amore 	}
246582beb602SGarrett D'Amore 	return (DDI_SUCCESS);
246682beb602SGarrett D'Amore }
246782beb602SGarrett D'Amore 
246882beb602SGarrett D'Amore static void
arcmsr_remove_intr(struct ACB * acb)246982beb602SGarrett D'Amore arcmsr_remove_intr(struct ACB *acb)
247082beb602SGarrett D'Amore {
247182beb602SGarrett D'Amore 	int x;
247282beb602SGarrett D'Amore 
247382beb602SGarrett D'Amore 	if (acb->phandle == NULL)
247482beb602SGarrett D'Amore 		return;
247582beb602SGarrett D'Amore 
247682beb602SGarrett D'Amore 	/* Disable all interrupts */
247782beb602SGarrett D'Amore 	if (acb->intr_cap & DDI_INTR_FLAG_BLOCK) {
247882beb602SGarrett D'Amore 		/* Call ddi_intr_block_disable() */
247982beb602SGarrett D'Amore 		(void) ddi_intr_block_disable(acb->phandle, acb->intr_count);
248082beb602SGarrett D'Amore 	} else {
248182beb602SGarrett D'Amore 		for (x = 0; x < acb->intr_count; x++) {
248282beb602SGarrett D'Amore 			(void) ddi_intr_disable(acb->phandle[x]);
248382beb602SGarrett D'Amore 		}
248482beb602SGarrett D'Amore 	}
248582beb602SGarrett D'Amore 	/* Call ddi_intr_remove_handler() */
248682beb602SGarrett D'Amore 	for (x = 0; x < acb->intr_count; x++) {
248782beb602SGarrett D'Amore 		(void) ddi_intr_remove_handler(acb->phandle[x]);
248882beb602SGarrett D'Amore 		(void) ddi_intr_free(acb->phandle[x]);
248982beb602SGarrett D'Amore 	}
249082beb602SGarrett D'Amore 	kmem_free(acb->phandle, acb->intr_size);
249182beb602SGarrett D'Amore 	acb->phandle = NULL;
249282beb602SGarrett D'Amore }
249382beb602SGarrett D'Amore 
249482beb602SGarrett D'Amore static void
arcmsr_mutex_init(struct ACB * acb)249582beb602SGarrett D'Amore arcmsr_mutex_init(struct ACB *acb)
249682beb602SGarrett D'Amore {
249782beb602SGarrett D'Amore 	mutex_init(&acb->isr_mutex, NULL, MUTEX_DRIVER, NULL);
249882beb602SGarrett D'Amore 	mutex_init(&acb->acb_mutex, NULL, MUTEX_DRIVER, NULL);
249982beb602SGarrett D'Amore 	mutex_init(&acb->postq_mutex, NULL, MUTEX_DRIVER, NULL);
250082beb602SGarrett D'Amore 	mutex_init(&acb->workingQ_mutex, NULL, MUTEX_DRIVER, NULL);
250182beb602SGarrett D'Amore 	mutex_init(&acb->ioctl_mutex, NULL, MUTEX_DRIVER, NULL);
250282beb602SGarrett D'Amore }
250382beb602SGarrett D'Amore 
250482beb602SGarrett D'Amore static void
arcmsr_mutex_destroy(struct ACB * acb)250582beb602SGarrett D'Amore arcmsr_mutex_destroy(struct ACB *acb)
250682beb602SGarrett D'Amore {
250782beb602SGarrett D'Amore 	mutex_destroy(&acb->isr_mutex);
250882beb602SGarrett D'Amore 	mutex_destroy(&acb->acb_mutex);
250982beb602SGarrett D'Amore 	mutex_destroy(&acb->postq_mutex);
251082beb602SGarrett D'Amore 	mutex_destroy(&acb->workingQ_mutex);
251182beb602SGarrett D'Amore 	mutex_destroy(&acb->ioctl_mutex);
251282beb602SGarrett D'Amore }
251382beb602SGarrett D'Amore 
251482beb602SGarrett D'Amore static int
arcmsr_initialize(struct ACB * acb)251582beb602SGarrett D'Amore arcmsr_initialize(struct ACB *acb)
251682beb602SGarrett D'Amore {
251782beb602SGarrett D'Amore 	struct CCB *pccb_tmp;
251882beb602SGarrett D'Amore 	size_t allocated_length;
251982beb602SGarrett D'Amore 	uint16_t wval;
252082beb602SGarrett D'Amore 	uint_t intmask_org, count;
252182beb602SGarrett D'Amore 	caddr_t	arcmsr_ccbs_area;
252282beb602SGarrett D'Amore 	uint32_t wlval, cdb_phyaddr, offset, realccb_size;
252382beb602SGarrett D'Amore 	int32_t dma_sync_size;
252482beb602SGarrett D'Amore 	int i, id, lun, instance;
252582beb602SGarrett D'Amore 
252682beb602SGarrett D'Amore 	instance = ddi_get_instance(acb->dev_info);
252782beb602SGarrett D'Amore 	wlval = pci_config_get32(acb->pci_acc_handle, 0);
252882beb602SGarrett D'Amore 	wval = (uint16_t)((wlval >> 16) & 0xffff);
252982beb602SGarrett D'Amore 	realccb_size = P2ROUNDUP(sizeof (struct CCB), 32);
253082beb602SGarrett D'Amore 	switch (wval) {
253182beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1880:
25327d14b8f2SRobert Mustacchi 	case PCI_DEVICE_ID_ARECA_1882:
253382beb602SGarrett D'Amore 	{
253482beb602SGarrett D'Amore 		uint32_t *iop_mu_regs_map0;
253582beb602SGarrett D'Amore 
253682beb602SGarrett D'Amore 		acb->adapter_type = ACB_ADAPTER_TYPE_C; /* lsi */
253782beb602SGarrett D'Amore 		dma_sync_size = ARCMSR_MAX_FREECCB_NUM * realccb_size + 0x20;
253882beb602SGarrett D'Amore 		if (ddi_regs_map_setup(acb->dev_info, 2,
253982beb602SGarrett D'Amore 		    (caddr_t *)&iop_mu_regs_map0, 0,
254082beb602SGarrett D'Amore 		    sizeof (struct HBC_msgUnit), &acb->dev_acc_attr,
254182beb602SGarrett D'Amore 		    &acb->reg_mu_acc_handle0) != DDI_SUCCESS) {
254282beb602SGarrett D'Amore 			arcmsr_warn(acb, "unable to map registers");
254382beb602SGarrett D'Amore 			return (DDI_FAILURE);
254482beb602SGarrett D'Amore 		}
254582beb602SGarrett D'Amore 
254682beb602SGarrett D'Amore 		if ((i = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_ccb_attr,
254782beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, &acb->ccbs_pool_handle)) !=
254882beb602SGarrett D'Amore 		    DDI_SUCCESS) {
254982beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
255082beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_alloc_handle failed");
255182beb602SGarrett D'Amore 			return (DDI_FAILURE);
255282beb602SGarrett D'Amore 		}
255382beb602SGarrett D'Amore 
255482beb602SGarrett D'Amore 		if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size,
255582beb602SGarrett D'Amore 		    &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
255682beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area,
255782beb602SGarrett D'Amore 		    &allocated_length, &acb->ccbs_acc_handle) != DDI_SUCCESS) {
255882beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_mem_alloc failed");
255982beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
256082beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
256182beb602SGarrett D'Amore 			return (DDI_FAILURE);
256282beb602SGarrett D'Amore 		}
256382beb602SGarrett D'Amore 
256482beb602SGarrett D'Amore 		if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL,
256582beb602SGarrett D'Amore 		    (caddr_t)arcmsr_ccbs_area, dma_sync_size, DDI_DMA_RDWR |
256682beb602SGarrett D'Amore 		    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &acb->ccb_cookie,
256782beb602SGarrett D'Amore 		    &count) != DDI_DMA_MAPPED) {
256882beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_addr_bind_handle failed");
256982beb602SGarrett D'Amore 			ddi_dma_mem_free(&acb->ccbs_acc_handle);
257082beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
257182beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
257282beb602SGarrett D'Amore 			return (DDI_FAILURE);
257382beb602SGarrett D'Amore 		}
257482beb602SGarrett D'Amore 		bzero(arcmsr_ccbs_area, dma_sync_size);
257582beb602SGarrett D'Amore 		offset = (uint32_t)(P2ROUNDUP(PtrToNum(arcmsr_ccbs_area), 32)
257682beb602SGarrett D'Amore 		    - PtrToNum(arcmsr_ccbs_area));
257782beb602SGarrett D'Amore 		arcmsr_ccbs_area = arcmsr_ccbs_area + offset;
257882beb602SGarrett D'Amore 		/* ioport base */
257982beb602SGarrett D'Amore 		acb->pmu = (struct msgUnit *)(intptr_t)iop_mu_regs_map0;
258082beb602SGarrett D'Amore 		break;
258182beb602SGarrett D'Amore 	}
258282beb602SGarrett D'Amore 
258382beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1201:
258482beb602SGarrett D'Amore 	{
258582beb602SGarrett D'Amore 		uint32_t *iop_mu_regs_map0;
258682beb602SGarrett D'Amore 		uint32_t *iop_mu_regs_map1;
258782beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
258882beb602SGarrett D'Amore 
258982beb602SGarrett D'Amore 		acb->adapter_type = ACB_ADAPTER_TYPE_B; /* marvell */
259082beb602SGarrett D'Amore 		dma_sync_size =
259182beb602SGarrett D'Amore 		    (ARCMSR_MAX_FREECCB_NUM * realccb_size + 0x20) +
259282beb602SGarrett D'Amore 		    sizeof (struct HBB_msgUnit);
259382beb602SGarrett D'Amore 		/* Allocate memory for the ccb */
259482beb602SGarrett D'Amore 		if ((i = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_ccb_attr,
259582beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, &acb->ccbs_pool_handle)) !=
259682beb602SGarrett D'Amore 		    DDI_SUCCESS) {
259782beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_alloc_handle failed");
259882beb602SGarrett D'Amore 			return (DDI_FAILURE);
259982beb602SGarrett D'Amore 		}
260082beb602SGarrett D'Amore 
260182beb602SGarrett D'Amore 		if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size,
260282beb602SGarrett D'Amore 		    &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
260382beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area,
260482beb602SGarrett D'Amore 		    &allocated_length, &acb->ccbs_acc_handle) != DDI_SUCCESS) {
260582beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_mem_alloc failed");
260682beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
260782beb602SGarrett D'Amore 			return (DDI_FAILURE);
260882beb602SGarrett D'Amore 		}
260982beb602SGarrett D'Amore 
261082beb602SGarrett D'Amore 		if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL,
261182beb602SGarrett D'Amore 		    (caddr_t)arcmsr_ccbs_area, dma_sync_size,
261282beb602SGarrett D'Amore 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
261382beb602SGarrett D'Amore 		    NULL, &acb->ccb_cookie, &count) != DDI_DMA_MAPPED) {
261482beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_addr_bind_handle failed");
261582beb602SGarrett D'Amore 			ddi_dma_mem_free(&acb->ccbs_acc_handle);
261682beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
261782beb602SGarrett D'Amore 			return (DDI_FAILURE);
261882beb602SGarrett D'Amore 		}
261982beb602SGarrett D'Amore 		bzero(arcmsr_ccbs_area, dma_sync_size);
262082beb602SGarrett D'Amore 		offset = (uint32_t)(P2ROUNDUP(PtrToNum(arcmsr_ccbs_area), 32)
262182beb602SGarrett D'Amore 		    - PtrToNum(arcmsr_ccbs_area));
262282beb602SGarrett D'Amore 		arcmsr_ccbs_area = arcmsr_ccbs_area + offset;
262382beb602SGarrett D'Amore 		acb->pmu = (struct msgUnit *)
262482beb602SGarrett D'Amore 		    NumToPtr(PtrToNum(arcmsr_ccbs_area) +
262582beb602SGarrett D'Amore 		    (realccb_size*ARCMSR_MAX_FREECCB_NUM));
262682beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
262782beb602SGarrett D'Amore 
262882beb602SGarrett D'Amore 		/* setup device register */
262982beb602SGarrett D'Amore 		if (ddi_regs_map_setup(acb->dev_info, 1,
263082beb602SGarrett D'Amore 		    (caddr_t *)&iop_mu_regs_map0, 0,
263182beb602SGarrett D'Amore 		    sizeof (struct HBB_DOORBELL), &acb->dev_acc_attr,
263282beb602SGarrett D'Amore 		    &acb->reg_mu_acc_handle0) != DDI_SUCCESS) {
263382beb602SGarrett D'Amore 			arcmsr_warn(acb, "unable to map base0 registers");
263482beb602SGarrett D'Amore 			(void) ddi_dma_unbind_handle(acb->ccbs_pool_handle);
263582beb602SGarrett D'Amore 			ddi_dma_mem_free(&acb->ccbs_acc_handle);
263682beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
263782beb602SGarrett D'Amore 			return (DDI_FAILURE);
263882beb602SGarrett D'Amore 		}
263982beb602SGarrett D'Amore 
264082beb602SGarrett D'Amore 		/* ARCMSR_DRV2IOP_DOORBELL */
264182beb602SGarrett D'Amore 		phbbmu->hbb_doorbell = (struct HBB_DOORBELL *)iop_mu_regs_map0;
264282beb602SGarrett D'Amore 		if (ddi_regs_map_setup(acb->dev_info, 2,
264382beb602SGarrett D'Amore 		    (caddr_t *)&iop_mu_regs_map1, 0,
264482beb602SGarrett D'Amore 		    sizeof (struct HBB_RWBUFFER), &acb->dev_acc_attr,
264582beb602SGarrett D'Amore 		    &acb->reg_mu_acc_handle1) != DDI_SUCCESS) {
264682beb602SGarrett D'Amore 			arcmsr_warn(acb, "unable to map base1 registers");
264782beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
264882beb602SGarrett D'Amore 			(void) ddi_dma_unbind_handle(acb->ccbs_pool_handle);
264982beb602SGarrett D'Amore 			ddi_dma_mem_free(&acb->ccbs_acc_handle);
265082beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
265182beb602SGarrett D'Amore 			return (DDI_FAILURE);
265282beb602SGarrett D'Amore 		}
265382beb602SGarrett D'Amore 
265482beb602SGarrett D'Amore 		/* ARCMSR_MSGCODE_RWBUFFER */
265582beb602SGarrett D'Amore 		phbbmu->hbb_rwbuffer = (struct HBB_RWBUFFER *)iop_mu_regs_map1;
265682beb602SGarrett D'Amore 		break;
265782beb602SGarrett D'Amore 	}
265882beb602SGarrett D'Amore 
265982beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1110:
266082beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1120:
266182beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1130:
266282beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1160:
266382beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1170:
266482beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1210:
266582beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1220:
266682beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1230:
266782beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1231:
266882beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1260:
266982beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1261:
267082beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1270:
267182beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1280:
267282beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1212:
267382beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1222:
267482beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1380:
267582beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1381:
267682beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1680:
267782beb602SGarrett D'Amore 	case	PCI_DEVICE_ID_ARECA_1681:
267882beb602SGarrett D'Amore 	{
267982beb602SGarrett D'Amore 		uint32_t *iop_mu_regs_map0;
268082beb602SGarrett D'Amore 
268182beb602SGarrett D'Amore 		acb->adapter_type = ACB_ADAPTER_TYPE_A; /* intel */
268282beb602SGarrett D'Amore 		dma_sync_size = ARCMSR_MAX_FREECCB_NUM * realccb_size + 0x20;
268382beb602SGarrett D'Amore 		if (ddi_regs_map_setup(acb->dev_info, 1,
268482beb602SGarrett D'Amore 		    (caddr_t *)&iop_mu_regs_map0, 0,
268582beb602SGarrett D'Amore 		    sizeof (struct HBA_msgUnit), &acb->dev_acc_attr,
268682beb602SGarrett D'Amore 		    &acb->reg_mu_acc_handle0) != DDI_SUCCESS) {
268782beb602SGarrett D'Amore 			arcmsr_warn(acb, "unable to map registers");
268882beb602SGarrett D'Amore 			return (DDI_FAILURE);
268982beb602SGarrett D'Amore 		}
269082beb602SGarrett D'Amore 
269182beb602SGarrett D'Amore 		if ((i = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_ccb_attr,
269282beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, &acb->ccbs_pool_handle)) !=
269382beb602SGarrett D'Amore 		    DDI_SUCCESS) {
269482beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_alloc_handle failed");
269582beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
269682beb602SGarrett D'Amore 			return (DDI_FAILURE);
269782beb602SGarrett D'Amore 		}
269882beb602SGarrett D'Amore 
269982beb602SGarrett D'Amore 		if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size,
270082beb602SGarrett D'Amore 		    &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
270182beb602SGarrett D'Amore 		    DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area,
270282beb602SGarrett D'Amore 		    &allocated_length, &acb->ccbs_acc_handle) != DDI_SUCCESS) {
270382beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_mem_alloc failed", instance);
270482beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
270582beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
270682beb602SGarrett D'Amore 			return (DDI_FAILURE);
270782beb602SGarrett D'Amore 		}
270882beb602SGarrett D'Amore 
270982beb602SGarrett D'Amore 		if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL,
271082beb602SGarrett D'Amore 		    (caddr_t)arcmsr_ccbs_area, dma_sync_size, DDI_DMA_RDWR |
271182beb602SGarrett D'Amore 		    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &acb->ccb_cookie,
271282beb602SGarrett D'Amore 		    &count) != DDI_DMA_MAPPED) {
271382beb602SGarrett D'Amore 			arcmsr_warn(acb, "ddi_dma_addr_bind_handle failed");
271482beb602SGarrett D'Amore 			ddi_dma_mem_free(&acb->ccbs_acc_handle);
271582beb602SGarrett D'Amore 			ddi_dma_free_handle(&acb->ccbs_pool_handle);
271682beb602SGarrett D'Amore 			ddi_regs_map_free(&acb->reg_mu_acc_handle0);
271782beb602SGarrett D'Amore 			return (DDI_FAILURE);
271882beb602SGarrett D'Amore 		}
271982beb602SGarrett D'Amore 		bzero(arcmsr_ccbs_area, dma_sync_size);
272082beb602SGarrett D'Amore 		offset = (uint32_t)(P2ROUNDUP(PtrToNum(arcmsr_ccbs_area), 32)
272182beb602SGarrett D'Amore 		    - PtrToNum(arcmsr_ccbs_area));
272282beb602SGarrett D'Amore 		arcmsr_ccbs_area = arcmsr_ccbs_area + offset;
272382beb602SGarrett D'Amore 		/* ioport base */
272482beb602SGarrett D'Amore 		acb->pmu = (struct msgUnit *)(intptr_t)iop_mu_regs_map0;
272582beb602SGarrett D'Amore 		break;
272682beb602SGarrett D'Amore 	}
272782beb602SGarrett D'Amore 
272882beb602SGarrett D'Amore 	default:
272982beb602SGarrett D'Amore 		arcmsr_warn(acb, "Unknown RAID adapter type!");
273082beb602SGarrett D'Amore 		return (DDI_FAILURE);
273182beb602SGarrett D'Amore 	}
273282beb602SGarrett D'Amore 	arcmsr_init_list_head(&acb->ccb_complete_list);
273382beb602SGarrett D'Amore 	/* here we can not access pci configuration again */
273482beb602SGarrett D'Amore 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
273582beb602SGarrett D'Amore 	    ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READ);
273682beb602SGarrett D'Amore 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
273782beb602SGarrett D'Amore 	/* physical address of acb->pccb_pool */
273882beb602SGarrett D'Amore 	cdb_phyaddr = acb->ccb_cookie.dmac_address + offset;
273982beb602SGarrett D'Amore 
274082beb602SGarrett D'Amore 	pccb_tmp = (struct CCB *)(intptr_t)arcmsr_ccbs_area;
274182beb602SGarrett D'Amore 
274282beb602SGarrett D'Amore 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
274382beb602SGarrett D'Amore 		pccb_tmp->cdb_phyaddr_pattern =
274482beb602SGarrett D'Amore 		    (acb->adapter_type == ACB_ADAPTER_TYPE_C) ?
274582beb602SGarrett D'Amore 		    cdb_phyaddr : (cdb_phyaddr >> 5);
274682beb602SGarrett D'Amore 		pccb_tmp->acb = acb;
274782beb602SGarrett D'Amore 		acb->ccbworkingQ[i] = acb->pccb_pool[i] = pccb_tmp;
274882beb602SGarrett D'Amore 		cdb_phyaddr = cdb_phyaddr + realccb_size;
274982beb602SGarrett D'Amore 		pccb_tmp = (struct CCB *)NumToPtr(PtrToNum(pccb_tmp) +
275082beb602SGarrett D'Amore 		    realccb_size);
275182beb602SGarrett D'Amore 	}
275282beb602SGarrett D'Amore 	acb->vir2phy_offset = PtrToNum(pccb_tmp) - cdb_phyaddr;
275382beb602SGarrett D'Amore 
275482beb602SGarrett D'Amore 	/* disable all outbound interrupt */
275582beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
275682beb602SGarrett D'Amore 
275782beb602SGarrett D'Amore 	if (!arcmsr_iop_confirm(acb)) {
275882beb602SGarrett D'Amore 		arcmsr_warn(acb, "arcmsr_iop_confirm error", instance);
275982beb602SGarrett D'Amore 		ddi_dma_mem_free(&acb->ccbs_acc_handle);
276082beb602SGarrett D'Amore 		ddi_dma_free_handle(&acb->ccbs_pool_handle);
276182beb602SGarrett D'Amore 		return (DDI_FAILURE);
276282beb602SGarrett D'Amore 	}
276382beb602SGarrett D'Amore 
276482beb602SGarrett D'Amore 	for (id = 0; id < ARCMSR_MAX_TARGETID; id++) {
276582beb602SGarrett D'Amore 		for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
276682beb602SGarrett D'Amore 			acb->devstate[id][lun] = ARECA_RAID_GONE;
276782beb602SGarrett D'Amore 		}
276882beb602SGarrett D'Amore 	}
276982beb602SGarrett D'Amore 
277082beb602SGarrett D'Amore 	/* enable outbound Post Queue, outbound doorbell Interrupt */
277182beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
277282beb602SGarrett D'Amore 
277382beb602SGarrett D'Amore 	return (0);
277482beb602SGarrett D'Amore }
277582beb602SGarrett D'Amore 
277682beb602SGarrett D'Amore static int
arcmsr_do_ddi_attach(dev_info_t * dev_info,int instance)277782beb602SGarrett D'Amore arcmsr_do_ddi_attach(dev_info_t *dev_info, int instance)
277882beb602SGarrett D'Amore {
277982beb602SGarrett D'Amore 	scsi_hba_tran_t *hba_trans;
278082beb602SGarrett D'Amore 	ddi_device_acc_attr_t dev_acc_attr;
278182beb602SGarrett D'Amore 	struct ACB *acb;
278282beb602SGarrett D'Amore 	uint16_t wval;
278382beb602SGarrett D'Amore 	int raid6 = 1;
278482beb602SGarrett D'Amore 	char *type;
278582beb602SGarrett D'Amore 	int intr_types;
278682beb602SGarrett D'Amore 
278782beb602SGarrett D'Amore 
278882beb602SGarrett D'Amore 	/*
278982beb602SGarrett D'Amore 	 * Soft State Structure
279082beb602SGarrett D'Amore 	 * The driver should allocate the per-device-instance
279182beb602SGarrett D'Amore 	 * soft state structure, being careful to clean up properly if
279282beb602SGarrett D'Amore 	 * an error occurs. Allocate data structure.
279382beb602SGarrett D'Amore 	 */
279482beb602SGarrett D'Amore 	if (ddi_soft_state_zalloc(arcmsr_soft_state, instance) != DDI_SUCCESS) {
279582beb602SGarrett D'Amore 		arcmsr_warn(NULL, "ddi_soft_state_zalloc failed");
279682beb602SGarrett D'Amore 		return (DDI_FAILURE);
279782beb602SGarrett D'Amore 	}
279882beb602SGarrett D'Amore 
279982beb602SGarrett D'Amore 	acb = ddi_get_soft_state(arcmsr_soft_state, instance);
280082beb602SGarrett D'Amore 	ASSERT(acb);
280182beb602SGarrett D'Amore 
280282beb602SGarrett D'Amore 	arcmsr_mutex_init(acb);
280382beb602SGarrett D'Amore 
280482beb602SGarrett D'Amore 	/* acb is already zalloc()d so we don't need to bzero() it */
280582beb602SGarrett D'Amore 	dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
280682beb602SGarrett D'Amore 	dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
280782beb602SGarrett D'Amore 	dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
280882beb602SGarrett D'Amore 
280982beb602SGarrett D'Amore 	acb->dev_info = dev_info;
281082beb602SGarrett D'Amore 	acb->dev_acc_attr = dev_acc_attr;
281182beb602SGarrett D'Amore 
281282beb602SGarrett D'Amore 	/*
281382beb602SGarrett D'Amore 	 * The driver, if providing DMA, should also check that its hardware is
281482beb602SGarrett D'Amore 	 * installed in a DMA-capable slot
281582beb602SGarrett D'Amore 	 */
281682beb602SGarrett D'Amore 	if (ddi_slaveonly(dev_info) == DDI_SUCCESS) {
281782beb602SGarrett D'Amore 		arcmsr_warn(acb, "hardware is not installed in"
281882beb602SGarrett D'Amore 		    " a DMA-capable slot");
281982beb602SGarrett D'Amore 		goto error_level_0;
282082beb602SGarrett D'Amore 	}
282182beb602SGarrett D'Amore 	if (pci_config_setup(dev_info, &acb->pci_acc_handle) != DDI_SUCCESS) {
282282beb602SGarrett D'Amore 		arcmsr_warn(acb, "pci_config_setup() failed, attach failed");
282382beb602SGarrett D'Amore 		goto error_level_0;
282482beb602SGarrett D'Amore 	}
282582beb602SGarrett D'Amore 
282682beb602SGarrett D'Amore 	wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_VENID);
282782beb602SGarrett D'Amore 	if (wval != PCI_VENDOR_ID_ARECA) {
282882beb602SGarrett D'Amore 		arcmsr_warn(acb,
282982beb602SGarrett D'Amore 		    "'vendorid (0x%04x) does not match 0x%04x "
283082beb602SGarrett D'Amore 		    "(PCI_VENDOR_ID_ARECA)",
283182beb602SGarrett D'Amore 		    wval, PCI_VENDOR_ID_ARECA);
283282beb602SGarrett D'Amore 		goto error_level_0;
283382beb602SGarrett D'Amore 	}
283482beb602SGarrett D'Amore 
283582beb602SGarrett D'Amore 	wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_DEVID);
283682beb602SGarrett D'Amore 	switch (wval) {
283782beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1110:
283882beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1210:
283982beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1201:
284082beb602SGarrett D'Amore 		raid6 = 0;
284182beb602SGarrett D'Amore 		/*FALLTHRU*/
284282beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1120:
284382beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1130:
284482beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1160:
284582beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1170:
284682beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1220:
284782beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1230:
284882beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1260:
284982beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1270:
285082beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1280:
285182beb602SGarrett D'Amore 		type = "SATA 3G";
285282beb602SGarrett D'Amore 		break;
285382beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1380:
285482beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1381:
285582beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1680:
285682beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1681:
285782beb602SGarrett D'Amore 		type = "SAS 3G";
285882beb602SGarrett D'Amore 		break;
285982beb602SGarrett D'Amore 	case PCI_DEVICE_ID_ARECA_1880:
286082beb602SGarrett D'Amore 		type = "SAS 6G";
286182beb602SGarrett D'Amore 		break;
286282beb602SGarrett D'Amore 	default:
286382beb602SGarrett D'Amore 		type = "X-TYPE";
286482beb602SGarrett D'Amore 		arcmsr_warn(acb, "Unknown Host Adapter RAID Controller!");
286582beb602SGarrett D'Amore 		goto error_level_0;
286682beb602SGarrett D'Amore 	}
286782beb602SGarrett D'Amore 
286882beb602SGarrett D'Amore 	arcmsr_log(acb, CE_CONT, "Areca %s Host Adapter RAID Controller%s\n",
286982beb602SGarrett D'Amore 	    type, raid6 ? " (RAID6 capable)" : "");
287082beb602SGarrett D'Amore 
287182beb602SGarrett D'Amore 	/* we disable iop interrupt here */
287282beb602SGarrett D'Amore 	if (arcmsr_initialize(acb) == DDI_FAILURE) {
287382beb602SGarrett D'Amore 		arcmsr_warn(acb, "arcmsr_initialize failed");
287482beb602SGarrett D'Amore 		goto error_level_1;
287582beb602SGarrett D'Amore 	}
287682beb602SGarrett D'Amore 
287782beb602SGarrett D'Amore 	/* Allocate a transport structure */
287882beb602SGarrett D'Amore 	hba_trans = scsi_hba_tran_alloc(dev_info, SCSI_HBA_CANSLEEP);
287982beb602SGarrett D'Amore 	if (hba_trans == NULL) {
288082beb602SGarrett D'Amore 		arcmsr_warn(acb, "scsi_hba_tran_alloc failed");
288182beb602SGarrett D'Amore 		goto error_level_2;
288282beb602SGarrett D'Amore 	}
288382beb602SGarrett D'Amore 	acb->scsi_hba_transport = hba_trans;
288482beb602SGarrett D'Amore 	acb->dev_info = dev_info;
288582beb602SGarrett D'Amore 	/* init scsi host adapter transport entry */
288682beb602SGarrett D'Amore 	hba_trans->tran_hba_private  = acb;
288782beb602SGarrett D'Amore 	hba_trans->tran_tgt_private  = NULL;
288882beb602SGarrett D'Amore 	/*
288982beb602SGarrett D'Amore 	 * If no per-target initialization is required, the HBA can leave
289082beb602SGarrett D'Amore 	 * tran_tgt_init set to NULL.
289182beb602SGarrett D'Amore 	 */
289282beb602SGarrett D'Amore 	hba_trans->tran_tgt_init = arcmsr_tran_tgt_init;
289382beb602SGarrett D'Amore 	hba_trans->tran_tgt_probe = scsi_hba_probe;
289482beb602SGarrett D'Amore 	hba_trans->tran_tgt_free = NULL;
289582beb602SGarrett D'Amore 	hba_trans->tran_start = arcmsr_tran_start;
289682beb602SGarrett D'Amore 	hba_trans->tran_abort = arcmsr_tran_abort;
289782beb602SGarrett D'Amore 	hba_trans->tran_reset = arcmsr_tran_reset;
289882beb602SGarrett D'Amore 	hba_trans->tran_getcap = arcmsr_tran_getcap;
289982beb602SGarrett D'Amore 	hba_trans->tran_setcap = arcmsr_tran_setcap;
290082beb602SGarrett D'Amore 	hba_trans->tran_init_pkt = arcmsr_tran_init_pkt;
290182beb602SGarrett D'Amore 	hba_trans->tran_destroy_pkt = arcmsr_tran_destroy_pkt;
290282beb602SGarrett D'Amore 	hba_trans->tran_dmafree = arcmsr_tran_dmafree;
290382beb602SGarrett D'Amore 	hba_trans->tran_sync_pkt = arcmsr_tran_sync_pkt;
290482beb602SGarrett D'Amore 
290582beb602SGarrett D'Amore 	hba_trans->tran_reset_notify = NULL;
290682beb602SGarrett D'Amore 	hba_trans->tran_get_bus_addr = NULL;
290782beb602SGarrett D'Amore 	hba_trans->tran_get_name = NULL;
290882beb602SGarrett D'Amore 	hba_trans->tran_quiesce = NULL;
290982beb602SGarrett D'Amore 	hba_trans->tran_unquiesce = NULL;
291082beb602SGarrett D'Amore 	hba_trans->tran_bus_reset = NULL;
291182beb602SGarrett D'Amore 	hba_trans->tran_bus_config = arcmsr_tran_bus_config;
291282beb602SGarrett D'Amore 	hba_trans->tran_add_eventcall = NULL;
291382beb602SGarrett D'Amore 	hba_trans->tran_get_eventcookie = NULL;
291482beb602SGarrett D'Amore 	hba_trans->tran_post_event = NULL;
291582beb602SGarrett D'Amore 	hba_trans->tran_remove_eventcall = NULL;
291682beb602SGarrett D'Amore 
291782beb602SGarrett D'Amore 	/* iop init and enable interrupt here */
291882beb602SGarrett D'Amore 	arcmsr_iop_init(acb);
291982beb602SGarrett D'Amore 
292082beb602SGarrett D'Amore 	/* Get supported interrupt types */
292182beb602SGarrett D'Amore 	if (ddi_intr_get_supported_types(dev_info, &intr_types) !=
292282beb602SGarrett D'Amore 	    DDI_SUCCESS) {
292382beb602SGarrett D'Amore 		arcmsr_warn(acb, "ddi_intr_get_supported_types failed");
292482beb602SGarrett D'Amore 		goto error_level_3;
292582beb602SGarrett D'Amore 	}
292682beb602SGarrett D'Amore 	if (intr_types & DDI_INTR_TYPE_FIXED) {
292782beb602SGarrett D'Amore 		if (arcmsr_add_intr(acb, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS)
292882beb602SGarrett D'Amore 			goto error_level_5;
292982beb602SGarrett D'Amore 	} else if (intr_types & DDI_INTR_TYPE_MSI) {
293082beb602SGarrett D'Amore 		if (arcmsr_add_intr(acb, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS)
293182beb602SGarrett D'Amore 			goto error_level_5;
293282beb602SGarrett D'Amore 	}
293382beb602SGarrett D'Amore 
293482beb602SGarrett D'Amore 	/*
293582beb602SGarrett D'Amore 	 * The driver should attach this instance of the device, and
293682beb602SGarrett D'Amore 	 * perform error cleanup if necessary
293782beb602SGarrett D'Amore 	 */
293882beb602SGarrett D'Amore 	if (scsi_hba_attach_setup(dev_info, &arcmsr_dma_attr,
293982beb602SGarrett D'Amore 	    hba_trans, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
294082beb602SGarrett D'Amore 		arcmsr_warn(acb, "scsi_hba_attach_setup failed");
294182beb602SGarrett D'Amore 		goto error_level_5;
294282beb602SGarrett D'Amore 	}
294382beb602SGarrett D'Amore 
294482beb602SGarrett D'Amore 	/* Create a taskq for dealing with dr events */
294582beb602SGarrett D'Amore 	if ((acb->taskq = ddi_taskq_create(dev_info, "arcmsr_dr_taskq", 1,
294682beb602SGarrett D'Amore 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
294782beb602SGarrett D'Amore 		arcmsr_warn(acb, "ddi_taskq_create failed");
294882beb602SGarrett D'Amore 		goto error_level_8;
2949508aff1aSJames C. McPherson 	}
2950508aff1aSJames C. McPherson 
295182beb602SGarrett D'Amore 	acb->timeout_count = 0;
295282beb602SGarrett D'Amore 	/* active ccbs "timeout" watchdog */
295382beb602SGarrett D'Amore 	acb->timeout_id = timeout(arcmsr_ccbs_timeout, (caddr_t)acb,
295482beb602SGarrett D'Amore 	    (ARCMSR_TIMEOUT_WATCH * drv_usectohz(1000000)));
295582beb602SGarrett D'Amore 	acb->timeout_sc_id = timeout(arcmsr_devMap_monitor, (caddr_t)acb,
295682beb602SGarrett D'Amore 	    (ARCMSR_DEV_MAP_WATCH * drv_usectohz(1000000)));
295782beb602SGarrett D'Amore 
295882beb602SGarrett D'Amore 	/* report device info */
295982beb602SGarrett D'Amore 	ddi_report_dev(dev_info);
2960508aff1aSJames C. McPherson 
2961508aff1aSJames C. McPherson 	return (DDI_SUCCESS);
2962508aff1aSJames C. McPherson 
296382beb602SGarrett D'Amore error_level_8:
2964508aff1aSJames C. McPherson 
296582beb602SGarrett D'Amore error_level_7:
296682beb602SGarrett D'Amore error_level_6:
296782beb602SGarrett D'Amore 	(void) scsi_hba_detach(dev_info);
2968508aff1aSJames C. McPherson 
296982beb602SGarrett D'Amore error_level_5:
297082beb602SGarrett D'Amore 	arcmsr_remove_intr(acb);
2971508aff1aSJames C. McPherson 
297282beb602SGarrett D'Amore error_level_3:
297382beb602SGarrett D'Amore error_level_4:
297482beb602SGarrett D'Amore 	if (acb->scsi_hba_transport)
297582beb602SGarrett D'Amore 		scsi_hba_tran_free(acb->scsi_hba_transport);
297682beb602SGarrett D'Amore 
297782beb602SGarrett D'Amore error_level_2:
297882beb602SGarrett D'Amore 	if (acb->ccbs_acc_handle)
297982beb602SGarrett D'Amore 		ddi_dma_mem_free(&acb->ccbs_acc_handle);
298082beb602SGarrett D'Amore 	if (acb->ccbs_pool_handle)
298182beb602SGarrett D'Amore 		ddi_dma_free_handle(&acb->ccbs_pool_handle);
298282beb602SGarrett D'Amore 
298382beb602SGarrett D'Amore error_level_1:
298482beb602SGarrett D'Amore 	if (acb->pci_acc_handle)
298582beb602SGarrett D'Amore 		pci_config_teardown(&acb->pci_acc_handle);
298682beb602SGarrett D'Amore 	arcmsr_mutex_destroy(acb);
298782beb602SGarrett D'Amore 	ddi_soft_state_free(arcmsr_soft_state, instance);
298882beb602SGarrett D'Amore 
298982beb602SGarrett D'Amore error_level_0:
299082beb602SGarrett D'Amore 	return (DDI_FAILURE);
2991508aff1aSJames C. McPherson }
2992508aff1aSJames C. McPherson 
2993508aff1aSJames C. McPherson 
299482beb602SGarrett D'Amore static void
arcmsr_vlog(struct ACB * acb,int level,char * fmt,va_list ap)299582beb602SGarrett D'Amore arcmsr_vlog(struct ACB *acb, int level, char *fmt, va_list ap)
299682beb602SGarrett D'Amore {
299782beb602SGarrett D'Amore 	char	buf[256];
2998508aff1aSJames C. McPherson 
299982beb602SGarrett D'Amore 	if (acb != NULL) {
300082beb602SGarrett D'Amore 		(void) snprintf(buf, sizeof (buf), "%s%d: %s",
300182beb602SGarrett D'Amore 		    ddi_driver_name(acb->dev_info),
300282beb602SGarrett D'Amore 		    ddi_get_instance(acb->dev_info), fmt);
300382beb602SGarrett D'Amore 		fmt = buf;
3004508aff1aSJames C. McPherson 	}
300582beb602SGarrett D'Amore 	vcmn_err(level, fmt, ap);
3006508aff1aSJames C. McPherson }
3007508aff1aSJames C. McPherson 
3008508aff1aSJames C. McPherson static void
arcmsr_log(struct ACB * acb,int level,char * fmt,...)300982beb602SGarrett D'Amore arcmsr_log(struct ACB *acb, int level, char *fmt, ...)
301082beb602SGarrett D'Amore {
301182beb602SGarrett D'Amore 	va_list ap;
3012508aff1aSJames C. McPherson 
301382beb602SGarrett D'Amore 	va_start(ap, fmt);
301482beb602SGarrett D'Amore 	arcmsr_vlog(acb, level, fmt, ap);
301582beb602SGarrett D'Amore 	va_end(ap);
301682beb602SGarrett D'Amore }
3017508aff1aSJames C. McPherson 
301882beb602SGarrett D'Amore static void
arcmsr_warn(struct ACB * acb,char * fmt,...)301982beb602SGarrett D'Amore arcmsr_warn(struct ACB *acb, char *fmt, ...)
302082beb602SGarrett D'Amore {
302182beb602SGarrett D'Amore 	va_list ap;
3022508aff1aSJames C. McPherson 
302382beb602SGarrett D'Amore 	va_start(ap, fmt);
302482beb602SGarrett D'Amore 	arcmsr_vlog(acb, CE_WARN, fmt, ap);
302582beb602SGarrett D'Amore 	va_end(ap);
3026508aff1aSJames C. McPherson }
3027508aff1aSJames C. McPherson 
302882beb602SGarrett D'Amore static void
arcmsr_init_list_head(struct list_head * list)302982beb602SGarrett D'Amore arcmsr_init_list_head(struct list_head *list)
303082beb602SGarrett D'Amore {
303182beb602SGarrett D'Amore 	list->next = list;
303282beb602SGarrett D'Amore 	list->prev = list;
303382beb602SGarrett D'Amore }
3034508aff1aSJames C. McPherson 
303582beb602SGarrett D'Amore static void
arcmsr_x_list_del(struct list_head * prev,struct list_head * next)303682beb602SGarrett D'Amore arcmsr_x_list_del(struct list_head *prev, struct list_head *next)
303782beb602SGarrett D'Amore {
303882beb602SGarrett D'Amore 	next->prev = prev;
303982beb602SGarrett D'Amore 	prev->next = next;
304082beb602SGarrett D'Amore }
3041508aff1aSJames C. McPherson 
304282beb602SGarrett D'Amore static void
arcmsr_x_list_add(struct list_head * new_one,struct list_head * prev,struct list_head * next)304382beb602SGarrett D'Amore arcmsr_x_list_add(struct list_head *new_one,  struct list_head *prev,
304482beb602SGarrett D'Amore     struct list_head *next)
304582beb602SGarrett D'Amore {
304682beb602SGarrett D'Amore 	next->prev = new_one;
304782beb602SGarrett D'Amore 	new_one->next = next;
304882beb602SGarrett D'Amore 	new_one->prev = prev;
304982beb602SGarrett D'Amore 	prev->next = new_one;
305082beb602SGarrett D'Amore }
3051508aff1aSJames C. McPherson 
305282beb602SGarrett D'Amore static void
arcmsr_list_add_tail(kmutex_t * list_lock,struct list_head * new_one,struct list_head * head)305382beb602SGarrett D'Amore arcmsr_list_add_tail(kmutex_t *list_lock, struct list_head *new_one,
305482beb602SGarrett D'Amore     struct list_head *head)
305582beb602SGarrett D'Amore {
305682beb602SGarrett D'Amore 	mutex_enter(list_lock);
305782beb602SGarrett D'Amore 	arcmsr_x_list_add(new_one, head->prev, head);
305882beb602SGarrett D'Amore 	mutex_exit(list_lock);
305982beb602SGarrett D'Amore }
3060508aff1aSJames C. McPherson 
306182beb602SGarrett D'Amore static struct list_head *
arcmsr_list_get_first(kmutex_t * list_lock,struct list_head * head)306282beb602SGarrett D'Amore arcmsr_list_get_first(kmutex_t *list_lock, struct list_head *head)
306382beb602SGarrett D'Amore {
306482beb602SGarrett D'Amore 	struct list_head *one = NULL;
306582beb602SGarrett D'Amore 
306682beb602SGarrett D'Amore 	mutex_enter(list_lock);
306782beb602SGarrett D'Amore 	if (head->next == head)	{
306882beb602SGarrett D'Amore 		mutex_exit(list_lock);
306982beb602SGarrett D'Amore 		return (NULL);
307082beb602SGarrett D'Amore 	}
307182beb602SGarrett D'Amore 	one = head->next;
307282beb602SGarrett D'Amore 	arcmsr_x_list_del(one->prev, one->next);
307382beb602SGarrett D'Amore 	arcmsr_init_list_head(one);
307482beb602SGarrett D'Amore 	mutex_exit(list_lock);
307582beb602SGarrett D'Amore 	return (one);
307682beb602SGarrett D'Amore }
3077508aff1aSJames C. McPherson 
307882beb602SGarrett D'Amore static struct CCB *
arcmsr_get_complete_ccb_from_list(struct ACB * acb)307982beb602SGarrett D'Amore arcmsr_get_complete_ccb_from_list(struct ACB *acb)
308082beb602SGarrett D'Amore {
308182beb602SGarrett D'Amore 	struct list_head *first_complete_ccb_list = NULL;
308282beb602SGarrett D'Amore 	struct CCB *ccb;
308382beb602SGarrett D'Amore 
308482beb602SGarrett D'Amore 	first_complete_ccb_list =
308582beb602SGarrett D'Amore 	    arcmsr_list_get_first(&acb->ccb_complete_list_mutex,
308682beb602SGarrett D'Amore 	    &acb->ccb_complete_list);
308782beb602SGarrett D'Amore 	if (first_complete_ccb_list == NULL) {
308882beb602SGarrett D'Amore 		return (NULL);
308982beb602SGarrett D'Amore 	}
309082beb602SGarrett D'Amore 	ccb = (void *)((caddr_t)(first_complete_ccb_list) -
309182beb602SGarrett D'Amore 	    offsetof(struct CCB, complete_queue_pointer));
309282beb602SGarrett D'Amore 	return (ccb);
3093508aff1aSJames C. McPherson }
3094508aff1aSJames C. McPherson 
309582beb602SGarrett D'Amore static struct CCB *
arcmsr_get_freeccb(struct ACB * acb)309682beb602SGarrett D'Amore arcmsr_get_freeccb(struct ACB *acb)
309782beb602SGarrett D'Amore {
309882beb602SGarrett D'Amore 	struct CCB *ccb;
309982beb602SGarrett D'Amore 	int ccb_get_index, ccb_put_index;
3100508aff1aSJames C. McPherson 
310182beb602SGarrett D'Amore 	mutex_enter(&acb->workingQ_mutex);
310282beb602SGarrett D'Amore 	ccb_put_index = acb->ccb_put_index;
310382beb602SGarrett D'Amore 	ccb_get_index = acb->ccb_get_index;
310482beb602SGarrett D'Amore 	ccb = acb->ccbworkingQ[ccb_get_index];
310582beb602SGarrett D'Amore 	ccb_get_index++;
310682beb602SGarrett D'Amore 	if (ccb_get_index >= ARCMSR_MAX_FREECCB_NUM)
310782beb602SGarrett D'Amore 		ccb_get_index = ccb_get_index - ARCMSR_MAX_FREECCB_NUM;
310882beb602SGarrett D'Amore 	if (ccb_put_index != ccb_get_index) {
310982beb602SGarrett D'Amore 		acb->ccb_get_index = ccb_get_index;
311082beb602SGarrett D'Amore 		arcmsr_init_list_head(&ccb->complete_queue_pointer);
311182beb602SGarrett D'Amore 		ccb->ccb_state = ARCMSR_CCB_UNBUILD;
311282beb602SGarrett D'Amore 	} else {
311382beb602SGarrett D'Amore 		ccb = NULL;
311482beb602SGarrett D'Amore 	}
311582beb602SGarrett D'Amore 	mutex_exit(&acb->workingQ_mutex);
311682beb602SGarrett D'Amore 	return (ccb);
311782beb602SGarrett D'Amore }
3118508aff1aSJames C. McPherson 
3119508aff1aSJames C. McPherson 
312082beb602SGarrett D'Amore static void
arcmsr_free_ccb(struct CCB * ccb)312182beb602SGarrett D'Amore arcmsr_free_ccb(struct CCB *ccb)
312282beb602SGarrett D'Amore {
312382beb602SGarrett D'Amore 	struct ACB *acb = ccb->acb;
3124508aff1aSJames C. McPherson 
312582beb602SGarrett D'Amore 	if (ccb->ccb_state == ARCMSR_CCB_FREE) {
312682beb602SGarrett D'Amore 		return;
312782beb602SGarrett D'Amore 	}
312882beb602SGarrett D'Amore 	mutex_enter(&acb->workingQ_mutex);
312982beb602SGarrett D'Amore 	ccb->ccb_state = ARCMSR_CCB_FREE;
313082beb602SGarrett D'Amore 	ccb->pkt = NULL;
313182beb602SGarrett D'Amore 	ccb->pkt_dma_handle = NULL;
313282beb602SGarrett D'Amore 	ccb->ccb_flags = 0;
313382beb602SGarrett D'Amore 	acb->ccbworkingQ[acb->ccb_put_index] = ccb;
313482beb602SGarrett D'Amore 	acb->ccb_put_index++;
313582beb602SGarrett D'Amore 	if (acb->ccb_put_index >= ARCMSR_MAX_FREECCB_NUM)
313682beb602SGarrett D'Amore 		acb->ccb_put_index =
313782beb602SGarrett D'Amore 		    acb->ccb_put_index - ARCMSR_MAX_FREECCB_NUM;
313882beb602SGarrett D'Amore 	mutex_exit(&acb->workingQ_mutex);
313982beb602SGarrett D'Amore }
3140508aff1aSJames C. McPherson 
314182beb602SGarrett D'Amore 
314282beb602SGarrett D'Amore static void
arcmsr_ccbs_timeout(void * arg)314382beb602SGarrett D'Amore arcmsr_ccbs_timeout(void* arg)
314482beb602SGarrett D'Amore {
314582beb602SGarrett D'Amore 	struct ACB *acb = (struct ACB *)arg;
314682beb602SGarrett D'Amore 	struct CCB *ccb;
314782beb602SGarrett D'Amore 	int i, instance, timeout_count = 0;
314882beb602SGarrett D'Amore 	uint32_t intmask_org;
314982beb602SGarrett D'Amore 	time_t current_time = ddi_get_time();
315082beb602SGarrett D'Amore 
315182beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
315282beb602SGarrett D'Amore 	mutex_enter(&acb->isr_mutex);
315382beb602SGarrett D'Amore 	if (acb->ccboutstandingcount != 0) {
315482beb602SGarrett D'Amore 		/* check each ccb */
315582beb602SGarrett D'Amore 		i = ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
315682beb602SGarrett D'Amore 		    DDI_DMA_SYNC_FORKERNEL);
315782beb602SGarrett D'Amore 		if (i != DDI_SUCCESS) {
315882beb602SGarrett D'Amore 			if ((acb->timeout_id != 0) &&
315982beb602SGarrett D'Amore 			    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
316082beb602SGarrett D'Amore 				/* do pkt timeout check each 60 secs */
316182beb602SGarrett D'Amore 				acb->timeout_id = timeout(arcmsr_ccbs_timeout,
316282beb602SGarrett D'Amore 				    (void*)acb, (ARCMSR_TIMEOUT_WATCH *
316382beb602SGarrett D'Amore 				    drv_usectohz(1000000)));
3164508aff1aSJames C. McPherson 			}
316582beb602SGarrett D'Amore 			mutex_exit(&acb->isr_mutex);
316682beb602SGarrett D'Amore 			arcmsr_enable_allintr(acb, intmask_org);
316782beb602SGarrett D'Amore 			return;
316882beb602SGarrett D'Amore 		}
316982beb602SGarrett D'Amore 		instance = ddi_get_instance(acb->dev_info);
317082beb602SGarrett D'Amore 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
317182beb602SGarrett D'Amore 			ccb = acb->pccb_pool[i];
317282beb602SGarrett D'Amore 			if (ccb->acb != acb) {
317382beb602SGarrett D'Amore 				break;
3174508aff1aSJames C. McPherson 			}
317582beb602SGarrett D'Amore 			if (ccb->ccb_state == ARCMSR_CCB_FREE) {
317682beb602SGarrett D'Amore 				continue;
317782beb602SGarrett D'Amore 			}
317882beb602SGarrett D'Amore 			if (ccb->pkt == NULL) {
317982beb602SGarrett D'Amore 				continue;
318082beb602SGarrett D'Amore 			}
318182beb602SGarrett D'Amore 			if (ccb->pkt->pkt_time == 0) {
318282beb602SGarrett D'Amore 				continue;
318382beb602SGarrett D'Amore 			}
318482beb602SGarrett D'Amore 			if (ccb->ccb_time >= current_time) {
318582beb602SGarrett D'Amore 				continue;
318682beb602SGarrett D'Amore 			}
318782beb602SGarrett D'Amore 			int id = ccb->pkt->pkt_address.a_target;
318882beb602SGarrett D'Amore 			int lun = ccb->pkt->pkt_address.a_lun;
318982beb602SGarrett D'Amore 			if (ccb->ccb_state == ARCMSR_CCB_START) {
319082beb602SGarrett D'Amore 				uint8_t	*cdb = (uint8_t	*)&ccb->arcmsr_cdb.Cdb;
319182beb602SGarrett D'Amore 
319282beb602SGarrett D'Amore 				timeout_count++;
319382beb602SGarrett D'Amore 				arcmsr_warn(acb,
319482beb602SGarrett D'Amore 				    "scsi target %d lun %d cmd=0x%x "
319582beb602SGarrett D'Amore 				    "command timeout, ccb=0x%p",
319682beb602SGarrett D'Amore 				    instance, id, lun, *cdb, (void *)ccb);
319782beb602SGarrett D'Amore 				ccb->ccb_state = ARCMSR_CCB_TIMEOUT;
319882beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_TIMEOUT;
319982beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics = STAT_TIMEOUT;
320082beb602SGarrett D'Amore 				/* acb->devstate[id][lun] = ARECA_RAID_GONE; */
320182beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 1);
320282beb602SGarrett D'Amore 				continue;
320382beb602SGarrett D'Amore 			} else if ((ccb->ccb_state & ARCMSR_CCB_CAN_BE_FREE) ==
320482beb602SGarrett D'Amore 			    ARCMSR_CCB_CAN_BE_FREE) {
320582beb602SGarrett D'Amore 				arcmsr_free_ccb(ccb);
320682beb602SGarrett D'Amore 			}
320782beb602SGarrett D'Amore 		}
320882beb602SGarrett D'Amore 	}
320982beb602SGarrett D'Amore 	if ((acb->timeout_id != 0) &&
321082beb602SGarrett D'Amore 	    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
321182beb602SGarrett D'Amore 		/* do pkt timeout check each 60 secs */
321282beb602SGarrett D'Amore 		acb->timeout_id = timeout(arcmsr_ccbs_timeout,
321382beb602SGarrett D'Amore 		    (void*)acb, (ARCMSR_TIMEOUT_WATCH * drv_usectohz(1000000)));
321482beb602SGarrett D'Amore 	}
321582beb602SGarrett D'Amore 	mutex_exit(&acb->isr_mutex);
321682beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
3217508aff1aSJames C. McPherson }
3218508aff1aSJames C. McPherson 
3219508aff1aSJames C. McPherson static void
arcmsr_abort_dr_ccbs(struct ACB * acb,uint16_t target,uint8_t lun)322082beb602SGarrett D'Amore arcmsr_abort_dr_ccbs(struct ACB *acb, uint16_t target, uint8_t lun)
322182beb602SGarrett D'Amore {
322282beb602SGarrett D'Amore 	struct CCB *ccb;
322382beb602SGarrett D'Amore 	uint32_t intmask_org;
322482beb602SGarrett D'Amore 	int i;
3225508aff1aSJames C. McPherson 
322682beb602SGarrett D'Amore 	/* disable all outbound interrupts */
322782beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
322882beb602SGarrett D'Amore 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
322982beb602SGarrett D'Amore 		ccb = acb->pccb_pool[i];
323082beb602SGarrett D'Amore 		if (ccb->ccb_state == ARCMSR_CCB_START) {
323182beb602SGarrett D'Amore 			if ((target == ccb->pkt->pkt_address.a_target) &&
323282beb602SGarrett D'Amore 			    (lun == ccb->pkt->pkt_address.a_lun)) {
323382beb602SGarrett D'Amore 				ccb->ccb_state = ARCMSR_CCB_ABORTED;
323482beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_ABORTED;
323582beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
323682beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 1);
323782beb602SGarrett D'Amore 				arcmsr_log(acb, CE_NOTE,
323882beb602SGarrett D'Amore 				    "abort T%dL%d ccb", target, lun);
323982beb602SGarrett D'Amore 			}
3240508aff1aSJames C. McPherson 		}
324182beb602SGarrett D'Amore 	}
324282beb602SGarrett D'Amore 	/* enable outbound Post Queue, outbound doorbell Interrupt */
324382beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
3244508aff1aSJames C. McPherson }
3245508aff1aSJames C. McPherson 
324682beb602SGarrett D'Amore static int
arcmsr_scsi_device_probe(struct ACB * acb,uint16_t tgt,uint8_t lun)324782beb602SGarrett D'Amore arcmsr_scsi_device_probe(struct ACB *acb, uint16_t tgt, uint8_t lun)
324882beb602SGarrett D'Amore {
324982beb602SGarrett D'Amore 	struct scsi_device sd;
325082beb602SGarrett D'Amore 	dev_info_t *child;
325182beb602SGarrett D'Amore 	int rval;
3252508aff1aSJames C. McPherson 
325382beb602SGarrett D'Amore 	bzero(&sd, sizeof (struct scsi_device));
325482beb602SGarrett D'Amore 	sd.sd_address.a_hba_tran = acb->scsi_hba_transport;
325582beb602SGarrett D'Amore 	sd.sd_address.a_target = (uint16_t)tgt;
325682beb602SGarrett D'Amore 	sd.sd_address.a_lun = (uint8_t)lun;
325782beb602SGarrett D'Amore 	if ((child = arcmsr_find_child(acb, tgt, lun)) != NULL) {
325882beb602SGarrett D'Amore 		rval = scsi_hba_probe(&sd, NULL);
325982beb602SGarrett D'Amore 		if (rval == SCSIPROBE_EXISTS) {
326082beb602SGarrett D'Amore 			rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
326182beb602SGarrett D'Amore 			if (rval != NDI_SUCCESS) {
326282beb602SGarrett D'Amore 				arcmsr_warn(acb, "unable to online T%dL%d",
326382beb602SGarrett D'Amore 				    tgt, lun);
326482beb602SGarrett D'Amore 			} else {
326582beb602SGarrett D'Amore 				arcmsr_log(acb, CE_NOTE, "T%dL%d onlined",
326682beb602SGarrett D'Amore 				    tgt, lun);
326782beb602SGarrett D'Amore 			}
3268508aff1aSJames C. McPherson 		}
326982beb602SGarrett D'Amore 	} else {
327082beb602SGarrett D'Amore 		rval = scsi_hba_probe(&sd, NULL);
327182beb602SGarrett D'Amore 		if (rval == SCSIPROBE_EXISTS)
327282beb602SGarrett D'Amore 			rval = arcmsr_config_child(acb, &sd, NULL);
327382beb602SGarrett D'Amore 	}
327482beb602SGarrett D'Amore 	scsi_unprobe(&sd);
327582beb602SGarrett D'Amore 	return (rval);
3276508aff1aSJames C. McPherson }
3277508aff1aSJames C. McPherson 
3278508aff1aSJames C. McPherson static void
arcmsr_dr_handle(struct ACB * acb)327982beb602SGarrett D'Amore arcmsr_dr_handle(struct ACB *acb)
328082beb602SGarrett D'Amore {
328182beb602SGarrett D'Amore 	char *acb_dev_map = (char *)acb->device_map;
328282beb602SGarrett D'Amore 	char *devicemap;
328382beb602SGarrett D'Amore 	char temp;
328482beb602SGarrett D'Amore 	uint16_t target;
328582beb602SGarrett D'Amore 	uint8_t lun;
328682beb602SGarrett D'Amore 	char diff;
328782beb602SGarrett D'Amore 	dev_info_t *dip;
328882beb602SGarrett D'Amore 	ddi_acc_handle_t reg;
3289508aff1aSJames C. McPherson 
329082beb602SGarrett D'Amore 	switch (acb->adapter_type) {
329182beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
329282beb602SGarrett D'Amore 	{
329382beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
3294508aff1aSJames C. McPherson 
329582beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
329682beb602SGarrett D'Amore 		devicemap = (char *)&phbamu->msgcode_rwbuffer[21];
329782beb602SGarrett D'Amore 		reg = acb->reg_mu_acc_handle0;
329882beb602SGarrett D'Amore 		break;
3299508aff1aSJames C. McPherson 	}
3300508aff1aSJames C. McPherson 
330182beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
330282beb602SGarrett D'Amore 	{
330382beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
3304508aff1aSJames C. McPherson 
330582beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
330682beb602SGarrett D'Amore 		devicemap = (char *)
330782beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[21];
330882beb602SGarrett D'Amore 		reg = acb->reg_mu_acc_handle1;
330982beb602SGarrett D'Amore 		break;
331082beb602SGarrett D'Amore 	}
3311508aff1aSJames C. McPherson 
331282beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
331382beb602SGarrett D'Amore 	{
331482beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
3315508aff1aSJames C. McPherson 
331682beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
331782beb602SGarrett D'Amore 		devicemap = (char *)&phbcmu->msgcode_rwbuffer[21];
331882beb602SGarrett D'Amore 		reg = acb->reg_mu_acc_handle0;
331982beb602SGarrett D'Amore 		break;
332082beb602SGarrett D'Amore 	}
3321508aff1aSJames C. McPherson 
332282beb602SGarrett D'Amore 	}
3323508aff1aSJames C. McPherson 
332482beb602SGarrett D'Amore 	for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
332582beb602SGarrett D'Amore 		temp = CHIP_REG_READ8(reg, devicemap);
332682beb602SGarrett D'Amore 		diff = (*acb_dev_map)^ temp;
332782beb602SGarrett D'Amore 		if (diff != 0) {
332882beb602SGarrett D'Amore 			*acb_dev_map = temp;
332982beb602SGarrett D'Amore 			for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
333082beb602SGarrett D'Amore 				if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
33313fe80ca4SDan Cross 					ndi_devi_enter(acb->dev_info);
333282beb602SGarrett D'Amore 					acb->devstate[target][lun] =
333382beb602SGarrett D'Amore 					    ARECA_RAID_GOOD;
333482beb602SGarrett D'Amore 					(void) arcmsr_scsi_device_probe(acb,
333582beb602SGarrett D'Amore 					    target, lun);
33363fe80ca4SDan Cross 					ndi_devi_exit(acb->dev_info);
333782beb602SGarrett D'Amore 					arcmsr_log(acb, CE_NOTE,
333882beb602SGarrett D'Amore 					    "T%dL%d on-line", target, lun);
333982beb602SGarrett D'Amore 				} else if ((temp & 0x01) == 0 &&
334082beb602SGarrett D'Amore 				    (diff & 0x01) == 1) {
334182beb602SGarrett D'Amore 					dip = arcmsr_find_child(acb, target,
334282beb602SGarrett D'Amore 					    lun);
334382beb602SGarrett D'Amore 					if (dip != NULL) {
334482beb602SGarrett D'Amore 						acb->devstate[target][lun] =
334582beb602SGarrett D'Amore 						    ARECA_RAID_GONE;
334682beb602SGarrett D'Amore 						if (mutex_owned(&acb->
334782beb602SGarrett D'Amore 						    isr_mutex)) {
334882beb602SGarrett D'Amore 							arcmsr_abort_dr_ccbs(
334982beb602SGarrett D'Amore 							    acb, target, lun);
335082beb602SGarrett D'Amore 							(void)
335182beb602SGarrett D'Amore 							    ndi_devi_offline(
335282beb602SGarrett D'Amore 							    dip,
335382beb602SGarrett D'Amore 							    NDI_DEVI_REMOVE |
335482beb602SGarrett D'Amore 							    NDI_DEVI_OFFLINE);
335582beb602SGarrett D'Amore 						} else {
335682beb602SGarrett D'Amore 							mutex_enter(&acb->
335782beb602SGarrett D'Amore 							    isr_mutex);
335882beb602SGarrett D'Amore 							arcmsr_abort_dr_ccbs(
335982beb602SGarrett D'Amore 							    acb, target, lun);
336082beb602SGarrett D'Amore 							(void)
336182beb602SGarrett D'Amore 							    ndi_devi_offline(
336282beb602SGarrett D'Amore 							    dip,
336382beb602SGarrett D'Amore 							    NDI_DEVI_REMOVE |
336482beb602SGarrett D'Amore 							    NDI_DEVI_OFFLINE);
336582beb602SGarrett D'Amore 							mutex_exit(&acb->
336682beb602SGarrett D'Amore 							    isr_mutex);
336782beb602SGarrett D'Amore 						}
336882beb602SGarrett D'Amore 					}
336982beb602SGarrett D'Amore 					arcmsr_log(acb, CE_NOTE,
337082beb602SGarrett D'Amore 					    "T%dL%d off-line", target, lun);
337182beb602SGarrett D'Amore 				}
337282beb602SGarrett D'Amore 				temp >>= 1;
337382beb602SGarrett D'Amore 				diff >>= 1;
337482beb602SGarrett D'Amore 			}
337582beb602SGarrett D'Amore 		}
337682beb602SGarrett D'Amore 		devicemap++;
337782beb602SGarrett D'Amore 		acb_dev_map++;
3378508aff1aSJames C. McPherson 	}
3379508aff1aSJames C. McPherson }
3380508aff1aSJames C. McPherson 
3381508aff1aSJames C. McPherson 
3382508aff1aSJames C. McPherson static void
arcmsr_devMap_monitor(void * arg)338382beb602SGarrett D'Amore arcmsr_devMap_monitor(void* arg)
338482beb602SGarrett D'Amore {
3385508aff1aSJames C. McPherson 
338682beb602SGarrett D'Amore 	struct ACB *acb = (struct ACB *)arg;
338782beb602SGarrett D'Amore 	switch (acb->adapter_type) {
338882beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
338982beb602SGarrett D'Amore 	{
339082beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
3391508aff1aSJames C. McPherson 
339282beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
339382beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
339482beb602SGarrett D'Amore 		    &phbamu->inbound_msgaddr0,
339582beb602SGarrett D'Amore 		    ARCMSR_INBOUND_MESG0_GET_CONFIG);
339682beb602SGarrett D'Amore 		break;
3397508aff1aSJames C. McPherson 	}
3398508aff1aSJames C. McPherson 
339982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
340082beb602SGarrett D'Amore 	{
340182beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
3402508aff1aSJames C. McPherson 
340382beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
340482beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
340582beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
340682beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_GET_CONFIG);
340782beb602SGarrett D'Amore 		break;
340882beb602SGarrett D'Amore 	}
3409508aff1aSJames C. McPherson 
341082beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
341182beb602SGarrett D'Amore 	{
341282beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
3413508aff1aSJames C. McPherson 
341482beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
341582beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
341682beb602SGarrett D'Amore 		    &phbcmu->inbound_msgaddr0,
341782beb602SGarrett D'Amore 		    ARCMSR_INBOUND_MESG0_GET_CONFIG);
341882beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
341982beb602SGarrett D'Amore 		    &phbcmu->inbound_doorbell,
342082beb602SGarrett D'Amore 		    ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
342182beb602SGarrett D'Amore 		break;
342282beb602SGarrett D'Amore 	}
3423508aff1aSJames C. McPherson 
342482beb602SGarrett D'Amore 	}
3425508aff1aSJames C. McPherson 
342682beb602SGarrett D'Amore 	if ((acb->timeout_id != 0) &&
342782beb602SGarrett D'Amore 	    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
342882beb602SGarrett D'Amore 		/* do pkt timeout check each 5 secs */
342982beb602SGarrett D'Amore 		acb->timeout_id = timeout(arcmsr_devMap_monitor, (void*)acb,
343082beb602SGarrett D'Amore 		    (ARCMSR_DEV_MAP_WATCH * drv_usectohz(1000000)));
3431508aff1aSJames C. McPherson 	}
3432508aff1aSJames C. McPherson }
3433508aff1aSJames C. McPherson 
3434508aff1aSJames C. McPherson 
343582beb602SGarrett D'Amore static uint32_t
arcmsr_disable_allintr(struct ACB * acb)3436d5ebc493SDan Cross arcmsr_disable_allintr(struct ACB *acb)
3437d5ebc493SDan Cross {
343882beb602SGarrett D'Amore 	uint32_t intmask_org;
3439508aff1aSJames C. McPherson 
344082beb602SGarrett D'Amore 	switch (acb->adapter_type) {
344182beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
344282beb602SGarrett D'Amore 	{
344382beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
3444508aff1aSJames C. McPherson 
344582beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
344682beb602SGarrett D'Amore 		/* disable all outbound interrupt */
344782beb602SGarrett D'Amore 		intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
344882beb602SGarrett D'Amore 		    &phbamu->outbound_intmask);
344982beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
345082beb602SGarrett D'Amore 		    &phbamu->outbound_intmask,
345182beb602SGarrett D'Amore 		    intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE);
345282beb602SGarrett D'Amore 		break;
345382beb602SGarrett D'Amore 	}
3454508aff1aSJames C. McPherson 
345582beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
345682beb602SGarrett D'Amore 	{
345782beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
3458508aff1aSJames C. McPherson 
345982beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
346082beb602SGarrett D'Amore 		/* disable all outbound interrupt */
346182beb602SGarrett D'Amore 		intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
346282beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask);
346382beb602SGarrett D'Amore 		/* disable all interrupts */
346482beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
346582beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask, 0);
346682beb602SGarrett D'Amore 		break;
346782beb602SGarrett D'Amore 	}
3468508aff1aSJames C. McPherson 
346982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
347082beb602SGarrett D'Amore 	{
347182beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
3472508aff1aSJames C. McPherson 
347382beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
347482beb602SGarrett D'Amore 		/* disable all outbound interrupt */
347582beb602SGarrett D'Amore 		intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
347682beb602SGarrett D'Amore 		    &phbcmu->host_int_mask); /* disable outbound message0 int */
347782beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
347882beb602SGarrett D'Amore 		    &phbcmu->host_int_mask,
347982beb602SGarrett D'Amore 		    intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE);
348082beb602SGarrett D'Amore 		break;
348182beb602SGarrett D'Amore 	}
3482508aff1aSJames C. McPherson 
3483508aff1aSJames C. McPherson 	}
348482beb602SGarrett D'Amore 	return (intmask_org);
3485508aff1aSJames C. McPherson }
3486508aff1aSJames C. McPherson 
3487508aff1aSJames C. McPherson 
3488508aff1aSJames C. McPherson static void
arcmsr_enable_allintr(struct ACB * acb,uint32_t intmask_org)3489d5ebc493SDan Cross arcmsr_enable_allintr(struct ACB *acb, uint32_t intmask_org)
3490d5ebc493SDan Cross {
349182beb602SGarrett D'Amore 	int mask;
3492508aff1aSJames C. McPherson 
3493508aff1aSJames C. McPherson 	switch (acb->adapter_type) {
3494508aff1aSJames C. McPherson 	case ACB_ADAPTER_TYPE_A:
3495508aff1aSJames C. McPherson 	{
3496508aff1aSJames C. McPherson 		struct HBA_msgUnit *phbamu;
3497508aff1aSJames C. McPherson 
3498508aff1aSJames C. McPherson 		phbamu = (struct HBA_msgUnit *)acb->pmu;
349982beb602SGarrett D'Amore 		/*
350082beb602SGarrett D'Amore 		 * enable outbound Post Queue, outbound doorbell message0
350182beb602SGarrett D'Amore 		 * Interrupt
350282beb602SGarrett D'Amore 		 */
350382beb602SGarrett D'Amore 		mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
350482beb602SGarrett D'Amore 		    ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE |
350582beb602SGarrett D'Amore 		    ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
3506508aff1aSJames C. McPherson 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
350782beb602SGarrett D'Amore 		    &phbamu->outbound_intmask, intmask_org & mask);
350882beb602SGarrett D'Amore 		acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
3509508aff1aSJames C. McPherson 		break;
351082beb602SGarrett D'Amore 	}
3511508aff1aSJames C. McPherson 
3512508aff1aSJames C. McPherson 	case ACB_ADAPTER_TYPE_B:
3513508aff1aSJames C. McPherson 	{
3514508aff1aSJames C. McPherson 		struct HBB_msgUnit *phbbmu;
3515508aff1aSJames C. McPherson 
3516508aff1aSJames C. McPherson 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
351782beb602SGarrett D'Amore 		mask = (ARCMSR_IOP2DRV_DATA_WRITE_OK |
351882beb602SGarrett D'Amore 		    ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE |
351982beb602SGarrett D'Amore 		    ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
352082beb602SGarrett D'Amore 		/* 1=interrupt enable, 0=interrupt disable */
352182beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
352282beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask,
352382beb602SGarrett D'Amore 		    intmask_org | mask);
352482beb602SGarrett D'Amore 		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
352582beb602SGarrett D'Amore 		break;
352682beb602SGarrett D'Amore 	}
3527508aff1aSJames C. McPherson 
352882beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
352982beb602SGarrett D'Amore 	{
353082beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
353182beb602SGarrett D'Amore 
353282beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
353382beb602SGarrett D'Amore 		/* enable outbound Post Queue,outbound doorbell Interrupt */
353482beb602SGarrett D'Amore 		mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK |
353582beb602SGarrett D'Amore 		    ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK |
353682beb602SGarrett D'Amore 		    ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
3537508aff1aSJames C. McPherson 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
353882beb602SGarrett D'Amore 		    &phbcmu->host_int_mask, intmask_org & mask);
353982beb602SGarrett D'Amore 		acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
3540508aff1aSJames C. McPherson 		break;
3541508aff1aSJames C. McPherson 	}
354282beb602SGarrett D'Amore 
3543508aff1aSJames C. McPherson 	}
3544508aff1aSJames C. McPherson }
3545508aff1aSJames C. McPherson 
3546508aff1aSJames C. McPherson 
354782beb602SGarrett D'Amore static void
arcmsr_iop_parking(struct ACB * acb)354882beb602SGarrett D'Amore arcmsr_iop_parking(struct ACB *acb)
354982beb602SGarrett D'Amore {
355082beb602SGarrett D'Amore 	/* stop adapter background rebuild */
355182beb602SGarrett D'Amore 	if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
355282beb602SGarrett D'Amore 		uint32_t intmask_org;
3553508aff1aSJames C. McPherson 
355482beb602SGarrett D'Amore 		acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
3555508aff1aSJames C. McPherson 		/* disable all outbound interrupt */
3556508aff1aSJames C. McPherson 		intmask_org = arcmsr_disable_allintr(acb);
355782beb602SGarrett D'Amore 		switch (acb->adapter_type) {
355882beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_A:
355982beb602SGarrett D'Amore 			arcmsr_stop_hba_bgrb(acb);
356082beb602SGarrett D'Amore 			arcmsr_flush_hba_cache(acb);
356182beb602SGarrett D'Amore 			break;
3562508aff1aSJames C. McPherson 
356382beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_B:
356482beb602SGarrett D'Amore 			arcmsr_stop_hbb_bgrb(acb);
356582beb602SGarrett D'Amore 			arcmsr_flush_hbb_cache(acb);
356682beb602SGarrett D'Amore 			break;
356782beb602SGarrett D'Amore 
356882beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_C:
356982beb602SGarrett D'Amore 			arcmsr_stop_hbc_bgrb(acb);
357082beb602SGarrett D'Amore 			arcmsr_flush_hbc_cache(acb);
357182beb602SGarrett D'Amore 			break;
3572508aff1aSJames C. McPherson 		}
357382beb602SGarrett D'Amore 		/*
357482beb602SGarrett D'Amore 		 * enable outbound Post Queue
357582beb602SGarrett D'Amore 		 * enable outbound doorbell Interrupt
357682beb602SGarrett D'Amore 		 */
3577508aff1aSJames C. McPherson 		arcmsr_enable_allintr(acb, intmask_org);
3578508aff1aSJames C. McPherson 	}
3579508aff1aSJames C. McPherson }
3580508aff1aSJames C. McPherson 
3581508aff1aSJames C. McPherson 
358282beb602SGarrett D'Amore static uint8_t
arcmsr_hba_wait_msgint_ready(struct ACB * acb)358382beb602SGarrett D'Amore arcmsr_hba_wait_msgint_ready(struct ACB *acb)
358482beb602SGarrett D'Amore {
358582beb602SGarrett D'Amore 	uint32_t i;
358682beb602SGarrett D'Amore 	uint8_t retries = 0x00;
358782beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
3588508aff1aSJames C. McPherson 
3589508aff1aSJames C. McPherson 
359082beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
3591508aff1aSJames C. McPherson 
359282beb602SGarrett D'Amore 	do {
359382beb602SGarrett D'Amore 		for (i = 0; i < 100; i++) {
359482beb602SGarrett D'Amore 			if (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
359582beb602SGarrett D'Amore 			    &phbamu->outbound_intstatus) &
359682beb602SGarrett D'Amore 			    ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
359782beb602SGarrett D'Amore 				/* clear interrupt */
359882beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
359982beb602SGarrett D'Amore 				    &phbamu->outbound_intstatus,
360082beb602SGarrett D'Amore 				    ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
360182beb602SGarrett D'Amore 				return (TRUE);
360282beb602SGarrett D'Amore 			}
360382beb602SGarrett D'Amore 			drv_usecwait(10000);
360482beb602SGarrett D'Amore 			if (ddi_in_panic()) {
360582beb602SGarrett D'Amore 				/* clear interrupts */
360682beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
360782beb602SGarrett D'Amore 				    &phbamu->outbound_intstatus,
360882beb602SGarrett D'Amore 				    ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
360982beb602SGarrett D'Amore 				return (TRUE);
361082beb602SGarrett D'Amore 			}
361182beb602SGarrett D'Amore 		} /* max 1 second */
361282beb602SGarrett D'Amore 	} while (retries++ < 20); /* max 20 seconds */
361382beb602SGarrett D'Amore 	return (FALSE);
361482beb602SGarrett D'Amore }
3615508aff1aSJames C. McPherson 
3616508aff1aSJames C. McPherson 
361782beb602SGarrett D'Amore static uint8_t
arcmsr_hbb_wait_msgint_ready(struct ACB * acb)361882beb602SGarrett D'Amore arcmsr_hbb_wait_msgint_ready(struct ACB *acb)
361982beb602SGarrett D'Amore {
362082beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
362182beb602SGarrett D'Amore 	uint32_t i;
362282beb602SGarrett D'Amore 	uint8_t retries = 0x00;
3623508aff1aSJames C. McPherson 
362482beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
3625508aff1aSJames C. McPherson 
362682beb602SGarrett D'Amore 	do {
362782beb602SGarrett D'Amore 		for (i = 0; i < 100; i++) {
362882beb602SGarrett D'Amore 			if (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
362982beb602SGarrett D'Amore 			    &phbbmu->hbb_doorbell->iop2drv_doorbell) &
363082beb602SGarrett D'Amore 			    ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
363182beb602SGarrett D'Amore 				/* clear interrupt */
363282beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
363382beb602SGarrett D'Amore 				    &phbbmu->hbb_doorbell->iop2drv_doorbell,
363482beb602SGarrett D'Amore 				    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
363582beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
363682beb602SGarrett D'Amore 				    &phbbmu->hbb_doorbell->drv2iop_doorbell,
363782beb602SGarrett D'Amore 				    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
363882beb602SGarrett D'Amore 				return (TRUE);
3639508aff1aSJames C. McPherson 			}
364082beb602SGarrett D'Amore 			drv_usecwait(10000);
364182beb602SGarrett D'Amore 			if (ddi_in_panic()) {
364282beb602SGarrett D'Amore 				/* clear interrupts */
364382beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
364482beb602SGarrett D'Amore 				    &phbbmu->hbb_doorbell->iop2drv_doorbell,
364582beb602SGarrett D'Amore 				    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
364682beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
364782beb602SGarrett D'Amore 				    &phbbmu->hbb_doorbell->drv2iop_doorbell,
364882beb602SGarrett D'Amore 				    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
364982beb602SGarrett D'Amore 				return (TRUE);
365082beb602SGarrett D'Amore 			}
365182beb602SGarrett D'Amore 		} /* max 1 second */
365282beb602SGarrett D'Amore 	} while (retries++ < 20); /* max 20 seconds */
3653508aff1aSJames C. McPherson 
365482beb602SGarrett D'Amore 	return (FALSE);
3655508aff1aSJames C. McPherson }
3656508aff1aSJames C. McPherson 
3657508aff1aSJames C. McPherson 
365882beb602SGarrett D'Amore static uint8_t
arcmsr_hbc_wait_msgint_ready(struct ACB * acb)365982beb602SGarrett D'Amore arcmsr_hbc_wait_msgint_ready(struct ACB *acb)
366082beb602SGarrett D'Amore {
366182beb602SGarrett D'Amore 	uint32_t i;
366282beb602SGarrett D'Amore 	uint8_t retries = 0x00;
366382beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
366482beb602SGarrett D'Amore 	uint32_t c = ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR;
3665508aff1aSJames C. McPherson 
3666508aff1aSJames C. McPherson 
366782beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
3668508aff1aSJames C. McPherson 
366982beb602SGarrett D'Amore 	do {
367082beb602SGarrett D'Amore 		for (i = 0; i < 100; i++) {
367182beb602SGarrett D'Amore 			if (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
367282beb602SGarrett D'Amore 			    &phbcmu->outbound_doorbell) &
367382beb602SGarrett D'Amore 			    ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
367482beb602SGarrett D'Amore 				/* clear interrupt */
367582beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
367682beb602SGarrett D'Amore 				    &phbcmu->outbound_doorbell_clear, c);
367782beb602SGarrett D'Amore 				return (TRUE);
367882beb602SGarrett D'Amore 			}
367982beb602SGarrett D'Amore 			drv_usecwait(10000);
368082beb602SGarrett D'Amore 			if (ddi_in_panic()) {
368182beb602SGarrett D'Amore 				/* clear interrupts */
368282beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
368382beb602SGarrett D'Amore 				    &phbcmu->outbound_doorbell_clear, c);
368482beb602SGarrett D'Amore 				return (TRUE);
368582beb602SGarrett D'Amore 			}
368682beb602SGarrett D'Amore 		} /* max 1 second */
368782beb602SGarrett D'Amore 	} while (retries++ < 20); /* max 20 seconds */
368882beb602SGarrett D'Amore 	return (FALSE);
368982beb602SGarrett D'Amore }
3690508aff1aSJames C. McPherson 
3691508aff1aSJames C. McPherson 
3692d5ebc493SDan Cross static void
arcmsr_flush_hba_cache(struct ACB * acb)3693d5ebc493SDan Cross arcmsr_flush_hba_cache(struct ACB *acb)
3694d5ebc493SDan Cross {
369582beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
369682beb602SGarrett D'Amore 	int retry_count = 30;
3697508aff1aSJames C. McPherson 
369882beb602SGarrett D'Amore 	/* enlarge wait flush adapter cache time: 10 minutes */
369982beb602SGarrett D'Amore 
370082beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
370182beb602SGarrett D'Amore 
370282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0,
370382beb602SGarrett D'Amore 	    ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
370482beb602SGarrett D'Amore 	do {
370582beb602SGarrett D'Amore 		if (arcmsr_hba_wait_msgint_ready(acb)) {
370682beb602SGarrett D'Amore 			break;
3707508aff1aSJames C. McPherson 		} else {
370882beb602SGarrett D'Amore 			retry_count--;
3709508aff1aSJames C. McPherson 		}
371082beb602SGarrett D'Amore 	} while (retry_count != 0);
3711508aff1aSJames C. McPherson }
3712508aff1aSJames C. McPherson 
371382beb602SGarrett D'Amore static void
arcmsr_flush_hbb_cache(struct ACB * acb)3714d5ebc493SDan Cross arcmsr_flush_hbb_cache(struct ACB *acb)
3715d5ebc493SDan Cross {
371682beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
371782beb602SGarrett D'Amore 	int retry_count = 30;
3718508aff1aSJames C. McPherson 
371982beb602SGarrett D'Amore 	/* enlarge wait flush adapter cache time: 10 minutes */
3720508aff1aSJames C. McPherson 
372182beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
372282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
372382beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
372482beb602SGarrett D'Amore 	    ARCMSR_MESSAGE_FLUSH_CACHE);
372582beb602SGarrett D'Amore 	do {
372682beb602SGarrett D'Amore 		if (arcmsr_hbb_wait_msgint_ready(acb)) {
372782beb602SGarrett D'Amore 			break;
372882beb602SGarrett D'Amore 		} else {
372982beb602SGarrett D'Amore 			retry_count--;
373082beb602SGarrett D'Amore 		}
373182beb602SGarrett D'Amore 	} while (retry_count != 0);
373282beb602SGarrett D'Amore }
3733508aff1aSJames C. McPherson 
3734508aff1aSJames C. McPherson 
373582beb602SGarrett D'Amore static void
arcmsr_flush_hbc_cache(struct ACB * acb)373682beb602SGarrett D'Amore arcmsr_flush_hbc_cache(struct ACB *acb)
373782beb602SGarrett D'Amore {
373882beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
373982beb602SGarrett D'Amore 	int retry_count = 30;
3740508aff1aSJames C. McPherson 
374182beb602SGarrett D'Amore 	/* enlarge wait flush adapter cache time: 10 minutes */
3742508aff1aSJames C. McPherson 
374382beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
3744508aff1aSJames C. McPherson 
374582beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbcmu->inbound_msgaddr0,
374682beb602SGarrett D'Amore 	    ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
374782beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbcmu->inbound_doorbell,
374882beb602SGarrett D'Amore 	    ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
374982beb602SGarrett D'Amore 	do {
375082beb602SGarrett D'Amore 		if (arcmsr_hbc_wait_msgint_ready(acb)) {
375182beb602SGarrett D'Amore 			break;
375282beb602SGarrett D'Amore 		} else {
375382beb602SGarrett D'Amore 			retry_count--;
375482beb602SGarrett D'Amore 		}
375582beb602SGarrett D'Amore 	} while (retry_count != 0);
375682beb602SGarrett D'Amore }
3757508aff1aSJames C. McPherson 
3758508aff1aSJames C. McPherson 
3759508aff1aSJames C. McPherson 
376082beb602SGarrett D'Amore static uint8_t
arcmsr_abort_hba_allcmd(struct ACB * acb)376182beb602SGarrett D'Amore arcmsr_abort_hba_allcmd(struct ACB *acb)
376282beb602SGarrett D'Amore {
376382beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *)acb->pmu;
3764508aff1aSJames C. McPherson 
376582beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0,
376682beb602SGarrett D'Amore 	    ARCMSR_INBOUND_MESG0_ABORT_CMD);
3767508aff1aSJames C. McPherson 
376882beb602SGarrett D'Amore 	if (!arcmsr_hba_wait_msgint_ready(acb)) {
376982beb602SGarrett D'Amore 		arcmsr_warn(acb,
377082beb602SGarrett D'Amore 		    "timeout while waiting for 'abort all "
377182beb602SGarrett D'Amore 		    "outstanding commands'");
377282beb602SGarrett D'Amore 		return (0xff);
3773508aff1aSJames C. McPherson 	}
377482beb602SGarrett D'Amore 	return (0x00);
3775508aff1aSJames C. McPherson }
3776508aff1aSJames C. McPherson 
3777508aff1aSJames C. McPherson 
3778508aff1aSJames C. McPherson 
377982beb602SGarrett D'Amore static uint8_t
arcmsr_abort_hbb_allcmd(struct ACB * acb)378082beb602SGarrett D'Amore arcmsr_abort_hbb_allcmd(struct ACB *acb)
378182beb602SGarrett D'Amore {
378282beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *)acb->pmu;
3783508aff1aSJames C. McPherson 
378482beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
378582beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell, ARCMSR_MESSAGE_ABORT_CMD);
3786508aff1aSJames C. McPherson 
378782beb602SGarrett D'Amore 	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
378882beb602SGarrett D'Amore 		arcmsr_warn(acb,
378982beb602SGarrett D'Amore 		    "timeout while waiting for 'abort all "
379082beb602SGarrett D'Amore 		    "outstanding commands'");
379182beb602SGarrett D'Amore 		return (0x00);
3792508aff1aSJames C. McPherson 	}
379382beb602SGarrett D'Amore 	return (0x00);
379482beb602SGarrett D'Amore }
3795508aff1aSJames C. McPherson 
379682beb602SGarrett D'Amore 
379782beb602SGarrett D'Amore static uint8_t
arcmsr_abort_hbc_allcmd(struct ACB * acb)379882beb602SGarrett D'Amore arcmsr_abort_hbc_allcmd(struct ACB *acb)
379982beb602SGarrett D'Amore {
380082beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu = (struct HBC_msgUnit *)acb->pmu;
380182beb602SGarrett D'Amore 
380282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbcmu->inbound_msgaddr0,
380382beb602SGarrett D'Amore 	    ARCMSR_INBOUND_MESG0_ABORT_CMD);
380482beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbcmu->inbound_doorbell,
380582beb602SGarrett D'Amore 	    ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
380682beb602SGarrett D'Amore 
380782beb602SGarrett D'Amore 	if (!arcmsr_hbc_wait_msgint_ready(acb)) {
380882beb602SGarrett D'Amore 		arcmsr_warn(acb,
380982beb602SGarrett D'Amore 		    "timeout while waiting for 'abort all "
381082beb602SGarrett D'Amore 		    "outstanding commands'");
381182beb602SGarrett D'Amore 		return (0xff);
3812508aff1aSJames C. McPherson 	}
381382beb602SGarrett D'Amore 	return (0x00);
3814508aff1aSJames C. McPherson }
3815508aff1aSJames C. McPherson 
3816508aff1aSJames C. McPherson 
3817508aff1aSJames C. McPherson static void
arcmsr_done4abort_postqueue(struct ACB * acb)381882beb602SGarrett D'Amore arcmsr_done4abort_postqueue(struct ACB *acb)
381982beb602SGarrett D'Amore {
382082beb602SGarrett D'Amore 
382182beb602SGarrett D'Amore 	struct CCB *ccb;
382282beb602SGarrett D'Amore 	uint32_t flag_ccb;
382382beb602SGarrett D'Amore 	int i = 0;
382482beb602SGarrett D'Amore 	boolean_t error;
3825508aff1aSJames C. McPherson 
3826508aff1aSJames C. McPherson 	switch (acb->adapter_type) {
3827508aff1aSJames C. McPherson 	case ACB_ADAPTER_TYPE_A:
3828508aff1aSJames C. McPherson 	{
3829508aff1aSJames C. McPherson 		struct HBA_msgUnit *phbamu;
383082beb602SGarrett D'Amore 		uint32_t outbound_intstatus;
3831508aff1aSJames C. McPherson 
3832508aff1aSJames C. McPherson 		phbamu = (struct HBA_msgUnit *)acb->pmu;
383382beb602SGarrett D'Amore 		/* clear and abort all outbound posted Q */
383482beb602SGarrett D'Amore 		outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
383582beb602SGarrett D'Amore 		    &phbamu->outbound_intstatus) & acb->outbound_int_enable;
383682beb602SGarrett D'Amore 		/* clear interrupt */
3837508aff1aSJames C. McPherson 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
383882beb602SGarrett D'Amore 		    &phbamu->outbound_intstatus, outbound_intstatus);
383982beb602SGarrett D'Amore 		while (((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
384082beb602SGarrett D'Amore 		    &phbamu->outbound_queueport)) != 0xFFFFFFFF) &&
384182beb602SGarrett D'Amore 		    (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
384282beb602SGarrett D'Amore 			/* frame must be 32 bytes aligned */
384382beb602SGarrett D'Amore 			/* the CDB is the first field of the CCB */
384482beb602SGarrett D'Amore 			ccb = NumToPtr((acb->vir2phy_offset + (flag_ccb << 5)));
384582beb602SGarrett D'Amore 			/* check if command done with no error */
384682beb602SGarrett D'Amore 			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
384782beb602SGarrett D'Amore 			    B_TRUE : B_FALSE;
384882beb602SGarrett D'Amore 			arcmsr_drain_donequeue(acb, ccb, error);
384982beb602SGarrett D'Amore 		}
385082beb602SGarrett D'Amore 		break;
3851508aff1aSJames C. McPherson 	}
385282beb602SGarrett D'Amore 
3853508aff1aSJames C. McPherson 	case ACB_ADAPTER_TYPE_B:
3854508aff1aSJames C. McPherson 	{
3855508aff1aSJames C. McPherson 		struct HBB_msgUnit *phbbmu;
3856508aff1aSJames C. McPherson 
3857508aff1aSJames C. McPherson 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
385882beb602SGarrett D'Amore 		/* clear all outbound posted Q */
385982beb602SGarrett D'Amore 		/* clear doorbell interrupt */
3860508aff1aSJames C. McPherson 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
386182beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->iop2drv_doorbell,
386282beb602SGarrett D'Amore 		    ARCMSR_DOORBELL_INT_CLEAR_PATTERN);
386382beb602SGarrett D'Amore 		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
386482beb602SGarrett D'Amore 			if ((flag_ccb = phbbmu->done_qbuffer[i]) != 0) {
386582beb602SGarrett D'Amore 				phbbmu->done_qbuffer[i] = 0;
386682beb602SGarrett D'Amore 				/* frame must be 32 bytes aligned */
386782beb602SGarrett D'Amore 				ccb = NumToPtr((acb->vir2phy_offset +
386882beb602SGarrett D'Amore 				    (flag_ccb << 5)));
386982beb602SGarrett D'Amore 				/* check if command done with no error */
387082beb602SGarrett D'Amore 				error =
387182beb602SGarrett D'Amore 				    (flag_ccb &
387282beb602SGarrett D'Amore 				    ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
387382beb602SGarrett D'Amore 				    B_TRUE : B_FALSE;
387482beb602SGarrett D'Amore 				arcmsr_drain_donequeue(acb, ccb, error);
387582beb602SGarrett D'Amore 			}
387682beb602SGarrett D'Amore 			phbbmu->post_qbuffer[i] = 0;
387782beb602SGarrett D'Amore 		}	/* drain reply FIFO */
387882beb602SGarrett D'Amore 		phbbmu->doneq_index = 0;
387982beb602SGarrett D'Amore 		phbbmu->postq_index = 0;
388082beb602SGarrett D'Amore 		break;
3881508aff1aSJames C. McPherson 	}
3882508aff1aSJames C. McPherson 
388382beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
388482beb602SGarrett D'Amore 	{
388582beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
388682beb602SGarrett D'Amore 		uint32_t ccb_cdb_phy;
3887508aff1aSJames C. McPherson 
388882beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
388982beb602SGarrett D'Amore 		while ((CHIP_REG_READ32(acb->reg_mu_acc_handle0,
389082beb602SGarrett D'Amore 		    &phbcmu->host_int_status) &
389182beb602SGarrett D'Amore 		    ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) &&
389282beb602SGarrett D'Amore 		    (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
389382beb602SGarrett D'Amore 			/* need to do */
389482beb602SGarrett D'Amore 			flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
389582beb602SGarrett D'Amore 			    &phbcmu->outbound_queueport_low);
389682beb602SGarrett D'Amore 			/* frame must be 32 bytes aligned */
389782beb602SGarrett D'Amore 			ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
389882beb602SGarrett D'Amore 			ccb = NumToPtr((acb->vir2phy_offset + ccb_cdb_phy));
389982beb602SGarrett D'Amore 			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)?
390082beb602SGarrett D'Amore 			    B_TRUE : B_FALSE;
390182beb602SGarrett D'Amore 			arcmsr_drain_donequeue(acb, ccb, error);
390282beb602SGarrett D'Amore 		}
390382beb602SGarrett D'Amore 		break;
390482beb602SGarrett D'Amore 	}
3905508aff1aSJames C. McPherson 
390682beb602SGarrett D'Amore 	}
390782beb602SGarrett D'Amore }
390882beb602SGarrett D'Amore /*
390982beb602SGarrett D'Amore  * Routine Description: try to get echo from iop.
391082beb602SGarrett D'Amore  *           Arguments:
391182beb602SGarrett D'Amore  *        Return Value: Nothing.
391282beb602SGarrett D'Amore  */
391382beb602SGarrett D'Amore static uint8_t
arcmsr_get_echo_from_iop(struct ACB * acb)391482beb602SGarrett D'Amore arcmsr_get_echo_from_iop(struct ACB *acb)
391582beb602SGarrett D'Amore {
391682beb602SGarrett D'Amore 	uint32_t intmask_org;
391782beb602SGarrett D'Amore 	uint8_t rtnval = 0;
3918508aff1aSJames C. McPherson 
391982beb602SGarrett D'Amore 	if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
392082beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
3921508aff1aSJames C. McPherson 
392282beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
392382beb602SGarrett D'Amore 		intmask_org = arcmsr_disable_allintr(acb);
392482beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
392582beb602SGarrett D'Amore 		    &phbamu->inbound_msgaddr0,
392682beb602SGarrett D'Amore 		    ARCMSR_INBOUND_MESG0_GET_CONFIG);
392782beb602SGarrett D'Amore 		if (!arcmsr_hba_wait_msgint_ready(acb)) {
392882beb602SGarrett D'Amore 			arcmsr_warn(acb, "try to get echo from iop,"
392982beb602SGarrett D'Amore 			    "... timeout ...");
393082beb602SGarrett D'Amore 			acb->acb_flags |= ACB_F_BUS_HANG_ON;
393182beb602SGarrett D'Amore 			rtnval = 0xFF;
3932508aff1aSJames C. McPherson 		}
393382beb602SGarrett D'Amore 		/* enable all outbound interrupt */
393482beb602SGarrett D'Amore 		arcmsr_enable_allintr(acb, intmask_org);
3935508aff1aSJames C. McPherson 	}
393682beb602SGarrett D'Amore 	return (rtnval);
3937508aff1aSJames C. McPherson }
3938508aff1aSJames C. McPherson 
393982beb602SGarrett D'Amore /*
394082beb602SGarrett D'Amore  * Routine Description: Reset 80331 iop.
394182beb602SGarrett D'Amore  *           Arguments:
394282beb602SGarrett D'Amore  *        Return Value: Nothing.
394382beb602SGarrett D'Amore  */
394482beb602SGarrett D'Amore static uint8_t
arcmsr_iop_reset(struct ACB * acb)394582beb602SGarrett D'Amore arcmsr_iop_reset(struct ACB *acb)
394682beb602SGarrett D'Amore {
394782beb602SGarrett D'Amore 	struct CCB *ccb;
394882beb602SGarrett D'Amore 	uint32_t intmask_org;
394982beb602SGarrett D'Amore 	uint8_t rtnval = 0;
395082beb602SGarrett D'Amore 	int i = 0;
3951508aff1aSJames C. McPherson 
395282beb602SGarrett D'Amore 	if (acb->ccboutstandingcount > 0) {
395382beb602SGarrett D'Amore 		/* disable all outbound interrupt */
395482beb602SGarrett D'Amore 		intmask_org = arcmsr_disable_allintr(acb);
395582beb602SGarrett D'Amore 		/* clear and abort all outbound posted Q */
395682beb602SGarrett D'Amore 		arcmsr_done4abort_postqueue(acb);
395782beb602SGarrett D'Amore 		/* talk to iop 331 outstanding command aborted */
395882beb602SGarrett D'Amore 		rtnval = (acb->acb_flags & ACB_F_BUS_HANG_ON) ?
395982beb602SGarrett D'Amore 		    0xFF : arcmsr_abort_host_command(acb);
3960508aff1aSJames C. McPherson 
396182beb602SGarrett D'Amore 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
396282beb602SGarrett D'Amore 			ccb = acb->pccb_pool[i];
396382beb602SGarrett D'Amore 			if (ccb->ccb_state == ARCMSR_CCB_START) {
396482beb602SGarrett D'Amore 				/* ccb->ccb_state = ARCMSR_CCB_RESET; */
396582beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_RESET;
396682beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_BUS_RESET;
396782beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 1);
396882beb602SGarrett D'Amore 			}
396982beb602SGarrett D'Amore 		}
397082beb602SGarrett D'Amore 		atomic_and_32(&acb->ccboutstandingcount, 0);
397182beb602SGarrett D'Amore 		/* enable all outbound interrupt */
397282beb602SGarrett D'Amore 		arcmsr_enable_allintr(acb, intmask_org);
397382beb602SGarrett D'Amore 	} else {
397482beb602SGarrett D'Amore 		rtnval = arcmsr_get_echo_from_iop(acb);
397582beb602SGarrett D'Amore 	}
397682beb602SGarrett D'Amore 	return (rtnval);
3977508aff1aSJames C. McPherson }
3978508aff1aSJames C. McPherson 
3979508aff1aSJames C. McPherson 
398082beb602SGarrett D'Amore static struct QBUFFER *
arcmsr_get_iop_rqbuffer(struct ACB * acb)398182beb602SGarrett D'Amore arcmsr_get_iop_rqbuffer(struct ACB *acb)
398282beb602SGarrett D'Amore {
398382beb602SGarrett D'Amore 	struct QBUFFER *qb;
3984508aff1aSJames C. McPherson 
398582beb602SGarrett D'Amore 	switch (acb->adapter_type) {
398682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
398782beb602SGarrett D'Amore 	{
398882beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
3989508aff1aSJames C. McPherson 
399082beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
399182beb602SGarrett D'Amore 		qb = (struct QBUFFER *)&phbamu->message_rbuffer;
399282beb602SGarrett D'Amore 		break;
399382beb602SGarrett D'Amore 	}
3994508aff1aSJames C. McPherson 
399582beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
399682beb602SGarrett D'Amore 	{
399782beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
3998508aff1aSJames C. McPherson 
399982beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
400082beb602SGarrett D'Amore 		qb = (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer;
400182beb602SGarrett D'Amore 		break;
400282beb602SGarrett D'Amore 	}
4003508aff1aSJames C. McPherson 
400482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
400582beb602SGarrett D'Amore 	{
400682beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
4007508aff1aSJames C. McPherson 
400882beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
400982beb602SGarrett D'Amore 		qb = (struct QBUFFER *)&phbcmu->message_rbuffer;
401082beb602SGarrett D'Amore 		break;
401182beb602SGarrett D'Amore 	}
4012508aff1aSJames C. McPherson 
401382beb602SGarrett D'Amore 	}
401482beb602SGarrett D'Amore 	return (qb);
401582beb602SGarrett D'Amore }
4016508aff1aSJames C. McPherson 
4017508aff1aSJames C. McPherson 
401882beb602SGarrett D'Amore static struct QBUFFER *
arcmsr_get_iop_wqbuffer(struct ACB * acb)401982beb602SGarrett D'Amore arcmsr_get_iop_wqbuffer(struct ACB *acb)
402082beb602SGarrett D'Amore {
402182beb602SGarrett D'Amore 	struct QBUFFER *qbuffer = NULL;
4022508aff1aSJames C. McPherson 
402382beb602SGarrett D'Amore 	switch (acb->adapter_type) {
402482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
402582beb602SGarrett D'Amore 	{
402682beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
4027508aff1aSJames C. McPherson 
402882beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
402982beb602SGarrett D'Amore 		qbuffer = (struct QBUFFER *)&phbamu->message_wbuffer;
403082beb602SGarrett D'Amore 		break;
4031508aff1aSJames C. McPherson 	}
4032508aff1aSJames C. McPherson 
403382beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
403482beb602SGarrett D'Amore 	{
403582beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
4036508aff1aSJames C. McPherson 
403782beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
403882beb602SGarrett D'Amore 		qbuffer = (struct QBUFFER *)
403982beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->message_wbuffer;
404082beb602SGarrett D'Amore 		break;
404182beb602SGarrett D'Amore 	}
404282beb602SGarrett D'Amore 
404382beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
4044508aff1aSJames C. McPherson 	{
404582beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
4046508aff1aSJames C. McPherson 
404782beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
404882beb602SGarrett D'Amore 		qbuffer = (struct QBUFFER *)&phbcmu->message_wbuffer;
404982beb602SGarrett D'Amore 		break;
405082beb602SGarrett D'Amore 	}
4051508aff1aSJames C. McPherson 
405282beb602SGarrett D'Amore 	}
405382beb602SGarrett D'Amore 	return (qbuffer);
405482beb602SGarrett D'Amore }
4055508aff1aSJames C. McPherson 
4056508aff1aSJames C. McPherson 
4057508aff1aSJames C. McPherson 
405882beb602SGarrett D'Amore static void
arcmsr_iop_message_read(struct ACB * acb)405982beb602SGarrett D'Amore arcmsr_iop_message_read(struct ACB *acb)
406082beb602SGarrett D'Amore {
406182beb602SGarrett D'Amore 	switch (acb->adapter_type) {
406282beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
406382beb602SGarrett D'Amore 	{
406482beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
4065508aff1aSJames C. McPherson 
406682beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
406782beb602SGarrett D'Amore 		/* let IOP know the data has been read */
406882beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
406982beb602SGarrett D'Amore 		    &phbamu->inbound_doorbell,
407082beb602SGarrett D'Amore 		    ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
407182beb602SGarrett D'Amore 		break;
4072508aff1aSJames C. McPherson 	}
407382beb602SGarrett D'Amore 
407482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
4075508aff1aSJames C. McPherson 	{
407682beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
4077508aff1aSJames C. McPherson 
407882beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
407982beb602SGarrett D'Amore 		/* let IOP know the data has been read */
408082beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
408182beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
408282beb602SGarrett D'Amore 		    ARCMSR_DRV2IOP_DATA_READ_OK);
408382beb602SGarrett D'Amore 		break;
408482beb602SGarrett D'Amore 	}
4085508aff1aSJames C. McPherson 
408682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
408782beb602SGarrett D'Amore 	{
408882beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
4089508aff1aSJames C. McPherson 
409082beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
409182beb602SGarrett D'Amore 		/* let IOP know data has been read */
409282beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
409382beb602SGarrett D'Amore 		    &phbcmu->inbound_doorbell,
409482beb602SGarrett D'Amore 		    ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK);
409582beb602SGarrett D'Amore 		break;
409682beb602SGarrett D'Amore 	}
4097508aff1aSJames C. McPherson 
409882beb602SGarrett D'Amore 	}
409982beb602SGarrett D'Amore }
4100508aff1aSJames C. McPherson 
4101508aff1aSJames C. McPherson 
4102508aff1aSJames C. McPherson 
410382beb602SGarrett D'Amore static void
arcmsr_iop_message_wrote(struct ACB * acb)410482beb602SGarrett D'Amore arcmsr_iop_message_wrote(struct ACB *acb)
410582beb602SGarrett D'Amore {
410682beb602SGarrett D'Amore 	switch (acb->adapter_type) {
410782beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A: {
410882beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
4109508aff1aSJames C. McPherson 
411082beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
411182beb602SGarrett D'Amore 		/*
411282beb602SGarrett D'Amore 		 * push inbound doorbell tell iop, driver data write ok
411382beb602SGarrett D'Amore 		 * and wait reply on next hwinterrupt for next Qbuffer post
411482beb602SGarrett D'Amore 		 */
411582beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
411682beb602SGarrett D'Amore 		    &phbamu->inbound_doorbell,
411782beb602SGarrett D'Amore 		    ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
411882beb602SGarrett D'Amore 		break;
4119508aff1aSJames C. McPherson 	}
4120508aff1aSJames C. McPherson 
412182beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
4122508aff1aSJames C. McPherson 	{
412382beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
4124508aff1aSJames C. McPherson 
412582beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
412682beb602SGarrett D'Amore 		/*
412782beb602SGarrett D'Amore 		 * push inbound doorbell tell iop, driver data was writen
412882beb602SGarrett D'Amore 		 * successfully, then await reply on next hwinterrupt for
412982beb602SGarrett D'Amore 		 * next Qbuffer post
413082beb602SGarrett D'Amore 		 */
413182beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
413282beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
413382beb602SGarrett D'Amore 		    ARCMSR_DRV2IOP_DATA_WRITE_OK);
413482beb602SGarrett D'Amore 		break;
4135508aff1aSJames C. McPherson 	}
413682beb602SGarrett D'Amore 
413782beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
4138508aff1aSJames C. McPherson 	{
413982beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
4140508aff1aSJames C. McPherson 
414182beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
414282beb602SGarrett D'Amore 		/*
414382beb602SGarrett D'Amore 		 * push inbound doorbell tell iop, driver data write ok
414482beb602SGarrett D'Amore 		 * and wait reply on next hwinterrupt for next Qbuffer post
414582beb602SGarrett D'Amore 		 */
414682beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
414782beb602SGarrett D'Amore 		    &phbcmu->inbound_doorbell,
414882beb602SGarrett D'Amore 		    ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK);
4149508aff1aSJames C. McPherson 		break;
415082beb602SGarrett D'Amore 	}
415182beb602SGarrett D'Amore 
415282beb602SGarrett D'Amore 	}
415382beb602SGarrett D'Amore }
415482beb602SGarrett D'Amore 
415582beb602SGarrett D'Amore 
415682beb602SGarrett D'Amore 
415782beb602SGarrett D'Amore static void
arcmsr_post_ioctldata2iop(struct ACB * acb)415882beb602SGarrett D'Amore arcmsr_post_ioctldata2iop(struct ACB *acb)
415982beb602SGarrett D'Amore {
416082beb602SGarrett D'Amore 	uint8_t *pQbuffer;
416182beb602SGarrett D'Amore 	struct QBUFFER *pwbuffer;
416282beb602SGarrett D'Amore 	uint8_t *iop_data;
416382beb602SGarrett D'Amore 	int32_t allxfer_len = 0;
416482beb602SGarrett D'Amore 
416582beb602SGarrett D'Amore 	pwbuffer = arcmsr_get_iop_wqbuffer(acb);
416682beb602SGarrett D'Amore 	iop_data = (uint8_t *)pwbuffer->data;
416782beb602SGarrett D'Amore 	if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) {
416882beb602SGarrett D'Amore 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
416982beb602SGarrett D'Amore 		while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) &&
417082beb602SGarrett D'Amore 		    (allxfer_len < 124)) {
417182beb602SGarrett D'Amore 			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx];
417282beb602SGarrett D'Amore 			(void) memcpy(iop_data, pQbuffer, 1);
417382beb602SGarrett D'Amore 			acb->wqbuf_firstidx++;
417482beb602SGarrett D'Amore 			/* if last index number set it to 0 */
417582beb602SGarrett D'Amore 			acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
417682beb602SGarrett D'Amore 			iop_data++;
417782beb602SGarrett D'Amore 			allxfer_len++;
4178508aff1aSJames C. McPherson 		}
417982beb602SGarrett D'Amore 		pwbuffer->data_len = allxfer_len;
418082beb602SGarrett D'Amore 		/*
418182beb602SGarrett D'Amore 		 * push inbound doorbell and wait reply at hwinterrupt
418282beb602SGarrett D'Amore 		 * routine for next Qbuffer post
418382beb602SGarrett D'Amore 		 */
418482beb602SGarrett D'Amore 		arcmsr_iop_message_wrote(acb);
4185508aff1aSJames C. McPherson 	}
418682beb602SGarrett D'Amore }
4187508aff1aSJames C. McPherson 
4188508aff1aSJames C. McPherson 
418982beb602SGarrett D'Amore 
419082beb602SGarrett D'Amore static void
arcmsr_stop_hba_bgrb(struct ACB * acb)419182beb602SGarrett D'Amore arcmsr_stop_hba_bgrb(struct ACB *acb)
419282beb602SGarrett D'Amore {
419382beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
419482beb602SGarrett D'Amore 
419582beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
419682beb602SGarrett D'Amore 
419782beb602SGarrett D'Amore 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
419882beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
419982beb602SGarrett D'Amore 	    &phbamu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
420082beb602SGarrett D'Amore 	if (!arcmsr_hba_wait_msgint_ready(acb))
420182beb602SGarrett D'Amore 		arcmsr_warn(acb,
420282beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild completion");
4203508aff1aSJames C. McPherson }
4204508aff1aSJames C. McPherson 
4205508aff1aSJames C. McPherson 
420682beb602SGarrett D'Amore static void
arcmsr_stop_hbb_bgrb(struct ACB * acb)420782beb602SGarrett D'Amore arcmsr_stop_hbb_bgrb(struct ACB *acb)
420882beb602SGarrett D'Amore {
420982beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
4210508aff1aSJames C. McPherson 
421182beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
4212508aff1aSJames C. McPherson 
421382beb602SGarrett D'Amore 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
421482beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
421582beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell, ARCMSR_MESSAGE_STOP_BGRB);
4216508aff1aSJames C. McPherson 
421782beb602SGarrett D'Amore 	if (!arcmsr_hbb_wait_msgint_ready(acb))
421882beb602SGarrett D'Amore 		arcmsr_warn(acb,
421982beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild completion");
422082beb602SGarrett D'Amore }
4221508aff1aSJames C. McPherson 
4222508aff1aSJames C. McPherson 
422382beb602SGarrett D'Amore static void
arcmsr_stop_hbc_bgrb(struct ACB * acb)422482beb602SGarrett D'Amore arcmsr_stop_hbc_bgrb(struct ACB *acb)
422582beb602SGarrett D'Amore {
422682beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
4227508aff1aSJames C. McPherson 
422882beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
4229508aff1aSJames C. McPherson 
423082beb602SGarrett D'Amore 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
423182beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
423282beb602SGarrett D'Amore 	    &phbcmu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
423382beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
423482beb602SGarrett D'Amore 	    &phbcmu->inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
423582beb602SGarrett D'Amore 	if (!arcmsr_hbc_wait_msgint_ready(acb))
423682beb602SGarrett D'Amore 		arcmsr_warn(acb,
423782beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild completion");
423882beb602SGarrett D'Amore }
4239508aff1aSJames C. McPherson 
4240508aff1aSJames C. McPherson 
424182beb602SGarrett D'Amore static int
arcmsr_iop_message_xfer(struct ACB * acb,struct scsi_pkt * pkt)424282beb602SGarrett D'Amore arcmsr_iop_message_xfer(struct ACB *acb, struct scsi_pkt *pkt)
424382beb602SGarrett D'Amore {
424482beb602SGarrett D'Amore 	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
424582beb602SGarrett D'Amore 	struct CCB *ccb = pkt->pkt_ha_private;
424682beb602SGarrett D'Amore 	struct buf *bp = ccb->bp;
424782beb602SGarrett D'Amore 	uint8_t *pQbuffer;
424882beb602SGarrett D'Amore 	int retvalue = 0, transfer_len = 0;
424982beb602SGarrett D'Amore 	char *buffer;
425082beb602SGarrett D'Amore 	uint32_t controlcode;
425182beb602SGarrett D'Amore 
425282beb602SGarrett D'Amore 
425382beb602SGarrett D'Amore 	/* 4 bytes: Areca io control code */
425482beb602SGarrett D'Amore 	controlcode =
425582beb602SGarrett D'Amore 	    (uint32_t)pkt->pkt_cdbp[5] << 24 |
425682beb602SGarrett D'Amore 	    (uint32_t)pkt->pkt_cdbp[6] << 16 |
425782beb602SGarrett D'Amore 	    (uint32_t)pkt->pkt_cdbp[7] << 8 |
425882beb602SGarrett D'Amore 	    (uint32_t)pkt->pkt_cdbp[8];
425982beb602SGarrett D'Amore 
426082beb602SGarrett D'Amore 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
426182beb602SGarrett D'Amore 		bp_mapin(bp);
426282beb602SGarrett D'Amore 
426382beb602SGarrett D'Amore 	buffer = bp->b_un.b_addr;
426482beb602SGarrett D'Amore 	transfer_len = bp->b_bcount;
426582beb602SGarrett D'Amore 	if (transfer_len > sizeof (struct CMD_MESSAGE_FIELD)) {
426682beb602SGarrett D'Amore 		retvalue = ARCMSR_MESSAGE_FAIL;
426782beb602SGarrett D'Amore 		goto message_out;
4268508aff1aSJames C. McPherson 	}
4269508aff1aSJames C. McPherson 
427082beb602SGarrett D'Amore 	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)(intptr_t)buffer;
427182beb602SGarrett D'Amore 	switch (controlcode) {
4272508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_READ_RQBUFFER:
4273508aff1aSJames C. McPherson 	{
4274508aff1aSJames C. McPherson 		unsigned long *ver_addr;
427582beb602SGarrett D'Amore 		uint8_t *ptmpQbuffer;
4276508aff1aSJames C. McPherson 		int32_t allxfer_len = 0;
4277508aff1aSJames C. McPherson 
4278508aff1aSJames C. McPherson 		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
4279508aff1aSJames C. McPherson 
4280508aff1aSJames C. McPherson 		ptmpQbuffer = (uint8_t *)ver_addr;
4281508aff1aSJames C. McPherson 		while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) &&
4282508aff1aSJames C. McPherson 		    (allxfer_len < (MSGDATABUFLEN - 1))) {
4283508aff1aSJames C. McPherson 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx];
4284508aff1aSJames C. McPherson 			(void) memcpy(ptmpQbuffer, pQbuffer, 1);
4285508aff1aSJames C. McPherson 			acb->rqbuf_firstidx++;
4286508aff1aSJames C. McPherson 			acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
4287508aff1aSJames C. McPherson 			ptmpQbuffer++;
4288508aff1aSJames C. McPherson 			allxfer_len++;
4289508aff1aSJames C. McPherson 		}
4290508aff1aSJames C. McPherson 
4291508aff1aSJames C. McPherson 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
4292508aff1aSJames C. McPherson 			struct QBUFFER *prbuffer;
429382beb602SGarrett D'Amore 			uint8_t  *iop_data;
4294508aff1aSJames C. McPherson 			int32_t iop_len;
4295508aff1aSJames C. McPherson 
4296508aff1aSJames C. McPherson 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
4297508aff1aSJames C. McPherson 			prbuffer = arcmsr_get_iop_rqbuffer(acb);
4298508aff1aSJames C. McPherson 			iop_data = (uint8_t *)prbuffer->data;
4299508aff1aSJames C. McPherson 			iop_len = (int32_t)prbuffer->data_len;
430082beb602SGarrett D'Amore 
4301508aff1aSJames C. McPherson 			while (iop_len > 0) {
4302508aff1aSJames C. McPherson 				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx];
4303508aff1aSJames C. McPherson 				(void) memcpy(pQbuffer, iop_data, 1);
4304508aff1aSJames C. McPherson 				acb->rqbuf_lastidx++;
4305508aff1aSJames C. McPherson 				acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
4306508aff1aSJames C. McPherson 				iop_data++;
4307508aff1aSJames C. McPherson 				iop_len--;
4308508aff1aSJames C. McPherson 			}
4309508aff1aSJames C. McPherson 			arcmsr_iop_message_read(acb);
4310508aff1aSJames C. McPherson 		}
431182beb602SGarrett D'Amore 
431282beb602SGarrett D'Amore 		(void) memcpy(pcmdmessagefld->messagedatabuffer,
4313508aff1aSJames C. McPherson 		    (uint8_t *)ver_addr, allxfer_len);
431482beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.Length = allxfer_len;
431582beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.ReturnCode =
4316508aff1aSJames C. McPherson 		    ARCMSR_MESSAGE_RETURNCODE_OK;
4317508aff1aSJames C. McPherson 		kmem_free(ver_addr, MSGDATABUFLEN);
431882beb602SGarrett D'Amore 		break;
4319508aff1aSJames C. McPherson 	}
432082beb602SGarrett D'Amore 
4321508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_WRITE_WQBUFFER:
4322508aff1aSJames C. McPherson 	{
432382beb602SGarrett D'Amore 		uint8_t *ver_addr;
432482beb602SGarrett D'Amore 		int32_t my_empty_len, user_len, wqbuf_firstidx,
432582beb602SGarrett D'Amore 		    wqbuf_lastidx;
432682beb602SGarrett D'Amore 		uint8_t *ptmpuserbuffer;
4327508aff1aSJames C. McPherson 
4328508aff1aSJames C. McPherson 		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
4329508aff1aSJames C. McPherson 
433082beb602SGarrett D'Amore 		ptmpuserbuffer = ver_addr;
433182beb602SGarrett D'Amore 		user_len = min(pcmdmessagefld->cmdmessage.Length,
433282beb602SGarrett D'Amore 		    MSGDATABUFLEN);
4333508aff1aSJames C. McPherson 		(void) memcpy(ptmpuserbuffer,
433482beb602SGarrett D'Amore 		    pcmdmessagefld->messagedatabuffer, user_len);
4335508aff1aSJames C. McPherson 		wqbuf_lastidx = acb->wqbuf_lastidx;
4336508aff1aSJames C. McPherson 		wqbuf_firstidx = acb->wqbuf_firstidx;
4337508aff1aSJames C. McPherson 		if (wqbuf_lastidx != wqbuf_firstidx) {
433882beb602SGarrett D'Amore 			struct scsi_arq_status *arq_status;
433982beb602SGarrett D'Amore 
4340508aff1aSJames C. McPherson 			arcmsr_post_ioctldata2iop(acb);
434182beb602SGarrett D'Amore 			arq_status = (struct scsi_arq_status *)
434282beb602SGarrett D'Amore 			    (intptr_t)(pkt->pkt_scbp);
434382beb602SGarrett D'Amore 			bzero((caddr_t)arq_status,
434482beb602SGarrett D'Amore 			    sizeof (struct scsi_arq_status));
434582beb602SGarrett D'Amore 			arq_status->sts_rqpkt_reason = CMD_CMPLT;
434682beb602SGarrett D'Amore 			arq_status->sts_rqpkt_state = (STATE_GOT_BUS |
434782beb602SGarrett D'Amore 			    STATE_GOT_TARGET | STATE_SENT_CMD |
434882beb602SGarrett D'Amore 			    STATE_XFERRED_DATA | STATE_GOT_STATUS);
434982beb602SGarrett D'Amore 
435082beb602SGarrett D'Amore 			arq_status->sts_rqpkt_statistics =
435182beb602SGarrett D'Amore 			    pkt->pkt_statistics;
435282beb602SGarrett D'Amore 			arq_status->sts_rqpkt_resid = 0;
435382beb602SGarrett D'Amore 
4354*2cbbfaaaSToomas Soome 			struct scsi_extended_sense *sts_sensedata;
435582beb602SGarrett D'Amore 
4356*2cbbfaaaSToomas Soome 			sts_sensedata = &arq_status->sts_sensedata;
4357*2cbbfaaaSToomas Soome 
4358*2cbbfaaaSToomas Soome 			/* has error report sensedata */
4359*2cbbfaaaSToomas Soome 			sts_sensedata->es_code = 0x0;
4360*2cbbfaaaSToomas Soome 			sts_sensedata->es_valid = 0x01;
4361*2cbbfaaaSToomas Soome 			sts_sensedata->es_key = KEY_ILLEGAL_REQUEST;
4362*2cbbfaaaSToomas Soome 			/* AdditionalSenseLength */
4363*2cbbfaaaSToomas Soome 			sts_sensedata->es_add_len = 0x0A;
4364*2cbbfaaaSToomas Soome 			/* AdditionalSenseCode */
4365*2cbbfaaaSToomas Soome 			sts_sensedata->es_add_code = 0x20;
436682beb602SGarrett D'Amore 			retvalue = ARCMSR_MESSAGE_FAIL;
4367508aff1aSJames C. McPherson 		} else {
436882beb602SGarrett D'Amore 			my_empty_len = (wqbuf_firstidx-wqbuf_lastidx - 1) &
436982beb602SGarrett D'Amore 			    (ARCMSR_MAX_QBUFFER - 1);
437082beb602SGarrett D'Amore 			if (my_empty_len >= user_len) {
437182beb602SGarrett D'Amore 				while (user_len > 0) {
437282beb602SGarrett D'Amore 					pQbuffer = &acb->wqbuffer[
437382beb602SGarrett D'Amore 					    acb->wqbuf_lastidx];
4374508aff1aSJames C. McPherson 					(void) memcpy(pQbuffer,
4375508aff1aSJames C. McPherson 					    ptmpuserbuffer, 1);
4376508aff1aSJames C. McPherson 					acb->wqbuf_lastidx++;
4377508aff1aSJames C. McPherson 					acb->wqbuf_lastidx %=
4378508aff1aSJames C. McPherson 					    ARCMSR_MAX_QBUFFER;
4379508aff1aSJames C. McPherson 					ptmpuserbuffer++;
4380508aff1aSJames C. McPherson 					user_len--;
4381508aff1aSJames C. McPherson 				}
4382508aff1aSJames C. McPherson 				if (acb->acb_flags &
4383508aff1aSJames C. McPherson 				    ACB_F_MESSAGE_WQBUFFER_CLEARED) {
4384508aff1aSJames C. McPherson 					acb->acb_flags &=
4385508aff1aSJames C. McPherson 					    ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
4386508aff1aSJames C. McPherson 					arcmsr_post_ioctldata2iop(acb);
4387508aff1aSJames C. McPherson 				}
4388508aff1aSJames C. McPherson 			} else {
438982beb602SGarrett D'Amore 				struct scsi_arq_status *arq_status;
439082beb602SGarrett D'Amore 
439182beb602SGarrett D'Amore 				/* has error report sensedata */
439282beb602SGarrett D'Amore 				arq_status = (struct scsi_arq_status *)
439382beb602SGarrett D'Amore 				    (intptr_t)(pkt->pkt_scbp);
439482beb602SGarrett D'Amore 				bzero((caddr_t)arq_status,
439582beb602SGarrett D'Amore 				    sizeof (struct scsi_arq_status));
439682beb602SGarrett D'Amore 				arq_status->sts_rqpkt_reason = CMD_CMPLT;
439782beb602SGarrett D'Amore 				arq_status->sts_rqpkt_state =
439882beb602SGarrett D'Amore 				    (STATE_GOT_BUS |
439982beb602SGarrett D'Amore 				    STATE_GOT_TARGET |STATE_SENT_CMD |
440082beb602SGarrett D'Amore 				    STATE_XFERRED_DATA | STATE_GOT_STATUS);
440182beb602SGarrett D'Amore 				arq_status->sts_rqpkt_statistics =
440282beb602SGarrett D'Amore 				    pkt->pkt_statistics;
440382beb602SGarrett D'Amore 				arq_status->sts_rqpkt_resid = 0;
4404*2cbbfaaaSToomas Soome 
4405*2cbbfaaaSToomas Soome 				struct scsi_extended_sense *sts_sensedata;
4406*2cbbfaaaSToomas Soome 				sts_sensedata = &arq_status->sts_sensedata;
4407*2cbbfaaaSToomas Soome 
4408*2cbbfaaaSToomas Soome 				/* has error report sensedata */
4409*2cbbfaaaSToomas Soome 				sts_sensedata->es_code  = 0x0;
4410*2cbbfaaaSToomas Soome 				sts_sensedata->es_valid = 0x01;
4411*2cbbfaaaSToomas Soome 				sts_sensedata->es_key = KEY_ILLEGAL_REQUEST;
4412*2cbbfaaaSToomas Soome 				/* AdditionalSenseLength */
4413*2cbbfaaaSToomas Soome 				sts_sensedata->es_add_len = 0x0A;
4414*2cbbfaaaSToomas Soome 				/* AdditionalSenseCode */
4415*2cbbfaaaSToomas Soome 				sts_sensedata->es_add_code = 0x20;
441682beb602SGarrett D'Amore 				retvalue = ARCMSR_MESSAGE_FAIL;
4417508aff1aSJames C. McPherson 			}
4418508aff1aSJames C. McPherson 		}
4419508aff1aSJames C. McPherson 		kmem_free(ver_addr, MSGDATABUFLEN);
442082beb602SGarrett D'Amore 		break;
4421508aff1aSJames C. McPherson 	}
442282beb602SGarrett D'Amore 
4423508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER:
442482beb602SGarrett D'Amore 		pQbuffer = acb->rqbuffer;
4425508aff1aSJames C. McPherson 
4426508aff1aSJames C. McPherson 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
4427508aff1aSJames C. McPherson 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
442882beb602SGarrett D'Amore 			arcmsr_iop_message_read(acb);
4429508aff1aSJames C. McPherson 		}
4430508aff1aSJames C. McPherson 		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
4431508aff1aSJames C. McPherson 		acb->rqbuf_firstidx = 0;
4432508aff1aSJames C. McPherson 		acb->rqbuf_lastidx = 0;
443382beb602SGarrett D'Amore 		(void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
443482beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.ReturnCode =
4435508aff1aSJames C. McPherson 		    ARCMSR_MESSAGE_RETURNCODE_OK;
443682beb602SGarrett D'Amore 		break;
4437508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER:
443882beb602SGarrett D'Amore 		pQbuffer = acb->wqbuffer;
4439508aff1aSJames C. McPherson 
4440508aff1aSJames C. McPherson 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
4441508aff1aSJames C. McPherson 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
4442508aff1aSJames C. McPherson 			arcmsr_iop_message_read(acb);
4443508aff1aSJames C. McPherson 		}
4444508aff1aSJames C. McPherson 		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
4445508aff1aSJames C. McPherson 		    ACB_F_MESSAGE_WQBUFFER_READ);
4446508aff1aSJames C. McPherson 		acb->wqbuf_firstidx = 0;
4447508aff1aSJames C. McPherson 		acb->wqbuf_lastidx = 0;
444882beb602SGarrett D'Amore 		(void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
444982beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.ReturnCode =
4450508aff1aSJames C. McPherson 		    ARCMSR_MESSAGE_RETURNCODE_OK;
445182beb602SGarrett D'Amore 		break;
4452508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER:
4453508aff1aSJames C. McPherson 
4454508aff1aSJames C. McPherson 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
4455508aff1aSJames C. McPherson 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
4456508aff1aSJames C. McPherson 			arcmsr_iop_message_read(acb);
4457508aff1aSJames C. McPherson 		}
4458508aff1aSJames C. McPherson 		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
4459508aff1aSJames C. McPherson 		    ACB_F_MESSAGE_RQBUFFER_CLEARED |
4460508aff1aSJames C. McPherson 		    ACB_F_MESSAGE_WQBUFFER_READ);
4461508aff1aSJames C. McPherson 		acb->rqbuf_firstidx = 0;
4462508aff1aSJames C. McPherson 		acb->rqbuf_lastidx = 0;
4463508aff1aSJames C. McPherson 		acb->wqbuf_firstidx = 0;
4464508aff1aSJames C. McPherson 		acb->wqbuf_lastidx = 0;
4465508aff1aSJames C. McPherson 		pQbuffer = acb->rqbuffer;
446682beb602SGarrett D'Amore 		(void) memset(pQbuffer, 0, sizeof (struct QBUFFER));
4467508aff1aSJames C. McPherson 		pQbuffer = acb->wqbuffer;
446882beb602SGarrett D'Amore 		(void) memset(pQbuffer, 0, sizeof (struct QBUFFER));
446982beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.ReturnCode =
4470508aff1aSJames C. McPherson 		    ARCMSR_MESSAGE_RETURNCODE_OK;
447182beb602SGarrett D'Amore 		break;
4472508aff1aSJames C. McPherson 
4473508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F:
447482beb602SGarrett D'Amore 		pcmdmessagefld->cmdmessage.ReturnCode =
4475508aff1aSJames C. McPherson 		    ARCMSR_MESSAGE_RETURNCODE_3F;
447682beb602SGarrett D'Amore 		break;
447782beb602SGarrett D'Amore 	/*
447882beb602SGarrett D'Amore 	 * Not supported - ARCMSR_MESSAGE_SAY_HELLO
447982beb602SGarrett D'Amore 	 */
4480508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_SAY_GOODBYE:
4481508aff1aSJames C. McPherson 		arcmsr_iop_parking(acb);
4482508aff1aSJames C. McPherson 		break;
4483508aff1aSJames C. McPherson 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
448482beb602SGarrett D'Amore 		switch (acb->adapter_type) {
448582beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_A:
4486508aff1aSJames C. McPherson 			arcmsr_flush_hba_cache(acb);
448782beb602SGarrett D'Amore 			break;
448882beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_B:
4489508aff1aSJames C. McPherson 			arcmsr_flush_hbb_cache(acb);
449082beb602SGarrett D'Amore 			break;
449182beb602SGarrett D'Amore 		case ACB_ADAPTER_TYPE_C:
449282beb602SGarrett D'Amore 			arcmsr_flush_hbc_cache(acb);
449382beb602SGarrett D'Amore 			break;
4494508aff1aSJames C. McPherson 		}
4495508aff1aSJames C. McPherson 		break;
4496508aff1aSJames C. McPherson 	default:
449782beb602SGarrett D'Amore 		retvalue = ARCMSR_MESSAGE_FAIL;
4498508aff1aSJames C. McPherson 	}
4499508aff1aSJames C. McPherson 
450082beb602SGarrett D'Amore message_out:
4501508aff1aSJames C. McPherson 
4502508aff1aSJames C. McPherson 	return (retvalue);
4503508aff1aSJames C. McPherson }
4504508aff1aSJames C. McPherson 
4505508aff1aSJames C. McPherson 
4506508aff1aSJames C. McPherson 
4507508aff1aSJames C. McPherson 
4508508aff1aSJames C. McPherson static void
arcmsr_pcidev_disattach(struct ACB * acb)450982beb602SGarrett D'Amore arcmsr_pcidev_disattach(struct ACB *acb)
451082beb602SGarrett D'Amore {
4511508aff1aSJames C. McPherson 	struct CCB *ccb;
4512508aff1aSJames C. McPherson 	int i = 0;
4513508aff1aSJames C. McPherson 
4514508aff1aSJames C. McPherson 	/* disable all outbound interrupts */
4515508aff1aSJames C. McPherson 	(void) arcmsr_disable_allintr(acb);
4516508aff1aSJames C. McPherson 	/* stop adapter background rebuild */
451782beb602SGarrett D'Amore 	switch (acb->adapter_type) {
451882beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
4519508aff1aSJames C. McPherson 		arcmsr_stop_hba_bgrb(acb);
4520508aff1aSJames C. McPherson 		arcmsr_flush_hba_cache(acb);
452182beb602SGarrett D'Amore 		break;
452282beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
4523508aff1aSJames C. McPherson 		arcmsr_stop_hbb_bgrb(acb);
4524508aff1aSJames C. McPherson 		arcmsr_flush_hbb_cache(acb);
452582beb602SGarrett D'Amore 		break;
452682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
452782beb602SGarrett D'Amore 		arcmsr_stop_hbc_bgrb(acb);
452882beb602SGarrett D'Amore 		arcmsr_flush_hbc_cache(acb);
452982beb602SGarrett D'Amore 		break;
4530508aff1aSJames C. McPherson 	}
4531508aff1aSJames C. McPherson 	/* abort all outstanding commands */
4532508aff1aSJames C. McPherson 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
4533508aff1aSJames C. McPherson 	acb->acb_flags &= ~ACB_F_IOP_INITED;
4534508aff1aSJames C. McPherson 
4535508aff1aSJames C. McPherson 	if (acb->ccboutstandingcount != 0) {
4536508aff1aSJames C. McPherson 		/* clear and abort all outbound posted Q */
4537508aff1aSJames C. McPherson 		arcmsr_done4abort_postqueue(acb);
453882beb602SGarrett D'Amore 		/* talk to iop outstanding command aborted */
453982beb602SGarrett D'Amore 		(void) arcmsr_abort_host_command(acb);
4540508aff1aSJames C. McPherson 
4541508aff1aSJames C. McPherson 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
4542508aff1aSJames C. McPherson 			ccb = acb->pccb_pool[i];
454382beb602SGarrett D'Amore 			if (ccb->ccb_state == ARCMSR_CCB_START) {
454482beb602SGarrett D'Amore 				/* ccb->ccb_state = ARCMSR_CCB_ABORTED; */
4545508aff1aSJames C. McPherson 				ccb->pkt->pkt_reason = CMD_ABORTED;
4546508aff1aSJames C. McPherson 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
4547508aff1aSJames C. McPherson 				arcmsr_ccb_complete(ccb, 1);
4548508aff1aSJames C. McPherson 			}
4549508aff1aSJames C. McPherson 		}
4550508aff1aSJames C. McPherson 	}
4551508aff1aSJames C. McPherson }
4552508aff1aSJames C. McPherson 
4553508aff1aSJames C. McPherson /* get firmware miscellaneous data */
4554508aff1aSJames C. McPherson static void
arcmsr_get_hba_config(struct ACB * acb)455582beb602SGarrett D'Amore arcmsr_get_hba_config(struct ACB *acb)
455682beb602SGarrett D'Amore {
4557508aff1aSJames C. McPherson 	struct HBA_msgUnit *phbamu;
4558508aff1aSJames C. McPherson 
4559508aff1aSJames C. McPherson 	char *acb_firm_model;
4560508aff1aSJames C. McPherson 	char *acb_firm_version;
4561ed632624SColin Yi 	char *acb_device_map;
4562508aff1aSJames C. McPherson 	char *iop_firm_model;
4563508aff1aSJames C. McPherson 	char *iop_firm_version;
4564ed632624SColin Yi 	char *iop_device_map;
4565508aff1aSJames C. McPherson 	int count;
4566508aff1aSJames C. McPherson 
4567508aff1aSJames C. McPherson 	phbamu = (struct HBA_msgUnit *)acb->pmu;
4568508aff1aSJames C. McPherson 	acb_firm_model = acb->firm_model;
4569508aff1aSJames C. McPherson 	acb_firm_version = acb->firm_version;
4570ed632624SColin Yi 	acb_device_map = acb->device_map;
4571508aff1aSJames C. McPherson 	/* firm_model, 15 */
457282beb602SGarrett D'Amore 	iop_firm_model =
457382beb602SGarrett D'Amore 	    (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);
4574508aff1aSJames C. McPherson 	/* firm_version, 17 */
4575508aff1aSJames C. McPherson 	iop_firm_version =
4576508aff1aSJames C. McPherson 	    (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);
4577508aff1aSJames C. McPherson 
4578ed632624SColin Yi 	/* device_map, 21 */
4579ed632624SColin Yi 	iop_device_map =
4580ed632624SColin Yi 	    (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]);
4581ed632624SColin Yi 
458282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
458382beb602SGarrett D'Amore 	    &phbamu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
4584508aff1aSJames C. McPherson 
4585508aff1aSJames C. McPherson 	if (!arcmsr_hba_wait_msgint_ready(acb))
458682beb602SGarrett D'Amore 		arcmsr_warn(acb,
458782beb602SGarrett D'Amore 		    "timeout while waiting for adapter firmware "
458882beb602SGarrett D'Amore 		    "miscellaneous data");
4589508aff1aSJames C. McPherson 
4590508aff1aSJames C. McPherson 	count = 8;
4591508aff1aSJames C. McPherson 	while (count) {
459282beb602SGarrett D'Amore 		*acb_firm_model = CHIP_REG_READ8(acb->reg_mu_acc_handle0,
459382beb602SGarrett D'Amore 		    iop_firm_model);
4594508aff1aSJames C. McPherson 		acb_firm_model++;
4595508aff1aSJames C. McPherson 		iop_firm_model++;
4596508aff1aSJames C. McPherson 		count--;
4597508aff1aSJames C. McPherson 	}
4598508aff1aSJames C. McPherson 
4599508aff1aSJames C. McPherson 	count = 16;
4600508aff1aSJames C. McPherson 	while (count) {
4601508aff1aSJames C. McPherson 		*acb_firm_version =
4602508aff1aSJames C. McPherson 		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_version);
4603508aff1aSJames C. McPherson 		acb_firm_version++;
4604508aff1aSJames C. McPherson 		iop_firm_version++;
4605508aff1aSJames C. McPherson 		count--;
4606508aff1aSJames C. McPherson 	}
4607508aff1aSJames C. McPherson 
4608ed632624SColin Yi 	count = 16;
4609ed632624SColin Yi 	while (count) {
4610ed632624SColin Yi 		*acb_device_map =
4611ed632624SColin Yi 		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_device_map);
4612ed632624SColin Yi 		acb_device_map++;
4613ed632624SColin Yi 		iop_device_map++;
4614ed632624SColin Yi 		count--;
4615ed632624SColin Yi 	}
4616ed632624SColin Yi 
461782beb602SGarrett D'Amore 	arcmsr_log(acb, CE_CONT, "ARECA RAID FIRMWARE VERSION %s\n",
461882beb602SGarrett D'Amore 	    acb->firm_version);
4619508aff1aSJames C. McPherson 
4620508aff1aSJames C. McPherson 	/* firm_request_len, 1 */
4621508aff1aSJames C. McPherson 	acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4622508aff1aSJames C. McPherson 	    &phbamu->msgcode_rwbuffer[1]);
4623508aff1aSJames C. McPherson 	/* firm_numbers_queue, 2 */
4624508aff1aSJames C. McPherson 	acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4625508aff1aSJames C. McPherson 	    &phbamu->msgcode_rwbuffer[2]);
4626508aff1aSJames C. McPherson 	/* firm_sdram_size, 3 */
4627508aff1aSJames C. McPherson 	acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4628508aff1aSJames C. McPherson 	    &phbamu->msgcode_rwbuffer[3]);
4629508aff1aSJames C. McPherson 	/* firm_ide_channels, 4 */
4630508aff1aSJames C. McPherson 	acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4631508aff1aSJames C. McPherson 	    &phbamu->msgcode_rwbuffer[4]);
4632508aff1aSJames C. McPherson }
4633508aff1aSJames C. McPherson 
4634508aff1aSJames C. McPherson /* get firmware miscellaneous data */
4635508aff1aSJames C. McPherson static void
arcmsr_get_hbb_config(struct ACB * acb)463682beb602SGarrett D'Amore arcmsr_get_hbb_config(struct ACB *acb)
463782beb602SGarrett D'Amore {
4638508aff1aSJames C. McPherson 	struct HBB_msgUnit *phbbmu;
4639508aff1aSJames C. McPherson 	char *acb_firm_model;
4640508aff1aSJames C. McPherson 	char *acb_firm_version;
4641ed632624SColin Yi 	char *acb_device_map;
4642508aff1aSJames C. McPherson 	char *iop_firm_model;
4643508aff1aSJames C. McPherson 	char *iop_firm_version;
4644ed632624SColin Yi 	char *iop_device_map;
4645508aff1aSJames C. McPherson 	int count;
4646508aff1aSJames C. McPherson 
4647508aff1aSJames C. McPherson 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
4648508aff1aSJames C. McPherson 	acb_firm_model = acb->firm_model;
4649508aff1aSJames C. McPherson 	acb_firm_version = acb->firm_version;
4650ed632624SColin Yi 	acb_device_map = acb->device_map;
4651508aff1aSJames C. McPherson 	/* firm_model, 15 */
4652508aff1aSJames C. McPherson 	iop_firm_model = (char *)
4653508aff1aSJames C. McPherson 	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);
4654508aff1aSJames C. McPherson 	/* firm_version, 17 */
465582beb602SGarrett D'Amore 	iop_firm_version = (char *)
465682beb602SGarrett D'Amore 	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);
465782beb602SGarrett D'Amore 	/* device_map, 21 */
465882beb602SGarrett D'Amore 	iop_device_map = (char *)
465982beb602SGarrett D'Amore 	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]);
466082beb602SGarrett D'Amore 
466182beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
466282beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG);
466382beb602SGarrett D'Amore 
466482beb602SGarrett D'Amore 	if (!arcmsr_hbb_wait_msgint_ready(acb))
466582beb602SGarrett D'Amore 		arcmsr_warn(acb,
466682beb602SGarrett D'Amore 		    "timeout while waiting for adapter firmware "
466782beb602SGarrett D'Amore 		    "miscellaneous data");
466882beb602SGarrett D'Amore 
466982beb602SGarrett D'Amore 	count = 8;
467082beb602SGarrett D'Amore 	while (count) {
467182beb602SGarrett D'Amore 		*acb_firm_model =
467282beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle1, iop_firm_model);
467382beb602SGarrett D'Amore 		acb_firm_model++;
467482beb602SGarrett D'Amore 		iop_firm_model++;
467582beb602SGarrett D'Amore 		count--;
467682beb602SGarrett D'Amore 	}
467782beb602SGarrett D'Amore 	count = 16;
467882beb602SGarrett D'Amore 	while (count) {
467982beb602SGarrett D'Amore 		*acb_firm_version =
468082beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle1, iop_firm_version);
468182beb602SGarrett D'Amore 		acb_firm_version++;
468282beb602SGarrett D'Amore 		iop_firm_version++;
468382beb602SGarrett D'Amore 		count--;
468482beb602SGarrett D'Amore 	}
468582beb602SGarrett D'Amore 	count = 16;
468682beb602SGarrett D'Amore 	while (count) {
468782beb602SGarrett D'Amore 		*acb_device_map =
468882beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle1, iop_device_map);
468982beb602SGarrett D'Amore 		acb_device_map++;
469082beb602SGarrett D'Amore 		iop_device_map++;
469182beb602SGarrett D'Amore 		count--;
469282beb602SGarrett D'Amore 	}
469382beb602SGarrett D'Amore 
469482beb602SGarrett D'Amore 	arcmsr_log(acb, CE_CONT, "ARECA RAID FIRMWARE VERSION %s\n",
469582beb602SGarrett D'Amore 	    acb->firm_version);
469682beb602SGarrett D'Amore 
469782beb602SGarrett D'Amore 	/* firm_request_len, 1 */
469882beb602SGarrett D'Amore 	acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
469982beb602SGarrett D'Amore 	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1]);
470082beb602SGarrett D'Amore 	/* firm_numbers_queue, 2 */
470182beb602SGarrett D'Amore 	acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
470282beb602SGarrett D'Amore 	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2]);
470382beb602SGarrett D'Amore 	/* firm_sdram_size, 3 */
470482beb602SGarrett D'Amore 	acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
470582beb602SGarrett D'Amore 	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3]);
470682beb602SGarrett D'Amore 	/* firm_ide_channels, 4 */
470782beb602SGarrett D'Amore 	acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
470882beb602SGarrett D'Amore 	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4]);
470982beb602SGarrett D'Amore }
471082beb602SGarrett D'Amore 
471182beb602SGarrett D'Amore 
471282beb602SGarrett D'Amore /* get firmware miscellaneous data */
471382beb602SGarrett D'Amore static void
arcmsr_get_hbc_config(struct ACB * acb)471482beb602SGarrett D'Amore arcmsr_get_hbc_config(struct ACB *acb)
471582beb602SGarrett D'Amore {
471682beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
471782beb602SGarrett D'Amore 
471882beb602SGarrett D'Amore 	char *acb_firm_model;
471982beb602SGarrett D'Amore 	char *acb_firm_version;
472082beb602SGarrett D'Amore 	char *acb_device_map;
472182beb602SGarrett D'Amore 	char *iop_firm_model;
472282beb602SGarrett D'Amore 	char *iop_firm_version;
472382beb602SGarrett D'Amore 	char *iop_device_map;
472482beb602SGarrett D'Amore 	int count;
472582beb602SGarrett D'Amore 
472682beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
472782beb602SGarrett D'Amore 	acb_firm_model = acb->firm_model;
472882beb602SGarrett D'Amore 	acb_firm_version = acb->firm_version;
472982beb602SGarrett D'Amore 	acb_device_map = acb->device_map;
473082beb602SGarrett D'Amore 	/* firm_model, 15 */
473182beb602SGarrett D'Amore 	iop_firm_model =
473282beb602SGarrett D'Amore 	    (char *)(&phbcmu->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);
473382beb602SGarrett D'Amore 	/* firm_version, 17 */
473482beb602SGarrett D'Amore 	iop_firm_version =
473582beb602SGarrett D'Amore 	    (char *)(&phbcmu->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);
4736ed632624SColin Yi 	/* device_map, 21 */
473782beb602SGarrett D'Amore 	iop_device_map =
473882beb602SGarrett D'Amore 	    (char *)(&phbcmu->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]);
473982beb602SGarrett D'Amore 	/* post "get config" instruction */
4740508aff1aSJames C. McPherson 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
474182beb602SGarrett D'Amore 	    &phbcmu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
474282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
474382beb602SGarrett D'Amore 	    &phbcmu->inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
474482beb602SGarrett D'Amore 	if (!arcmsr_hbc_wait_msgint_ready(acb))
474582beb602SGarrett D'Amore 		arcmsr_warn(acb,
474682beb602SGarrett D'Amore 		    "timeout while waiting for adapter firmware "
474782beb602SGarrett D'Amore 		    "miscellaneous data");
4748508aff1aSJames C. McPherson 	count = 8;
4749508aff1aSJames C. McPherson 	while (count) {
475082beb602SGarrett D'Amore 		*acb_firm_model =
475182beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_model);
4752508aff1aSJames C. McPherson 		acb_firm_model++;
4753508aff1aSJames C. McPherson 		iop_firm_model++;
4754508aff1aSJames C. McPherson 		count--;
4755508aff1aSJames C. McPherson 	}
4756508aff1aSJames C. McPherson 
4757508aff1aSJames C. McPherson 	count = 16;
4758508aff1aSJames C. McPherson 	while (count) {
475982beb602SGarrett D'Amore 		*acb_firm_version =
476082beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_version);
4761508aff1aSJames C. McPherson 		acb_firm_version++;
4762508aff1aSJames C. McPherson 		iop_firm_version++;
4763508aff1aSJames C. McPherson 		count--;
4764508aff1aSJames C. McPherson 	}
476582beb602SGarrett D'Amore 
4766ed632624SColin Yi 	count = 16;
4767ed632624SColin Yi 	while (count) {
4768ed632624SColin Yi 		*acb_device_map =
476982beb602SGarrett D'Amore 		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_device_map);
4770ed632624SColin Yi 		acb_device_map++;
4771ed632624SColin Yi 		iop_device_map++;
4772ed632624SColin Yi 		count--;
4773ed632624SColin Yi 	}
4774508aff1aSJames C. McPherson 
477582beb602SGarrett D'Amore 	arcmsr_log(acb, CE_CONT, "ARECA RAID FIRMWARE VERSION %s\n",
477682beb602SGarrett D'Amore 	    acb->firm_version);
4777508aff1aSJames C. McPherson 
477882beb602SGarrett D'Amore 	/* firm_request_len, 1, 04-07 */
477982beb602SGarrett D'Amore 	acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
478082beb602SGarrett D'Amore 	    &phbcmu->msgcode_rwbuffer[1]);
478182beb602SGarrett D'Amore 	/* firm_numbers_queue, 2, 08-11 */
478282beb602SGarrett D'Amore 	acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
478382beb602SGarrett D'Amore 	    &phbcmu->msgcode_rwbuffer[2]);
478482beb602SGarrett D'Amore 	/* firm_sdram_size, 3, 12-15 */
478582beb602SGarrett D'Amore 	acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
478682beb602SGarrett D'Amore 	    &phbcmu->msgcode_rwbuffer[3]);
478782beb602SGarrett D'Amore 	/* firm_ide_channels, 4, 16-19 */
478882beb602SGarrett D'Amore 	acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
478982beb602SGarrett D'Amore 	    &phbcmu->msgcode_rwbuffer[4]);
479082beb602SGarrett D'Amore 	/* firm_cfg_version, 25, 100-103 */
479182beb602SGarrett D'Amore 	acb->firm_cfg_version = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
479282beb602SGarrett D'Amore 	    &phbcmu->msgcode_rwbuffer[25]);
4793508aff1aSJames C. McPherson }
4794508aff1aSJames C. McPherson 
4795508aff1aSJames C. McPherson 
4796508aff1aSJames C. McPherson /* start background rebuild */
4797508aff1aSJames C. McPherson static void
arcmsr_start_hba_bgrb(struct ACB * acb)4798d5ebc493SDan Cross arcmsr_start_hba_bgrb(struct ACB *acb)
4799d5ebc493SDan Cross {
4800508aff1aSJames C. McPherson 	struct HBA_msgUnit *phbamu;
4801508aff1aSJames C. McPherson 
4802508aff1aSJames C. McPherson 	phbamu = (struct HBA_msgUnit *)acb->pmu;
4803508aff1aSJames C. McPherson 
4804508aff1aSJames C. McPherson 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
4805508aff1aSJames C. McPherson 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4806508aff1aSJames C. McPherson 	    &phbamu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
4807508aff1aSJames C. McPherson 
4808508aff1aSJames C. McPherson 	if (!arcmsr_hba_wait_msgint_ready(acb))
480982beb602SGarrett D'Amore 		arcmsr_warn(acb,
481082beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild to start");
4811508aff1aSJames C. McPherson }
4812508aff1aSJames C. McPherson 
4813508aff1aSJames C. McPherson 
4814508aff1aSJames C. McPherson static void
arcmsr_start_hbb_bgrb(struct ACB * acb)4815d5ebc493SDan Cross arcmsr_start_hbb_bgrb(struct ACB *acb)
4816d5ebc493SDan Cross {
4817508aff1aSJames C. McPherson 	struct HBB_msgUnit *phbbmu;
4818508aff1aSJames C. McPherson 
4819508aff1aSJames C. McPherson 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
4820508aff1aSJames C. McPherson 
4821508aff1aSJames C. McPherson 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
4822508aff1aSJames C. McPherson 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4823508aff1aSJames C. McPherson 	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
4824508aff1aSJames C. McPherson 	    ARCMSR_MESSAGE_START_BGRB);
4825508aff1aSJames C. McPherson 
4826508aff1aSJames C. McPherson 	if (!arcmsr_hbb_wait_msgint_ready(acb))
482782beb602SGarrett D'Amore 		arcmsr_warn(acb,
482882beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild to start");
4829508aff1aSJames C. McPherson }
4830508aff1aSJames C. McPherson 
4831508aff1aSJames C. McPherson 
4832508aff1aSJames C. McPherson static void
arcmsr_start_hbc_bgrb(struct ACB * acb)4833d5ebc493SDan Cross arcmsr_start_hbc_bgrb(struct ACB *acb)
4834d5ebc493SDan Cross {
483582beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
483682beb602SGarrett D'Amore 
483782beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
483882beb602SGarrett D'Amore 
483982beb602SGarrett D'Amore 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
484082beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
484182beb602SGarrett D'Amore 	    &phbcmu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
484282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
484382beb602SGarrett D'Amore 	    &phbcmu->inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
484482beb602SGarrett D'Amore 	if (!arcmsr_hbc_wait_msgint_ready(acb))
484582beb602SGarrett D'Amore 		arcmsr_warn(acb,
484682beb602SGarrett D'Amore 		    "timeout while waiting for background rebuild to start");
484782beb602SGarrett D'Amore }
4848508aff1aSJames C. McPherson 
484982beb602SGarrett D'Amore static void
arcmsr_polling_hba_ccbdone(struct ACB * acb,struct CCB * poll_ccb)485082beb602SGarrett D'Amore arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb)
485182beb602SGarrett D'Amore {
4852508aff1aSJames C. McPherson 	struct HBA_msgUnit *phbamu;
4853508aff1aSJames C. McPherson 	struct CCB *ccb;
485482beb602SGarrett D'Amore 	boolean_t error;
485582beb602SGarrett D'Amore 	uint32_t flag_ccb, outbound_intstatus, intmask_org;
485682beb602SGarrett D'Amore 	boolean_t poll_ccb_done = B_FALSE;
4857508aff1aSJames C. McPherson 	uint32_t poll_count = 0;
4858508aff1aSJames C. McPherson 
4859508aff1aSJames C. McPherson 
4860508aff1aSJames C. McPherson 	phbamu = (struct HBA_msgUnit *)acb->pmu;
4861508aff1aSJames C. McPherson 
4862508aff1aSJames C. McPherson polling_ccb_retry:
486382beb602SGarrett D'Amore 	/* TODO: Use correct offset and size for syncing? */
486482beb602SGarrett D'Amore 	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
4865508aff1aSJames C. McPherson 	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
4866508aff1aSJames C. McPherson 		return;
486782beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
4868508aff1aSJames C. McPherson 
486982beb602SGarrett D'Amore 	for (;;) {
4870508aff1aSJames C. McPherson 		if ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4871508aff1aSJames C. McPherson 		    &phbamu->outbound_queueport)) == 0xFFFFFFFF) {
4872508aff1aSJames C. McPherson 			if (poll_ccb_done) {
4873508aff1aSJames C. McPherson 				/* chip FIFO no ccb for completion already */
4874508aff1aSJames C. McPherson 				break;
4875508aff1aSJames C. McPherson 			} else {
4876508aff1aSJames C. McPherson 				drv_usecwait(25000);
4877ed632624SColin Yi 				if ((poll_count > 100) && (poll_ccb != NULL)) {
4878508aff1aSJames C. McPherson 					break;
4879508aff1aSJames C. McPherson 				}
4880ed632624SColin Yi 				if (acb->ccboutstandingcount == 0) {
4881ed632624SColin Yi 					break;
4882ed632624SColin Yi 				}
488382beb602SGarrett D'Amore 				poll_count++;
488482beb602SGarrett D'Amore 				outbound_intstatus =
488582beb602SGarrett D'Amore 				    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
488682beb602SGarrett D'Amore 				    &phbamu->outbound_intstatus) &
488782beb602SGarrett D'Amore 				    acb->outbound_int_enable;
488882beb602SGarrett D'Amore 
488982beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
489082beb602SGarrett D'Amore 				    &phbamu->outbound_intstatus,
489182beb602SGarrett D'Amore 				    outbound_intstatus); /* clear interrupt */
4892508aff1aSJames C. McPherson 			}
4893508aff1aSJames C. McPherson 		}
4894508aff1aSJames C. McPherson 
489582beb602SGarrett D'Amore 		/* frame must be 32 bytes aligned */
489682beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset + (flag_ccb << 5)));
489782beb602SGarrett D'Amore 
489882beb602SGarrett D'Amore 		/* check if command done with no error */
489982beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
490082beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
4901ed632624SColin Yi 		if (poll_ccb != NULL)
490282beb602SGarrett D'Amore 			poll_ccb_done = (ccb == poll_ccb) ? B_TRUE : B_FALSE;
4903508aff1aSJames C. McPherson 
490482beb602SGarrett D'Amore 		if (ccb->acb != acb) {
490582beb602SGarrett D'Amore 			arcmsr_warn(acb, "ccb got a wrong acb!");
490682beb602SGarrett D'Amore 			continue;
490782beb602SGarrett D'Amore 		}
490882beb602SGarrett D'Amore 		if (ccb->ccb_state != ARCMSR_CCB_START) {
490982beb602SGarrett D'Amore 			if (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
491082beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
4911508aff1aSJames C. McPherson 				ccb->pkt->pkt_reason = CMD_ABORTED;
4912508aff1aSJames C. McPherson 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
4913508aff1aSJames C. McPherson 				arcmsr_ccb_complete(ccb, 1);
4914508aff1aSJames C. McPherson 				continue;
4915508aff1aSJames C. McPherson 			}
491682beb602SGarrett D'Amore 			arcmsr_report_ccb_state(acb, ccb, error);
491782beb602SGarrett D'Amore 			arcmsr_warn(acb,
491882beb602SGarrett D'Amore 			    "polling op got unexpected ccb command done");
4919508aff1aSJames C. McPherson 			continue;
4920508aff1aSJames C. McPherson 		}
492182beb602SGarrett D'Amore 		arcmsr_report_ccb_state(acb, ccb, error);
4922508aff1aSJames C. McPherson 	}	/* drain reply FIFO */
492382beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
4924508aff1aSJames C. McPherson }
4925508aff1aSJames C. McPherson 
4926508aff1aSJames C. McPherson 
4927508aff1aSJames C. McPherson static void
arcmsr_polling_hbb_ccbdone(struct ACB * acb,struct CCB * poll_ccb)492882beb602SGarrett D'Amore arcmsr_polling_hbb_ccbdone(struct ACB *acb, struct CCB *poll_ccb)
492982beb602SGarrett D'Amore {
4930508aff1aSJames C. McPherson 	struct HBB_msgUnit *phbbmu;
4931508aff1aSJames C. McPherson 	struct CCB *ccb;
493282beb602SGarrett D'Amore 	uint32_t flag_ccb, intmask_org;
493382beb602SGarrett D'Amore 	boolean_t error;
4934508aff1aSJames C. McPherson 	uint32_t poll_count = 0;
4935508aff1aSJames C. McPherson 	int index;
493682beb602SGarrett D'Amore 	boolean_t poll_ccb_done = B_FALSE;
4937508aff1aSJames C. McPherson 
4938508aff1aSJames C. McPherson 
4939508aff1aSJames C. McPherson 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
4940508aff1aSJames C. McPherson 
4941508aff1aSJames C. McPherson 
4942508aff1aSJames C. McPherson polling_ccb_retry:
4943508aff1aSJames C. McPherson 	/* Use correct offset and size for syncing */
494482beb602SGarrett D'Amore 	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
4945508aff1aSJames C. McPherson 	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
4946508aff1aSJames C. McPherson 		return;
4947508aff1aSJames C. McPherson 
494882beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
4949508aff1aSJames C. McPherson 
495082beb602SGarrett D'Amore 	for (;;) {
4951508aff1aSJames C. McPherson 		index = phbbmu->doneq_index;
4952508aff1aSJames C. McPherson 		if ((flag_ccb = phbbmu->done_qbuffer[index]) == 0) {
4953508aff1aSJames C. McPherson 			if (poll_ccb_done) {
4954508aff1aSJames C. McPherson 				/* chip FIFO no ccb for completion already */
4955508aff1aSJames C. McPherson 				break;
4956508aff1aSJames C. McPherson 			} else {
4957508aff1aSJames C. McPherson 				drv_usecwait(25000);
4958ed632624SColin Yi 				if ((poll_count > 100) && (poll_ccb != NULL))
4959ed632624SColin Yi 					break;
4960ed632624SColin Yi 				if (acb->ccboutstandingcount == 0)
4961508aff1aSJames C. McPherson 					break;
496282beb602SGarrett D'Amore 				poll_count++;
496382beb602SGarrett D'Amore 				/* clear doorbell interrupt */
496482beb602SGarrett D'Amore 				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
496582beb602SGarrett D'Amore 				    &phbbmu->hbb_doorbell->iop2drv_doorbell,
496682beb602SGarrett D'Amore 				    ARCMSR_DOORBELL_INT_CLEAR_PATTERN);
4967508aff1aSJames C. McPherson 			}
4968508aff1aSJames C. McPherson 		}
4969508aff1aSJames C. McPherson 
4970508aff1aSJames C. McPherson 		phbbmu->done_qbuffer[index] = 0;
4971508aff1aSJames C. McPherson 		index++;
4972508aff1aSJames C. McPherson 		/* if last index number set it to 0 */
4973508aff1aSJames C. McPherson 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
4974508aff1aSJames C. McPherson 		phbbmu->doneq_index = index;
4975508aff1aSJames C. McPherson 		/* check if command done with no error */
4976508aff1aSJames C. McPherson 		/* frame must be 32 bytes aligned */
497782beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset + (flag_ccb << 5)));
497882beb602SGarrett D'Amore 
497982beb602SGarrett D'Amore 		/* check if command done with no error */
498082beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
498182beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
498282beb602SGarrett D'Amore 
4983ed632624SColin Yi 		if (poll_ccb != NULL)
498482beb602SGarrett D'Amore 			poll_ccb_done = (ccb == poll_ccb) ? B_TRUE : B_FALSE;
498582beb602SGarrett D'Amore 		if (ccb->acb != acb) {
498682beb602SGarrett D'Amore 			arcmsr_warn(acb, "ccb got a wrong acb!");
498782beb602SGarrett D'Amore 			continue;
498882beb602SGarrett D'Amore 		}
498982beb602SGarrett D'Amore 		if (ccb->ccb_state != ARCMSR_CCB_START) {
499082beb602SGarrett D'Amore 			if (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
499182beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
4992508aff1aSJames C. McPherson 				ccb->pkt->pkt_reason = CMD_ABORTED;
4993508aff1aSJames C. McPherson 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
4994508aff1aSJames C. McPherson 				arcmsr_ccb_complete(ccb, 1);
4995508aff1aSJames C. McPherson 				continue;
4996508aff1aSJames C. McPherson 			}
499782beb602SGarrett D'Amore 			arcmsr_report_ccb_state(acb, ccb, error);
499882beb602SGarrett D'Amore 			arcmsr_warn(acb,
499982beb602SGarrett D'Amore 			    "polling op got unexpect ccb command done");
5000508aff1aSJames C. McPherson 			continue;
5001508aff1aSJames C. McPherson 		}
500282beb602SGarrett D'Amore 		arcmsr_report_ccb_state(acb, ccb, error);
5003508aff1aSJames C. McPherson 	}	/* drain reply FIFO */
500482beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
5005508aff1aSJames C. McPherson }
5006508aff1aSJames C. McPherson 
5007508aff1aSJames C. McPherson 
500882beb602SGarrett D'Amore static void
arcmsr_polling_hbc_ccbdone(struct ACB * acb,struct CCB * poll_ccb)500982beb602SGarrett D'Amore arcmsr_polling_hbc_ccbdone(struct ACB *acb, struct CCB *poll_ccb)
501082beb602SGarrett D'Amore {
5011508aff1aSJames C. McPherson 
501282beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
5013508aff1aSJames C. McPherson 	struct CCB *ccb;
501482beb602SGarrett D'Amore 	boolean_t error;
501582beb602SGarrett D'Amore 	uint32_t ccb_cdb_phy;
501682beb602SGarrett D'Amore 	uint32_t flag_ccb, intmask_org;
501782beb602SGarrett D'Amore 	boolean_t poll_ccb_done = B_FALSE;
501882beb602SGarrett D'Amore 	uint32_t poll_count = 0;
5019508aff1aSJames C. McPherson 
5020508aff1aSJames C. McPherson 
502182beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
5022508aff1aSJames C. McPherson 
502382beb602SGarrett D'Amore polling_ccb_retry:
5024508aff1aSJames C. McPherson 
502582beb602SGarrett D'Amore 	/* Use correct offset and size for syncing */
502682beb602SGarrett D'Amore 	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
502782beb602SGarrett D'Amore 	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
502882beb602SGarrett D'Amore 		return;
5029508aff1aSJames C. McPherson 
503082beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
5031508aff1aSJames C. McPherson 
503282beb602SGarrett D'Amore 	for (;;) {
503382beb602SGarrett D'Amore 		if (!(CHIP_REG_READ32(acb->reg_mu_acc_handle0,
503482beb602SGarrett D'Amore 		    &phbcmu->host_int_status) &
503582beb602SGarrett D'Amore 		    ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)) {
5036508aff1aSJames C. McPherson 
503782beb602SGarrett D'Amore 			if (poll_ccb_done) {
503882beb602SGarrett D'Amore 				/* chip FIFO no ccb for completion already */
503982beb602SGarrett D'Amore 				break;
504082beb602SGarrett D'Amore 			} else {
504182beb602SGarrett D'Amore 				drv_usecwait(25000);
504282beb602SGarrett D'Amore 				if ((poll_count > 100) && (poll_ccb != NULL)) {
504382beb602SGarrett D'Amore 					break;
5044508aff1aSJames C. McPherson 				}
504582beb602SGarrett D'Amore 				if (acb->ccboutstandingcount == 0) {
504682beb602SGarrett D'Amore 					break;
504782beb602SGarrett D'Amore 				}
504882beb602SGarrett D'Amore 				poll_count++;
5049508aff1aSJames C. McPherson 			}
5050508aff1aSJames C. McPherson 		}
505182beb602SGarrett D'Amore 		flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
505282beb602SGarrett D'Amore 		    &phbcmu->outbound_queueport_low);
505382beb602SGarrett D'Amore 		/* frame must be 32 bytes aligned */
505482beb602SGarrett D'Amore 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
505582beb602SGarrett D'Amore 		/* the CDB is the first field of the CCB */
505682beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset + ccb_cdb_phy));
5057508aff1aSJames C. McPherson 
505882beb602SGarrett D'Amore 		/* check if command done with no error */
505982beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ?
506082beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
506182beb602SGarrett D'Amore 		if (poll_ccb != NULL)
506282beb602SGarrett D'Amore 			poll_ccb_done = (ccb == poll_ccb) ? B_TRUE : B_FALSE;
5063508aff1aSJames C. McPherson 
506482beb602SGarrett D'Amore 		if (ccb->acb != acb) {
506582beb602SGarrett D'Amore 			arcmsr_warn(acb, "ccb got a wrong acb!");
506682beb602SGarrett D'Amore 			continue;
506782beb602SGarrett D'Amore 		}
506882beb602SGarrett D'Amore 		if (ccb->ccb_state != ARCMSR_CCB_START) {
506982beb602SGarrett D'Amore 			if (ccb->ccb_state & ARCMSR_ABNORMAL_MASK) {
507082beb602SGarrett D'Amore 				ccb->ccb_state |= ARCMSR_CCB_BACK;
507182beb602SGarrett D'Amore 				ccb->pkt->pkt_reason = CMD_ABORTED;
507282beb602SGarrett D'Amore 				ccb->pkt->pkt_statistics |= STAT_ABORTED;
507382beb602SGarrett D'Amore 				arcmsr_ccb_complete(ccb, 1);
507482beb602SGarrett D'Amore 				continue;
507582beb602SGarrett D'Amore 			}
507682beb602SGarrett D'Amore 			arcmsr_report_ccb_state(acb, ccb, error);
507782beb602SGarrett D'Amore 			arcmsr_warn(acb,
507882beb602SGarrett D'Amore 			    "polling op got unexpected ccb command done");
507982beb602SGarrett D'Amore 			continue;
508082beb602SGarrett D'Amore 		}
508182beb602SGarrett D'Amore 		arcmsr_report_ccb_state(acb, ccb, error);
508282beb602SGarrett D'Amore 	}	/* drain reply FIFO */
508382beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
5084508aff1aSJames C. McPherson }
5085508aff1aSJames C. McPherson 
5086ed632624SColin Yi 
5087508aff1aSJames C. McPherson /*
508882beb602SGarrett D'Amore  * Function: arcmsr_hba_hardware_reset()
508982beb602SGarrett D'Amore  *           Bug Fix for Intel IOP cause firmware hang on.
509082beb602SGarrett D'Amore  *           and kernel panic
5091508aff1aSJames C. McPherson  */
509282beb602SGarrett D'Amore static void
arcmsr_hba_hardware_reset(struct ACB * acb)509382beb602SGarrett D'Amore arcmsr_hba_hardware_reset(struct ACB *acb)
509482beb602SGarrett D'Amore {
509582beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
509682beb602SGarrett D'Amore 	uint8_t value[64];
509782beb602SGarrett D'Amore 	int i;
5098508aff1aSJames C. McPherson 
509982beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
510082beb602SGarrett D'Amore 	/* backup pci config data */
510182beb602SGarrett D'Amore 	for (i = 0; i < 64; i++) {
510282beb602SGarrett D'Amore 		value[i] = pci_config_get8(acb->pci_acc_handle, i);
510382beb602SGarrett D'Amore 	}
510482beb602SGarrett D'Amore 	/* hardware reset signal */
510582beb602SGarrett D'Amore 	if ((PCI_DEVICE_ID_ARECA_1680 ==
510682beb602SGarrett D'Amore 	    pci_config_get16(acb->pci_acc_handle, PCI_CONF_DEVID))) {
510782beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
510882beb602SGarrett D'Amore 		    &phbamu->reserved1[0], 0x00000003);
510982beb602SGarrett D'Amore 	} else {
511082beb602SGarrett D'Amore 		pci_config_put8(acb->pci_acc_handle, 0x84, 0x20);
5111508aff1aSJames C. McPherson 	}
511282beb602SGarrett D'Amore 	drv_usecwait(1000000);
511382beb602SGarrett D'Amore 	/* write back pci config data */
511482beb602SGarrett D'Amore 	for (i = 0; i < 64; i++) {
511582beb602SGarrett D'Amore 		pci_config_put8(acb->pci_acc_handle, i, value[i]);
511682beb602SGarrett D'Amore 	}
511782beb602SGarrett D'Amore 	drv_usecwait(1000000);
511882beb602SGarrett D'Amore }
5119508aff1aSJames C. McPherson 
512082beb602SGarrett D'Amore /*
512182beb602SGarrett D'Amore  * Function: arcmsr_abort_host_command
512282beb602SGarrett D'Amore  */
512382beb602SGarrett D'Amore static uint8_t
arcmsr_abort_host_command(struct ACB * acb)512482beb602SGarrett D'Amore arcmsr_abort_host_command(struct ACB *acb)
512582beb602SGarrett D'Amore {
512682beb602SGarrett D'Amore 	uint8_t rtnval = 0;
512782beb602SGarrett D'Amore 
512882beb602SGarrett D'Amore 	switch (acb->adapter_type) {
512982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
513082beb602SGarrett D'Amore 		rtnval = arcmsr_abort_hba_allcmd(acb);
5131508aff1aSJames C. McPherson 		break;
513282beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
513382beb602SGarrett D'Amore 		rtnval = arcmsr_abort_hbb_allcmd(acb);
513482beb602SGarrett D'Amore 		break;
513582beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
513682beb602SGarrett D'Amore 		rtnval = arcmsr_abort_hbc_allcmd(acb);
5137508aff1aSJames C. McPherson 		break;
5138508aff1aSJames C. McPherson 	}
513982beb602SGarrett D'Amore 	return (rtnval);
5140508aff1aSJames C. McPherson }
5141508aff1aSJames C. McPherson 
514282beb602SGarrett D'Amore /*
514382beb602SGarrett D'Amore  * Function: arcmsr_handle_iop_bus_hold
514482beb602SGarrett D'Amore  */
5145508aff1aSJames C. McPherson static void
arcmsr_handle_iop_bus_hold(struct ACB * acb)514682beb602SGarrett D'Amore arcmsr_handle_iop_bus_hold(struct ACB *acb)
514782beb602SGarrett D'Amore {
5148508aff1aSJames C. McPherson 
514982beb602SGarrett D'Amore 	switch (acb->adapter_type) {
515082beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
515182beb602SGarrett D'Amore 	{
515282beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
515382beb602SGarrett D'Amore 		int retry_count = 0;
5154508aff1aSJames C. McPherson 
515582beb602SGarrett D'Amore 		acb->timeout_count = 0;
515682beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
515782beb602SGarrett D'Amore 		arcmsr_hba_hardware_reset(acb);
515882beb602SGarrett D'Amore 		acb->acb_flags &= ~ACB_F_IOP_INITED;
515982beb602SGarrett D'Amore 	sleep_again:
516082beb602SGarrett D'Amore 		drv_usecwait(1000000);
516182beb602SGarrett D'Amore 		if ((CHIP_REG_READ32(acb->reg_mu_acc_handle0,
516282beb602SGarrett D'Amore 		    &phbamu->outbound_msgaddr1) &
516382beb602SGarrett D'Amore 		    ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
516482beb602SGarrett D'Amore 			if (retry_count > 60) {
516582beb602SGarrett D'Amore 				arcmsr_warn(acb,
516682beb602SGarrett D'Amore 				    "waiting for hardware"
516782beb602SGarrett D'Amore 				    "bus reset return, RETRY TERMINATED!!");
516882beb602SGarrett D'Amore 				return;
516982beb602SGarrett D'Amore 			}
517082beb602SGarrett D'Amore 			retry_count++;
517182beb602SGarrett D'Amore 			goto sleep_again;
517282beb602SGarrett D'Amore 		}
517382beb602SGarrett D'Amore 		arcmsr_iop_init(acb);
517482beb602SGarrett D'Amore 		break;
517582beb602SGarrett D'Amore 	}
5176508aff1aSJames C. McPherson 
517782beb602SGarrett D'Amore 	}
517882beb602SGarrett D'Amore }
5179508aff1aSJames C. McPherson 
5180508aff1aSJames C. McPherson static void
arcmsr_iop2drv_data_wrote_handle(struct ACB * acb)5181d5ebc493SDan Cross arcmsr_iop2drv_data_wrote_handle(struct ACB *acb)
5182d5ebc493SDan Cross {
5183508aff1aSJames C. McPherson 	struct QBUFFER *prbuffer;
5184508aff1aSJames C. McPherson 	uint8_t *pQbuffer;
5185508aff1aSJames C. McPherson 	uint8_t *iop_data;
5186508aff1aSJames C. McPherson 	int my_empty_len, iop_len;
5187508aff1aSJames C. McPherson 	int rqbuf_firstidx, rqbuf_lastidx;
5188508aff1aSJames C. McPherson 
5189508aff1aSJames C. McPherson 	/* check this iop data if overflow my rqbuffer */
5190508aff1aSJames C. McPherson 	rqbuf_lastidx = acb->rqbuf_lastidx;
5191508aff1aSJames C. McPherson 	rqbuf_firstidx = acb->rqbuf_firstidx;
5192508aff1aSJames C. McPherson 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
5193508aff1aSJames C. McPherson 	iop_data = (uint8_t *)prbuffer->data;
5194508aff1aSJames C. McPherson 	iop_len = prbuffer->data_len;
5195508aff1aSJames C. McPherson 	my_empty_len = (rqbuf_firstidx-rqbuf_lastidx - 1) &
5196508aff1aSJames C. McPherson 	    (ARCMSR_MAX_QBUFFER - 1);
5197508aff1aSJames C. McPherson 
5198508aff1aSJames C. McPherson 	if (my_empty_len >= iop_len) {
5199508aff1aSJames C. McPherson 		while (iop_len > 0) {
5200508aff1aSJames C. McPherson 			pQbuffer = &acb->rqbuffer[rqbuf_lastidx];
5201508aff1aSJames C. McPherson 			(void) memcpy(pQbuffer, iop_data, 1);
5202508aff1aSJames C. McPherson 			rqbuf_lastidx++;
5203508aff1aSJames C. McPherson 			/* if last index number set it to 0 */
5204508aff1aSJames C. McPherson 			rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
5205508aff1aSJames C. McPherson 			iop_data++;
5206508aff1aSJames C. McPherson 			iop_len--;
5207508aff1aSJames C. McPherson 		}
5208508aff1aSJames C. McPherson 		acb->rqbuf_lastidx = rqbuf_lastidx;
5209508aff1aSJames C. McPherson 		arcmsr_iop_message_read(acb);
5210508aff1aSJames C. McPherson 		/* signature, let IOP know data has been read */
5211508aff1aSJames C. McPherson 	} else {
5212508aff1aSJames C. McPherson 		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
5213508aff1aSJames C. McPherson 	}
5214508aff1aSJames C. McPherson }
5215508aff1aSJames C. McPherson 
5216508aff1aSJames C. McPherson 
5217508aff1aSJames C. McPherson 
5218508aff1aSJames C. McPherson static void
arcmsr_iop2drv_data_read_handle(struct ACB * acb)5219d5ebc493SDan Cross arcmsr_iop2drv_data_read_handle(struct ACB *acb)
5220d5ebc493SDan Cross {
5221508aff1aSJames C. McPherson 	acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ;
5222508aff1aSJames C. McPherson 	/*
5223508aff1aSJames C. McPherson 	 * check if there are any mail packages from user space program
5224508aff1aSJames C. McPherson 	 * in my post bag, now is the time to send them into Areca's firmware
5225508aff1aSJames C. McPherson 	 */
5226508aff1aSJames C. McPherson 
5227508aff1aSJames C. McPherson 	if (acb->wqbuf_firstidx != acb->wqbuf_lastidx) {
5228508aff1aSJames C. McPherson 
5229508aff1aSJames C. McPherson 		uint8_t *pQbuffer;
5230508aff1aSJames C. McPherson 		struct QBUFFER *pwbuffer;
5231508aff1aSJames C. McPherson 		uint8_t *iop_data;
5232508aff1aSJames C. McPherson 		int allxfer_len = 0;
5233508aff1aSJames C. McPherson 
5234508aff1aSJames C. McPherson 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
5235508aff1aSJames C. McPherson 		pwbuffer = arcmsr_get_iop_wqbuffer(acb);
5236508aff1aSJames C. McPherson 		iop_data = (uint8_t *)pwbuffer->data;
5237508aff1aSJames C. McPherson 
5238508aff1aSJames C. McPherson 		while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) &&
5239508aff1aSJames C. McPherson 		    (allxfer_len < 124)) {
5240508aff1aSJames C. McPherson 			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx];
5241508aff1aSJames C. McPherson 			(void) memcpy(iop_data, pQbuffer, 1);
5242508aff1aSJames C. McPherson 			acb->wqbuf_firstidx++;
5243508aff1aSJames C. McPherson 			/* if last index number set it to 0 */
5244508aff1aSJames C. McPherson 			acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
5245508aff1aSJames C. McPherson 			iop_data++;
5246508aff1aSJames C. McPherson 			allxfer_len++;
5247508aff1aSJames C. McPherson 		}
5248508aff1aSJames C. McPherson 		pwbuffer->data_len = allxfer_len;
5249508aff1aSJames C. McPherson 		/*
5250508aff1aSJames C. McPherson 		 * push inbound doorbell, tell iop driver data write ok
5251508aff1aSJames C. McPherson 		 * await reply on next hwinterrupt for next Qbuffer post
5252508aff1aSJames C. McPherson 		 */
5253508aff1aSJames C. McPherson 		arcmsr_iop_message_wrote(acb);
5254508aff1aSJames C. McPherson 	}
5255508aff1aSJames C. McPherson 
5256508aff1aSJames C. McPherson 	if (acb->wqbuf_firstidx == acb->wqbuf_lastidx)
5257508aff1aSJames C. McPherson 		acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
5258508aff1aSJames C. McPherson }
5259508aff1aSJames C. McPherson 
5260508aff1aSJames C. McPherson 
5261508aff1aSJames C. McPherson static void
arcmsr_hba_doorbell_isr(struct ACB * acb)526282beb602SGarrett D'Amore arcmsr_hba_doorbell_isr(struct ACB *acb)
526382beb602SGarrett D'Amore {
5264508aff1aSJames C. McPherson 	uint32_t outbound_doorbell;
5265508aff1aSJames C. McPherson 	struct HBA_msgUnit *phbamu;
5266508aff1aSJames C. McPherson 
5267508aff1aSJames C. McPherson 	phbamu = (struct HBA_msgUnit *)acb->pmu;
5268508aff1aSJames C. McPherson 
5269508aff1aSJames C. McPherson 	/*
5270508aff1aSJames C. McPherson 	 *  Maybe here we need to check wrqbuffer_lock is locked or not
5271508aff1aSJames C. McPherson 	 *  DOORBELL: ding! dong!
5272508aff1aSJames C. McPherson 	 *  check if there are any mail need to pack from firmware
5273508aff1aSJames C. McPherson 	 */
5274508aff1aSJames C. McPherson 
5275508aff1aSJames C. McPherson 	outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
5276508aff1aSJames C. McPherson 	    &phbamu->outbound_doorbell);
5277508aff1aSJames C. McPherson 	/* clear doorbell interrupt */
5278508aff1aSJames C. McPherson 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
5279508aff1aSJames C. McPherson 	    &phbamu->outbound_doorbell, outbound_doorbell);
5280508aff1aSJames C. McPherson 
5281508aff1aSJames C. McPherson 	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
5282508aff1aSJames C. McPherson 		arcmsr_iop2drv_data_wrote_handle(acb);
5283508aff1aSJames C. McPherson 
5284508aff1aSJames C. McPherson 
5285508aff1aSJames C. McPherson 	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
5286508aff1aSJames C. McPherson 		arcmsr_iop2drv_data_read_handle(acb);
5287508aff1aSJames C. McPherson }
5288508aff1aSJames C. McPherson 
5289508aff1aSJames C. McPherson 
5290508aff1aSJames C. McPherson 
5291508aff1aSJames C. McPherson static void
arcmsr_hbc_doorbell_isr(struct ACB * acb)529282beb602SGarrett D'Amore arcmsr_hbc_doorbell_isr(struct ACB *acb)
5293ed632624SColin Yi {
5294508aff1aSJames C. McPherson 	uint32_t outbound_doorbell;
529582beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
5296508aff1aSJames C. McPherson 
529782beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
5298508aff1aSJames C. McPherson 
529982beb602SGarrett D'Amore 	/*
530082beb602SGarrett D'Amore 	 *  Maybe here we need to check wrqbuffer_lock is locked or not
530182beb602SGarrett D'Amore 	 *  DOORBELL: ding! dong!
530282beb602SGarrett D'Amore 	 *  check if there are any mail need to pick from firmware
530382beb602SGarrett D'Amore 	 */
5304508aff1aSJames C. McPherson 
5305508aff1aSJames C. McPherson 	outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
530682beb602SGarrett D'Amore 	    &phbcmu->outbound_doorbell);
5307508aff1aSJames C. McPherson 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
530882beb602SGarrett D'Amore 	    &phbcmu->outbound_doorbell_clear,
530982beb602SGarrett D'Amore 	    outbound_doorbell); /* clear interrupt */
531082beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
5311508aff1aSJames C. McPherson 		arcmsr_iop2drv_data_wrote_handle(acb);
531282beb602SGarrett D'Amore 	}
531382beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
5314508aff1aSJames C. McPherson 		arcmsr_iop2drv_data_read_handle(acb);
5315ed632624SColin Yi 	}
531682beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
531782beb602SGarrett D'Amore 		/* messenger of "driver to iop commands" */
531882beb602SGarrett D'Amore 		arcmsr_hbc_message_isr(acb);
531982beb602SGarrett D'Amore 	}
5320508aff1aSJames C. McPherson }
5321508aff1aSJames C. McPherson 
5322508aff1aSJames C. McPherson 
532382beb602SGarrett D'Amore static void
arcmsr_hba_message_isr(struct ACB * acb)532482beb602SGarrett D'Amore arcmsr_hba_message_isr(struct ACB *acb)
532582beb602SGarrett D'Amore {
532682beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *)acb->pmu;
532782beb602SGarrett D'Amore 	uint32_t  *signature = (&phbamu->msgcode_rwbuffer[0]);
532882beb602SGarrett D'Amore 	uint32_t outbound_message;
5329508aff1aSJames C. McPherson 
533082beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
533182beb602SGarrett D'Amore 	    &phbamu->outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
5332508aff1aSJames C. McPherson 
533382beb602SGarrett D'Amore 	outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0, signature);
533482beb602SGarrett D'Amore 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
533582beb602SGarrett D'Amore 		if ((ddi_taskq_dispatch(acb->taskq,
533682beb602SGarrett D'Amore 		    (void (*)(void *))arcmsr_dr_handle,
533782beb602SGarrett D'Amore 		    acb, DDI_NOSLEEP)) != DDI_SUCCESS) {
533882beb602SGarrett D'Amore 			arcmsr_warn(acb, "DR task start failed");
533982beb602SGarrett D'Amore 		}
5340508aff1aSJames C. McPherson }
5341508aff1aSJames C. McPherson 
5342508aff1aSJames C. McPherson static void
arcmsr_hbb_message_isr(struct ACB * acb)534382beb602SGarrett D'Amore arcmsr_hbb_message_isr(struct ACB *acb)
534482beb602SGarrett D'Amore {
534582beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *)acb->pmu;
534682beb602SGarrett D'Amore 	uint32_t  *signature = (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0]);
534782beb602SGarrett D'Amore 	uint32_t outbound_message;
5348508aff1aSJames C. McPherson 
534982beb602SGarrett D'Amore 	/* clear interrupts */
535082beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
535182beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->iop2drv_doorbell,
535282beb602SGarrett D'Amore 	    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
535382beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
535482beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
535582beb602SGarrett D'Amore 	    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
5356508aff1aSJames C. McPherson 
535782beb602SGarrett D'Amore 	outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0, signature);
535882beb602SGarrett D'Amore 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
535982beb602SGarrett D'Amore 		if ((ddi_taskq_dispatch(acb->taskq,
536082beb602SGarrett D'Amore 		    (void (*)(void *))arcmsr_dr_handle,
536182beb602SGarrett D'Amore 		    acb, DDI_NOSLEEP)) != DDI_SUCCESS) {
536282beb602SGarrett D'Amore 			arcmsr_warn(acb, "DR task start failed");
536382beb602SGarrett D'Amore 		}
536482beb602SGarrett D'Amore }
5365508aff1aSJames C. McPherson 
536682beb602SGarrett D'Amore static void
arcmsr_hbc_message_isr(struct ACB * acb)536782beb602SGarrett D'Amore arcmsr_hbc_message_isr(struct ACB *acb)
536882beb602SGarrett D'Amore {
536982beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu = (struct HBC_msgUnit *)acb->pmu;
537082beb602SGarrett D'Amore 	uint32_t  *signature = (&phbcmu->msgcode_rwbuffer[0]);
537182beb602SGarrett D'Amore 	uint32_t outbound_message;
5372508aff1aSJames C. McPherson 
537382beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
537482beb602SGarrett D'Amore 	    &phbcmu->outbound_doorbell_clear,
537582beb602SGarrett D'Amore 	    ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR);
5376508aff1aSJames C. McPherson 
537782beb602SGarrett D'Amore 	outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0, signature);
537882beb602SGarrett D'Amore 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
537982beb602SGarrett D'Amore 		if ((ddi_taskq_dispatch(acb->taskq,
538082beb602SGarrett D'Amore 		    (void (*)(void *))arcmsr_dr_handle,
538182beb602SGarrett D'Amore 		    acb, DDI_NOSLEEP)) != DDI_SUCCESS) {
538282beb602SGarrett D'Amore 			arcmsr_warn(acb, "DR task start failed");
538382beb602SGarrett D'Amore 		}
5384508aff1aSJames C. McPherson }
5385508aff1aSJames C. McPherson 
538682beb602SGarrett D'Amore 
5387508aff1aSJames C. McPherson static void
arcmsr_hba_postqueue_isr(struct ACB * acb)538882beb602SGarrett D'Amore arcmsr_hba_postqueue_isr(struct ACB *acb)
538982beb602SGarrett D'Amore {
5390508aff1aSJames C. McPherson 
539182beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
539282beb602SGarrett D'Amore 	struct CCB *ccb;
539382beb602SGarrett D'Amore 	uint32_t flag_ccb;
539482beb602SGarrett D'Amore 	boolean_t error;
5395508aff1aSJames C. McPherson 
539682beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
5397508aff1aSJames C. McPherson 
539882beb602SGarrett D'Amore 	/* areca cdb command done */
539982beb602SGarrett D'Amore 	/* Use correct offset and size for syncing */
540082beb602SGarrett D'Amore 	(void) ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
540182beb602SGarrett D'Amore 	    DDI_DMA_SYNC_FORKERNEL);
5402508aff1aSJames C. McPherson 
540382beb602SGarrett D'Amore 	while ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
540482beb602SGarrett D'Amore 	    &phbamu->outbound_queueport)) != 0xFFFFFFFF) {
540582beb602SGarrett D'Amore 		/* frame must be 32 bytes aligned */
540682beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset+(flag_ccb << 5)));
540782beb602SGarrett D'Amore 		/* check if command done with no error */
540882beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
540982beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
541082beb602SGarrett D'Amore 		arcmsr_drain_donequeue(acb, ccb, error);
541182beb602SGarrett D'Amore 	}	/* drain reply FIFO */
5412508aff1aSJames C. McPherson }
5413508aff1aSJames C. McPherson 
5414508aff1aSJames C. McPherson 
541582beb602SGarrett D'Amore static void
arcmsr_hbb_postqueue_isr(struct ACB * acb)541682beb602SGarrett D'Amore arcmsr_hbb_postqueue_isr(struct ACB *acb)
541782beb602SGarrett D'Amore {
541882beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
541982beb602SGarrett D'Amore 	struct CCB *ccb;
542082beb602SGarrett D'Amore 	uint32_t flag_ccb;
542182beb602SGarrett D'Amore 	boolean_t error;
542282beb602SGarrett D'Amore 	int index;
5423508aff1aSJames C. McPherson 
542482beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
5425508aff1aSJames C. McPherson 
542682beb602SGarrett D'Amore 	/* areca cdb command done */
542782beb602SGarrett D'Amore 	index = phbbmu->doneq_index;
542882beb602SGarrett D'Amore 	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
542982beb602SGarrett D'Amore 	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
543082beb602SGarrett D'Amore 		return;
543182beb602SGarrett D'Amore 	while ((flag_ccb = phbbmu->done_qbuffer[index]) != 0) {
543282beb602SGarrett D'Amore 		phbbmu->done_qbuffer[index] = 0;
543382beb602SGarrett D'Amore 		/* frame must be 32 bytes aligned */
5434508aff1aSJames C. McPherson 
543582beb602SGarrett D'Amore 		/* the CDB is the first field of the CCB */
543682beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset + (flag_ccb << 5)));
5437508aff1aSJames C. McPherson 
543882beb602SGarrett D'Amore 		/* check if command done with no error */
543982beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
544082beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
544182beb602SGarrett D'Amore 		arcmsr_drain_donequeue(acb, ccb, error);
544282beb602SGarrett D'Amore 		index++;
544382beb602SGarrett D'Amore 		/* if last index number set it to 0 */
544482beb602SGarrett D'Amore 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
544582beb602SGarrett D'Amore 		phbbmu->doneq_index = index;
544682beb602SGarrett D'Amore 	}	/* drain reply FIFO */
544782beb602SGarrett D'Amore }
5448508aff1aSJames C. McPherson 
5449508aff1aSJames C. McPherson 
545082beb602SGarrett D'Amore static void
arcmsr_hbc_postqueue_isr(struct ACB * acb)545182beb602SGarrett D'Amore arcmsr_hbc_postqueue_isr(struct ACB *acb)
545282beb602SGarrett D'Amore {
5453508aff1aSJames C. McPherson 
545482beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
545582beb602SGarrett D'Amore 	struct CCB *ccb;
545682beb602SGarrett D'Amore 	uint32_t flag_ccb, ccb_cdb_phy, throttling = 0;
545782beb602SGarrett D'Amore 	boolean_t error;
5458508aff1aSJames C. McPherson 
545982beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
546082beb602SGarrett D'Amore 	/* areca cdb command done */
546182beb602SGarrett D'Amore 	/* Use correct offset and size for syncing */
546282beb602SGarrett D'Amore 	(void) ddi_dma_sync(acb->ccbs_pool_handle, 0, 0,
546382beb602SGarrett D'Amore 	    DDI_DMA_SYNC_FORKERNEL);
5464508aff1aSJames C. McPherson 
546582beb602SGarrett D'Amore 	while (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
546682beb602SGarrett D'Amore 	    &phbcmu->host_int_status) &
546782beb602SGarrett D'Amore 	    ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
546882beb602SGarrett D'Amore 		/* check if command done with no error */
546982beb602SGarrett D'Amore 		flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
547082beb602SGarrett D'Amore 		    &phbcmu->outbound_queueport_low);
547182beb602SGarrett D'Amore 		/* frame must be 32 bytes aligned */
547282beb602SGarrett D'Amore 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
5473508aff1aSJames C. McPherson 
547482beb602SGarrett D'Amore 		/* the CDB is the first field of the CCB */
547582beb602SGarrett D'Amore 		ccb = NumToPtr((acb->vir2phy_offset + ccb_cdb_phy));
5476508aff1aSJames C. McPherson 
547782beb602SGarrett D'Amore 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ?
547882beb602SGarrett D'Amore 		    B_TRUE : B_FALSE;
547982beb602SGarrett D'Amore 		/* check if command done with no error */
548082beb602SGarrett D'Amore 		arcmsr_drain_donequeue(acb, ccb, error);
548182beb602SGarrett D'Amore 		if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
548282beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
548382beb602SGarrett D'Amore 			    &phbcmu->inbound_doorbell,
548482beb602SGarrett D'Amore 			    ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING);
548582beb602SGarrett D'Amore 			break;
5486508aff1aSJames C. McPherson 		}
548782beb602SGarrett D'Amore 		throttling++;
548882beb602SGarrett D'Amore 	}	/* drain reply FIFO */
5489508aff1aSJames C. McPherson }
5490508aff1aSJames C. McPherson 
5491508aff1aSJames C. McPherson 
549282beb602SGarrett D'Amore static uint_t
arcmsr_handle_hba_isr(struct ACB * acb)5493d5ebc493SDan Cross arcmsr_handle_hba_isr(struct ACB *acb)
5494d5ebc493SDan Cross {
549582beb602SGarrett D'Amore 	uint32_t outbound_intstatus;
549682beb602SGarrett D'Amore 	struct HBA_msgUnit *phbamu;
5497508aff1aSJames C. McPherson 
549882beb602SGarrett D'Amore 	phbamu = (struct HBA_msgUnit *)acb->pmu;
5499508aff1aSJames C. McPherson 
550082beb602SGarrett D'Amore 	outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
550182beb602SGarrett D'Amore 	    &phbamu->outbound_intstatus) & acb->outbound_int_enable;
5502508aff1aSJames C. McPherson 
550382beb602SGarrett D'Amore 	if (outbound_intstatus == 0)	/* it must be a shared irq */
550482beb602SGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
5505508aff1aSJames C. McPherson 
550682beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus,
550782beb602SGarrett D'Amore 	    outbound_intstatus); /* clear interrupt */
5508508aff1aSJames C. McPherson 
550982beb602SGarrett D'Amore 	/* MU doorbell interrupts */
5510508aff1aSJames C. McPherson 
551182beb602SGarrett D'Amore 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
551282beb602SGarrett D'Amore 		arcmsr_hba_doorbell_isr(acb);
5513508aff1aSJames C. McPherson 
551482beb602SGarrett D'Amore 	/* MU post queue interrupts */
551582beb602SGarrett D'Amore 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
551682beb602SGarrett D'Amore 		arcmsr_hba_postqueue_isr(acb);
5517508aff1aSJames C. McPherson 
551882beb602SGarrett D'Amore 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
551982beb602SGarrett D'Amore 		arcmsr_hba_message_isr(acb);
552082beb602SGarrett D'Amore 	}
5521508aff1aSJames C. McPherson 
552282beb602SGarrett D'Amore 	return (DDI_INTR_CLAIMED);
5523508aff1aSJames C. McPherson }
5524508aff1aSJames C. McPherson 
5525508aff1aSJames C. McPherson 
552682beb602SGarrett D'Amore static uint_t
arcmsr_handle_hbb_isr(struct ACB * acb)5527d5ebc493SDan Cross arcmsr_handle_hbb_isr(struct ACB *acb)
5528d5ebc493SDan Cross {
552982beb602SGarrett D'Amore 	uint32_t outbound_doorbell;
553082beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
5531508aff1aSJames C. McPherson 
5532508aff1aSJames C. McPherson 
553382beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
5534508aff1aSJames C. McPherson 
553582beb602SGarrett D'Amore 	outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
553682beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->iop2drv_doorbell) & acb->outbound_int_enable;
5537508aff1aSJames C. McPherson 
553882beb602SGarrett D'Amore 	if (outbound_doorbell == 0)		/* it must be a shared irq */
553982beb602SGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
5540508aff1aSJames C. McPherson 
554182beb602SGarrett D'Amore 	/* clear doorbell interrupt */
554282beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
554382beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->iop2drv_doorbell, ~outbound_doorbell);
554482beb602SGarrett D'Amore 	/* wait a cycle */
554582beb602SGarrett D'Amore 	(void) CHIP_REG_READ32(acb->reg_mu_acc_handle0,
554682beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->iop2drv_doorbell);
554782beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
554882beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
554982beb602SGarrett D'Amore 	    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
5550508aff1aSJames C. McPherson 
555182beb602SGarrett D'Amore 	/* MU ioctl transfer doorbell interrupts */
555282beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
555382beb602SGarrett D'Amore 		arcmsr_iop2drv_data_wrote_handle(acb);
5554508aff1aSJames C. McPherson 
555582beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
555682beb602SGarrett D'Amore 		arcmsr_iop2drv_data_read_handle(acb);
5557508aff1aSJames C. McPherson 
555882beb602SGarrett D'Amore 	/* MU post queue interrupts */
555982beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
556082beb602SGarrett D'Amore 		arcmsr_hbb_postqueue_isr(acb);
5561508aff1aSJames C. McPherson 
556282beb602SGarrett D'Amore 	/* MU message interrupt */
5563508aff1aSJames C. McPherson 
556482beb602SGarrett D'Amore 	if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
556582beb602SGarrett D'Amore 		arcmsr_hbb_message_isr(acb);
556682beb602SGarrett D'Amore 	}
5567508aff1aSJames C. McPherson 
556882beb602SGarrett D'Amore 	return (DDI_INTR_CLAIMED);
556982beb602SGarrett D'Amore }
5570508aff1aSJames C. McPherson 
557182beb602SGarrett D'Amore static uint_t
arcmsr_handle_hbc_isr(struct ACB * acb)557282beb602SGarrett D'Amore arcmsr_handle_hbc_isr(struct ACB *acb)
557382beb602SGarrett D'Amore {
557482beb602SGarrett D'Amore 	uint32_t host_interrupt_status;
557582beb602SGarrett D'Amore 	struct HBC_msgUnit *phbcmu;
557682beb602SGarrett D'Amore 
557782beb602SGarrett D'Amore 	phbcmu = (struct HBC_msgUnit *)acb->pmu;
557882beb602SGarrett D'Amore 	/*  check outbound intstatus */
557982beb602SGarrett D'Amore 	host_interrupt_status=
558082beb602SGarrett D'Amore 	    CHIP_REG_READ32(acb->reg_mu_acc_handle0, &phbcmu->host_int_status);
558182beb602SGarrett D'Amore 	if (host_interrupt_status == 0)	/* it must be share irq */
558282beb602SGarrett D'Amore 		return (DDI_INTR_UNCLAIMED);
558382beb602SGarrett D'Amore 	/* MU ioctl transfer doorbell interrupts */
558482beb602SGarrett D'Amore 	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
558582beb602SGarrett D'Amore 		/* messenger of "ioctl message read write" */
558682beb602SGarrett D'Amore 		arcmsr_hbc_doorbell_isr(acb);
558782beb602SGarrett D'Amore 	}
558882beb602SGarrett D'Amore 	/* MU post queue interrupts */
558982beb602SGarrett D'Amore 	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
559082beb602SGarrett D'Amore 		/* messenger of "scsi commands" */
559182beb602SGarrett D'Amore 		arcmsr_hbc_postqueue_isr(acb);
559282beb602SGarrett D'Amore 	}
559382beb602SGarrett D'Amore 	return (DDI_INTR_CLAIMED);
559482beb602SGarrett D'Amore }
5595508aff1aSJames C. McPherson 
559682beb602SGarrett D'Amore static uint_t
arcmsr_intr_handler(caddr_t arg,caddr_t arg2)559782beb602SGarrett D'Amore arcmsr_intr_handler(caddr_t arg, caddr_t arg2)
559882beb602SGarrett D'Amore {
559982beb602SGarrett D'Amore 	struct ACB *acb = (void *)arg;
560082beb602SGarrett D'Amore 	struct CCB *ccb;
560182beb602SGarrett D'Amore 	uint_t retrn = DDI_INTR_UNCLAIMED;
560282beb602SGarrett D'Amore 	_NOTE(ARGUNUSED(arg2))
5603508aff1aSJames C. McPherson 
560482beb602SGarrett D'Amore 	mutex_enter(&acb->isr_mutex);
560582beb602SGarrett D'Amore 	switch (acb->adapter_type) {
560682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
560782beb602SGarrett D'Amore 		retrn = arcmsr_handle_hba_isr(acb);
560882beb602SGarrett D'Amore 		break;
5609508aff1aSJames C. McPherson 
561082beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
561182beb602SGarrett D'Amore 		retrn = arcmsr_handle_hbb_isr(acb);
561282beb602SGarrett D'Amore 		break;
561382beb602SGarrett D'Amore 
561482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
561582beb602SGarrett D'Amore 		retrn = arcmsr_handle_hbc_isr(acb);
561682beb602SGarrett D'Amore 		break;
5617508aff1aSJames C. McPherson 
561882beb602SGarrett D'Amore 	default:
561982beb602SGarrett D'Amore 		/* We should never be here */
562082beb602SGarrett D'Amore 		ASSERT(0);
562182beb602SGarrett D'Amore 		break;
562282beb602SGarrett D'Amore 	}
562382beb602SGarrett D'Amore 	mutex_exit(&acb->isr_mutex);
562482beb602SGarrett D'Amore 	while ((ccb = arcmsr_get_complete_ccb_from_list(acb)) != NULL) {
562582beb602SGarrett D'Amore 		arcmsr_ccb_complete(ccb, 1);
5626508aff1aSJames C. McPherson 	}
562782beb602SGarrett D'Amore 	return (retrn);
562882beb602SGarrett D'Amore }
5629508aff1aSJames C. McPherson 
5630508aff1aSJames C. McPherson 
563182beb602SGarrett D'Amore static void
arcmsr_wait_firmware_ready(struct ACB * acb)5632d5ebc493SDan Cross arcmsr_wait_firmware_ready(struct ACB *acb)
5633d5ebc493SDan Cross {
563482beb602SGarrett D'Amore 	uint32_t firmware_state;
5635508aff1aSJames C. McPherson 
563682beb602SGarrett D'Amore 	firmware_state = 0;
5637508aff1aSJames C. McPherson 
563882beb602SGarrett D'Amore 	switch (acb->adapter_type) {
563982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
564082beb602SGarrett D'Amore 	{
564182beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
564282beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
564382beb602SGarrett D'Amore 		do {
564482beb602SGarrett D'Amore 			firmware_state =
564582beb602SGarrett D'Amore 			    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
564682beb602SGarrett D'Amore 			    &phbamu->outbound_msgaddr1);
564782beb602SGarrett D'Amore 		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)
564882beb602SGarrett D'Amore 		    == 0);
564982beb602SGarrett D'Amore 		break;
5650508aff1aSJames C. McPherson 	}
5651508aff1aSJames C. McPherson 
565282beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
565382beb602SGarrett D'Amore 	{
565482beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
565582beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
565682beb602SGarrett D'Amore 		do {
565782beb602SGarrett D'Amore 			firmware_state =
565882beb602SGarrett D'Amore 			    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
5659d5ebc493SDan Cross 			    &phbbmu->hbb_doorbell->iop2drv_doorbell);
566082beb602SGarrett D'Amore 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
566182beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
566282beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
566382beb602SGarrett D'Amore 		    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
566482beb602SGarrett D'Amore 		break;
5665508aff1aSJames C. McPherson 	}
5666508aff1aSJames C. McPherson 
566782beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
566882beb602SGarrett D'Amore 	{
566982beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
567082beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
567182beb602SGarrett D'Amore 		do {
567282beb602SGarrett D'Amore 			firmware_state =
567382beb602SGarrett D'Amore 			    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
5674d5ebc493SDan Cross 			    &phbcmu->outbound_msgaddr1);
567582beb602SGarrett D'Amore 		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK)
567682beb602SGarrett D'Amore 		    == 0);
567782beb602SGarrett D'Amore 		break;
567882beb602SGarrett D'Amore 	}
5679508aff1aSJames C. McPherson 
568082beb602SGarrett D'Amore 	}
5681508aff1aSJames C. McPherson }
5682ed632624SColin Yi 
568382beb602SGarrett D'Amore static void
arcmsr_clear_doorbell_queue_buffer(struct ACB * acb)568482beb602SGarrett D'Amore arcmsr_clear_doorbell_queue_buffer(struct ACB *acb)
5685ed632624SColin Yi {
568682beb602SGarrett D'Amore 	switch (acb->adapter_type) {
568782beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A: {
568882beb602SGarrett D'Amore 		struct HBA_msgUnit *phbamu;
568982beb602SGarrett D'Amore 		uint32_t outbound_doorbell;
5690ed632624SColin Yi 
569182beb602SGarrett D'Amore 		phbamu = (struct HBA_msgUnit *)acb->pmu;
569282beb602SGarrett D'Amore 		/* empty doorbell Qbuffer if door bell rung */
569382beb602SGarrett D'Amore 		outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
569482beb602SGarrett D'Amore 		    &phbamu->outbound_doorbell);
569582beb602SGarrett D'Amore 		/* clear doorbell interrupt */
569682beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
569782beb602SGarrett D'Amore 		    &phbamu->outbound_doorbell, outbound_doorbell);
569882beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
569982beb602SGarrett D'Amore 		    &phbamu->inbound_doorbell,
570082beb602SGarrett D'Amore 		    ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
570182beb602SGarrett D'Amore 		break;
570282beb602SGarrett D'Amore 	}
570382beb602SGarrett D'Amore 
570482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B: {
570582beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
570682beb602SGarrett D'Amore 
570782beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
570882beb602SGarrett D'Amore 		/* clear interrupt and message state */
570982beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
571082beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->iop2drv_doorbell,
571182beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
571282beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
571382beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
571482beb602SGarrett D'Amore 		    ARCMSR_DRV2IOP_DATA_READ_OK);
571582beb602SGarrett D'Amore 		/* let IOP know data has been read */
571682beb602SGarrett D'Amore 		break;
5717ed632624SColin Yi 	}
5718ed632624SColin Yi 
571982beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C: {
572082beb602SGarrett D'Amore 		struct HBC_msgUnit *phbcmu;
572182beb602SGarrett D'Amore 		uint32_t outbound_doorbell;
572282beb602SGarrett D'Amore 
572382beb602SGarrett D'Amore 		phbcmu = (struct HBC_msgUnit *)acb->pmu;
572482beb602SGarrett D'Amore 		/* empty doorbell Qbuffer if door bell ringed */
572582beb602SGarrett D'Amore 		outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
572682beb602SGarrett D'Amore 		    &phbcmu->outbound_doorbell);
572782beb602SGarrett D'Amore 		/* clear outbound doobell isr */
572882beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
572982beb602SGarrett D'Amore 		    &phbcmu->outbound_doorbell_clear, outbound_doorbell);
573082beb602SGarrett D'Amore 		/* let IOP know data has been read */
573182beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
573282beb602SGarrett D'Amore 		    &phbcmu->inbound_doorbell,
573382beb602SGarrett D'Amore 		    ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK);
573482beb602SGarrett D'Amore 		break;
5735ed632624SColin Yi 	}
573682beb602SGarrett D'Amore 
5737ed632624SColin Yi 	}
5738ed632624SColin Yi }
5739ed632624SColin Yi 
5740ed632624SColin Yi 
574182beb602SGarrett D'Amore static uint32_t
arcmsr_iop_confirm(struct ACB * acb)5742d5ebc493SDan Cross arcmsr_iop_confirm(struct ACB *acb)
5743d5ebc493SDan Cross {
574482beb602SGarrett D'Amore 	uint64_t cdb_phyaddr;
574582beb602SGarrett D'Amore 	uint32_t cdb_phyaddr_hi32;
5746ed632624SColin Yi 
574782beb602SGarrett D'Amore 	/*
574882beb602SGarrett D'Amore 	 * here we need to tell iop 331 about our freeccb.HighPart
574982beb602SGarrett D'Amore 	 * if freeccb.HighPart is non-zero
575082beb602SGarrett D'Amore 	 */
575182beb602SGarrett D'Amore 	cdb_phyaddr = acb->ccb_cookie.dmac_laddress;
575282beb602SGarrett D'Amore 	cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
575382beb602SGarrett D'Amore 	acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
575482beb602SGarrett D'Amore 	switch (acb->adapter_type) {
575582beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
575682beb602SGarrett D'Amore 		if (cdb_phyaddr_hi32 != 0) {
575782beb602SGarrett D'Amore 			struct HBA_msgUnit *phbamu;
5758ed632624SColin Yi 
575982beb602SGarrett D'Amore 			phbamu = (struct HBA_msgUnit *)acb->pmu;
576082beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
576182beb602SGarrett D'Amore 			    &phbamu->msgcode_rwbuffer[0],
576282beb602SGarrett D'Amore 			    ARCMSR_SIGNATURE_SET_CONFIG);
576382beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
576482beb602SGarrett D'Amore 			    &phbamu->msgcode_rwbuffer[1], cdb_phyaddr_hi32);
576582beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
576682beb602SGarrett D'Amore 			    &phbamu->inbound_msgaddr0,
576782beb602SGarrett D'Amore 			    ARCMSR_INBOUND_MESG0_SET_CONFIG);
576882beb602SGarrett D'Amore 			if (!arcmsr_hba_wait_msgint_ready(acb)) {
576982beb602SGarrett D'Amore 				arcmsr_warn(acb,
577082beb602SGarrett D'Amore 				    "timeout setting ccb "
577182beb602SGarrett D'Amore 				    "high physical address");
577282beb602SGarrett D'Amore 				return (FALSE);
577382beb602SGarrett D'Amore 			}
577482beb602SGarrett D'Amore 		}
577582beb602SGarrett D'Amore 		break;
5776ed632624SColin Yi 
577782beb602SGarrett D'Amore 	/* if adapter is type B, set window of "post command queue" */
577882beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B: {
577982beb602SGarrett D'Amore 		uint32_t post_queue_phyaddr;
578082beb602SGarrett D'Amore 		struct HBB_msgUnit *phbbmu;
5781ed632624SColin Yi 
578282beb602SGarrett D'Amore 		phbbmu = (struct HBB_msgUnit *)acb->pmu;
578382beb602SGarrett D'Amore 		phbbmu->postq_index = 0;
578482beb602SGarrett D'Amore 		phbbmu->doneq_index = 0;
578582beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
578682beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
578782beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_SET_POST_WINDOW);
5788ed632624SColin Yi 
578982beb602SGarrett D'Amore 		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
579082beb602SGarrett D'Amore 			arcmsr_warn(acb, "timeout setting post command "
579182beb602SGarrett D'Amore 			    "queue window");
579282beb602SGarrett D'Amore 			return (FALSE);
5793ed632624SColin Yi 		}
579482beb602SGarrett D'Amore 
579582beb602SGarrett D'Amore 		post_queue_phyaddr = (uint32_t)cdb_phyaddr +
579682beb602SGarrett D'Amore 		    ARCMSR_MAX_FREECCB_NUM * P2ROUNDUP(sizeof (struct CCB), 32)
579782beb602SGarrett D'Amore 		    + offsetof(struct HBB_msgUnit, post_qbuffer);
579882beb602SGarrett D'Amore 		/* driver "set config" signature */
579982beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
580082beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0],
580182beb602SGarrett D'Amore 		    ARCMSR_SIGNATURE_SET_CONFIG);
580282beb602SGarrett D'Amore 		/* normal should be zero */
580382beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
580482beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1],
580582beb602SGarrett D'Amore 		    cdb_phyaddr_hi32);
580682beb602SGarrett D'Amore 		/* postQ size (256+8)*4 */
580782beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
580882beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2],
580982beb602SGarrett D'Amore 		    post_queue_phyaddr);
581082beb602SGarrett D'Amore 		/* doneQ size (256+8)*4 */
581182beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
581282beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3],
581382beb602SGarrett D'Amore 		    post_queue_phyaddr+1056);
581482beb602SGarrett D'Amore 		/* ccb maxQ size must be --> [(256+8)*4] */
581582beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
581682beb602SGarrett D'Amore 		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4], 1056);
581782beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
581882beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
581982beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_SET_CONFIG);
582082beb602SGarrett D'Amore 
582182beb602SGarrett D'Amore 		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
582282beb602SGarrett D'Amore 			arcmsr_warn(acb,
582382beb602SGarrett D'Amore 			    "timeout setting command queue window");
582482beb602SGarrett D'Amore 			return (FALSE);
5825ed632624SColin Yi 		}
582682beb602SGarrett D'Amore 		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
582782beb602SGarrett D'Amore 		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
582882beb602SGarrett D'Amore 		    ARCMSR_MESSAGE_START_DRIVER_MODE);
5829ed632624SColin Yi 
583082beb602SGarrett D'Amore 		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
583182beb602SGarrett D'Amore 			arcmsr_warn(acb, "timeout in 'start driver mode'");
583282beb602SGarrett D'Amore 			return (FALSE);
583382beb602SGarrett D'Amore 		}
583482beb602SGarrett D'Amore 		break;
5835ed632624SColin Yi 	}
5836ed632624SColin Yi 
583782beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
583882beb602SGarrett D'Amore 		if (cdb_phyaddr_hi32 != 0) {
583982beb602SGarrett D'Amore 			struct HBC_msgUnit *phbcmu;
584082beb602SGarrett D'Amore 
584182beb602SGarrett D'Amore 			phbcmu = (struct HBC_msgUnit *)acb->pmu;
584282beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
584382beb602SGarrett D'Amore 			    &phbcmu->msgcode_rwbuffer[0],
584482beb602SGarrett D'Amore 			    ARCMSR_SIGNATURE_SET_CONFIG);
584582beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
584682beb602SGarrett D'Amore 			    &phbcmu->msgcode_rwbuffer[1], cdb_phyaddr_hi32);
584782beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
584882beb602SGarrett D'Amore 			    &phbcmu->inbound_msgaddr0,
584982beb602SGarrett D'Amore 			    ARCMSR_INBOUND_MESG0_SET_CONFIG);
585082beb602SGarrett D'Amore 			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
585182beb602SGarrett D'Amore 			    &phbcmu->inbound_doorbell,
585282beb602SGarrett D'Amore 			    ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
585382beb602SGarrett D'Amore 			if (!arcmsr_hbc_wait_msgint_ready(acb)) {
585482beb602SGarrett D'Amore 				arcmsr_warn(acb, "'set ccb "
585582beb602SGarrett D'Amore 				    "high part physical address' timeout");
585682beb602SGarrett D'Amore 				return (FALSE);
585782beb602SGarrett D'Amore 			}
585882beb602SGarrett D'Amore 		}
585982beb602SGarrett D'Amore 		break;
586082beb602SGarrett D'Amore 	}
586182beb602SGarrett D'Amore 	return (TRUE);
5862ed632624SColin Yi }
5863ed632624SColin Yi 
586482beb602SGarrett D'Amore 
586582beb602SGarrett D'Amore /*
586682beb602SGarrett D'Amore  * ONLY used for Adapter type B
586782beb602SGarrett D'Amore  */
586882beb602SGarrett D'Amore static void
arcmsr_enable_eoi_mode(struct ACB * acb)586982beb602SGarrett D'Amore arcmsr_enable_eoi_mode(struct ACB *acb)
5870ed632624SColin Yi {
587182beb602SGarrett D'Amore 	struct HBB_msgUnit *phbbmu;
5872ed632624SColin Yi 
587382beb602SGarrett D'Amore 	phbbmu = (struct HBB_msgUnit *)acb->pmu;
5874ed632624SColin Yi 
587582beb602SGarrett D'Amore 	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
587682beb602SGarrett D'Amore 	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
587782beb602SGarrett D'Amore 	    ARCMSR_MESSAGE_ACTIVE_EOI_MODE);
587882beb602SGarrett D'Amore 
587982beb602SGarrett D'Amore 	if (!arcmsr_hbb_wait_msgint_ready(acb))
588082beb602SGarrett D'Amore 		arcmsr_warn(acb, "'iop enable eoi mode' timeout");
5881ed632624SColin Yi }
5882ed632624SColin Yi 
588382beb602SGarrett D'Amore /* start background rebuild */
588482beb602SGarrett D'Amore static void
arcmsr_iop_init(struct ACB * acb)588582beb602SGarrett D'Amore arcmsr_iop_init(struct ACB *acb)
5886ed632624SColin Yi {
588782beb602SGarrett D'Amore 	uint32_t intmask_org;
5888ed632624SColin Yi 
588982beb602SGarrett D'Amore 	/* disable all outbound interrupt */
589082beb602SGarrett D'Amore 	intmask_org = arcmsr_disable_allintr(acb);
589182beb602SGarrett D'Amore 	arcmsr_wait_firmware_ready(acb);
589282beb602SGarrett D'Amore 	(void) arcmsr_iop_confirm(acb);
5893ed632624SColin Yi 
589482beb602SGarrett D'Amore 	/* start background rebuild */
589582beb602SGarrett D'Amore 	switch (acb->adapter_type) {
589682beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_A:
589782beb602SGarrett D'Amore 		arcmsr_get_hba_config(acb);
589882beb602SGarrett D'Amore 		arcmsr_start_hba_bgrb(acb);
589982beb602SGarrett D'Amore 		break;
590082beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_B:
590182beb602SGarrett D'Amore 		arcmsr_get_hbb_config(acb);
590282beb602SGarrett D'Amore 		arcmsr_start_hbb_bgrb(acb);
590382beb602SGarrett D'Amore 		break;
590482beb602SGarrett D'Amore 	case ACB_ADAPTER_TYPE_C:
590582beb602SGarrett D'Amore 		arcmsr_get_hbc_config(acb);
590682beb602SGarrett D'Amore 		arcmsr_start_hbc_bgrb(acb);
5907ed632624SColin Yi 		break;
5908ed632624SColin Yi 	}
590982beb602SGarrett D'Amore 	/* empty doorbell Qbuffer if door bell rang */
591082beb602SGarrett D'Amore 	arcmsr_clear_doorbell_queue_buffer(acb);
591182beb602SGarrett D'Amore 
591282beb602SGarrett D'Amore 	if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
591382beb602SGarrett D'Amore 		arcmsr_enable_eoi_mode(acb);
591482beb602SGarrett D'Amore 
591582beb602SGarrett D'Amore 	/* enable outbound Post Queue, outbound doorbell Interrupt */
591682beb602SGarrett D'Amore 	arcmsr_enable_allintr(acb, intmask_org);
591782beb602SGarrett D'Amore 	acb->acb_flags |= ACB_F_IOP_INITED;
5918ed632624SColin Yi }
5919