xref: /freebsd/sys/dev/arcmsr/arcmsr.c (revision bca8e8c00c4ed9d5a52943f3b58d6f2238f4dd74)
1f1c579b1SScott Long /*
235689395SXin LI ********************************************************************************
335689395SXin LI **        OS    : FreeBSD
4f1c579b1SScott Long **   FILE NAME  : arcmsr.c
5d74001adSXin LI **        BY    : Erich Chen, Ching Huang
6f1c579b1SScott Long **   Description: SCSI RAID Device Driver for
735689395SXin LI **                ARECA (ARC11XX/ARC12XX/ARC13XX/ARC16XX/ARC188x)
835689395SXin LI **                SATA/SAS RAID HOST Adapter
935689395SXin LI ********************************************************************************
1035689395SXin LI ********************************************************************************
11f1c579b1SScott Long **
12718cf2ccSPedro F. Giffuni ** SPDX-License-Identifier: BSD-3-Clause
13718cf2ccSPedro F. Giffuni **
1435689395SXin LI ** Copyright (C) 2002 - 2012, Areca Technology Corporation All rights reserved.
15f1c579b1SScott Long **
16f1c579b1SScott Long ** Redistribution and use in source and binary forms, with or without
17f1c579b1SScott Long ** modification, are permitted provided that the following conditions
18f1c579b1SScott Long ** are met:
19f1c579b1SScott Long ** 1. Redistributions of source code must retain the above copyright
20f1c579b1SScott Long **    notice, this list of conditions and the following disclaimer.
21f1c579b1SScott Long ** 2. Redistributions in binary form must reproduce the above copyright
22f1c579b1SScott Long **    notice, this list of conditions and the following disclaimer in the
23f1c579b1SScott Long **    documentation and/or other materials provided with the distribution.
24f1c579b1SScott Long ** 3. The name of the author may not be used to endorse or promote products
25f1c579b1SScott Long **    derived from this software without specific prior written permission.
26f1c579b1SScott Long **
27f1c579b1SScott Long ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28f1c579b1SScott Long ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29f1c579b1SScott Long ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30f1c579b1SScott Long ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31f1c579b1SScott Long ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
32f1c579b1SScott Long ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33f1c579b1SScott Long ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
34f1c579b1SScott Long ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35f1c579b1SScott Long **(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
36f1c579b1SScott Long ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3735689395SXin LI ********************************************************************************
38f1c579b1SScott Long ** History
39f1c579b1SScott Long **
40f1c579b1SScott Long **    REV#         DATE         NAME        DESCRIPTION
4122f2616bSXin LI ** 1.00.00.00   03/31/2004  Erich Chen      First release
42f1c579b1SScott Long ** 1.20.00.02   11/29/2004  Erich Chen      bug fix with arcmsr_bus_reset when PHY error
4322f2616bSXin LI ** 1.20.00.03   04/19/2005  Erich Chen      add SATA 24 Ports adapter type support
44ad6d6297SScott Long **                                          clean unused function
4522f2616bSXin LI ** 1.20.00.12   09/12/2005  Erich Chen      bug fix with abort command handling,
46ad6d6297SScott Long **                                          firmware version check
47ad6d6297SScott Long **                                          and firmware update notify for hardware bug fix
48ad6d6297SScott Long **                                          handling if none zero high part physical address
49ad6d6297SScott Long **                                          of srb resource
5022f2616bSXin LI ** 1.20.00.13   08/18/2006  Erich Chen      remove pending srb and report busy
51ad6d6297SScott Long **                                          add iop message xfer
52ad6d6297SScott Long **                                          with scsi pass-through command
53ad6d6297SScott Long **                                          add new device id of sas raid adapters
54ad6d6297SScott Long **                                          code fit for SPARC64 & PPC
55f48f00a1SScott Long ** 1.20.00.14   02/05/2007  Erich Chen      bug fix for incorrect ccb_h.status report
56f48f00a1SScott Long **                                          and cause g_vfs_done() read write error
5744f05562SScott Long ** 1.20.00.15   10/10/2007  Erich Chen      support new RAID adapter type ARC120x
58641182baSXin LI ** 1.20.00.16   10/10/2009  Erich Chen      Bug fix for RAID adapter type ARC120x
59641182baSXin LI **                                          bus_dmamem_alloc() with BUS_DMA_ZERO
60d74001adSXin LI ** 1.20.00.17   07/15/2010  Ching Huang     Added support ARC1880
61d74001adSXin LI **                                          report CAM_DEV_NOT_THERE instead of CAM_SEL_TIMEOUT when device failed,
62d74001adSXin LI **                                          prevent cam_periph_error removing all LUN devices of one Target id
63d74001adSXin LI **                                          for any one LUN device failed
64231c8b71SXin LI ** 1.20.00.18   10/14/2010  Ching Huang     Fixed "inquiry data fails comparion at DV1 step"
65231c8b71SXin LI **              10/25/2010  Ching Huang     Fixed bad range input in bus_alloc_resource for ADAPTER_TYPE_B
66231c8b71SXin LI ** 1.20.00.19   11/11/2010  Ching Huang     Fixed arcmsr driver prevent arcsas support for Areca SAS HBA ARC13x0
6722f2616bSXin LI ** 1.20.00.20   12/08/2010  Ching Huang     Avoid calling atomic_set_int function
6822f2616bSXin LI ** 1.20.00.21   02/08/2011  Ching Huang     Implement I/O request timeout
6922f2616bSXin LI **              02/14/2011  Ching Huang     Modified pktRequestCount
7022f2616bSXin LI ** 1.20.00.21   03/03/2011  Ching Huang     if a command timeout, then wait its ccb back before free it
714e32649fSXin LI ** 1.20.00.22   07/04/2011  Ching Huang     Fixed multiple MTX panic
72dac36688SXin LI ** 1.20.00.23   10/28/2011  Ching Huang     Added TIMEOUT_DELAY in case of too many HDDs need to start
73dac36688SXin LI ** 1.20.00.23   11/08/2011  Ching Huang     Added report device transfer speed
74dac36688SXin LI ** 1.20.00.23   01/30/2012  Ching Huang     Fixed Request requeued and Retrying command
75dac36688SXin LI ** 1.20.00.24   06/11/2012  Ching Huang     Fixed return sense data condition
76dac36688SXin LI ** 1.20.00.25   08/17/2012  Ching Huang     Fixed hotplug device no function on type A adapter
77abfdbca9SXin LI ** 1.20.00.26   12/14/2012  Ching Huang     Added support ARC1214,1224,1264,1284
78abfdbca9SXin LI ** 1.20.00.27   05/06/2013  Ching Huang     Fixed out standing cmd full on ARC-12x4
791e7d660aSXin LI ** 1.20.00.28   09/13/2013  Ching Huang     Removed recursive mutex in arcmsr_abort_dr_ccbs
80224a78aeSXin LI ** 1.20.00.29   12/18/2013  Ching Huang     Change simq allocation number, support ARC1883
81b23a1998SXin LI ** 1.30.00.00   11/30/2015  Ching Huang     Added support ARC1203
82a1103e04SXin LI ** 1.40.00.00   07/11/2017  Ching Huang     Added support ARC1884
83fc5ef1caSXin LI ** 1.40.00.01   10/30/2017  Ching Huang     Fixed release memory resource
84fa42a0bfSXin LI ** 1.50.00.00   09/30/2020  Ching Huang     Added support ARC-1886, NVMe/SAS/SATA controller
855842073aSXin LI ** 1.50.00.01   02/26/2021  Ching Huang     Fixed no action of hot plugging device on type_F adapter
86438b5532SXin LI ** 1.50.00.02   04/16/2021  Ching Huang     Fixed scsi command timeout on ARC-1886 when
87438b5532SXin LI **                                          scatter-gather count large than some number
88f1c579b1SScott Long ******************************************************************************************
89f1c579b1SScott Long */
904b7ec270SMarius Strobl 
914b7ec270SMarius Strobl #include <sys/cdefs.h>
924b7ec270SMarius Strobl __FBSDID("$FreeBSD$");
934b7ec270SMarius Strobl 
9422f2616bSXin LI #if 0
9522f2616bSXin LI #define ARCMSR_DEBUG1			1
9622f2616bSXin LI #endif
97f1c579b1SScott Long #include <sys/param.h>
98f1c579b1SScott Long #include <sys/systm.h>
99f1c579b1SScott Long #include <sys/malloc.h>
100f1c579b1SScott Long #include <sys/kernel.h>
101f1c579b1SScott Long #include <sys/bus.h>
102f1c579b1SScott Long #include <sys/queue.h>
103f1c579b1SScott Long #include <sys/stat.h>
104f1c579b1SScott Long #include <sys/devicestat.h>
105f1c579b1SScott Long #include <sys/kthread.h>
106f1c579b1SScott Long #include <sys/module.h>
107f1c579b1SScott Long #include <sys/proc.h>
108f1c579b1SScott Long #include <sys/lock.h>
109f1c579b1SScott Long #include <sys/sysctl.h>
110f1c579b1SScott Long #include <sys/poll.h>
111f1c579b1SScott Long #include <sys/ioccom.h>
112f1c579b1SScott Long #include <vm/vm.h>
113f1c579b1SScott Long #include <vm/vm_param.h>
114f1c579b1SScott Long #include <vm/pmap.h>
115f1c579b1SScott Long 
116f1c579b1SScott Long #include <isa/rtc.h>
117f1c579b1SScott Long 
118f1c579b1SScott Long #include <machine/bus.h>
119f1c579b1SScott Long #include <machine/resource.h>
120f1c579b1SScott Long #include <machine/atomic.h>
121f1c579b1SScott Long #include <sys/conf.h>
122f1c579b1SScott Long #include <sys/rman.h>
123f1c579b1SScott Long 
124f1c579b1SScott Long #include <cam/cam.h>
125f1c579b1SScott Long #include <cam/cam_ccb.h>
126f1c579b1SScott Long #include <cam/cam_sim.h>
127d74001adSXin LI #include <cam/cam_periph.h>
128d74001adSXin LI #include <cam/cam_xpt_periph.h>
129f1c579b1SScott Long #include <cam/cam_xpt_sim.h>
130f1c579b1SScott Long #include <cam/cam_debug.h>
131f1c579b1SScott Long #include <cam/scsi/scsi_all.h>
132f1c579b1SScott Long #include <cam/scsi/scsi_message.h>
133f1c579b1SScott Long /*
134f1c579b1SScott Long **************************************************************************
135f1c579b1SScott Long **************************************************************************
136f1c579b1SScott Long */
137f1c579b1SScott Long #include <sys/selinfo.h>
138f1c579b1SScott Long #include <sys/mutex.h>
139ad6d6297SScott Long #include <sys/endian.h>
140f1c579b1SScott Long #include <dev/pci/pcivar.h>
141f1c579b1SScott Long #include <dev/pci/pcireg.h>
14244f05562SScott Long 
14322f2616bSXin LI #define arcmsr_callout_init(a)	callout_init(a, /*mpsafe*/1);
14422f2616bSXin LI 
145438b5532SXin LI #define ARCMSR_DRIVER_VERSION	"arcmsr version 1.50.00.02 2021-04-16"
146f1c579b1SScott Long #include <dev/arcmsr/arcmsr.h>
147f1c579b1SScott Long /*
148f1c579b1SScott Long **************************************************************************
149f1c579b1SScott Long **************************************************************************
150f1c579b1SScott Long */
15122f2616bSXin LI static void arcmsr_free_srb(struct CommandControlBlock *srb);
152ad6d6297SScott Long static struct CommandControlBlock *arcmsr_get_freesrb(struct AdapterControlBlock *acb);
153ad6d6297SScott Long static u_int8_t arcmsr_seek_cmd2abort(union ccb *abortccb);
154f2aa0e9fSWarner Losh static int arcmsr_probe(device_t dev);
155f2aa0e9fSWarner Losh static int arcmsr_attach(device_t dev);
156f2aa0e9fSWarner Losh static int arcmsr_detach(device_t dev);
157ad6d6297SScott Long static u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg);
158ad6d6297SScott Long static void arcmsr_iop_parking(struct AdapterControlBlock *acb);
159f2aa0e9fSWarner Losh static int arcmsr_shutdown(device_t dev);
16044f05562SScott Long static void arcmsr_interrupt(struct AdapterControlBlock *acb);
161ad6d6297SScott Long static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb);
162ad6d6297SScott Long static void arcmsr_free_resource(struct AdapterControlBlock *acb);
163ad6d6297SScott Long static void arcmsr_bus_reset(struct AdapterControlBlock *acb);
164ad6d6297SScott Long static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
165ad6d6297SScott Long static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
166ad6d6297SScott Long static void arcmsr_iop_init(struct AdapterControlBlock *acb);
167ad6d6297SScott Long static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
16835689395SXin LI static u_int32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, struct QBUFFER *prbuffer);
1697a7bc959SXin LI static void arcmsr_Write_data_2iop_wqbuffer(struct AdapterControlBlock *acb);
170ad6d6297SScott Long static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb);
171ad6d6297SScott Long static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag);
172ad6d6297SScott Long static void arcmsr_iop_reset(struct AdapterControlBlock *acb);
173ad6d6297SScott Long static void arcmsr_report_sense_info(struct CommandControlBlock *srb);
174ad6d6297SScott Long static void arcmsr_build_srb(struct CommandControlBlock *srb, bus_dma_segment_t *dm_segs, u_int32_t nseg);
175ad6d6297SScott Long static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb *pccb);
176ad6d6297SScott Long static int arcmsr_resume(device_t dev);
177ad6d6297SScott Long static int arcmsr_suspend(device_t dev);
178d74001adSXin LI static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb);
179d74001adSXin LI static void arcmsr_polling_devmap(void *arg);
18022f2616bSXin LI static void arcmsr_srb_timeout(void *arg);
1817a7bc959SXin LI static void arcmsr_hbd_postqueue_isr(struct AdapterControlBlock *acb);
182a1103e04SXin LI static void arcmsr_hbe_postqueue_isr(struct AdapterControlBlock *acb);
183fa42a0bfSXin LI static void arcmsr_hbf_postqueue_isr(struct AdapterControlBlock *acb);
184fc5ef1caSXin LI static void arcmsr_teardown_intr(device_t dev, struct AdapterControlBlock *acb);
18522f2616bSXin LI #ifdef ARCMSR_DEBUG1
18622f2616bSXin LI static void arcmsr_dump_data(struct AdapterControlBlock *acb);
18722f2616bSXin LI #endif
188f1c579b1SScott Long /*
189f1c579b1SScott Long **************************************************************************
190ad6d6297SScott Long **************************************************************************
191ad6d6297SScott Long */
192ad6d6297SScott Long static void UDELAY(u_int32_t us) { DELAY(us); }
193ad6d6297SScott Long /*
194ad6d6297SScott Long **************************************************************************
195f1c579b1SScott Long **************************************************************************
196f1c579b1SScott Long */
197231c8b71SXin LI static bus_dmamap_callback_t arcmsr_map_free_srb;
198231c8b71SXin LI static bus_dmamap_callback_t arcmsr_execute_srb;
199f1c579b1SScott Long /*
200f1c579b1SScott Long **************************************************************************
201f1c579b1SScott Long **************************************************************************
202f1c579b1SScott Long */
203f1c579b1SScott Long static d_open_t	arcmsr_open;
204f1c579b1SScott Long static d_close_t arcmsr_close;
205f1c579b1SScott Long static d_ioctl_t arcmsr_ioctl;
206f1c579b1SScott Long 
207f1c579b1SScott Long static device_method_t arcmsr_methods[]={
208f1c579b1SScott Long 	DEVMETHOD(device_probe,		arcmsr_probe),
209f1c579b1SScott Long 	DEVMETHOD(device_attach,	arcmsr_attach),
210f1c579b1SScott Long 	DEVMETHOD(device_detach,	arcmsr_detach),
211f1c579b1SScott Long 	DEVMETHOD(device_shutdown,	arcmsr_shutdown),
212ad6d6297SScott Long 	DEVMETHOD(device_suspend,	arcmsr_suspend),
213ad6d6297SScott Long 	DEVMETHOD(device_resume,	arcmsr_resume),
2144b7ec270SMarius Strobl 	DEVMETHOD_END
215f1c579b1SScott Long };
216f1c579b1SScott Long 
217f1c579b1SScott Long static driver_t arcmsr_driver={
218ad6d6297SScott Long 	"arcmsr", arcmsr_methods, sizeof(struct AdapterControlBlock)
219f1c579b1SScott Long };
220f1c579b1SScott Long 
221f1c579b1SScott Long static devclass_t arcmsr_devclass;
222f1c579b1SScott Long DRIVER_MODULE(arcmsr, pci, arcmsr_driver, arcmsr_devclass, 0, 0);
223d3cf342dSScott Long MODULE_DEPEND(arcmsr, pci, 1, 1, 1);
224d3cf342dSScott Long MODULE_DEPEND(arcmsr, cam, 1, 1, 1);
225ad6d6297SScott Long #ifndef BUS_DMA_COHERENT
226ad6d6297SScott Long 	#define	BUS_DMA_COHERENT	0x04	/* hint: map memory in a coherent way */
227ad6d6297SScott Long #endif
228f1c579b1SScott Long static struct cdevsw arcmsr_cdevsw={
229f1c579b1SScott Long 		.d_version = D_VERSION,
230f1c579b1SScott Long 		.d_open    = arcmsr_open, 	/* open     */
231f1c579b1SScott Long 		.d_close   = arcmsr_close, 	/* close    */
232f1c579b1SScott Long 		.d_ioctl   = arcmsr_ioctl, 	/* ioctl    */
233f1c579b1SScott Long 		.d_name    = "arcmsr", 		/* name     */
234f1c579b1SScott Long 	};
235d74001adSXin LI /*
236d74001adSXin LI **************************************************************************
237d74001adSXin LI **************************************************************************
238d74001adSXin LI */
23900b4e54aSWarner Losh static int arcmsr_open(struct cdev *dev, int flags, int fmt, struct thread *proc)
240f1c579b1SScott Long {
2416bfa9a2dSEd Schouten 	int	unit = dev2unit(dev);
242ad6d6297SScott Long 	struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit);
2439ea5bef2SWarner Losh 
244ad6d6297SScott Long 	if (acb == NULL) {
245f1c579b1SScott Long 		return ENXIO;
246f1c579b1SScott Long 	}
247dac36688SXin LI 	return (0);
248f1c579b1SScott Long }
249f1c579b1SScott Long /*
250f1c579b1SScott Long **************************************************************************
251f1c579b1SScott Long **************************************************************************
252f1c579b1SScott Long */
25300b4e54aSWarner Losh static int arcmsr_close(struct cdev *dev, int flags, int fmt, struct thread *proc)
254f1c579b1SScott Long {
2556bfa9a2dSEd Schouten 	int	unit = dev2unit(dev);
256ad6d6297SScott Long 	struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit);
2579ea5bef2SWarner Losh 
258ad6d6297SScott Long 	if (acb == NULL) {
259f1c579b1SScott Long 		return ENXIO;
260f1c579b1SScott Long 	}
261f1c579b1SScott Long 	return 0;
262f1c579b1SScott Long }
263f1c579b1SScott Long /*
264f1c579b1SScott Long **************************************************************************
265f1c579b1SScott Long **************************************************************************
266f1c579b1SScott Long */
26700b4e54aSWarner Losh static int arcmsr_ioctl(struct cdev *dev, u_long ioctl_cmd, caddr_t arg, int flags, struct thread *proc)
268f1c579b1SScott Long {
2696bfa9a2dSEd Schouten 	int	unit = dev2unit(dev);
270ad6d6297SScott Long 	struct AdapterControlBlock *acb = devclass_get_softc(arcmsr_devclass, unit);
271f1c579b1SScott Long 
272ad6d6297SScott Long 	if (acb == NULL) {
273f1c579b1SScott Long 		return ENXIO;
274f1c579b1SScott Long 	}
275ad6d6297SScott Long 	return (arcmsr_iop_ioctlcmd(acb, ioctl_cmd, arg));
276f1c579b1SScott Long }
277f1c579b1SScott Long /*
27844f05562SScott Long **********************************************************************
27944f05562SScott Long **********************************************************************
28044f05562SScott Long */
28144f05562SScott Long static u_int32_t arcmsr_disable_allintr( struct AdapterControlBlock *acb)
28244f05562SScott Long {
28344f05562SScott Long 	u_int32_t intmask_org = 0;
28444f05562SScott Long 
28544f05562SScott Long 	switch (acb->adapter_type) {
28644f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
28744f05562SScott Long 			/* disable all outbound interrupt */
288d74001adSXin LI 			intmask_org = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intmask); /* disable outbound message0 int */
289d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE);
29044f05562SScott Long 		}
29144f05562SScott Long 		break;
29244f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
293b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
29444f05562SScott Long 			/* disable all outbound interrupt */
295b23a1998SXin LI 			intmask_org = READ_CHIP_REG32(0, phbbmu->iop2drv_doorbell_mask)
296b23a1998SXin LI 						& (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); /* disable outbound message0 int */
297b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell_mask, 0); /* disable all interrupt */
298d74001adSXin LI 		}
299d74001adSXin LI 		break;
300d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
301d74001adSXin LI 			/* disable all outbound interrupt */
302d74001adSXin LI 			intmask_org = CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_mask); /* disable outbound message0 int */
303d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE);
30444f05562SScott Long 		}
30544f05562SScott Long 		break;
3067a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
3077a7bc959SXin LI 			/* disable all outbound interrupt */
3087a7bc959SXin LI 			intmask_org = CHIP_REG_READ32(HBD_MessageUnit, 0, pcief0_int_enable); /* disable outbound message0 int */
3097a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, pcief0_int_enable, ARCMSR_HBDMU_ALL_INT_DISABLE);
3107a7bc959SXin LI 		}
3117a7bc959SXin LI 		break;
312fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
313fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
314a1103e04SXin LI 			/* disable all outbound interrupt */
315fa42a0bfSXin LI 			intmask_org = CHIP_REG_READ32(HBE_MessageUnit, 0, host_int_mask); /* disable outbound message0 int */
316a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_mask, intmask_org | ARCMSR_HBEMU_ALL_INTMASKENABLE);
317a1103e04SXin LI 		}
318a1103e04SXin LI 		break;
31944f05562SScott Long 	}
32044f05562SScott Long 	return (intmask_org);
32144f05562SScott Long }
32244f05562SScott Long /*
32344f05562SScott Long **********************************************************************
32444f05562SScott Long **********************************************************************
32544f05562SScott Long */
32644f05562SScott Long static void arcmsr_enable_allintr( struct AdapterControlBlock *acb, u_int32_t intmask_org)
32744f05562SScott Long {
32844f05562SScott Long 	u_int32_t mask;
32944f05562SScott Long 
33044f05562SScott Long 	switch (acb->adapter_type) {
33144f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
33244f05562SScott Long 			/* enable outbound Post Queue, outbound doorbell Interrupt */
333d74001adSXin LI 			mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE|ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
33444f05562SScott Long 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intmask, intmask_org & mask);
33544f05562SScott Long 			acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
33644f05562SScott Long 		}
33744f05562SScott Long 		break;
33844f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
339b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
340d74001adSXin LI 			/* enable ARCMSR_IOP2DRV_MESSAGE_CMD_DONE */
341d74001adSXin LI 			mask = (ARCMSR_IOP2DRV_DATA_WRITE_OK|ARCMSR_IOP2DRV_DATA_READ_OK|ARCMSR_IOP2DRV_CDB_DONE|ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
342b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell_mask, intmask_org | mask); /*1=interrupt enable, 0=interrupt disable*/
34344f05562SScott Long 			acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
34444f05562SScott Long 		}
34544f05562SScott Long 		break;
346d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
347d74001adSXin LI 			/* enable outbound Post Queue, outbound doorbell Interrupt */
348d74001adSXin LI 			mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
349d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, host_int_mask, intmask_org & mask);
350d74001adSXin LI 			acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
351d74001adSXin LI 		}
352d74001adSXin LI 		break;
3537a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
3547a7bc959SXin LI 			/* enable outbound Post Queue, outbound doorbell Interrupt */
3557a7bc959SXin LI 			mask = ARCMSR_HBDMU_ALL_INT_ENABLE;
3567a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, pcief0_int_enable, intmask_org | mask);
3577a7bc959SXin LI 			CHIP_REG_READ32(HBD_MessageUnit, 0, pcief0_int_enable);
3587a7bc959SXin LI 			acb->outbound_int_enable = mask;
3597a7bc959SXin LI 		}
3607a7bc959SXin LI 		break;
361fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
362fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
363a1103e04SXin LI 			/* enable outbound Post Queue, outbound doorbell Interrupt */
364a1103e04SXin LI 			mask = ~(ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR | ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR);
365a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_mask, intmask_org & mask);
366a1103e04SXin LI 			acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
367a1103e04SXin LI 		}
368a1103e04SXin LI 		break;
36944f05562SScott Long 	}
37044f05562SScott Long }
37144f05562SScott Long /*
37244f05562SScott Long **********************************************************************
37344f05562SScott Long **********************************************************************
37444f05562SScott Long */
37544f05562SScott Long static u_int8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
37644f05562SScott Long {
37744f05562SScott Long 	u_int32_t Index;
37844f05562SScott Long 	u_int8_t Retries = 0x00;
37944f05562SScott Long 
38044f05562SScott Long 	do {
38144f05562SScott Long 		for(Index=0; Index < 100; Index++) {
382d74001adSXin LI 			if(CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
383d74001adSXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);/*clear interrupt*/
38444f05562SScott Long 				return TRUE;
38544f05562SScott Long 			}
38644f05562SScott Long 			UDELAY(10000);
38744f05562SScott Long 		}/*max 1 seconds*/
38844f05562SScott Long 	}while(Retries++ < 20);/*max 20 sec*/
389dac36688SXin LI 	return (FALSE);
39044f05562SScott Long }
39144f05562SScott Long /*
39244f05562SScott Long **********************************************************************
39344f05562SScott Long **********************************************************************
39444f05562SScott Long */
39544f05562SScott Long static u_int8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
39644f05562SScott Long {
39744f05562SScott Long 	u_int32_t Index;
39844f05562SScott Long 	u_int8_t Retries = 0x00;
399b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
40044f05562SScott Long 
40144f05562SScott Long 	do {
40244f05562SScott Long 		for(Index=0; Index < 100; Index++) {
403b23a1998SXin LI 			if(READ_CHIP_REG32(0, phbbmu->iop2drv_doorbell) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
404b23a1998SXin LI 				WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);/*clear interrupt*/
405b23a1998SXin LI 				WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT);
406d74001adSXin LI 				return TRUE;
407d74001adSXin LI 			}
408d74001adSXin LI 			UDELAY(10000);
409d74001adSXin LI 		}/*max 1 seconds*/
410d74001adSXin LI 	}while(Retries++ < 20);/*max 20 sec*/
411dac36688SXin LI 	return (FALSE);
412d74001adSXin LI }
413d74001adSXin LI /*
414d74001adSXin LI **********************************************************************
415d74001adSXin LI **********************************************************************
416d74001adSXin LI */
417d74001adSXin LI static u_int8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *acb)
418d74001adSXin LI {
419d74001adSXin LI 	u_int32_t Index;
420d74001adSXin LI 	u_int8_t Retries = 0x00;
421d74001adSXin LI 
422d74001adSXin LI 	do {
423d74001adSXin LI 		for(Index=0; Index < 100; Index++) {
424d74001adSXin LI 			if(CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
425d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR);/*clear interrupt*/
42644f05562SScott Long 				return TRUE;
42744f05562SScott Long 			}
42844f05562SScott Long 			UDELAY(10000);
42944f05562SScott Long 		}/*max 1 seconds*/
43044f05562SScott Long 	}while(Retries++ < 20);/*max 20 sec*/
431dac36688SXin LI 	return (FALSE);
43244f05562SScott Long }
43344f05562SScott Long /*
4347a7bc959SXin LI **********************************************************************
4357a7bc959SXin LI **********************************************************************
4367a7bc959SXin LI */
4377a7bc959SXin LI static u_int8_t arcmsr_hbd_wait_msgint_ready(struct AdapterControlBlock *acb)
4387a7bc959SXin LI {
4397a7bc959SXin LI 	u_int32_t Index;
4407a7bc959SXin LI 	u_int8_t Retries = 0x00;
4417a7bc959SXin LI 
4427a7bc959SXin LI 	do {
4437a7bc959SXin LI 		for(Index=0; Index < 100; Index++) {
4447a7bc959SXin LI 			if(CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE) {
4457a7bc959SXin LI 				CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE_CLEAR);/*clear interrupt*/
4467a7bc959SXin LI 				return TRUE;
4477a7bc959SXin LI 			}
4487a7bc959SXin LI 			UDELAY(10000);
4497a7bc959SXin LI 		}/*max 1 seconds*/
4507a7bc959SXin LI 	}while(Retries++ < 20);/*max 20 sec*/
4517a7bc959SXin LI 	return (FALSE);
4527a7bc959SXin LI }
4537a7bc959SXin LI /*
454a1103e04SXin LI **********************************************************************
455a1103e04SXin LI **********************************************************************
456a1103e04SXin LI */
457a1103e04SXin LI static u_int8_t arcmsr_hbe_wait_msgint_ready(struct AdapterControlBlock *acb)
458a1103e04SXin LI {
459a1103e04SXin LI 	u_int32_t Index, read_doorbell;
460a1103e04SXin LI 	u_int8_t Retries = 0x00;
461a1103e04SXin LI 
462a1103e04SXin LI 	do {
463a1103e04SXin LI 		for(Index=0; Index < 100; Index++) {
464a1103e04SXin LI 			read_doorbell = CHIP_REG_READ32(HBE_MessageUnit, 0, iobound_doorbell);
465a1103e04SXin LI 			if((read_doorbell ^ acb->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
466a1103e04SXin LI 				CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_status, 0);/*clear interrupt*/
467a1103e04SXin LI 				acb->in_doorbell = read_doorbell;
468a1103e04SXin LI 				return TRUE;
469a1103e04SXin LI 			}
470a1103e04SXin LI 			UDELAY(10000);
471a1103e04SXin LI 		}/*max 1 seconds*/
472a1103e04SXin LI 	}while(Retries++ < 20);/*max 20 sec*/
473a1103e04SXin LI 	return (FALSE);
474a1103e04SXin LI }
475a1103e04SXin LI /*
47644f05562SScott Long ************************************************************************
47744f05562SScott Long ************************************************************************
47844f05562SScott Long */
47944f05562SScott Long static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
48044f05562SScott Long {
48144f05562SScott Long 	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
48244f05562SScott Long 
483d74001adSXin LI 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
48444f05562SScott Long 	do {
48544f05562SScott Long 		if(arcmsr_hba_wait_msgint_ready(acb)) {
48644f05562SScott Long 			break;
48744f05562SScott Long 		} else {
48844f05562SScott Long 			retry_count--;
48944f05562SScott Long 		}
49044f05562SScott Long 	}while(retry_count != 0);
49144f05562SScott Long }
49244f05562SScott Long /*
49344f05562SScott Long ************************************************************************
49444f05562SScott Long ************************************************************************
49544f05562SScott Long */
49644f05562SScott Long static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
49744f05562SScott Long {
49844f05562SScott Long 	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
499b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
50044f05562SScott Long 
501b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_FLUSH_CACHE);
50244f05562SScott Long 	do {
50344f05562SScott Long 		if(arcmsr_hbb_wait_msgint_ready(acb)) {
50444f05562SScott Long 			break;
50544f05562SScott Long 		} else {
50644f05562SScott Long 			retry_count--;
50744f05562SScott Long 		}
50844f05562SScott Long 	}while(retry_count != 0);
50944f05562SScott Long }
51044f05562SScott Long /*
51144f05562SScott Long ************************************************************************
51244f05562SScott Long ************************************************************************
51344f05562SScott Long */
514d74001adSXin LI static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *acb)
515d74001adSXin LI {
516d74001adSXin LI 	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
517d74001adSXin LI 
518d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
519d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
520d74001adSXin LI 	do {
521d74001adSXin LI 		if(arcmsr_hbc_wait_msgint_ready(acb)) {
522d74001adSXin LI 			break;
523d74001adSXin LI 		} else {
524d74001adSXin LI 			retry_count--;
525d74001adSXin LI 		}
526d74001adSXin LI 	}while(retry_count != 0);
527d74001adSXin LI }
528d74001adSXin LI /*
529d74001adSXin LI ************************************************************************
530d74001adSXin LI ************************************************************************
531d74001adSXin LI */
5327a7bc959SXin LI static void arcmsr_flush_hbd_cache(struct AdapterControlBlock *acb)
5337a7bc959SXin LI {
5347a7bc959SXin LI 	int retry_count = 30; /* enlarge wait flush adapter cache time: 10 minute */
5357a7bc959SXin LI 
5367a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
5377a7bc959SXin LI 	do {
5387a7bc959SXin LI 		if(arcmsr_hbd_wait_msgint_ready(acb)) {
5397a7bc959SXin LI 			break;
5407a7bc959SXin LI 		} else {
5417a7bc959SXin LI 			retry_count--;
5427a7bc959SXin LI 		}
5437a7bc959SXin LI 	}while(retry_count != 0);
5447a7bc959SXin LI }
5457a7bc959SXin LI /*
5467a7bc959SXin LI ************************************************************************
5477a7bc959SXin LI ************************************************************************
5487a7bc959SXin LI */
549a1103e04SXin LI static void arcmsr_flush_hbe_cache(struct AdapterControlBlock *acb)
550a1103e04SXin LI {
551a1103e04SXin LI 	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
552a1103e04SXin LI 
553a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
554a1103e04SXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
555a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
556a1103e04SXin LI 	do {
557a1103e04SXin LI 		if(arcmsr_hbe_wait_msgint_ready(acb)) {
558a1103e04SXin LI 			break;
559a1103e04SXin LI 		} else {
560a1103e04SXin LI 			retry_count--;
561a1103e04SXin LI 		}
562a1103e04SXin LI 	}while(retry_count != 0);
563a1103e04SXin LI }
564a1103e04SXin LI /*
565a1103e04SXin LI ************************************************************************
566a1103e04SXin LI ************************************************************************
567a1103e04SXin LI */
56844f05562SScott Long static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
56944f05562SScott Long {
57044f05562SScott Long 	switch (acb->adapter_type) {
57144f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
57244f05562SScott Long 			arcmsr_flush_hba_cache(acb);
57344f05562SScott Long 		}
57444f05562SScott Long 		break;
57544f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
57644f05562SScott Long 			arcmsr_flush_hbb_cache(acb);
57744f05562SScott Long 		}
57844f05562SScott Long 		break;
579d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
580d74001adSXin LI 			arcmsr_flush_hbc_cache(acb);
581d74001adSXin LI 		}
582d74001adSXin LI 		break;
5837a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
5847a7bc959SXin LI 			arcmsr_flush_hbd_cache(acb);
5857a7bc959SXin LI 		}
5867a7bc959SXin LI 		break;
587fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
588fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
589a1103e04SXin LI 			arcmsr_flush_hbe_cache(acb);
590a1103e04SXin LI 		}
591a1103e04SXin LI 		break;
59244f05562SScott Long 	}
59344f05562SScott Long }
59444f05562SScott Long /*
595ad6d6297SScott Long *******************************************************************************
596ad6d6297SScott Long *******************************************************************************
597f1c579b1SScott Long */
598ad6d6297SScott Long static int arcmsr_suspend(device_t dev)
599f1c579b1SScott Long {
600ad6d6297SScott Long 	struct AdapterControlBlock	*acb = device_get_softc(dev);
601f1c579b1SScott Long 
602ad6d6297SScott Long 	/* flush controller */
603ad6d6297SScott Long 	arcmsr_iop_parking(acb);
604d74001adSXin LI 	/* disable all outbound interrupt */
605d74001adSXin LI 	arcmsr_disable_allintr(acb);
606ad6d6297SScott Long 	return(0);
607ad6d6297SScott Long }
608ad6d6297SScott Long /*
609ad6d6297SScott Long *******************************************************************************
610ad6d6297SScott Long *******************************************************************************
611ad6d6297SScott Long */
612ad6d6297SScott Long static int arcmsr_resume(device_t dev)
613ad6d6297SScott Long {
614ad6d6297SScott Long 	struct AdapterControlBlock	*acb = device_get_softc(dev);
615f1c579b1SScott Long 
616ad6d6297SScott Long 	arcmsr_iop_init(acb);
617ad6d6297SScott Long 	return(0);
618f1c579b1SScott Long }
619f1c579b1SScott Long /*
620f1c579b1SScott Long *********************************************************************************
621f1c579b1SScott Long *********************************************************************************
622f1c579b1SScott Long */
623ad6d6297SScott Long static void arcmsr_async(void *cb_arg, u_int32_t code, struct cam_path *path, void *arg)
624f1c579b1SScott Long {
625ad6d6297SScott Long 	u_int8_t target_id, target_lun;
626f1c579b1SScott Long 
627ad6d6297SScott Long 	switch (code) {
628f1c579b1SScott Long 	case AC_LOST_DEVICE:
629f1c579b1SScott Long 		target_id = xpt_path_target_id(path);
630f1c579b1SScott Long 		target_lun = xpt_path_lun_id(path);
631d74001adSXin LI 		if((target_id > ARCMSR_MAX_TARGETID) || (target_lun > ARCMSR_MAX_TARGETLUN)) {
632f1c579b1SScott Long 			break;
633f1c579b1SScott Long 		}
634f1c579b1SScott Long 		break;
635f1c579b1SScott Long 	default:
636f1c579b1SScott Long 		break;
637f1c579b1SScott Long 	}
638f1c579b1SScott Long }
639f1c579b1SScott Long /*
640f1c579b1SScott Long **********************************************************************
641f1c579b1SScott Long **********************************************************************
642f1c579b1SScott Long */
643ad6d6297SScott Long static void arcmsr_report_sense_info(struct CommandControlBlock *srb)
644f1c579b1SScott Long {
645ad6d6297SScott Long 	union ccb *pccb = srb->pccb;
646f1c579b1SScott Long 
647ad6d6297SScott Long 	pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
648ad6d6297SScott Long 	pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
649dac36688SXin LI 	if(pccb->csio.sense_len) {
650ad6d6297SScott Long 		memset(&pccb->csio.sense_data, 0, sizeof(pccb->csio.sense_data));
651ad6d6297SScott Long 		memcpy(&pccb->csio.sense_data, srb->arcmsr_cdb.SenseData,
652ad6d6297SScott Long 		get_min(sizeof(struct SENSE_DATA), sizeof(pccb->csio.sense_data)));
653ad6d6297SScott Long 		((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70); /* Valid,ErrorCode */
654f1c579b1SScott Long 		pccb->ccb_h.status |= CAM_AUTOSNS_VALID;
655f1c579b1SScott Long 	}
656f1c579b1SScott Long }
657f1c579b1SScott Long /*
658f1c579b1SScott Long *********************************************************************
65944f05562SScott Long *********************************************************************
66044f05562SScott Long */
66144f05562SScott Long static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
66244f05562SScott Long {
66344f05562SScott Long 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD);
66444f05562SScott Long 	if(!arcmsr_hba_wait_msgint_ready(acb)) {
665d74001adSXin LI 		printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit);
66644f05562SScott Long 	}
66744f05562SScott Long }
66844f05562SScott Long /*
66944f05562SScott Long *********************************************************************
67044f05562SScott Long *********************************************************************
67144f05562SScott Long */
67244f05562SScott Long static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
67344f05562SScott Long {
674b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
675b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_ABORT_CMD);
67644f05562SScott Long 	if(!arcmsr_hbb_wait_msgint_ready(acb)) {
677d74001adSXin LI 		printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit);
678d74001adSXin LI 	}
679d74001adSXin LI }
680d74001adSXin LI /*
681d74001adSXin LI *********************************************************************
682d74001adSXin LI *********************************************************************
683d74001adSXin LI */
684d74001adSXin LI static void arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *acb)
685d74001adSXin LI {
686d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD);
687d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
688d74001adSXin LI 	if(!arcmsr_hbc_wait_msgint_ready(acb)) {
689d74001adSXin LI 		printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit);
69044f05562SScott Long 	}
69144f05562SScott Long }
69244f05562SScott Long /*
69344f05562SScott Long *********************************************************************
694f1c579b1SScott Long *********************************************************************
695f1c579b1SScott Long */
6967a7bc959SXin LI static void arcmsr_abort_hbd_allcmd(struct AdapterControlBlock *acb)
6977a7bc959SXin LI {
6987a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD);
6997a7bc959SXin LI 	if(!arcmsr_hbd_wait_msgint_ready(acb)) {
7007a7bc959SXin LI 		printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit);
7017a7bc959SXin LI 	}
7027a7bc959SXin LI }
7037a7bc959SXin LI /*
7047a7bc959SXin LI *********************************************************************
7057a7bc959SXin LI *********************************************************************
7067a7bc959SXin LI */
707a1103e04SXin LI static void arcmsr_abort_hbe_allcmd(struct AdapterControlBlock *acb)
708a1103e04SXin LI {
709a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_ABORT_CMD);
710a1103e04SXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
711a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
712a1103e04SXin LI 	if(!arcmsr_hbe_wait_msgint_ready(acb)) {
713a1103e04SXin LI 		printf("arcmsr%d: wait 'abort all outstanding command' timeout \n", acb->pci_unit);
714a1103e04SXin LI 	}
715a1103e04SXin LI }
716a1103e04SXin LI /*
717a1103e04SXin LI *********************************************************************
718a1103e04SXin LI *********************************************************************
719a1103e04SXin LI */
720ad6d6297SScott Long static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
721f1c579b1SScott Long {
72244f05562SScott Long 	switch (acb->adapter_type) {
72344f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
72444f05562SScott Long 			arcmsr_abort_hba_allcmd(acb);
72544f05562SScott Long 		}
72644f05562SScott Long 		break;
72744f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
72844f05562SScott Long 			arcmsr_abort_hbb_allcmd(acb);
72944f05562SScott Long 		}
73044f05562SScott Long 		break;
731d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
732d74001adSXin LI 			arcmsr_abort_hbc_allcmd(acb);
733d74001adSXin LI 		}
734d74001adSXin LI 		break;
7357a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
7367a7bc959SXin LI 			arcmsr_abort_hbd_allcmd(acb);
7377a7bc959SXin LI 		}
7387a7bc959SXin LI 		break;
739fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
740fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
741a1103e04SXin LI 			arcmsr_abort_hbe_allcmd(acb);
742a1103e04SXin LI 		}
743a1103e04SXin LI 		break;
74444f05562SScott Long 	}
74544f05562SScott Long }
74644f05562SScott Long /*
747231c8b71SXin LI **********************************************************************
748231c8b71SXin LI **********************************************************************
749231c8b71SXin LI */
750231c8b71SXin LI static void arcmsr_srb_complete(struct CommandControlBlock *srb, int stand_flag)
751231c8b71SXin LI {
752231c8b71SXin LI 	struct AdapterControlBlock *acb = srb->acb;
753231c8b71SXin LI 	union ccb *pccb = srb->pccb;
754231c8b71SXin LI 
75522f2616bSXin LI 	if(srb->srb_flags & SRB_FLAG_TIMER_START)
75622f2616bSXin LI 		callout_stop(&srb->ccb_callout);
757231c8b71SXin LI 	if((pccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
758231c8b71SXin LI 		bus_dmasync_op_t op;
759231c8b71SXin LI 
760231c8b71SXin LI 		if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
761231c8b71SXin LI 			op = BUS_DMASYNC_POSTREAD;
762231c8b71SXin LI 		} else {
763231c8b71SXin LI 			op = BUS_DMASYNC_POSTWRITE;
764231c8b71SXin LI 		}
765231c8b71SXin LI 		bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op);
766231c8b71SXin LI 		bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap);
767231c8b71SXin LI 	}
768231c8b71SXin LI 	if(stand_flag == 1) {
769231c8b71SXin LI 		atomic_subtract_int(&acb->srboutstandingcount, 1);
770231c8b71SXin LI 		if((acb->acb_flags & ACB_F_CAM_DEV_QFRZN) && (
771abfdbca9SXin LI 		acb->srboutstandingcount < (acb->maxOutstanding -10))) {
772231c8b71SXin LI 			acb->acb_flags &= ~ACB_F_CAM_DEV_QFRZN;
773231c8b71SXin LI 			pccb->ccb_h.status |= CAM_RELEASE_SIMQ;
774231c8b71SXin LI 		}
775231c8b71SXin LI 	}
77622f2616bSXin LI 	if(srb->srb_state != ARCMSR_SRB_TIMEOUT)
77722f2616bSXin LI 		arcmsr_free_srb(srb);
77822f2616bSXin LI 	acb->pktReturnCount++;
779231c8b71SXin LI 	xpt_done(pccb);
780231c8b71SXin LI }
781231c8b71SXin LI /*
78244f05562SScott Long **************************************************************************
78344f05562SScott Long **************************************************************************
78444f05562SScott Long */
785d74001adSXin LI static void arcmsr_report_srb_state(struct AdapterControlBlock *acb, struct CommandControlBlock *srb, u_int16_t error)
78644f05562SScott Long {
78744f05562SScott Long 	int target, lun;
78844f05562SScott Long 
78944f05562SScott Long 	target = srb->pccb->ccb_h.target_id;
79044f05562SScott Long 	lun = srb->pccb->ccb_h.target_lun;
791d74001adSXin LI 	if(error == FALSE) {
79244f05562SScott Long 		if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
79344f05562SScott Long 			acb->devstate[target][lun] = ARECA_RAID_GOOD;
79444f05562SScott Long 		}
79544f05562SScott Long 		srb->pccb->ccb_h.status |= CAM_REQ_CMP;
79644f05562SScott Long 		arcmsr_srb_complete(srb, 1);
79744f05562SScott Long 	} else {
79844f05562SScott Long 		switch(srb->arcmsr_cdb.DeviceStatus) {
79944f05562SScott Long 		case ARCMSR_DEV_SELECT_TIMEOUT: {
80044f05562SScott Long 				if(acb->devstate[target][lun] == ARECA_RAID_GOOD) {
801d74001adSXin LI 					printf( "arcmsr%d: Target=%x, Lun=%x, selection timeout, raid volume was lost\n", acb->pci_unit, target, lun);
802ad6d6297SScott Long 				}
80344f05562SScott Long 				acb->devstate[target][lun] = ARECA_RAID_GONE;
804d74001adSXin LI 				srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE;
80544f05562SScott Long 				arcmsr_srb_complete(srb, 1);
80644f05562SScott Long 			}
80744f05562SScott Long 			break;
80844f05562SScott Long 		case ARCMSR_DEV_ABORTED:
80944f05562SScott Long 		case ARCMSR_DEV_INIT_FAIL: {
81044f05562SScott Long 				acb->devstate[target][lun] = ARECA_RAID_GONE;
81144f05562SScott Long 				srb->pccb->ccb_h.status |= CAM_DEV_NOT_THERE;
81244f05562SScott Long 				arcmsr_srb_complete(srb, 1);
81344f05562SScott Long 			}
81444f05562SScott Long 			break;
81544f05562SScott Long 		case SCSISTAT_CHECK_CONDITION: {
81644f05562SScott Long 				acb->devstate[target][lun] = ARECA_RAID_GOOD;
81744f05562SScott Long 				arcmsr_report_sense_info(srb);
81844f05562SScott Long 				arcmsr_srb_complete(srb, 1);
81944f05562SScott Long 			}
82044f05562SScott Long 			break;
82144f05562SScott Long 		default:
82210d66948SKevin Lo 			printf("arcmsr%d: scsi id=%d lun=%d isr got command error done,but got unknown DeviceStatus=0x%x \n"
823d74001adSXin LI 					, acb->pci_unit, target, lun ,srb->arcmsr_cdb.DeviceStatus);
82444f05562SScott Long 			acb->devstate[target][lun] = ARECA_RAID_GONE;
82544f05562SScott Long 			srb->pccb->ccb_h.status |= CAM_UNCOR_PARITY;
82610d66948SKevin Lo 			/*unknown error or crc error just for retry*/
82744f05562SScott Long 			arcmsr_srb_complete(srb, 1);
82844f05562SScott Long 			break;
82944f05562SScott Long 		}
83044f05562SScott Long 	}
83144f05562SScott Long }
83244f05562SScott Long /*
83344f05562SScott Long **************************************************************************
83444f05562SScott Long **************************************************************************
83544f05562SScott Long */
836d74001adSXin LI static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, u_int32_t flag_srb, u_int16_t error)
83744f05562SScott Long {
83844f05562SScott Long 	struct CommandControlBlock *srb;
83944f05562SScott Long 
84044f05562SScott Long 	/* check if command done with no error*/
841d74001adSXin LI 	switch (acb->adapter_type) {
842fc5ef1caSXin LI 	case ACB_ADAPTER_TYPE_A:
843fc5ef1caSXin LI 	case ACB_ADAPTER_TYPE_B:
844fc5ef1caSXin LI 		srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/
845fc5ef1caSXin LI 		break;
846d74001adSXin LI 	case ACB_ADAPTER_TYPE_C:
8477a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D:
84822f2616bSXin LI 		srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFE0)); /*frame must be 32 bytes aligned*/
849d74001adSXin LI 		break;
850a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E:
851fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
852a1103e04SXin LI 		srb = acb->psrb_pool[flag_srb];
853a1103e04SXin LI 		break;
854d74001adSXin LI 	default:
855d74001adSXin LI 		srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/
856d74001adSXin LI 		break;
857d74001adSXin LI 	}
85822f2616bSXin LI 	if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
85922f2616bSXin LI 		if(srb->srb_state == ARCMSR_SRB_TIMEOUT) {
86022f2616bSXin LI 			arcmsr_free_srb(srb);
86122f2616bSXin LI 			printf("arcmsr%d: srb='%p' return srb has been timeouted\n", acb->pci_unit, srb);
86244f05562SScott Long 			return;
86344f05562SScott Long 		}
86422f2616bSXin LI 		printf("arcmsr%d: return srb has been completed\n"
86522f2616bSXin LI 			"srb='%p' srb_state=0x%x outstanding srb count=%d \n",
86622f2616bSXin LI 			acb->pci_unit, srb, srb->srb_state, acb->srboutstandingcount);
86744f05562SScott Long 		return;
86844f05562SScott Long 	}
869d74001adSXin LI 	arcmsr_report_srb_state(acb, srb, error);
87044f05562SScott Long }
87144f05562SScott Long /*
87222f2616bSXin LI **************************************************************************
87322f2616bSXin LI **************************************************************************
87422f2616bSXin LI */
87522f2616bSXin LI static void	arcmsr_srb_timeout(void *arg)
87622f2616bSXin LI {
87722f2616bSXin LI 	struct CommandControlBlock *srb = (struct CommandControlBlock *)arg;
87822f2616bSXin LI 	struct AdapterControlBlock *acb;
87922f2616bSXin LI 	int target, lun;
88022f2616bSXin LI 	u_int8_t cmd;
88122f2616bSXin LI 
88222f2616bSXin LI 	target = srb->pccb->ccb_h.target_id;
88322f2616bSXin LI 	lun = srb->pccb->ccb_h.target_lun;
88422f2616bSXin LI 	acb = srb->acb;
8857a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
88622f2616bSXin LI 	if(srb->srb_state == ARCMSR_SRB_START)
88722f2616bSXin LI 	{
8884aa947cbSWarner Losh 		cmd = scsiio_cdb_ptr(&srb->pccb->csio)[0];
88922f2616bSXin LI 		srb->srb_state = ARCMSR_SRB_TIMEOUT;
89022f2616bSXin LI 		srb->pccb->ccb_h.status |= CAM_CMD_TIMEOUT;
89122f2616bSXin LI 		arcmsr_srb_complete(srb, 1);
89222f2616bSXin LI 		printf("arcmsr%d: scsi id %d lun %d cmd=0x%x srb='%p' ccb command time out!\n",
89322f2616bSXin LI 				 acb->pci_unit, target, lun, cmd, srb);
89422f2616bSXin LI 	}
8957a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->isr_lock);
89622f2616bSXin LI #ifdef ARCMSR_DEBUG1
89722f2616bSXin LI 	arcmsr_dump_data(acb);
89822f2616bSXin LI #endif
89922f2616bSXin LI }
90022f2616bSXin LI 
90122f2616bSXin LI /*
90244f05562SScott Long **********************************************************************
90344f05562SScott Long **********************************************************************
90444f05562SScott Long */
90544f05562SScott Long static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
90644f05562SScott Long {
90744f05562SScott Long 	int i=0;
90844f05562SScott Long 	u_int32_t flag_srb;
909d74001adSXin LI 	u_int16_t error;
91044f05562SScott Long 
91144f05562SScott Long 	switch (acb->adapter_type) {
91244f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
91344f05562SScott Long 			u_int32_t outbound_intstatus;
91444f05562SScott Long 
91544f05562SScott Long 			/*clear and abort all outbound posted Q*/
916d74001adSXin LI 			outbound_intstatus = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable;
917d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);/*clear interrupt*/
918d74001adSXin LI 			while(((flag_srb=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_queueport)) != 0xFFFFFFFF) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
919d74001adSXin LI 				error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
920d74001adSXin LI 				arcmsr_drain_donequeue(acb, flag_srb, error);
92144f05562SScott Long 			}
92244f05562SScott Long 		}
92344f05562SScott Long 		break;
92444f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
92544f05562SScott Long 			struct HBB_MessageUnit *phbbmu=(struct HBB_MessageUnit *)acb->pmu;
92644f05562SScott Long 
92744f05562SScott Long 			/*clear all outbound posted Q*/
928b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */
92944f05562SScott Long 			for(i=0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
93044f05562SScott Long 				if((flag_srb = phbbmu->done_qbuffer[i]) != 0) {
93144f05562SScott Long 					phbbmu->done_qbuffer[i] = 0;
932d74001adSXin LI 					error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
933d74001adSXin LI 					arcmsr_drain_donequeue(acb, flag_srb, error);
93444f05562SScott Long 				}
93544f05562SScott Long 				phbbmu->post_qbuffer[i] = 0;
93644f05562SScott Long 			}/*drain reply FIFO*/
93744f05562SScott Long 			phbbmu->doneq_index = 0;
93844f05562SScott Long 			phbbmu->postq_index = 0;
93944f05562SScott Long 		}
94044f05562SScott Long 		break;
941d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
942d74001adSXin LI 			while((CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
943d74001adSXin LI 				flag_srb = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low);
944d74001adSXin LI 				error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
945d74001adSXin LI 				arcmsr_drain_donequeue(acb, flag_srb, error);
946d74001adSXin LI 			}
947d74001adSXin LI 		}
948d74001adSXin LI 		break;
949fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_D:
9507a7bc959SXin LI 		arcmsr_hbd_postqueue_isr(acb);
9517a7bc959SXin LI 		break;
952fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
953a1103e04SXin LI 		arcmsr_hbe_postqueue_isr(acb);
954fa42a0bfSXin LI 		break;
955fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
956fa42a0bfSXin LI 		arcmsr_hbf_postqueue_isr(acb);
957a1103e04SXin LI 		break;
95844f05562SScott Long 	}
959f1c579b1SScott Long }
960f1c579b1SScott Long /*
961f1c579b1SScott Long ****************************************************************************
962f1c579b1SScott Long ****************************************************************************
963f1c579b1SScott Long */
964ad6d6297SScott Long static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
965f1c579b1SScott Long {
966ad6d6297SScott Long 	struct CommandControlBlock *srb;
96744f05562SScott Long 	u_int32_t intmask_org;
968ad6d6297SScott Long 	u_int32_t i=0;
969f1c579b1SScott Long 
97044f05562SScott Long 	if(acb->srboutstandingcount>0) {
97144f05562SScott Long 		/* disable all outbound interrupt */
97244f05562SScott Long 		intmask_org = arcmsr_disable_allintr(acb);
97344f05562SScott Long 		/*clear and abort all outbound posted Q*/
97444f05562SScott Long 		arcmsr_done4abort_postqueue(acb);
975f1c579b1SScott Long 		/* talk to iop 331 outstanding command aborted*/
976ad6d6297SScott Long 		arcmsr_abort_allcmd(acb);
977ad6d6297SScott Long 		for(i=0; i < ARCMSR_MAX_FREESRB_NUM; i++) {
978ad6d6297SScott Long 			srb = acb->psrb_pool[i];
97922f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_START) {
98022f2616bSXin LI 				srb->srb_state = ARCMSR_SRB_ABORTED;
981ad6d6297SScott Long 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
982ad6d6297SScott Long 				arcmsr_srb_complete(srb, 1);
983123055f0SNathan Whitehorn 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p' aborted\n"
98422f2616bSXin LI 						, acb->pci_unit, srb->pccb->ccb_h.target_id
985123055f0SNathan Whitehorn 						, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
986f1c579b1SScott Long 			}
987f1c579b1SScott Long 		}
988f1c579b1SScott Long 		/* enable all outbound interrupt */
98944f05562SScott Long 		arcmsr_enable_allintr(acb, intmask_org);
990f1c579b1SScott Long 	}
99122f2616bSXin LI 	acb->srboutstandingcount = 0;
992ad6d6297SScott Long 	acb->workingsrb_doneindex = 0;
993ad6d6297SScott Long 	acb->workingsrb_startindex = 0;
99422f2616bSXin LI 	acb->pktRequestCount = 0;
99522f2616bSXin LI 	acb->pktReturnCount = 0;
996f1c579b1SScott Long }
997f1c579b1SScott Long /*
998f1c579b1SScott Long **********************************************************************
999f1c579b1SScott Long **********************************************************************
1000f1c579b1SScott Long */
100144f05562SScott Long static void arcmsr_build_srb(struct CommandControlBlock *srb,
100244f05562SScott Long 		bus_dma_segment_t *dm_segs, u_int32_t nseg)
1003f1c579b1SScott Long {
1004ad6d6297SScott Long 	struct ARCMSR_CDB *arcmsr_cdb = &srb->arcmsr_cdb;
1005ad6d6297SScott Long 	u_int8_t *psge = (u_int8_t *)&arcmsr_cdb->u;
1006ad6d6297SScott Long 	u_int32_t address_lo, address_hi;
1007ad6d6297SScott Long 	union ccb *pccb = srb->pccb;
1008f1c579b1SScott Long 	struct ccb_scsiio *pcsio = &pccb->csio;
1009ad6d6297SScott Long 	u_int32_t arccdbsize = 0x30;
1010f1c579b1SScott Long 
1011ad6d6297SScott Long 	memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
1012ad6d6297SScott Long 	arcmsr_cdb->Bus = 0;
1013ad6d6297SScott Long 	arcmsr_cdb->TargetID = pccb->ccb_h.target_id;
1014ad6d6297SScott Long 	arcmsr_cdb->LUN = pccb->ccb_h.target_lun;
1015ad6d6297SScott Long 	arcmsr_cdb->Function = 1;
1016ad6d6297SScott Long 	arcmsr_cdb->CdbLength = (u_int8_t)pcsio->cdb_len;
10174aa947cbSWarner Losh 	bcopy(scsiio_cdb_ptr(pcsio), arcmsr_cdb->Cdb, pcsio->cdb_len);
1018ad6d6297SScott Long 	if(nseg != 0) {
1019ad6d6297SScott Long 		struct AdapterControlBlock *acb = srb->acb;
1020f1c579b1SScott Long 		bus_dmasync_op_t op;
1021ad6d6297SScott Long 		u_int32_t length, i, cdb_sgcount = 0;
1022f1c579b1SScott Long 
1023ad6d6297SScott Long 		if((pccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1024ad6d6297SScott Long 			op = BUS_DMASYNC_PREREAD;
1025ad6d6297SScott Long 		} else {
1026ad6d6297SScott Long 			op = BUS_DMASYNC_PREWRITE;
1027ad6d6297SScott Long 			arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
1028ad6d6297SScott Long 			srb->srb_flags |= SRB_FLAG_WRITE;
1029ad6d6297SScott Long 		}
1030ad6d6297SScott Long 		bus_dmamap_sync(acb->dm_segs_dmat, srb->dm_segs_dmamap, op);
1031ad6d6297SScott Long 		for(i=0; i < nseg; i++) {
1032f1c579b1SScott Long 			/* Get the physical address of the current data pointer */
1033ad6d6297SScott Long 			length = arcmsr_htole32(dm_segs[i].ds_len);
1034ad6d6297SScott Long 			address_lo = arcmsr_htole32(dma_addr_lo32(dm_segs[i].ds_addr));
1035ad6d6297SScott Long 			address_hi = arcmsr_htole32(dma_addr_hi32(dm_segs[i].ds_addr));
1036ad6d6297SScott Long 			if(address_hi == 0) {
1037ad6d6297SScott Long 				struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
1038f1c579b1SScott Long 				pdma_sg->address = address_lo;
1039f1c579b1SScott Long 				pdma_sg->length = length;
1040ad6d6297SScott Long 				psge += sizeof(struct SG32ENTRY);
1041ad6d6297SScott Long 				arccdbsize += sizeof(struct SG32ENTRY);
1042ad6d6297SScott Long 			} else {
1043ad6d6297SScott Long 				u_int32_t sg64s_size = 0, tmplength = length;
1044f1c579b1SScott Long 
1045ad6d6297SScott Long 				while(1) {
1046ad6d6297SScott Long 					u_int64_t span4G, length0;
1047ad6d6297SScott Long 					struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
1048f1c579b1SScott Long 
1049ad6d6297SScott Long 					span4G = (u_int64_t)address_lo + tmplength;
1050f1c579b1SScott Long 					pdma_sg->addresshigh = address_hi;
1051f1c579b1SScott Long 					pdma_sg->address = address_lo;
1052ad6d6297SScott Long 					if(span4G > 0x100000000) {
1053f1c579b1SScott Long 						/*see if cross 4G boundary*/
1054f1c579b1SScott Long 						length0 = 0x100000000-address_lo;
1055ad6d6297SScott Long 						pdma_sg->length = (u_int32_t)length0 | IS_SG64_ADDR;
1056f1c579b1SScott Long 						address_hi = address_hi+1;
1057f1c579b1SScott Long 						address_lo = 0;
1058ad6d6297SScott Long 						tmplength = tmplength - (u_int32_t)length0;
1059ad6d6297SScott Long 						sg64s_size += sizeof(struct SG64ENTRY);
1060ad6d6297SScott Long 						psge += sizeof(struct SG64ENTRY);
1061f1c579b1SScott Long 						cdb_sgcount++;
1062ad6d6297SScott Long 					} else {
1063f1c579b1SScott Long 						pdma_sg->length = tmplength | IS_SG64_ADDR;
1064ad6d6297SScott Long 						sg64s_size += sizeof(struct SG64ENTRY);
1065ad6d6297SScott Long 						psge += sizeof(struct SG64ENTRY);
1066f1c579b1SScott Long 						break;
1067f1c579b1SScott Long 					}
1068f1c579b1SScott Long 				}
1069f1c579b1SScott Long 				arccdbsize += sg64s_size;
1070f1c579b1SScott Long 			}
1071f1c579b1SScott Long 			cdb_sgcount++;
1072f1c579b1SScott Long 		}
1073ad6d6297SScott Long 		arcmsr_cdb->sgcount = (u_int8_t)cdb_sgcount;
1074ad6d6297SScott Long 		arcmsr_cdb->DataLength = pcsio->dxfer_len;
1075ad6d6297SScott Long 		if( arccdbsize > 256) {
1076ad6d6297SScott Long 			arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
1077f1c579b1SScott Long 		}
1078d74001adSXin LI 	} else {
1079d74001adSXin LI 		arcmsr_cdb->DataLength = 0;
1080f1c579b1SScott Long 	}
1081d74001adSXin LI 	srb->arc_cdb_size = arccdbsize;
10827a7bc959SXin LI 	arcmsr_cdb->msgPages = (arccdbsize/256) + ((arccdbsize % 256) ? 1 : 0);
1083f1c579b1SScott Long }
1084f1c579b1SScott Long /*
1085f1c579b1SScott Long **************************************************************************
1086f1c579b1SScott Long **************************************************************************
1087f1c579b1SScott Long */
1088ad6d6297SScott Long static void arcmsr_post_srb(struct AdapterControlBlock *acb, struct CommandControlBlock *srb)
1089f1c579b1SScott Long {
10907a7bc959SXin LI 	u_int32_t cdb_phyaddr_low = (u_int32_t) srb->cdb_phyaddr_low;
1091ad6d6297SScott Long 	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&srb->arcmsr_cdb;
1092f1c579b1SScott Long 
1093d74001adSXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, (srb->srb_flags & SRB_FLAG_WRITE) ? BUS_DMASYNC_POSTWRITE:BUS_DMASYNC_POSTREAD);
1094ad6d6297SScott Long 	atomic_add_int(&acb->srboutstandingcount, 1);
109522f2616bSXin LI 	srb->srb_state = ARCMSR_SRB_START;
1096d74001adSXin LI 
109744f05562SScott Long 	switch (acb->adapter_type) {
109844f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
1099ad6d6297SScott Long 			if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
11007a7bc959SXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_phyaddr_low|ARCMSR_SRBPOST_FLAG_SGL_BSIZE);
1101ad6d6297SScott Long 			} else {
11027a7bc959SXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_queueport, cdb_phyaddr_low);
110344f05562SScott Long 			}
110444f05562SScott Long 		}
110544f05562SScott Long 		break;
110644f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
110744f05562SScott Long 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
110844f05562SScott Long 			int ending_index, index;
110944f05562SScott Long 
111044f05562SScott Long 			index = phbbmu->postq_index;
111144f05562SScott Long 			ending_index = ((index+1) % ARCMSR_MAX_HBB_POSTQUEUE);
111244f05562SScott Long 			phbbmu->post_qbuffer[ending_index] = 0;
111344f05562SScott Long 			if(arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
11147a7bc959SXin LI 				phbbmu->post_qbuffer[index] = cdb_phyaddr_low | ARCMSR_SRBPOST_FLAG_SGL_BSIZE;
111544f05562SScott Long 			} else {
11167a7bc959SXin LI 				phbbmu->post_qbuffer[index] = cdb_phyaddr_low;
111744f05562SScott Long 			}
111844f05562SScott Long 			index++;
111944f05562SScott Long 			index %= ARCMSR_MAX_HBB_POSTQUEUE;     /*if last index number set it to 0 */
112044f05562SScott Long 			phbbmu->postq_index = index;
1121b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_CDB_POSTED);
1122d74001adSXin LI 		}
1123d74001adSXin LI 		break;
11247a7bc959SXin LI 	case ACB_ADAPTER_TYPE_C: {
1125d74001adSXin LI 			u_int32_t ccb_post_stamp, arc_cdb_size, cdb_phyaddr_hi32;
1126d74001adSXin LI 
1127d74001adSXin LI 			arc_cdb_size = (srb->arc_cdb_size > 0x300) ? 0x300 : srb->arc_cdb_size;
11287a7bc959SXin LI 			ccb_post_stamp = (cdb_phyaddr_low | ((arc_cdb_size-1) >> 6) | 1);
1129d74001adSXin LI 			cdb_phyaddr_hi32 = acb->srb_phyaddr.B.phyadd_high;
1130d74001adSXin LI 			if(cdb_phyaddr_hi32)
1131d74001adSXin LI 			{
1132d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_high, cdb_phyaddr_hi32);
1133d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp);
1134d74001adSXin LI 			}
1135d74001adSXin LI 			else
1136d74001adSXin LI 			{
1137d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit,0,inbound_queueport_low, ccb_post_stamp);
1138d74001adSXin LI 			}
113944f05562SScott Long 		}
114044f05562SScott Long 		break;
11417a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
11427a7bc959SXin LI 			struct HBD_MessageUnit0 *phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
11437a7bc959SXin LI 			u_int16_t index_stripped;
11447a7bc959SXin LI 			u_int16_t postq_index;
11457a7bc959SXin LI 			struct InBound_SRB *pinbound_srb;
11467a7bc959SXin LI 
11477a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->postDone_lock);
11487a7bc959SXin LI 			postq_index = phbdmu->postq_index;
11497a7bc959SXin LI 			pinbound_srb = (struct InBound_SRB *)&phbdmu->post_qbuffer[postq_index & 0xFF];
11507a7bc959SXin LI 			pinbound_srb->addressHigh = srb->cdb_phyaddr_high;
11517a7bc959SXin LI 			pinbound_srb->addressLow = srb->cdb_phyaddr_low;
11527a7bc959SXin LI 			pinbound_srb->length = srb->arc_cdb_size >> 2;
11537a7bc959SXin LI 			arcmsr_cdb->Context = srb->cdb_phyaddr_low;
11547a7bc959SXin LI 			if (postq_index & 0x4000) {
11557a7bc959SXin LI 				index_stripped = postq_index & 0xFF;
11567a7bc959SXin LI 				index_stripped += 1;
11577a7bc959SXin LI 				index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE;
11587a7bc959SXin LI 				phbdmu->postq_index = index_stripped ? (index_stripped | 0x4000) : index_stripped;
11597a7bc959SXin LI 			} else {
11607a7bc959SXin LI 				index_stripped = postq_index;
11617a7bc959SXin LI 				index_stripped += 1;
11627a7bc959SXin LI 				index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE;
11637a7bc959SXin LI 				phbdmu->postq_index = index_stripped ? index_stripped : (index_stripped | 0x4000);
11647a7bc959SXin LI 			}
11657a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, inboundlist_write_pointer, postq_index);
11667a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->postDone_lock);
11677a7bc959SXin LI 		}
11687a7bc959SXin LI 		break;
1169a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E: {
1170a1103e04SXin LI 			u_int32_t ccb_post_stamp, arc_cdb_size;
1171a1103e04SXin LI 
1172a1103e04SXin LI 			arc_cdb_size = (srb->arc_cdb_size > 0x300) ? 0x300 : srb->arc_cdb_size;
1173a1103e04SXin LI 			ccb_post_stamp = (srb->smid | ((arc_cdb_size-1) >> 6));
1174a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_queueport_high, 0);
1175a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_queueport_low, ccb_post_stamp);
1176a1103e04SXin LI 		}
1177a1103e04SXin LI 		break;
1178fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
1179fa42a0bfSXin LI 			u_int32_t ccb_post_stamp, arc_cdb_size;
1180fa42a0bfSXin LI 
1181fa42a0bfSXin LI 			if (srb->arc_cdb_size <= 0x300)
1182fa42a0bfSXin LI 				arc_cdb_size = (srb->arc_cdb_size - 1) >> 6 | 1;
1183438b5532SXin LI 			else {
1184438b5532SXin LI 				arc_cdb_size = ((srb->arc_cdb_size + 0xff) >> 8) + 2;
1185438b5532SXin LI 				if (arc_cdb_size > 0xF)
1186438b5532SXin LI 					arc_cdb_size = 0xF;
1187438b5532SXin LI 				arc_cdb_size = (arc_cdb_size << 1) | 1;
1188438b5532SXin LI 			}
1189fa42a0bfSXin LI 			ccb_post_stamp = (srb->smid | arc_cdb_size);
1190fa42a0bfSXin LI 			CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_queueport_high, 0);
1191fa42a0bfSXin LI 			CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_queueport_low, ccb_post_stamp);
1192fa42a0bfSXin LI 		}
1193fa42a0bfSXin LI 		break;
1194f1c579b1SScott Long 	}
1195f1c579b1SScott Long }
1196f1c579b1SScott Long /*
119744f05562SScott Long ************************************************************************
119844f05562SScott Long ************************************************************************
119944f05562SScott Long */
120044f05562SScott Long static struct QBUFFER *arcmsr_get_iop_rqbuffer( struct AdapterControlBlock *acb)
120144f05562SScott Long {
120244f05562SScott Long 	struct QBUFFER *qbuffer=NULL;
120344f05562SScott Long 
120444f05562SScott Long 	switch (acb->adapter_type) {
120544f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
120644f05562SScott Long 			struct HBA_MessageUnit *phbamu = (struct HBA_MessageUnit *)acb->pmu;
120744f05562SScott Long 
120844f05562SScott Long 			qbuffer = (struct QBUFFER *)&phbamu->message_rbuffer;
120944f05562SScott Long 		}
121044f05562SScott Long 		break;
121144f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
121244f05562SScott Long 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
121344f05562SScott Long 
121444f05562SScott Long 			qbuffer = (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer;
121544f05562SScott Long 		}
121644f05562SScott Long 		break;
1217d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
1218d74001adSXin LI 			struct HBC_MessageUnit *phbcmu = (struct HBC_MessageUnit *)acb->pmu;
1219d74001adSXin LI 
1220d74001adSXin LI 			qbuffer = (struct QBUFFER *)&phbcmu->message_rbuffer;
1221d74001adSXin LI 		}
1222d74001adSXin LI 		break;
12237a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
12247a7bc959SXin LI 			struct HBD_MessageUnit0 *phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
12257a7bc959SXin LI 
12267a7bc959SXin LI 			qbuffer = (struct QBUFFER *)&phbdmu->phbdmu->message_rbuffer;
12277a7bc959SXin LI 		}
12287a7bc959SXin LI 		break;
1229a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E: {
1230a1103e04SXin LI 			struct HBE_MessageUnit *phbcmu = (struct HBE_MessageUnit *)acb->pmu;
1231a1103e04SXin LI 
1232a1103e04SXin LI 			qbuffer = (struct QBUFFER *)&phbcmu->message_rbuffer;
1233a1103e04SXin LI 		}
1234a1103e04SXin LI 		break;
1235fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
1236fa42a0bfSXin LI 		qbuffer = (struct QBUFFER *)acb->message_rbuffer;
1237fa42a0bfSXin LI 		break;
123844f05562SScott Long 	}
123944f05562SScott Long 	return(qbuffer);
124044f05562SScott Long }
124144f05562SScott Long /*
124244f05562SScott Long ************************************************************************
124344f05562SScott Long ************************************************************************
124444f05562SScott Long */
124544f05562SScott Long static struct QBUFFER *arcmsr_get_iop_wqbuffer( struct AdapterControlBlock *acb)
124644f05562SScott Long {
124744f05562SScott Long 	struct QBUFFER *qbuffer = NULL;
124844f05562SScott Long 
124944f05562SScott Long 	switch (acb->adapter_type) {
125044f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
125144f05562SScott Long 			struct HBA_MessageUnit *phbamu = (struct HBA_MessageUnit *)acb->pmu;
125244f05562SScott Long 
125344f05562SScott Long 			qbuffer = (struct QBUFFER *)&phbamu->message_wbuffer;
125444f05562SScott Long 		}
125544f05562SScott Long 		break;
125644f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
125744f05562SScott Long 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
125844f05562SScott Long 
125944f05562SScott Long 			qbuffer = (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer;
126044f05562SScott Long 		}
126144f05562SScott Long 		break;
1262d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
1263d74001adSXin LI 			struct HBC_MessageUnit *phbcmu = (struct HBC_MessageUnit *)acb->pmu;
1264d74001adSXin LI 
1265d74001adSXin LI 			qbuffer = (struct QBUFFER *)&phbcmu->message_wbuffer;
1266d74001adSXin LI 		}
1267d74001adSXin LI 		break;
12687a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
12697a7bc959SXin LI 			struct HBD_MessageUnit0 *phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
12707a7bc959SXin LI 
12717a7bc959SXin LI 			qbuffer = (struct QBUFFER *)&phbdmu->phbdmu->message_wbuffer;
12727a7bc959SXin LI 		}
12737a7bc959SXin LI 		break;
1274a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E: {
1275a1103e04SXin LI 			struct HBE_MessageUnit *phbcmu = (struct HBE_MessageUnit *)acb->pmu;
1276a1103e04SXin LI 
1277a1103e04SXin LI 			qbuffer = (struct QBUFFER *)&phbcmu->message_wbuffer;
1278a1103e04SXin LI 		}
1279a1103e04SXin LI 		break;
1280fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
1281fa42a0bfSXin LI 		qbuffer = (struct QBUFFER *)acb->message_wbuffer;
1282fa42a0bfSXin LI 		break;
128344f05562SScott Long 	}
128444f05562SScott Long 	return(qbuffer);
128544f05562SScott Long }
128644f05562SScott Long /*
128744f05562SScott Long **************************************************************************
128844f05562SScott Long **************************************************************************
128944f05562SScott Long */
129044f05562SScott Long static void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
129144f05562SScott Long {
129244f05562SScott Long 	switch (acb->adapter_type) {
129344f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
129444f05562SScott Long 			/* let IOP know data has been read */
1295d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
129644f05562SScott Long 		}
129744f05562SScott Long 		break;
129844f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
1299b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
130044f05562SScott Long 			/* let IOP know data has been read */
1301b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK);
130244f05562SScott Long 		}
130344f05562SScott Long 		break;
1304d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
1305d74001adSXin LI 			/* let IOP know data has been read */
1306d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK);
1307d74001adSXin LI 		}
13087a7bc959SXin LI 		break;
13097a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
13107a7bc959SXin LI 			/* let IOP know data has been read */
13117a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_doorbell, ARCMSR_HBDMU_DRV2IOP_DATA_OUT_READ);
13127a7bc959SXin LI 		}
13137a7bc959SXin LI 		break;
1314fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
1315fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
1316a1103e04SXin LI 			/* let IOP know data has been read */
1317a1103e04SXin LI 			acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
1318a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
1319a1103e04SXin LI 		}
1320a1103e04SXin LI 		break;
132144f05562SScott Long 	}
132244f05562SScott Long }
132344f05562SScott Long /*
132444f05562SScott Long **************************************************************************
132544f05562SScott Long **************************************************************************
132644f05562SScott Long */
132744f05562SScott Long static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
132844f05562SScott Long {
132944f05562SScott Long 	switch (acb->adapter_type) {
133044f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
133144f05562SScott Long 			/*
133244f05562SScott Long 			** push inbound doorbell tell iop, driver data write ok
133344f05562SScott Long 			** and wait reply on next hwinterrupt for next Qbuffer post
133444f05562SScott Long 			*/
1335d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
133644f05562SScott Long 		}
133744f05562SScott Long 		break;
133844f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
1339b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
134044f05562SScott Long 			/*
134144f05562SScott Long 			** push inbound doorbell tell iop, driver data write ok
134244f05562SScott Long 			** and wait reply on next hwinterrupt for next Qbuffer post
134344f05562SScott Long 			*/
1344b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_WRITE_OK);
1345d74001adSXin LI 		}
1346d74001adSXin LI 		break;
1347d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
1348d74001adSXin LI 			/*
1349d74001adSXin LI 			** push inbound doorbell tell iop, driver data write ok
1350d74001adSXin LI 			** and wait reply on next hwinterrupt for next Qbuffer post
1351d74001adSXin LI 			*/
1352d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK);
135344f05562SScott Long 		}
135444f05562SScott Long 		break;
13557a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
135644f05562SScott Long 			/*
13577a7bc959SXin LI 			** push inbound doorbell tell iop, driver data write ok
13587a7bc959SXin LI 			** and wait reply on next hwinterrupt for next Qbuffer post
1359f1c579b1SScott Long 			*/
13607a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_doorbell, ARCMSR_HBDMU_DRV2IOP_DATA_IN_READY);
1361f1c579b1SScott Long 		}
13627a7bc959SXin LI 		break;
1363fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
1364fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
1365a1103e04SXin LI 			/*
1366a1103e04SXin LI 			** push inbound doorbell tell iop, driver data write ok
1367a1103e04SXin LI 			** and wait reply on next hwinterrupt for next Qbuffer post
1368a1103e04SXin LI 			*/
1369a1103e04SXin LI 			acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_WRITE_OK;
1370a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
1371a1103e04SXin LI 		}
1372a1103e04SXin LI 		break;
1373ad6d6297SScott Long 	}
1374f1c579b1SScott Long }
1375f1c579b1SScott Long /*
1376f1c579b1SScott Long ************************************************************************
1377f1c579b1SScott Long ************************************************************************
1378f1c579b1SScott Long */
137944f05562SScott Long static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
1380f1c579b1SScott Long {
1381ad6d6297SScott Long 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
138244f05562SScott Long 	CHIP_REG_WRITE32(HBA_MessageUnit,
138344f05562SScott Long 		0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
138444f05562SScott Long 	if(!arcmsr_hba_wait_msgint_ready(acb)) {
1385d74001adSXin LI 		printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
1386ad6d6297SScott Long 			, acb->pci_unit);
1387ad6d6297SScott Long 	}
1388f1c579b1SScott Long }
1389f1c579b1SScott Long /*
1390f1c579b1SScott Long ************************************************************************
1391f1c579b1SScott Long ************************************************************************
1392f1c579b1SScott Long */
139344f05562SScott Long static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
139444f05562SScott Long {
1395b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
139644f05562SScott Long 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
1397b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_STOP_BGRB);
139844f05562SScott Long 	if(!arcmsr_hbb_wait_msgint_ready(acb)) {
1399d74001adSXin LI 		printf( "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
140044f05562SScott Long 			, acb->pci_unit);
140144f05562SScott Long 	}
140244f05562SScott Long }
140344f05562SScott Long /*
140444f05562SScott Long ************************************************************************
140544f05562SScott Long ************************************************************************
140644f05562SScott Long */
1407d74001adSXin LI static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *acb)
1408d74001adSXin LI {
1409d74001adSXin LI 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
1410d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
1411d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
1412d74001adSXin LI 	if(!arcmsr_hbc_wait_msgint_ready(acb)) {
1413d74001adSXin LI 		printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", acb->pci_unit);
1414d74001adSXin LI 	}
1415d74001adSXin LI }
1416d74001adSXin LI /*
1417d74001adSXin LI ************************************************************************
1418d74001adSXin LI ************************************************************************
1419d74001adSXin LI */
14207a7bc959SXin LI static void arcmsr_stop_hbd_bgrb(struct AdapterControlBlock *acb)
14217a7bc959SXin LI {
14227a7bc959SXin LI 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
14237a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
14247a7bc959SXin LI 	if(!arcmsr_hbd_wait_msgint_ready(acb)) {
14257a7bc959SXin LI 		printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", acb->pci_unit);
14267a7bc959SXin LI 	}
14277a7bc959SXin LI }
14287a7bc959SXin LI /*
14297a7bc959SXin LI ************************************************************************
14307a7bc959SXin LI ************************************************************************
14317a7bc959SXin LI */
1432a1103e04SXin LI static void arcmsr_stop_hbe_bgrb(struct AdapterControlBlock *acb)
1433a1103e04SXin LI {
1434a1103e04SXin LI 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
1435a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_STOP_BGRB);
1436a1103e04SXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
1437a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
1438a1103e04SXin LI 	if(!arcmsr_hbe_wait_msgint_ready(acb)) {
1439a1103e04SXin LI 		printf("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", acb->pci_unit);
1440a1103e04SXin LI 	}
1441a1103e04SXin LI }
1442a1103e04SXin LI /*
1443a1103e04SXin LI ************************************************************************
1444a1103e04SXin LI ************************************************************************
1445a1103e04SXin LI */
144644f05562SScott Long static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
144744f05562SScott Long {
144844f05562SScott Long 	switch (acb->adapter_type) {
144944f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
145044f05562SScott Long 			arcmsr_stop_hba_bgrb(acb);
145144f05562SScott Long 		}
145244f05562SScott Long 		break;
145344f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
145444f05562SScott Long 			arcmsr_stop_hbb_bgrb(acb);
145544f05562SScott Long 		}
145644f05562SScott Long 		break;
1457d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
1458d74001adSXin LI 			arcmsr_stop_hbc_bgrb(acb);
1459d74001adSXin LI 		}
1460d74001adSXin LI 		break;
14617a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
14627a7bc959SXin LI 			arcmsr_stop_hbd_bgrb(acb);
14637a7bc959SXin LI 		}
14647a7bc959SXin LI 		break;
1465fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
1466fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
1467a1103e04SXin LI 			arcmsr_stop_hbe_bgrb(acb);
1468a1103e04SXin LI 		}
1469a1103e04SXin LI 		break;
147044f05562SScott Long 	}
147144f05562SScott Long }
147244f05562SScott Long /*
147344f05562SScott Long ************************************************************************
147444f05562SScott Long ************************************************************************
147544f05562SScott Long */
1476ad6d6297SScott Long static void arcmsr_poll(struct cam_sim *psim)
1477f1c579b1SScott Long {
1478579ec1a5SScott Long 	struct AdapterControlBlock *acb;
14794e32649fSXin LI 	int	mutex;
1480579ec1a5SScott Long 
1481579ec1a5SScott Long 	acb = (struct AdapterControlBlock *)cam_sim_softc(psim);
14827a7bc959SXin LI 	mutex = mtx_owned(&acb->isr_lock);
14834e32649fSXin LI 	if( mutex == 0 )
14847a7bc959SXin LI 		ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
1485579ec1a5SScott Long 	arcmsr_interrupt(acb);
14864e32649fSXin LI 	if( mutex == 0 )
14877a7bc959SXin LI 		ARCMSR_LOCK_RELEASE(&acb->isr_lock);
14887a7bc959SXin LI }
14897a7bc959SXin LI /*
14907a7bc959SXin LI **************************************************************************
14917a7bc959SXin LI **************************************************************************
14927a7bc959SXin LI */
149335689395SXin LI static u_int32_t arcmsr_Read_iop_rqbuffer_data_D(struct AdapterControlBlock *acb,
149435689395SXin LI 	struct QBUFFER *prbuffer) {
149535689395SXin LI 	u_int8_t *pQbuffer;
14964d24901aSPedro F. Giffuni 	u_int8_t *buf1 = NULL;
14974d24901aSPedro F. Giffuni 	u_int32_t *iop_data, *buf2 = NULL;
149835689395SXin LI 	u_int32_t iop_len, data_len;
149935689395SXin LI 
150035689395SXin LI 	iop_data = (u_int32_t *)prbuffer->data;
150135689395SXin LI 	iop_len = (u_int32_t)prbuffer->data_len;
150235689395SXin LI 	if ( iop_len > 0 )
150335689395SXin LI 	{
150435689395SXin LI 		buf1 = malloc(128, M_DEVBUF, M_NOWAIT | M_ZERO);
150535689395SXin LI 		buf2 = (u_int32_t *)buf1;
150635689395SXin LI 		if( buf1 == NULL)
150735689395SXin LI 			return (0);
150835689395SXin LI 		data_len = iop_len;
150935689395SXin LI 		while(data_len >= 4)
151035689395SXin LI 		{
151135689395SXin LI 			*buf2++ = *iop_data++;
151235689395SXin LI 			data_len -= 4;
151335689395SXin LI 		}
151435689395SXin LI 		if(data_len)
151535689395SXin LI 			*buf2 = *iop_data;
151635689395SXin LI 		buf2 = (u_int32_t *)buf1;
151735689395SXin LI 	}
151835689395SXin LI 	while (iop_len > 0) {
151935689395SXin LI 		pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
152035689395SXin LI 		*pQbuffer = *buf1;
152135689395SXin LI 		acb->rqbuf_lastindex++;
152235689395SXin LI 		/* if last, index number set it to 0 */
152335689395SXin LI 		acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
152435689395SXin LI 		buf1++;
152535689395SXin LI 		iop_len--;
152635689395SXin LI 	}
152735689395SXin LI 	if(buf2)
152835689395SXin LI 		free( (u_int8_t *)buf2, M_DEVBUF);
152935689395SXin LI 	/* let IOP know data has been read */
153035689395SXin LI 	arcmsr_iop_message_read(acb);
153135689395SXin LI 	return (1);
153235689395SXin LI }
153335689395SXin LI /*
153435689395SXin LI **************************************************************************
153535689395SXin LI **************************************************************************
153635689395SXin LI */
153735689395SXin LI static u_int32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb,
15387a7bc959SXin LI 	struct QBUFFER *prbuffer) {
15397a7bc959SXin LI 	u_int8_t *pQbuffer;
15407a7bc959SXin LI 	u_int8_t *iop_data;
15417a7bc959SXin LI 	u_int32_t iop_len;
15427a7bc959SXin LI 
1543fc5ef1caSXin LI 	if(acb->adapter_type >= ACB_ADAPTER_TYPE_B) {
154435689395SXin LI 		return(arcmsr_Read_iop_rqbuffer_data_D(acb, prbuffer));
154535689395SXin LI 	}
15467a7bc959SXin LI 	iop_data = (u_int8_t *)prbuffer->data;
15477a7bc959SXin LI 	iop_len = (u_int32_t)prbuffer->data_len;
15487a7bc959SXin LI 	while (iop_len > 0) {
15497a7bc959SXin LI 		pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
15507a7bc959SXin LI 		*pQbuffer = *iop_data;
15517a7bc959SXin LI 		acb->rqbuf_lastindex++;
15527a7bc959SXin LI 		/* if last, index number set it to 0 */
15537a7bc959SXin LI 		acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
15547a7bc959SXin LI 		iop_data++;
15557a7bc959SXin LI 		iop_len--;
15567a7bc959SXin LI 	}
15577a7bc959SXin LI 	/* let IOP know data has been read */
15587a7bc959SXin LI 	arcmsr_iop_message_read(acb);
155935689395SXin LI 	return (1);
1560f1c579b1SScott Long }
1561f1c579b1SScott Long /*
156244f05562SScott Long **************************************************************************
156344f05562SScott Long **************************************************************************
15645878cbecSScott Long */
156544f05562SScott Long static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
1566f1c579b1SScott Long {
156744f05562SScott Long 	struct QBUFFER *prbuffer;
15687a7bc959SXin LI 	int my_empty_len;
1569ad6d6297SScott Long 
1570f1c579b1SScott Long 	/*check this iop data if overflow my rqbuffer*/
15717a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
157244f05562SScott Long 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
15737a7bc959SXin LI 	my_empty_len = (acb->rqbuf_lastindex - acb->rqbuf_firstindex - 1) &
15747a7bc959SXin LI 		(ARCMSR_MAX_QBUFFER-1);
15757a7bc959SXin LI 	if(my_empty_len >= prbuffer->data_len) {
157635689395SXin LI 		if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
157735689395SXin LI 			acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
1578ad6d6297SScott Long 	} else {
1579ad6d6297SScott Long 		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
1580f1c579b1SScott Long 	}
15817a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
15827a7bc959SXin LI }
15837a7bc959SXin LI /*
15847a7bc959SXin LI **********************************************************************
15857a7bc959SXin LI **********************************************************************
15867a7bc959SXin LI */
158735689395SXin LI static void arcmsr_Write_data_2iop_wqbuffer_D(struct AdapterControlBlock *acb)
158835689395SXin LI {
158935689395SXin LI 	u_int8_t *pQbuffer;
159035689395SXin LI 	struct QBUFFER *pwbuffer;
15914d24901aSPedro F. Giffuni 	u_int8_t *buf1 = NULL;
15924d24901aSPedro F. Giffuni 	u_int32_t *iop_data, *buf2 = NULL;
159335689395SXin LI 	u_int32_t allxfer_len = 0, data_len;
159435689395SXin LI 
159535689395SXin LI 	if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) {
159635689395SXin LI 		buf1 = malloc(128, M_DEVBUF, M_NOWAIT | M_ZERO);
159735689395SXin LI 		buf2 = (u_int32_t *)buf1;
159835689395SXin LI 		if( buf1 == NULL)
159935689395SXin LI 			return;
160035689395SXin LI 
160135689395SXin LI 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
160235689395SXin LI 		pwbuffer = arcmsr_get_iop_wqbuffer(acb);
160335689395SXin LI 		iop_data = (u_int32_t *)pwbuffer->data;
160435689395SXin LI 		while((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
160535689395SXin LI 			&& (allxfer_len < 124)) {
160635689395SXin LI 			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
160735689395SXin LI 			*buf1 = *pQbuffer;
160835689395SXin LI 			acb->wqbuf_firstindex++;
160935689395SXin LI 			acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
161035689395SXin LI 			buf1++;
161135689395SXin LI 			allxfer_len++;
161235689395SXin LI 		}
161335689395SXin LI 		pwbuffer->data_len = allxfer_len;
161435689395SXin LI 		data_len = allxfer_len;
161535689395SXin LI 		buf1 = (u_int8_t *)buf2;
161635689395SXin LI 		while(data_len >= 4)
161735689395SXin LI 		{
161835689395SXin LI 			*iop_data++ = *buf2++;
161935689395SXin LI 			data_len -= 4;
162035689395SXin LI 		}
162135689395SXin LI 		if(data_len)
162235689395SXin LI 			*iop_data = *buf2;
162335689395SXin LI 		free( buf1, M_DEVBUF);
162435689395SXin LI 		arcmsr_iop_message_wrote(acb);
162535689395SXin LI 	}
162635689395SXin LI }
162735689395SXin LI /*
162835689395SXin LI **********************************************************************
162935689395SXin LI **********************************************************************
163035689395SXin LI */
16317a7bc959SXin LI static void arcmsr_Write_data_2iop_wqbuffer(struct AdapterControlBlock *acb)
16327a7bc959SXin LI {
16337a7bc959SXin LI 	u_int8_t *pQbuffer;
16347a7bc959SXin LI 	struct QBUFFER *pwbuffer;
16357a7bc959SXin LI 	u_int8_t *iop_data;
16367a7bc959SXin LI 	int32_t allxfer_len=0;
16377a7bc959SXin LI 
1638fc5ef1caSXin LI 	if(acb->adapter_type >= ACB_ADAPTER_TYPE_B) {
163935689395SXin LI 		arcmsr_Write_data_2iop_wqbuffer_D(acb);
164035689395SXin LI 		return;
164135689395SXin LI 	}
16427a7bc959SXin LI 	if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) {
16437a7bc959SXin LI 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
16447a7bc959SXin LI 		pwbuffer = arcmsr_get_iop_wqbuffer(acb);
16457a7bc959SXin LI 		iop_data = (u_int8_t *)pwbuffer->data;
16467a7bc959SXin LI 		while((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
16477a7bc959SXin LI 			&& (allxfer_len < 124)) {
16487a7bc959SXin LI 			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
16497a7bc959SXin LI 			*iop_data = *pQbuffer;
16507a7bc959SXin LI 			acb->wqbuf_firstindex++;
16517a7bc959SXin LI 			acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
16527a7bc959SXin LI 			iop_data++;
16537a7bc959SXin LI 			allxfer_len++;
16547a7bc959SXin LI 		}
16557a7bc959SXin LI 		pwbuffer->data_len = allxfer_len;
16567a7bc959SXin LI 		arcmsr_iop_message_wrote(acb);
16577a7bc959SXin LI 	}
1658f1c579b1SScott Long }
1659f1c579b1SScott Long /*
166044f05562SScott Long **************************************************************************
166144f05562SScott Long **************************************************************************
166244f05562SScott Long */
166344f05562SScott Long static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
166444f05562SScott Long {
16657a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
166644f05562SScott Long 	acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ;
166744f05562SScott Long 	/*
166844f05562SScott Long 	*****************************************************************
166944f05562SScott Long 	**   check if there are any mail packages from user space program
167044f05562SScott Long 	**   in my post bag, now is the time to send them into Areca's firmware
167144f05562SScott Long 	*****************************************************************
1672f1c579b1SScott Long 	*/
1673ad6d6297SScott Long 	if(acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
16747a7bc959SXin LI 		arcmsr_Write_data_2iop_wqbuffer(acb);
1675f1c579b1SScott Long 	}
1676ad6d6297SScott Long 	if(acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
1677ad6d6297SScott Long 		acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
1678f1c579b1SScott Long 	}
16797a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
1680f1c579b1SScott Long }
16817a7bc959SXin LI /*
16827a7bc959SXin LI **************************************************************************
16837a7bc959SXin LI **************************************************************************
16847a7bc959SXin LI */
1685d74001adSXin LI static void arcmsr_rescanLun_cb(struct cam_periph *periph, union ccb *ccb)
1686d74001adSXin LI {
1687d74001adSXin LI /*
1688d74001adSXin LI 	if (ccb->ccb_h.status != CAM_REQ_CMP)
16897a7bc959SXin LI 		printf("arcmsr_rescanLun_cb: Rescan Target=%x, lun=%x,"
16907a7bc959SXin LI 			"failure status=%x\n", ccb->ccb_h.target_id,
16917a7bc959SXin LI 			ccb->ccb_h.target_lun, ccb->ccb_h.status);
1692d74001adSXin LI 	else
1693d74001adSXin LI 		printf("arcmsr_rescanLun_cb: Rescan lun successfully!\n");
1694d74001adSXin LI */
1695d74001adSXin LI 	xpt_free_path(ccb->ccb_h.path);
1696d74001adSXin LI 	xpt_free_ccb(ccb);
1697d74001adSXin LI }
1698d74001adSXin LI 
1699d74001adSXin LI static void	arcmsr_rescan_lun(struct AdapterControlBlock *acb, int target, int lun)
1700d74001adSXin LI {
1701d74001adSXin LI 	struct cam_path     *path;
1702d74001adSXin LI 	union ccb           *ccb;
1703d74001adSXin LI 
1704d74001adSXin LI 	if ((ccb = (union ccb *)xpt_alloc_ccb_nowait()) == NULL)
1705d74001adSXin LI 		return;
1706abfdbca9SXin LI 	if (xpt_create_path(&path, NULL, cam_sim_path(acb->psim), target, lun) != CAM_REQ_CMP)
1707d74001adSXin LI 	{
1708d74001adSXin LI 		xpt_free_ccb(ccb);
1709d74001adSXin LI 		return;
1710d74001adSXin LI 	}
1711d74001adSXin LI /*	printf("arcmsr_rescan_lun: Rescan Target=%x, Lun=%x\n", target, lun); */
1712d74001adSXin LI 	xpt_setup_ccb(&ccb->ccb_h, path, 5);
1713d74001adSXin LI 	ccb->ccb_h.func_code = XPT_SCAN_LUN;
1714d74001adSXin LI 	ccb->ccb_h.cbfcnp = arcmsr_rescanLun_cb;
1715d74001adSXin LI 	ccb->crcn.flags = CAM_FLAG_NONE;
1716d74001adSXin LI 	xpt_action(ccb);
1717d74001adSXin LI }
1718d74001adSXin LI 
1719d74001adSXin LI static void arcmsr_abort_dr_ccbs(struct AdapterControlBlock *acb, int target, int lun)
1720d74001adSXin LI {
1721d74001adSXin LI 	struct CommandControlBlock *srb;
1722d74001adSXin LI 	u_int32_t intmask_org;
1723d74001adSXin LI 	int i;
1724d74001adSXin LI 
1725d74001adSXin LI 	/* disable all outbound interrupts */
1726d74001adSXin LI 	intmask_org = arcmsr_disable_allintr(acb);
1727d74001adSXin LI 	for (i = 0; i < ARCMSR_MAX_FREESRB_NUM; i++)
1728d74001adSXin LI 	{
1729d74001adSXin LI 		srb = acb->psrb_pool[i];
173022f2616bSXin LI 		if (srb->srb_state == ARCMSR_SRB_START)
1731d74001adSXin LI 		{
1732d74001adSXin LI 			if((target == srb->pccb->ccb_h.target_id) && (lun == srb->pccb->ccb_h.target_lun))
1733d74001adSXin LI 			{
173422f2616bSXin LI 				srb->srb_state = ARCMSR_SRB_ABORTED;
1735d74001adSXin LI 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
1736d74001adSXin LI 				arcmsr_srb_complete(srb, 1);
173722f2616bSXin LI 				printf("arcmsr%d: abort scsi id %d lun %d srb=%p \n", acb->pci_unit, target, lun, srb);
1738d74001adSXin LI 			}
1739d74001adSXin LI 		}
1740d74001adSXin LI 	}
1741d74001adSXin LI 	/* enable outbound Post Queue, outbound doorbell Interrupt */
1742d74001adSXin LI 	arcmsr_enable_allintr(acb, intmask_org);
1743d74001adSXin LI }
1744d74001adSXin LI /*
1745d74001adSXin LI **************************************************************************
1746d74001adSXin LI **************************************************************************
1747d74001adSXin LI */
1748d74001adSXin LI static void arcmsr_dr_handle(struct AdapterControlBlock *acb) {
1749d74001adSXin LI 	u_int32_t	devicemap;
1750d74001adSXin LI 	u_int32_t	target, lun;
1751d74001adSXin LI 	u_int32_t	deviceMapCurrent[4]={0};
1752d74001adSXin LI 	u_int8_t	*pDevMap;
1753d74001adSXin LI 
1754d74001adSXin LI 	switch (acb->adapter_type) {
1755d74001adSXin LI 	case ACB_ADAPTER_TYPE_A:
1756d74001adSXin LI 		devicemap = offsetof(struct HBA_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
1757d74001adSXin LI 		for (target = 0; target < 4; target++)
1758d74001adSXin LI 		{
1759d74001adSXin LI 			deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0],  devicemap);
1760d74001adSXin LI 			devicemap += 4;
1761d74001adSXin LI 		}
1762d74001adSXin LI 		break;
1763d74001adSXin LI 
1764d74001adSXin LI 	case ACB_ADAPTER_TYPE_B:
1765d74001adSXin LI 		devicemap = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
1766d74001adSXin LI 		for (target = 0; target < 4; target++)
1767d74001adSXin LI 		{
1768d74001adSXin LI 			deviceMapCurrent[target]=bus_space_read_4(acb->btag[1], acb->bhandle[1],  devicemap);
1769d74001adSXin LI 			devicemap += 4;
1770d74001adSXin LI 		}
1771d74001adSXin LI 		break;
1772d74001adSXin LI 
1773d74001adSXin LI 	case ACB_ADAPTER_TYPE_C:
1774d74001adSXin LI 		devicemap = offsetof(struct HBC_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
1775d74001adSXin LI 		for (target = 0; target < 4; target++)
1776d74001adSXin LI 		{
1777d74001adSXin LI 			deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0],  devicemap);
1778d74001adSXin LI 			devicemap += 4;
1779d74001adSXin LI 		}
1780d74001adSXin LI 		break;
17817a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D:
17827a7bc959SXin LI 		devicemap = offsetof(struct HBD_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
17837a7bc959SXin LI 		for (target = 0; target < 4; target++)
17847a7bc959SXin LI 		{
17857a7bc959SXin LI 			deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0],  devicemap);
17867a7bc959SXin LI 			devicemap += 4;
17877a7bc959SXin LI 		}
17887a7bc959SXin LI 		break;
1789a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E:
1790a1103e04SXin LI 		devicemap = offsetof(struct HBE_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
1791a1103e04SXin LI 		for (target = 0; target < 4; target++)
1792a1103e04SXin LI 		{
1793a1103e04SXin LI 			deviceMapCurrent[target]=bus_space_read_4(acb->btag[0], acb->bhandle[0],  devicemap);
1794a1103e04SXin LI 			devicemap += 4;
1795a1103e04SXin LI 		}
1796a1103e04SXin LI 		break;
1797fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
1798fa42a0bfSXin LI 		devicemap = ARCMSR_FW_DEVMAP_OFFSET;
1799fa42a0bfSXin LI 		for (target = 0; target < 4; target++)
1800fa42a0bfSXin LI 		{
1801fa42a0bfSXin LI 			deviceMapCurrent[target] = acb->msgcode_rwbuffer[devicemap];
1802fa42a0bfSXin LI 			devicemap += 1;
1803fa42a0bfSXin LI 		}
1804fa42a0bfSXin LI 		break;
1805d74001adSXin LI 	}
1806dac36688SXin LI 
1807d74001adSXin LI 	if(acb->acb_flags & ACB_F_BUS_HANG_ON)
1808d74001adSXin LI 	{
1809d74001adSXin LI 		acb->acb_flags &= ~ACB_F_BUS_HANG_ON;
1810d74001adSXin LI 	}
1811d74001adSXin LI 	/*
1812d74001adSXin LI 	** adapter posted CONFIG message
1813d74001adSXin LI 	** copy the new map, note if there are differences with the current map
1814d74001adSXin LI 	*/
1815d74001adSXin LI 	pDevMap = (u_int8_t *)&deviceMapCurrent[0];
1816d74001adSXin LI 	for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++)
1817d74001adSXin LI 	{
1818d74001adSXin LI 		if (*pDevMap != acb->device_map[target])
1819d74001adSXin LI 		{
1820d74001adSXin LI 			u_int8_t difference, bit_check;
1821d74001adSXin LI 
1822d74001adSXin LI 			difference = *pDevMap ^ acb->device_map[target];
1823d74001adSXin LI 			for(lun=0; lun < ARCMSR_MAX_TARGETLUN; lun++)
1824d74001adSXin LI 			{
1825d74001adSXin LI 				bit_check = (1 << lun);		/*check bit from 0....31*/
1826d74001adSXin LI 				if(difference & bit_check)
1827d74001adSXin LI 				{
1828d74001adSXin LI 					if(acb->device_map[target] & bit_check)
1829d74001adSXin LI 					{/* unit departed */
1830d74001adSXin LI 						printf("arcmsr_dr_handle: Target=%x, lun=%x, GONE!!!\n",target,lun);
1831d74001adSXin LI 						arcmsr_abort_dr_ccbs(acb, target, lun);
1832d74001adSXin LI 						arcmsr_rescan_lun(acb, target, lun);
1833d74001adSXin LI 						acb->devstate[target][lun] = ARECA_RAID_GONE;
1834d74001adSXin LI 					}
1835d74001adSXin LI 					else
1836d74001adSXin LI 					{/* unit arrived */
183722f2616bSXin LI 						printf("arcmsr_dr_handle: Target=%x, lun=%x, Plug-IN!!!\n",target,lun);
1838d74001adSXin LI 						arcmsr_rescan_lun(acb, target, lun);
1839d74001adSXin LI 						acb->devstate[target][lun] = ARECA_RAID_GOOD;
1840d74001adSXin LI 					}
1841d74001adSXin LI 				}
1842d74001adSXin LI 			}
1843d74001adSXin LI /*			printf("arcmsr_dr_handle: acb->device_map[%x]=0x%x, deviceMapCurrent[%x]=%x\n",target,acb->device_map[target],target,*pDevMap); */
1844d74001adSXin LI 			acb->device_map[target] = *pDevMap;
1845d74001adSXin LI 		}
1846d74001adSXin LI 		pDevMap++;
1847d74001adSXin LI 	}
1848d74001adSXin LI }
1849d74001adSXin LI /*
1850d74001adSXin LI **************************************************************************
1851d74001adSXin LI **************************************************************************
1852d74001adSXin LI */
1853d74001adSXin LI static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) {
1854d74001adSXin LI 	u_int32_t outbound_message;
1855d74001adSXin LI 
1856d74001adSXin LI 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
1857d74001adSXin LI 	outbound_message = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[0]);
1858d74001adSXin LI 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
1859d74001adSXin LI 		arcmsr_dr_handle( acb );
1860d74001adSXin LI }
1861d74001adSXin LI /*
1862d74001adSXin LI **************************************************************************
1863d74001adSXin LI **************************************************************************
1864d74001adSXin LI */
1865d74001adSXin LI static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) {
1866d74001adSXin LI 	u_int32_t outbound_message;
1867b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
1868d74001adSXin LI 
1869d74001adSXin LI 	/* clear interrupts */
1870b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
1871d74001adSXin LI 	outbound_message = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[0]);
1872d74001adSXin LI 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
1873d74001adSXin LI 		arcmsr_dr_handle( acb );
1874d74001adSXin LI }
1875d74001adSXin LI /*
1876d74001adSXin LI **************************************************************************
1877d74001adSXin LI **************************************************************************
1878d74001adSXin LI */
1879d74001adSXin LI static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) {
1880d74001adSXin LI 	u_int32_t outbound_message;
1881d74001adSXin LI 
1882d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR);
1883d74001adSXin LI 	outbound_message = CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[0]);
1884d74001adSXin LI 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
1885d74001adSXin LI 		arcmsr_dr_handle( acb );
1886d74001adSXin LI }
188744f05562SScott Long /*
188844f05562SScott Long **************************************************************************
188944f05562SScott Long **************************************************************************
189044f05562SScott Long */
18917a7bc959SXin LI static void arcmsr_hbd_message_isr(struct AdapterControlBlock *acb) {
18927a7bc959SXin LI 	u_int32_t outbound_message;
18937a7bc959SXin LI 
18947a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE_CLEAR);
18957a7bc959SXin LI 	outbound_message = CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[0]);
18967a7bc959SXin LI 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
18977a7bc959SXin LI 		arcmsr_dr_handle( acb );
18987a7bc959SXin LI }
18997a7bc959SXin LI /*
19007a7bc959SXin LI **************************************************************************
19017a7bc959SXin LI **************************************************************************
19027a7bc959SXin LI */
1903a1103e04SXin LI static void arcmsr_hbe_message_isr(struct AdapterControlBlock *acb) {
1904a1103e04SXin LI 	u_int32_t outbound_message;
1905a1103e04SXin LI 
1906a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_status, 0);
19075842073aSXin LI 	if (acb->adapter_type == ACB_ADAPTER_TYPE_E)
1908a1103e04SXin LI 		outbound_message = CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[0]);
19095842073aSXin LI 	else
19105842073aSXin LI 		outbound_message = acb->msgcode_rwbuffer[0];
1911a1103e04SXin LI 	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
1912a1103e04SXin LI 		arcmsr_dr_handle( acb );
1913a1103e04SXin LI }
1914a1103e04SXin LI /*
1915a1103e04SXin LI **************************************************************************
1916a1103e04SXin LI **************************************************************************
1917a1103e04SXin LI */
191844f05562SScott Long static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
191944f05562SScott Long {
1920224a78aeSXin LI 	u_int32_t doorbell_status;
192144f05562SScott Long 
192244f05562SScott Long 	/*
192344f05562SScott Long 	*******************************************************************
192444f05562SScott Long 	**  Maybe here we need to check wrqbuffer_lock is lock or not
192544f05562SScott Long 	**  DOORBELL: din! don!
192644f05562SScott Long 	**  check if there are any mail need to pack from firmware
192744f05562SScott Long 	*******************************************************************
192844f05562SScott Long 	*/
1929224a78aeSXin LI 	doorbell_status = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_doorbell);
1930224a78aeSXin LI 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_doorbell, doorbell_status); /* clear doorbell interrupt */
1931224a78aeSXin LI 	if(doorbell_status & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
193244f05562SScott Long 		arcmsr_iop2drv_data_wrote_handle(acb);
1933ad6d6297SScott Long 	}
1934224a78aeSXin LI 	if(doorbell_status & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
193544f05562SScott Long 		arcmsr_iop2drv_data_read_handle(acb);
193644f05562SScott Long 	}
193744f05562SScott Long }
193844f05562SScott Long /*
193944f05562SScott Long **************************************************************************
194044f05562SScott Long **************************************************************************
194144f05562SScott Long */
1942d74001adSXin LI static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *acb)
1943d74001adSXin LI {
1944224a78aeSXin LI 	u_int32_t doorbell_status;
1945d74001adSXin LI 
1946d74001adSXin LI 	/*
1947d74001adSXin LI 	*******************************************************************
1948d74001adSXin LI 	**  Maybe here we need to check wrqbuffer_lock is lock or not
1949d74001adSXin LI 	**  DOORBELL: din! don!
1950d74001adSXin LI 	**  check if there are any mail need to pack from firmware
1951d74001adSXin LI 	*******************************************************************
1952d74001adSXin LI 	*/
1953224a78aeSXin LI 	doorbell_status = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell);
1954224a78aeSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, doorbell_status); /* clear doorbell interrupt */
1955224a78aeSXin LI 	if(doorbell_status & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
1956d74001adSXin LI 		arcmsr_iop2drv_data_wrote_handle(acb);
1957d74001adSXin LI 	}
1958224a78aeSXin LI 	if(doorbell_status & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
1959d74001adSXin LI 		arcmsr_iop2drv_data_read_handle(acb);
1960d74001adSXin LI 	}
1961224a78aeSXin LI 	if(doorbell_status & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
1962d74001adSXin LI 		arcmsr_hbc_message_isr(acb);    /* messenger of "driver to iop commands" */
1963d74001adSXin LI 	}
1964d74001adSXin LI }
1965d74001adSXin LI /*
1966d74001adSXin LI **************************************************************************
1967d74001adSXin LI **************************************************************************
1968d74001adSXin LI */
19697a7bc959SXin LI static void arcmsr_hbd_doorbell_isr(struct AdapterControlBlock *acb)
19707a7bc959SXin LI {
1971224a78aeSXin LI 	u_int32_t doorbell_status;
19727a7bc959SXin LI 
19737a7bc959SXin LI 	/*
19747a7bc959SXin LI 	*******************************************************************
19757a7bc959SXin LI 	**  Maybe here we need to check wrqbuffer_lock is lock or not
19767a7bc959SXin LI 	**  DOORBELL: din! don!
19777a7bc959SXin LI 	**  check if there are any mail need to pack from firmware
19787a7bc959SXin LI 	*******************************************************************
19797a7bc959SXin LI 	*/
1980224a78aeSXin LI 	doorbell_status = CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBDMU_F0_DOORBELL_CAUSE;
1981224a78aeSXin LI 	if(doorbell_status)
1982224a78aeSXin LI 		CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, doorbell_status); /* clear doorbell interrupt */
1983224a78aeSXin LI 	while( doorbell_status & ARCMSR_HBDMU_F0_DOORBELL_CAUSE ) {
1984224a78aeSXin LI 		if(doorbell_status & ARCMSR_HBDMU_IOP2DRV_DATA_WRITE_OK) {
19857a7bc959SXin LI 			arcmsr_iop2drv_data_wrote_handle(acb);
19867a7bc959SXin LI 		}
1987224a78aeSXin LI 		if(doorbell_status & ARCMSR_HBDMU_IOP2DRV_DATA_READ_OK) {
19887a7bc959SXin LI 			arcmsr_iop2drv_data_read_handle(acb);
19897a7bc959SXin LI 		}
1990224a78aeSXin LI 		if(doorbell_status & ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE) {
19917a7bc959SXin LI 			arcmsr_hbd_message_isr(acb);    /* messenger of "driver to iop commands" */
19927a7bc959SXin LI 		}
1993224a78aeSXin LI 		doorbell_status = CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBDMU_F0_DOORBELL_CAUSE;
1994224a78aeSXin LI 		if(doorbell_status)
1995224a78aeSXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, doorbell_status); /* clear doorbell interrupt */
19967a7bc959SXin LI 	}
19977a7bc959SXin LI }
19987a7bc959SXin LI /*
19997a7bc959SXin LI **************************************************************************
20007a7bc959SXin LI **************************************************************************
20017a7bc959SXin LI */
2002a1103e04SXin LI static void arcmsr_hbe_doorbell_isr(struct AdapterControlBlock *acb)
2003a1103e04SXin LI {
2004a1103e04SXin LI 	u_int32_t doorbell_status, in_doorbell;
2005a1103e04SXin LI 
2006a1103e04SXin LI 	/*
2007a1103e04SXin LI 	*******************************************************************
2008a1103e04SXin LI 	**  Maybe here we need to check wrqbuffer_lock is lock or not
2009a1103e04SXin LI 	**  DOORBELL: din! don!
2010a1103e04SXin LI 	**  check if there are any mail need to pack from firmware
2011a1103e04SXin LI 	*******************************************************************
2012a1103e04SXin LI 	*/
2013a1103e04SXin LI 	in_doorbell = CHIP_REG_READ32(HBE_MessageUnit, 0, iobound_doorbell);
2014a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_status, 0); /* clear doorbell interrupt */
2015a1103e04SXin LI 	doorbell_status = in_doorbell ^ acb->in_doorbell;
2016a1103e04SXin LI 	if(doorbell_status & ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK) {
2017a1103e04SXin LI 		arcmsr_iop2drv_data_wrote_handle(acb);
2018a1103e04SXin LI 	}
2019a1103e04SXin LI 	if(doorbell_status & ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK) {
2020a1103e04SXin LI 		arcmsr_iop2drv_data_read_handle(acb);
2021a1103e04SXin LI 	}
2022a1103e04SXin LI 	if(doorbell_status & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
2023a1103e04SXin LI 		arcmsr_hbe_message_isr(acb);    /* messenger of "driver to iop commands" */
2024a1103e04SXin LI 	}
2025a1103e04SXin LI 	acb->in_doorbell = in_doorbell;
2026a1103e04SXin LI }
2027a1103e04SXin LI /*
2028a1103e04SXin LI **************************************************************************
2029a1103e04SXin LI **************************************************************************
2030a1103e04SXin LI */
203144f05562SScott Long static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
203244f05562SScott Long {
203344f05562SScott Long 	u_int32_t flag_srb;
2034d74001adSXin LI 	u_int16_t error;
203544f05562SScott Long 
2036f1c579b1SScott Long 	/*
2037f1c579b1SScott Long 	*****************************************************************************
2038f1c579b1SScott Long 	**               areca cdb command done
2039f1c579b1SScott Long 	*****************************************************************************
2040f1c579b1SScott Long 	*/
204144f05562SScott Long 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap,
204244f05562SScott Long 		BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
204344f05562SScott Long 	while((flag_srb = CHIP_REG_READ32(HBA_MessageUnit,
204444f05562SScott Long 		0, outbound_queueport)) != 0xFFFFFFFF) {
2045f1c579b1SScott Long 		/* check if command done with no error*/
2046d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0) ? TRUE : FALSE;
2047d74001adSXin LI 		arcmsr_drain_donequeue(acb, flag_srb, error);
204844f05562SScott Long 	}	/*drain reply FIFO*/
2049f1c579b1SScott Long }
205044f05562SScott Long /*
205144f05562SScott Long **************************************************************************
205244f05562SScott Long **************************************************************************
205344f05562SScott Long */
205444f05562SScott Long static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
205544f05562SScott Long {
205644f05562SScott Long 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
205744f05562SScott Long 	u_int32_t flag_srb;
205844f05562SScott Long 	int index;
2059d74001adSXin LI 	u_int16_t error;
206044f05562SScott Long 
206144f05562SScott Long 	/*
206244f05562SScott Long 	*****************************************************************************
206344f05562SScott Long 	**               areca cdb command done
206444f05562SScott Long 	*****************************************************************************
206544f05562SScott Long 	*/
206644f05562SScott Long 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap,
206744f05562SScott Long 		BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
206844f05562SScott Long 	index = phbbmu->doneq_index;
206944f05562SScott Long 	while((flag_srb = phbbmu->done_qbuffer[index]) != 0) {
207044f05562SScott Long 		phbbmu->done_qbuffer[index] = 0;
207144f05562SScott Long 		index++;
207244f05562SScott Long 		index %= ARCMSR_MAX_HBB_POSTQUEUE;     /*if last index number set it to 0 */
207344f05562SScott Long 		phbbmu->doneq_index = index;
207444f05562SScott Long 		/* check if command done with no error*/
2075d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
2076d74001adSXin LI 		arcmsr_drain_donequeue(acb, flag_srb, error);
2077d74001adSXin LI 	}	/*drain reply FIFO*/
2078d74001adSXin LI }
2079d74001adSXin LI /*
2080d74001adSXin LI **************************************************************************
2081d74001adSXin LI **************************************************************************
2082d74001adSXin LI */
2083d74001adSXin LI static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
2084d74001adSXin LI {
2085d74001adSXin LI 	u_int32_t flag_srb,throttling = 0;
2086d74001adSXin LI 	u_int16_t error;
2087d74001adSXin LI 
2088d74001adSXin LI 	/*
2089d74001adSXin LI 	*****************************************************************************
2090d74001adSXin LI 	**               areca cdb command done
2091d74001adSXin LI 	*****************************************************************************
2092d74001adSXin LI 	*/
2093d74001adSXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2094224a78aeSXin LI 	do {
2095d74001adSXin LI 		flag_srb = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low);
2096b23a1998SXin LI 		if (flag_srb == 0xFFFFFFFF)
2097b23a1998SXin LI 			break;
2098d74001adSXin LI 		/* check if command done with no error*/
2099d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE;
2100d74001adSXin LI 		arcmsr_drain_donequeue(acb, flag_srb, error);
2101abfdbca9SXin LI 		throttling++;
2102d74001adSXin LI 		if(throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
2103d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING);
2104abfdbca9SXin LI 			throttling = 0;
2105d74001adSXin LI 		}
2106224a78aeSXin LI 	} while(CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR);
2107f1c579b1SScott Long }
210844f05562SScott Long /*
210944f05562SScott Long **********************************************************************
21107a7bc959SXin LI **
21117a7bc959SXin LI **********************************************************************
21127a7bc959SXin LI */
21137a7bc959SXin LI static uint16_t arcmsr_get_doneq_index(struct HBD_MessageUnit0 *phbdmu)
21147a7bc959SXin LI {
21157a7bc959SXin LI 	uint16_t doneq_index, index_stripped;
21167a7bc959SXin LI 
21177a7bc959SXin LI 	doneq_index = phbdmu->doneq_index;
21187a7bc959SXin LI 	if (doneq_index & 0x4000) {
21197a7bc959SXin LI 		index_stripped = doneq_index & 0xFF;
21207a7bc959SXin LI 		index_stripped += 1;
21217a7bc959SXin LI 		index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE;
21227a7bc959SXin LI 		phbdmu->doneq_index = index_stripped ?
21237a7bc959SXin LI 		    (index_stripped | 0x4000) : index_stripped;
21247a7bc959SXin LI 	} else {
21257a7bc959SXin LI 		index_stripped = doneq_index;
21267a7bc959SXin LI 		index_stripped += 1;
21277a7bc959SXin LI 		index_stripped %= ARCMSR_MAX_HBD_POSTQUEUE;
21287a7bc959SXin LI 		phbdmu->doneq_index = index_stripped ?
21297a7bc959SXin LI 		    index_stripped : (index_stripped | 0x4000);
21307a7bc959SXin LI 	}
21317a7bc959SXin LI 	return (phbdmu->doneq_index);
21327a7bc959SXin LI }
21337a7bc959SXin LI /*
21347a7bc959SXin LI **************************************************************************
21357a7bc959SXin LI **************************************************************************
21367a7bc959SXin LI */
21377a7bc959SXin LI static void arcmsr_hbd_postqueue_isr(struct AdapterControlBlock *acb)
21387a7bc959SXin LI {
21397a7bc959SXin LI 	struct HBD_MessageUnit0 *phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
21407a7bc959SXin LI 	u_int32_t outbound_write_pointer;
21417a7bc959SXin LI 	u_int32_t addressLow;
21427a7bc959SXin LI 	uint16_t doneq_index;
21437a7bc959SXin LI 	u_int16_t error;
21447a7bc959SXin LI 	/*
21457a7bc959SXin LI 	*****************************************************************************
21467a7bc959SXin LI 	**               areca cdb command done
21477a7bc959SXin LI 	*****************************************************************************
21487a7bc959SXin LI 	*/
21497a7bc959SXin LI 	if((CHIP_REG_READ32(HBD_MessageUnit, 0, outboundlist_interrupt_cause) &
21507a7bc959SXin LI 		ARCMSR_HBDMU_OUTBOUND_LIST_INTERRUPT) == 0)
21517a7bc959SXin LI 		return;
21527a7bc959SXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap,
21537a7bc959SXin LI 		BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
21547a7bc959SXin LI 	outbound_write_pointer = phbdmu->done_qbuffer[0].addressLow;
21557a7bc959SXin LI 	doneq_index = phbdmu->doneq_index;
21567a7bc959SXin LI 	while ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
21577a7bc959SXin LI 		doneq_index = arcmsr_get_doneq_index(phbdmu);
21587a7bc959SXin LI 		addressLow = phbdmu->done_qbuffer[(doneq_index & 0xFF)+1].addressLow;
21597a7bc959SXin LI 		error = (addressLow & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
21607a7bc959SXin LI 		arcmsr_drain_donequeue(acb, addressLow, error); /*Check if command done with no error */
21617a7bc959SXin LI 		CHIP_REG_WRITE32(HBD_MessageUnit, 0, outboundlist_read_pointer, doneq_index);
21627a7bc959SXin LI 		outbound_write_pointer = phbdmu->done_qbuffer[0].addressLow;
21637a7bc959SXin LI 	}
21647a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, outboundlist_interrupt_cause, ARCMSR_HBDMU_OUTBOUND_LIST_INTERRUPT_CLEAR);
21657a7bc959SXin LI 	CHIP_REG_READ32(HBD_MessageUnit, 0, outboundlist_interrupt_cause); /*Dummy ioread32 to force pci flush */
21667a7bc959SXin LI }
21677a7bc959SXin LI /*
2168a1103e04SXin LI **************************************************************************
2169a1103e04SXin LI **************************************************************************
2170a1103e04SXin LI */
2171a1103e04SXin LI static void arcmsr_hbe_postqueue_isr(struct AdapterControlBlock *acb)
2172a1103e04SXin LI {
2173a1103e04SXin LI 	u_int16_t error;
2174a1103e04SXin LI 	uint32_t doneq_index;
2175a1103e04SXin LI 	uint16_t cmdSMID;
2176a1103e04SXin LI 
2177a1103e04SXin LI 	/*
2178a1103e04SXin LI 	*****************************************************************************
2179a1103e04SXin LI 	**               areca cdb command done
2180a1103e04SXin LI 	*****************************************************************************
2181a1103e04SXin LI 	*/
2182a1103e04SXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2183a1103e04SXin LI 	doneq_index = acb->doneq_index;
2184a1103e04SXin LI 	while ((CHIP_REG_READ32(HBE_MessageUnit, 0, reply_post_producer_index) & 0xFFFF) != doneq_index) {
2185a1103e04SXin LI 		cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
2186a1103e04SXin LI 		error = (acb->pCompletionQ[doneq_index].cmdFlag & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
2187a1103e04SXin LI 		arcmsr_drain_donequeue(acb, (u_int32_t)cmdSMID, error);
2188a1103e04SXin LI 		doneq_index++;
2189a1103e04SXin LI 		if (doneq_index >= acb->completionQ_entry)
2190a1103e04SXin LI 			doneq_index = 0;
2191a1103e04SXin LI 	}
2192a1103e04SXin LI 	acb->doneq_index = doneq_index;
2193a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, reply_post_consumer_index, doneq_index);
2194a1103e04SXin LI }
2195fa42a0bfSXin LI 
2196fa42a0bfSXin LI static void arcmsr_hbf_postqueue_isr(struct AdapterControlBlock *acb)
2197fa42a0bfSXin LI {
2198fa42a0bfSXin LI 	uint16_t error;
2199fa42a0bfSXin LI 	uint32_t doneq_index;
2200fa42a0bfSXin LI 	uint16_t cmdSMID;
2201fa42a0bfSXin LI 
2202fa42a0bfSXin LI 	/*
2203fa42a0bfSXin LI 	*****************************************************************************
2204fa42a0bfSXin LI 	**               areca cdb command done
2205fa42a0bfSXin LI 	*****************************************************************************
2206fa42a0bfSXin LI 	*/
2207fa42a0bfSXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2208fa42a0bfSXin LI 	doneq_index = acb->doneq_index;
2209fa42a0bfSXin LI 	while (1) {
2210fa42a0bfSXin LI 		cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
2211fa42a0bfSXin LI 		if (cmdSMID == 0xffff)
2212fa42a0bfSXin LI 			break;
2213fa42a0bfSXin LI 		error = (acb->pCompletionQ[doneq_index].cmdFlag & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
2214fa42a0bfSXin LI 		arcmsr_drain_donequeue(acb, (u_int32_t)cmdSMID, error);
2215fa42a0bfSXin LI 		acb->pCompletionQ[doneq_index].cmdSMID = 0xffff;
2216fa42a0bfSXin LI 		doneq_index++;
2217fa42a0bfSXin LI 		if (doneq_index >= acb->completionQ_entry)
2218fa42a0bfSXin LI 			doneq_index = 0;
2219fa42a0bfSXin LI 	}
2220fa42a0bfSXin LI 	acb->doneq_index = doneq_index;
2221fa42a0bfSXin LI 	CHIP_REG_WRITE32(HBF_MessageUnit, 0, reply_post_consumer_index, doneq_index);
2222fa42a0bfSXin LI }
2223fa42a0bfSXin LI 
2224a1103e04SXin LI /*
22257a7bc959SXin LI **********************************************************************
222644f05562SScott Long **********************************************************************
222744f05562SScott Long */
222844f05562SScott Long static void arcmsr_handle_hba_isr( struct AdapterControlBlock *acb)
222944f05562SScott Long {
2230dac36688SXin LI 	u_int32_t outbound_intStatus;
223144f05562SScott Long 	/*
223244f05562SScott Long 	*********************************************
223344f05562SScott Long 	**   check outbound intstatus
223444f05562SScott Long 	*********************************************
223544f05562SScott Long 	*/
2236dac36688SXin LI 	outbound_intStatus = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable;
2237dac36688SXin LI 	if(!outbound_intStatus) {
223844f05562SScott Long 		/*it must be share irq*/
223944f05562SScott Long 		return;
2240f1c579b1SScott Long 	}
2241dac36688SXin LI 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intStatus); /*clear interrupt*/
224244f05562SScott Long 	/* MU doorbell interrupts*/
2243dac36688SXin LI 	if(outbound_intStatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
224444f05562SScott Long 		arcmsr_hba_doorbell_isr(acb);
2245f1c579b1SScott Long 	}
224644f05562SScott Long 	/* MU post queue interrupts*/
2247dac36688SXin LI 	if(outbound_intStatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
224844f05562SScott Long 		arcmsr_hba_postqueue_isr(acb);
224944f05562SScott Long 	}
2250dac36688SXin LI 	if(outbound_intStatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
2251d74001adSXin LI 		arcmsr_hba_message_isr(acb);
2252d74001adSXin LI 	}
225344f05562SScott Long }
225444f05562SScott Long /*
225544f05562SScott Long **********************************************************************
225644f05562SScott Long **********************************************************************
225744f05562SScott Long */
225844f05562SScott Long static void arcmsr_handle_hbb_isr( struct AdapterControlBlock *acb)
225944f05562SScott Long {
226044f05562SScott Long 	u_int32_t outbound_doorbell;
2261b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
226244f05562SScott Long 	/*
226344f05562SScott Long 	*********************************************
226444f05562SScott Long 	**   check outbound intstatus
226544f05562SScott Long 	*********************************************
226644f05562SScott Long 	*/
2267b23a1998SXin LI 	outbound_doorbell = READ_CHIP_REG32(0, phbbmu->iop2drv_doorbell) & acb->outbound_int_enable;
226844f05562SScott Long 	if(!outbound_doorbell) {
226944f05562SScott Long 		/*it must be share irq*/
227044f05562SScott Long 		return;
227144f05562SScott Long 	}
2272b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ~outbound_doorbell); /* clear doorbell interrupt */
2273b23a1998SXin LI 	READ_CHIP_REG32(0, phbbmu->iop2drv_doorbell);
2274b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT);
227544f05562SScott Long 	/* MU ioctl transfer doorbell interrupts*/
227644f05562SScott Long 	if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
227744f05562SScott Long 		arcmsr_iop2drv_data_wrote_handle(acb);
227844f05562SScott Long 	}
227944f05562SScott Long 	if(outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
228044f05562SScott Long 		arcmsr_iop2drv_data_read_handle(acb);
228144f05562SScott Long 	}
228244f05562SScott Long 	/* MU post queue interrupts*/
228344f05562SScott Long 	if(outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
228444f05562SScott Long 		arcmsr_hbb_postqueue_isr(acb);
228544f05562SScott Long 	}
2286d74001adSXin LI 	if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
2287d74001adSXin LI 		arcmsr_hbb_message_isr(acb);
2288d74001adSXin LI 	}
2289d74001adSXin LI }
2290d74001adSXin LI /*
2291d74001adSXin LI **********************************************************************
2292d74001adSXin LI **********************************************************************
2293d74001adSXin LI */
2294d74001adSXin LI static void arcmsr_handle_hbc_isr( struct AdapterControlBlock *acb)
2295d74001adSXin LI {
2296d74001adSXin LI 	u_int32_t host_interrupt_status;
2297d74001adSXin LI 	/*
2298d74001adSXin LI 	*********************************************
2299d74001adSXin LI 	**   check outbound intstatus
2300d74001adSXin LI 	*********************************************
2301d74001adSXin LI 	*/
2302224a78aeSXin LI 	host_interrupt_status = CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) &
2303224a78aeSXin LI 		(ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
2304224a78aeSXin LI 		ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR);
2305d74001adSXin LI 	if(!host_interrupt_status) {
2306d74001adSXin LI 		/*it must be share irq*/
2307d74001adSXin LI 		return;
2308d74001adSXin LI 	}
2309224a78aeSXin LI 	do {
2310d74001adSXin LI 		/* MU doorbell interrupts*/
2311d74001adSXin LI 		if(host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
2312d74001adSXin LI 			arcmsr_hbc_doorbell_isr(acb);
2313d74001adSXin LI 		}
2314d74001adSXin LI 		/* MU post queue interrupts*/
2315d74001adSXin LI 		if(host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
2316d74001adSXin LI 			arcmsr_hbc_postqueue_isr(acb);
2317d74001adSXin LI 		}
2318224a78aeSXin LI 		host_interrupt_status = CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status);
2319224a78aeSXin LI 	} while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
232044f05562SScott Long }
232144f05562SScott Long /*
23227a7bc959SXin LI **********************************************************************
23237a7bc959SXin LI **********************************************************************
23247a7bc959SXin LI */
23257a7bc959SXin LI static void arcmsr_handle_hbd_isr( struct AdapterControlBlock *acb)
23267a7bc959SXin LI {
23277a7bc959SXin LI 	u_int32_t host_interrupt_status;
23287a7bc959SXin LI 	u_int32_t intmask_org;
23297a7bc959SXin LI 	/*
23307a7bc959SXin LI 	*********************************************
23317a7bc959SXin LI 	**   check outbound intstatus
23327a7bc959SXin LI 	*********************************************
23337a7bc959SXin LI 	*/
23347a7bc959SXin LI 	host_interrupt_status = CHIP_REG_READ32(HBD_MessageUnit, 0, host_int_status) & acb->outbound_int_enable;
23357a7bc959SXin LI 	if(!(host_interrupt_status & ARCMSR_HBDMU_OUTBOUND_INT)) {
23367a7bc959SXin LI 		/*it must be share irq*/
23377a7bc959SXin LI 		return;
23387a7bc959SXin LI 	}
23397a7bc959SXin LI 	/* disable outbound interrupt */
23407a7bc959SXin LI 	intmask_org = CHIP_REG_READ32(HBD_MessageUnit, 0, pcief0_int_enable)	; /* disable outbound message0 int */
23417a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, pcief0_int_enable, ARCMSR_HBDMU_ALL_INT_DISABLE);
23427a7bc959SXin LI 	/* MU doorbell interrupts*/
23437a7bc959SXin LI 	if(host_interrupt_status & ARCMSR_HBDMU_OUTBOUND_DOORBELL_INT) {
23447a7bc959SXin LI 		arcmsr_hbd_doorbell_isr(acb);
23457a7bc959SXin LI 	}
23467a7bc959SXin LI 	/* MU post queue interrupts*/
23477a7bc959SXin LI 	if(host_interrupt_status & ARCMSR_HBDMU_OUTBOUND_POSTQUEUE_INT) {
23487a7bc959SXin LI 		arcmsr_hbd_postqueue_isr(acb);
23497a7bc959SXin LI 	}
23507a7bc959SXin LI 	/* enable all outbound interrupt */
23517a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, pcief0_int_enable, intmask_org | ARCMSR_HBDMU_ALL_INT_ENABLE);
23527a7bc959SXin LI //	CHIP_REG_READ32(HBD_MessageUnit, 0, pcief0_int_enable);
23537a7bc959SXin LI }
23547a7bc959SXin LI /*
2355a1103e04SXin LI **********************************************************************
2356a1103e04SXin LI **********************************************************************
2357a1103e04SXin LI */
2358a1103e04SXin LI static void arcmsr_handle_hbe_isr( struct AdapterControlBlock *acb)
2359a1103e04SXin LI {
2360a1103e04SXin LI 	u_int32_t host_interrupt_status;
2361a1103e04SXin LI 	/*
2362a1103e04SXin LI 	*********************************************
2363a1103e04SXin LI 	**   check outbound intstatus
2364a1103e04SXin LI 	*********************************************
2365a1103e04SXin LI 	*/
2366a1103e04SXin LI 	host_interrupt_status = CHIP_REG_READ32(HBE_MessageUnit, 0, host_int_status) &
2367a1103e04SXin LI 		(ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
2368a1103e04SXin LI 		ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR);
2369a1103e04SXin LI 	if(!host_interrupt_status) {
2370a1103e04SXin LI 		/*it must be share irq*/
2371a1103e04SXin LI 		return;
2372a1103e04SXin LI 	}
2373a1103e04SXin LI 	do {
2374a1103e04SXin LI 		/* MU doorbell interrupts*/
2375a1103e04SXin LI 		if(host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR) {
2376a1103e04SXin LI 			arcmsr_hbe_doorbell_isr(acb);
2377a1103e04SXin LI 		}
2378a1103e04SXin LI 		/* MU post queue interrupts*/
2379a1103e04SXin LI 		if(host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR) {
2380a1103e04SXin LI 			arcmsr_hbe_postqueue_isr(acb);
2381a1103e04SXin LI 		}
2382a1103e04SXin LI 		host_interrupt_status = CHIP_REG_READ32(HBE_MessageUnit, 0, host_int_status);
2383a1103e04SXin LI 	} while (host_interrupt_status & (ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR | ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR));
2384a1103e04SXin LI }
2385fa42a0bfSXin LI 
2386fa42a0bfSXin LI static void arcmsr_handle_hbf_isr( struct AdapterControlBlock *acb)
2387fa42a0bfSXin LI {
2388fa42a0bfSXin LI 	u_int32_t host_interrupt_status;
2389fa42a0bfSXin LI 	/*
2390fa42a0bfSXin LI 	*********************************************
2391fa42a0bfSXin LI 	**   check outbound intstatus
2392fa42a0bfSXin LI 	*********************************************
2393fa42a0bfSXin LI 	*/
2394fa42a0bfSXin LI 	host_interrupt_status = CHIP_REG_READ32(HBF_MessageUnit, 0, host_int_status) &
2395fa42a0bfSXin LI 		(ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
2396fa42a0bfSXin LI 		ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR);
2397fa42a0bfSXin LI 	if(!host_interrupt_status) {
2398fa42a0bfSXin LI 		/*it must be share irq*/
2399fa42a0bfSXin LI 		return;
2400fa42a0bfSXin LI 	}
2401fa42a0bfSXin LI 	do {
2402fa42a0bfSXin LI 		/* MU doorbell interrupts*/
2403fa42a0bfSXin LI 		if(host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR) {
2404fa42a0bfSXin LI 			arcmsr_hbe_doorbell_isr(acb);
2405fa42a0bfSXin LI 		}
2406fa42a0bfSXin LI 		/* MU post queue interrupts*/
2407fa42a0bfSXin LI 		if(host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR) {
2408fa42a0bfSXin LI 			arcmsr_hbf_postqueue_isr(acb);
2409fa42a0bfSXin LI 		}
2410fa42a0bfSXin LI 		host_interrupt_status = CHIP_REG_READ32(HBF_MessageUnit, 0, host_int_status);
2411fa42a0bfSXin LI 	} while (host_interrupt_status & (ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR | ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR));
2412fa42a0bfSXin LI }
2413a1103e04SXin LI /*
241444f05562SScott Long ******************************************************************************
241544f05562SScott Long ******************************************************************************
241644f05562SScott Long */
241744f05562SScott Long static void arcmsr_interrupt(struct AdapterControlBlock *acb)
241844f05562SScott Long {
241944f05562SScott Long 	switch (acb->adapter_type) {
242044f05562SScott Long 	case ACB_ADAPTER_TYPE_A:
242144f05562SScott Long 		arcmsr_handle_hba_isr(acb);
2422f1c579b1SScott Long 		break;
242344f05562SScott Long 	case ACB_ADAPTER_TYPE_B:
242444f05562SScott Long 		arcmsr_handle_hbb_isr(acb);
2425f1c579b1SScott Long 		break;
2426d74001adSXin LI 	case ACB_ADAPTER_TYPE_C:
2427d74001adSXin LI 		arcmsr_handle_hbc_isr(acb);
2428d74001adSXin LI 		break;
24297a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D:
24307a7bc959SXin LI 		arcmsr_handle_hbd_isr(acb);
24317a7bc959SXin LI 		break;
2432a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E:
2433a1103e04SXin LI 		arcmsr_handle_hbe_isr(acb);
2434a1103e04SXin LI 		break;
2435fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
2436fa42a0bfSXin LI 		arcmsr_handle_hbf_isr(acb);
2437fa42a0bfSXin LI 		break;
2438f1c579b1SScott Long 	default:
243944f05562SScott Long 		printf("arcmsr%d: interrupt service,"
244010d66948SKevin Lo 		" unknown adapter type =%d\n", acb->pci_unit, acb->adapter_type);
2441f1c579b1SScott Long 		break;
2442f1c579b1SScott Long 	}
2443f1c579b1SScott Long }
2444f1c579b1SScott Long /*
2445d74001adSXin LI **********************************************************************
2446d74001adSXin LI **********************************************************************
2447d74001adSXin LI */
2448d74001adSXin LI static void arcmsr_intr_handler(void *arg)
2449d74001adSXin LI {
2450d74001adSXin LI 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)arg;
2451d74001adSXin LI 
24527a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
2453d74001adSXin LI 	arcmsr_interrupt(acb);
24547a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->isr_lock);
2455d74001adSXin LI }
2456d74001adSXin LI /*
2457d74001adSXin LI ******************************************************************************
2458d74001adSXin LI ******************************************************************************
2459d74001adSXin LI */
2460d74001adSXin LI static void	arcmsr_polling_devmap(void *arg)
2461d74001adSXin LI {
2462d74001adSXin LI 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)arg;
2463d74001adSXin LI 	switch (acb->adapter_type) {
2464d74001adSXin LI 	case ACB_ADAPTER_TYPE_A:
2465dac36688SXin LI 		CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
2466d74001adSXin LI 		break;
2467d74001adSXin LI 
2468b23a1998SXin LI 	case ACB_ADAPTER_TYPE_B: {
2469b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
2470b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG);
2471b23a1998SXin LI 		}
2472d74001adSXin LI 		break;
2473d74001adSXin LI 
2474d74001adSXin LI 	case ACB_ADAPTER_TYPE_C:
2475d74001adSXin LI 		CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
2476d74001adSXin LI 		CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
2477d74001adSXin LI 		break;
24787a7bc959SXin LI 
24797a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D:
24807a7bc959SXin LI 		CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
24817a7bc959SXin LI 		break;
2482a1103e04SXin LI 
2483a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E:
2484a1103e04SXin LI 		CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
2485a1103e04SXin LI 		acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
2486a1103e04SXin LI 		CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
2487a1103e04SXin LI 		break;
2488d74001adSXin LI 
2489fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
2490fa42a0bfSXin LI 		u_int32_t outMsg1 = CHIP_REG_READ32(HBF_MessageUnit, 0, outbound_msgaddr1);
2491fa42a0bfSXin LI 		if (!(outMsg1 & ARCMSR_HBFMU_MESSAGE_FIRMWARE_OK) ||
2492fa42a0bfSXin LI 			(outMsg1 & ARCMSR_HBFMU_MESSAGE_NO_VOLUME_CHANGE))
2493fa42a0bfSXin LI 			goto nxt6s;
2494fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
2495fa42a0bfSXin LI 		acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
2496fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
2497fa42a0bfSXin LI 		break;
2498fa42a0bfSXin LI 		}
2499fa42a0bfSXin LI 	}
2500fa42a0bfSXin LI nxt6s:
2501d74001adSXin LI 	if((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)
2502d74001adSXin LI 	{
2503d74001adSXin LI 		callout_reset(&acb->devmap_callout, 5 * hz, arcmsr_polling_devmap, acb);	/* polling per 5 seconds */
2504d74001adSXin LI 	}
2505d74001adSXin LI }
2506d74001adSXin LI 
2507d74001adSXin LI /*
2508ad6d6297SScott Long *******************************************************************************
2509ad6d6297SScott Long **
2510ad6d6297SScott Long *******************************************************************************
2511ad6d6297SScott Long */
2512ad6d6297SScott Long static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
2513ad6d6297SScott Long {
2514d74001adSXin LI 	u_int32_t intmask_org;
2515d74001adSXin LI 
2516ad6d6297SScott Long 	if(acb != NULL) {
2517ad6d6297SScott Long 		/* stop adapter background rebuild */
2518ad6d6297SScott Long 		if(acb->acb_flags & ACB_F_MSG_START_BGRB) {
2519d74001adSXin LI 			intmask_org = arcmsr_disable_allintr(acb);
2520ad6d6297SScott Long 			arcmsr_stop_adapter_bgrb(acb);
2521ad6d6297SScott Long 			arcmsr_flush_adapter_cache(acb);
2522d74001adSXin LI 			arcmsr_enable_allintr(acb, intmask_org);
2523ad6d6297SScott Long 		}
2524ad6d6297SScott Long 	}
2525ad6d6297SScott Long }
2526ad6d6297SScott Long /*
2527f1c579b1SScott Long ***********************************************************************
2528f1c579b1SScott Long **
2529f1c579b1SScott Long ************************************************************************
2530f1c579b1SScott Long */
2531fc5ef1caSXin LI static u_int32_t arcmsr_iop_ioctlcmd(struct AdapterControlBlock *acb, u_int32_t ioctl_cmd, caddr_t arg)
2532f1c579b1SScott Long {
2533ad6d6297SScott Long 	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
2534ad6d6297SScott Long 	u_int32_t retvalue = EINVAL;
2535f1c579b1SScott Long 
2536ad6d6297SScott Long 	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) arg;
2537ad6d6297SScott Long 	if(memcmp(pcmdmessagefld->cmdmessage.Signature, "ARCMSR", 6)!=0) {
2538ad6d6297SScott Long 		return retvalue;
2539f1c579b1SScott Long 	}
2540ad6d6297SScott Long 	ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2541ad6d6297SScott Long 	switch(ioctl_cmd) {
2542ad6d6297SScott Long 	case ARCMSR_MESSAGE_READ_RQBUFFER: {
2543ad6d6297SScott Long 			u_int8_t *pQbuffer;
2544ad6d6297SScott Long 			u_int8_t *ptmpQbuffer = pcmdmessagefld->messagedatabuffer;
2545ad6d6297SScott Long 			u_int32_t allxfer_len=0;
2546f1c579b1SScott Long 
254744f05562SScott Long 			while((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
254844f05562SScott Long 				&& (allxfer_len < 1031)) {
2549f1c579b1SScott Long 				/*copy READ QBUFFER to srb*/
2550ad6d6297SScott Long 				pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
25517a7bc959SXin LI 				*ptmpQbuffer = *pQbuffer;
2552ad6d6297SScott Long 				acb->rqbuf_firstindex++;
2553ad6d6297SScott Long 				acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
2554ad6d6297SScott Long 				/*if last index number set it to 0 */
2555f1c579b1SScott Long 				ptmpQbuffer++;
2556f1c579b1SScott Long 				allxfer_len++;
2557f1c579b1SScott Long 			}
2558ad6d6297SScott Long 			if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
255944f05562SScott Long 				struct QBUFFER *prbuffer;
2560f1c579b1SScott Long 
2561ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
256244f05562SScott Long 				prbuffer = arcmsr_get_iop_rqbuffer(acb);
256335689395SXin LI 				if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
256435689395SXin LI 					acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
2565f1c579b1SScott Long 			}
2566ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.Length = allxfer_len;
2567ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2568ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2569f1c579b1SScott Long 		}
2570f1c579b1SScott Long 		break;
2571ad6d6297SScott Long 	case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
2572ad6d6297SScott Long 			u_int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
2573ad6d6297SScott Long 			u_int8_t *pQbuffer;
2574ad6d6297SScott Long 			u_int8_t *ptmpuserbuffer = pcmdmessagefld->messagedatabuffer;
2575f1c579b1SScott Long 
2576ad6d6297SScott Long 			user_len = pcmdmessagefld->cmdmessage.Length;
2577f1c579b1SScott Long 			/*check if data xfer length of this request will overflow my array qbuffer */
2578ad6d6297SScott Long 			wqbuf_lastindex = acb->wqbuf_lastindex;
2579ad6d6297SScott Long 			wqbuf_firstindex = acb->wqbuf_firstindex;
2580ad6d6297SScott Long 			if(wqbuf_lastindex != wqbuf_firstindex) {
25817a7bc959SXin LI 				arcmsr_Write_data_2iop_wqbuffer(acb);
2582ad6d6297SScott Long 				pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_ERROR;
2583ad6d6297SScott Long 			} else {
25847a7bc959SXin LI 				my_empty_len = (wqbuf_firstindex - wqbuf_lastindex - 1) &
25857a7bc959SXin LI 					(ARCMSR_MAX_QBUFFER - 1);
2586ad6d6297SScott Long 				if(my_empty_len >= user_len) {
2587ad6d6297SScott Long 					while(user_len > 0) {
2588f1c579b1SScott Long 						/*copy srb data to wqbuffer*/
2589ad6d6297SScott Long 						pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
25907a7bc959SXin LI 						*pQbuffer = *ptmpuserbuffer;
2591ad6d6297SScott Long 						acb->wqbuf_lastindex++;
2592ad6d6297SScott Long 						acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
2593ad6d6297SScott Long 						/*if last index number set it to 0 */
2594f1c579b1SScott Long 						ptmpuserbuffer++;
2595f1c579b1SScott Long 						user_len--;
2596f1c579b1SScott Long 					}
2597f1c579b1SScott Long 					/*post fist Qbuffer*/
2598ad6d6297SScott Long 					if(acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
2599ad6d6297SScott Long 						acb->acb_flags &= ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
26007a7bc959SXin LI 						arcmsr_Write_data_2iop_wqbuffer(acb);
2601f1c579b1SScott Long 					}
2602ad6d6297SScott Long 					pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2603ad6d6297SScott Long 				} else {
2604ad6d6297SScott Long 					pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_ERROR;
2605f1c579b1SScott Long 				}
2606f1c579b1SScott Long 			}
2607ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2608f1c579b1SScott Long 		}
2609f1c579b1SScott Long 		break;
2610ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
2611ad6d6297SScott Long 			u_int8_t *pQbuffer = acb->rqbuffer;
2612ad6d6297SScott Long 
2613ad6d6297SScott Long 			if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2614ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
261544f05562SScott Long 				arcmsr_iop_message_read(acb);
261644f05562SScott Long 				/*signature, let IOP know data has been readed */
2617f1c579b1SScott Long 			}
2618ad6d6297SScott Long 			acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
2619ad6d6297SScott Long 			acb->rqbuf_firstindex = 0;
2620ad6d6297SScott Long 			acb->rqbuf_lastindex = 0;
2621f1c579b1SScott Long 			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
2622ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2623ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2624f1c579b1SScott Long 		}
2625f1c579b1SScott Long 		break;
2626ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER:
2627f1c579b1SScott Long 		{
2628ad6d6297SScott Long 			u_int8_t *pQbuffer = acb->wqbuffer;
2629f1c579b1SScott Long 
2630ad6d6297SScott Long 			if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2631ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
263244f05562SScott Long 				arcmsr_iop_message_read(acb);
263344f05562SScott Long 				/*signature, let IOP know data has been readed */
2634f1c579b1SScott Long 			}
263544f05562SScott Long 			acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED|ACB_F_MESSAGE_WQBUFFER_READ);
2636ad6d6297SScott Long 			acb->wqbuf_firstindex = 0;
2637ad6d6297SScott Long 			acb->wqbuf_lastindex = 0;
2638f1c579b1SScott Long 			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
2639ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2640ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2641f1c579b1SScott Long 		}
2642f1c579b1SScott Long 		break;
2643ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
2644ad6d6297SScott Long 			u_int8_t *pQbuffer;
2645f1c579b1SScott Long 
2646ad6d6297SScott Long 			if(acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2647ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
264844f05562SScott Long 				arcmsr_iop_message_read(acb);
264944f05562SScott Long 				/*signature, let IOP know data has been readed */
2650f1c579b1SScott Long 			}
2651ad6d6297SScott Long 			acb->acb_flags  |= (ACB_F_MESSAGE_WQBUFFER_CLEARED
2652ad6d6297SScott Long 					|ACB_F_MESSAGE_RQBUFFER_CLEARED
265344f05562SScott Long 					|ACB_F_MESSAGE_WQBUFFER_READ);
2654ad6d6297SScott Long 			acb->rqbuf_firstindex = 0;
2655ad6d6297SScott Long 			acb->rqbuf_lastindex = 0;
2656ad6d6297SScott Long 			acb->wqbuf_firstindex = 0;
2657ad6d6297SScott Long 			acb->wqbuf_lastindex = 0;
2658ad6d6297SScott Long 			pQbuffer = acb->rqbuffer;
2659ad6d6297SScott Long 			memset(pQbuffer, 0, sizeof(struct QBUFFER));
2660ad6d6297SScott Long 			pQbuffer = acb->wqbuffer;
2661ad6d6297SScott Long 			memset(pQbuffer, 0, sizeof(struct QBUFFER));
2662ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2663ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2664f1c579b1SScott Long 		}
2665f1c579b1SScott Long 		break;
2666ad6d6297SScott Long 	case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: {
2667ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
2668ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2669f1c579b1SScott Long 		}
2670f1c579b1SScott Long 		break;
2671ad6d6297SScott Long 	case ARCMSR_MESSAGE_SAY_HELLO: {
2672ad6d6297SScott Long 			u_int8_t *hello_string = "Hello! I am ARCMSR";
2673ad6d6297SScott Long 			u_int8_t *puserbuffer = (u_int8_t *)pcmdmessagefld->messagedatabuffer;
2674f1c579b1SScott Long 
2675ad6d6297SScott Long 			if(memcpy(puserbuffer, hello_string, (int16_t)strlen(hello_string))) {
2676ad6d6297SScott Long 				pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_ERROR;
2677ad6d6297SScott Long 				ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2678f1c579b1SScott Long 				return ENOIOCTL;
2679f1c579b1SScott Long 			}
2680ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2681ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2682ad6d6297SScott Long 		}
2683ad6d6297SScott Long 		break;
2684ad6d6297SScott Long 	case ARCMSR_MESSAGE_SAY_GOODBYE: {
2685ad6d6297SScott Long 			arcmsr_iop_parking(acb);
2686ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2687ad6d6297SScott Long 		}
2688ad6d6297SScott Long 		break;
2689ad6d6297SScott Long 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: {
2690ad6d6297SScott Long 			arcmsr_flush_adapter_cache(acb);
2691ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
2692f1c579b1SScott Long 		}
2693f1c579b1SScott Long 		break;
2694f1c579b1SScott Long 	}
2695ad6d6297SScott Long 	ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2696dac36688SXin LI 	return (retvalue);
2697f1c579b1SScott Long }
2698f1c579b1SScott Long /*
2699f1c579b1SScott Long **************************************************************************
2700f1c579b1SScott Long **************************************************************************
2701f1c579b1SScott Long */
270222f2616bSXin LI static void arcmsr_free_srb(struct CommandControlBlock *srb)
270322f2616bSXin LI {
270422f2616bSXin LI 	struct AdapterControlBlock	*acb;
270522f2616bSXin LI 
270622f2616bSXin LI 	acb = srb->acb;
27077a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->srb_lock);
270822f2616bSXin LI 	srb->srb_state = ARCMSR_SRB_DONE;
270922f2616bSXin LI 	srb->srb_flags = 0;
271022f2616bSXin LI 	acb->srbworkingQ[acb->workingsrb_doneindex] = srb;
271122f2616bSXin LI 	acb->workingsrb_doneindex++;
271222f2616bSXin LI 	acb->workingsrb_doneindex %= ARCMSR_MAX_FREESRB_NUM;
27137a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->srb_lock);
271422f2616bSXin LI }
271522f2616bSXin LI /*
271622f2616bSXin LI **************************************************************************
271722f2616bSXin LI **************************************************************************
271822f2616bSXin LI */
2719fc5ef1caSXin LI static struct CommandControlBlock *arcmsr_get_freesrb(struct AdapterControlBlock *acb)
2720f1c579b1SScott Long {
2721ad6d6297SScott Long 	struct CommandControlBlock *srb = NULL;
2722ad6d6297SScott Long 	u_int32_t workingsrb_startindex, workingsrb_doneindex;
2723f1c579b1SScott Long 
27247a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->srb_lock);
2725ad6d6297SScott Long 	workingsrb_doneindex = acb->workingsrb_doneindex;
2726ad6d6297SScott Long 	workingsrb_startindex = acb->workingsrb_startindex;
2727ad6d6297SScott Long 	srb = acb->srbworkingQ[workingsrb_startindex];
2728ad6d6297SScott Long 	workingsrb_startindex++;
2729ad6d6297SScott Long 	workingsrb_startindex %= ARCMSR_MAX_FREESRB_NUM;
2730ad6d6297SScott Long 	if(workingsrb_doneindex != workingsrb_startindex) {
2731ad6d6297SScott Long 		acb->workingsrb_startindex = workingsrb_startindex;
2732ad6d6297SScott Long 	} else {
2733ad6d6297SScott Long 		srb = NULL;
2734ad6d6297SScott Long 	}
27357a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->srb_lock);
2736ad6d6297SScott Long 	return(srb);
2737ad6d6297SScott Long }
2738ad6d6297SScott Long /*
2739ad6d6297SScott Long **************************************************************************
2740ad6d6297SScott Long **************************************************************************
2741ad6d6297SScott Long */
2742ad6d6297SScott Long static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb *pccb)
2743ad6d6297SScott Long {
2744ad6d6297SScott Long 	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
2745ad6d6297SScott Long 	int retvalue = 0, transfer_len = 0;
2746ad6d6297SScott Long 	char *buffer;
27474aa947cbSWarner Losh 	uint8_t *ptr = scsiio_cdb_ptr(&pccb->csio);
27484aa947cbSWarner Losh 	u_int32_t controlcode = (u_int32_t ) ptr[5] << 24 |
27494aa947cbSWarner Losh 				(u_int32_t ) ptr[6] << 16 |
27504aa947cbSWarner Losh 				(u_int32_t ) ptr[7] << 8  |
27514aa947cbSWarner Losh 				(u_int32_t ) ptr[8];
2752ad6d6297SScott Long 					/* 4 bytes: Areca io control code */
2753dd0b4fb6SKonstantin Belousov 	if ((pccb->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
2754ad6d6297SScott Long 		buffer = pccb->csio.data_ptr;
2755ad6d6297SScott Long 		transfer_len = pccb->csio.dxfer_len;
2756ad6d6297SScott Long 	} else {
2757ad6d6297SScott Long 		retvalue = ARCMSR_MESSAGE_FAIL;
2758ad6d6297SScott Long 		goto message_out;
2759ad6d6297SScott Long 	}
2760ad6d6297SScott Long 	if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
2761ad6d6297SScott Long 		retvalue = ARCMSR_MESSAGE_FAIL;
2762ad6d6297SScott Long 		goto message_out;
2763ad6d6297SScott Long 	}
2764ad6d6297SScott Long 	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
2765ad6d6297SScott Long 	switch(controlcode) {
2766ad6d6297SScott Long 	case ARCMSR_MESSAGE_READ_RQBUFFER: {
2767ad6d6297SScott Long 			u_int8_t *pQbuffer;
2768ad6d6297SScott Long 			u_int8_t *ptmpQbuffer = pcmdmessagefld->messagedatabuffer;
2769ad6d6297SScott Long 			int32_t allxfer_len = 0;
2770f1c579b1SScott Long 
27717a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2772ad6d6297SScott Long 			while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
2773ad6d6297SScott Long 				&& (allxfer_len < 1031)) {
2774ad6d6297SScott Long 				pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
27757a7bc959SXin LI 				*ptmpQbuffer = *pQbuffer;
2776ad6d6297SScott Long 				acb->rqbuf_firstindex++;
2777ad6d6297SScott Long 				acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
2778ad6d6297SScott Long 				ptmpQbuffer++;
2779ad6d6297SScott Long 				allxfer_len++;
2780f1c579b1SScott Long 			}
2781ad6d6297SScott Long 			if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
278244f05562SScott Long 				struct QBUFFER  *prbuffer;
2783ad6d6297SScott Long 
2784ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
278544f05562SScott Long 				prbuffer = arcmsr_get_iop_rqbuffer(acb);
278635689395SXin LI 				if(arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
278735689395SXin LI 					acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
2788ad6d6297SScott Long 			}
2789ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.Length = allxfer_len;
2790ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2791ad6d6297SScott Long 			retvalue = ARCMSR_MESSAGE_SUCCESS;
27927a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2793ad6d6297SScott Long 		}
2794ad6d6297SScott Long 		break;
2795ad6d6297SScott Long 	case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
2796ad6d6297SScott Long 			int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
2797ad6d6297SScott Long 			u_int8_t *pQbuffer;
2798ad6d6297SScott Long 			u_int8_t *ptmpuserbuffer = pcmdmessagefld->messagedatabuffer;
2799ad6d6297SScott Long 
2800ad6d6297SScott Long 			user_len = pcmdmessagefld->cmdmessage.Length;
28017a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2802ad6d6297SScott Long 			wqbuf_lastindex = acb->wqbuf_lastindex;
2803ad6d6297SScott Long 			wqbuf_firstindex = acb->wqbuf_firstindex;
2804ad6d6297SScott Long 			if (wqbuf_lastindex != wqbuf_firstindex) {
28057a7bc959SXin LI 				arcmsr_Write_data_2iop_wqbuffer(acb);
2806ad6d6297SScott Long 				/* has error report sensedata */
2807dac36688SXin LI 				if(pccb->csio.sense_len) {
2808ad6d6297SScott Long 				((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70);
2809ad6d6297SScott Long 				/* Valid,ErrorCode */
2810ad6d6297SScott Long 				((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05;
2811ad6d6297SScott Long 				/* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */
2812ad6d6297SScott Long 				((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A;
2813ad6d6297SScott Long 				/* AdditionalSenseLength */
2814ad6d6297SScott Long 				((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20;
2815ad6d6297SScott Long 				/* AdditionalSenseCode */
2816ad6d6297SScott Long 				}
2817ad6d6297SScott Long 				retvalue = ARCMSR_MESSAGE_FAIL;
2818ad6d6297SScott Long 			} else {
2819ad6d6297SScott Long 				my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
2820ad6d6297SScott Long 						&(ARCMSR_MAX_QBUFFER - 1);
2821ad6d6297SScott Long 				if (my_empty_len >= user_len) {
2822ad6d6297SScott Long 					while (user_len > 0) {
2823ad6d6297SScott Long 						pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
28247a7bc959SXin LI 						*pQbuffer = *ptmpuserbuffer;
2825ad6d6297SScott Long 						acb->wqbuf_lastindex++;
2826ad6d6297SScott Long 						acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
2827ad6d6297SScott Long 						ptmpuserbuffer++;
2828ad6d6297SScott Long 						user_len--;
2829ad6d6297SScott Long 					}
2830ad6d6297SScott Long 					if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
2831ad6d6297SScott Long 						acb->acb_flags &=
2832ad6d6297SScott Long 						    ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
28337a7bc959SXin LI 						arcmsr_Write_data_2iop_wqbuffer(acb);
2834ad6d6297SScott Long 					}
2835ad6d6297SScott Long 				} else {
2836ad6d6297SScott Long 					/* has error report sensedata */
2837dac36688SXin LI 					if(pccb->csio.sense_len) {
2838ad6d6297SScott Long 					((u_int8_t *)&pccb->csio.sense_data)[0] = (0x1 << 7 | 0x70);
2839ad6d6297SScott Long 					/* Valid,ErrorCode */
2840ad6d6297SScott Long 					((u_int8_t *)&pccb->csio.sense_data)[2] = 0x05;
2841ad6d6297SScott Long 					/* FileMark,EndOfMedia,IncorrectLength,Reserved,SenseKey */
2842ad6d6297SScott Long 					((u_int8_t *)&pccb->csio.sense_data)[7] = 0x0A;
2843ad6d6297SScott Long 					/* AdditionalSenseLength */
2844ad6d6297SScott Long 					((u_int8_t *)&pccb->csio.sense_data)[12] = 0x20;
2845ad6d6297SScott Long 					/* AdditionalSenseCode */
2846ad6d6297SScott Long 					}
2847ad6d6297SScott Long 					retvalue = ARCMSR_MESSAGE_FAIL;
2848ad6d6297SScott Long 				}
2849ad6d6297SScott Long 			}
28507a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2851ad6d6297SScott Long 		}
2852ad6d6297SScott Long 		break;
2853ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
2854ad6d6297SScott Long 			u_int8_t *pQbuffer = acb->rqbuffer;
2855ad6d6297SScott Long 
28567a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2857ad6d6297SScott Long 			if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2858ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
285944f05562SScott Long 				arcmsr_iop_message_read(acb);
2860ad6d6297SScott Long 			}
2861ad6d6297SScott Long 			acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
2862ad6d6297SScott Long 			acb->rqbuf_firstindex = 0;
2863ad6d6297SScott Long 			acb->rqbuf_lastindex = 0;
2864ad6d6297SScott Long 			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
2865ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode =
2866ad6d6297SScott Long 			    ARCMSR_MESSAGE_RETURNCODE_OK;
28677a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2868ad6d6297SScott Long 		}
2869ad6d6297SScott Long 		break;
2870ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
2871ad6d6297SScott Long 			u_int8_t *pQbuffer = acb->wqbuffer;
2872ad6d6297SScott Long 
28737a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2874ad6d6297SScott Long 			if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2875ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
287644f05562SScott Long 				arcmsr_iop_message_read(acb);
2877ad6d6297SScott Long 			}
2878ad6d6297SScott Long 			acb->acb_flags |=
2879ad6d6297SScott Long 				(ACB_F_MESSAGE_WQBUFFER_CLEARED |
288044f05562SScott Long 					ACB_F_MESSAGE_WQBUFFER_READ);
2881ad6d6297SScott Long 			acb->wqbuf_firstindex = 0;
2882ad6d6297SScott Long 			acb->wqbuf_lastindex = 0;
2883ad6d6297SScott Long 			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
2884ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode =
2885ad6d6297SScott Long 				ARCMSR_MESSAGE_RETURNCODE_OK;
28867a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2887ad6d6297SScott Long 		}
2888ad6d6297SScott Long 		break;
2889ad6d6297SScott Long 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
2890ad6d6297SScott Long 			u_int8_t *pQbuffer;
2891ad6d6297SScott Long 
28927a7bc959SXin LI 			ARCMSR_LOCK_ACQUIRE(&acb->qbuffer_lock);
2893ad6d6297SScott Long 			if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
2894ad6d6297SScott Long 				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
289544f05562SScott Long 				arcmsr_iop_message_read(acb);
2896ad6d6297SScott Long 			}
2897ad6d6297SScott Long 			acb->acb_flags |=
2898ad6d6297SScott Long 				(ACB_F_MESSAGE_WQBUFFER_CLEARED
2899ad6d6297SScott Long 				| ACB_F_MESSAGE_RQBUFFER_CLEARED
290044f05562SScott Long 				| ACB_F_MESSAGE_WQBUFFER_READ);
2901ad6d6297SScott Long 			acb->rqbuf_firstindex = 0;
2902ad6d6297SScott Long 			acb->rqbuf_lastindex = 0;
2903ad6d6297SScott Long 			acb->wqbuf_firstindex = 0;
2904ad6d6297SScott Long 			acb->wqbuf_lastindex = 0;
2905ad6d6297SScott Long 			pQbuffer = acb->rqbuffer;
2906ad6d6297SScott Long 			memset(pQbuffer, 0, sizeof (struct QBUFFER));
2907ad6d6297SScott Long 			pQbuffer = acb->wqbuffer;
2908ad6d6297SScott Long 			memset(pQbuffer, 0, sizeof (struct QBUFFER));
2909ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
29107a7bc959SXin LI 			ARCMSR_LOCK_RELEASE(&acb->qbuffer_lock);
2911ad6d6297SScott Long 		}
2912ad6d6297SScott Long 		break;
2913ad6d6297SScott Long 	case ARCMSR_MESSAGE_REQUEST_RETURNCODE_3F: {
2914ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
2915ad6d6297SScott Long 		}
2916ad6d6297SScott Long 		break;
2917ad6d6297SScott Long 	case ARCMSR_MESSAGE_SAY_HELLO: {
2918ad6d6297SScott Long 			int8_t *hello_string = "Hello! I am ARCMSR";
2919ad6d6297SScott Long 
2920ad6d6297SScott Long 			memcpy(pcmdmessagefld->messagedatabuffer, hello_string
2921ad6d6297SScott Long 				, (int16_t)strlen(hello_string));
2922ad6d6297SScott Long 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
2923ad6d6297SScott Long 		}
2924ad6d6297SScott Long 		break;
2925ad6d6297SScott Long 	case ARCMSR_MESSAGE_SAY_GOODBYE:
2926ad6d6297SScott Long 		arcmsr_iop_parking(acb);
2927ad6d6297SScott Long 		break;
2928ad6d6297SScott Long 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
2929ad6d6297SScott Long 		arcmsr_flush_adapter_cache(acb);
2930ad6d6297SScott Long 		break;
2931ad6d6297SScott Long 	default:
2932ad6d6297SScott Long 		retvalue = ARCMSR_MESSAGE_FAIL;
2933ad6d6297SScott Long 	}
2934ad6d6297SScott Long message_out:
2935dac36688SXin LI 	return (retvalue);
2936f1c579b1SScott Long }
2937f1c579b1SScott Long /*
2938f1c579b1SScott Long *********************************************************************
2939f1c579b1SScott Long *********************************************************************
2940f1c579b1SScott Long */
2941231c8b71SXin LI static void arcmsr_execute_srb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
2942f1c579b1SScott Long {
2943ad6d6297SScott Long 	struct CommandControlBlock *srb = (struct CommandControlBlock *)arg;
2944ad6d6297SScott Long 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)srb->acb;
2945f1c579b1SScott Long 	union ccb *pccb;
2946ad6d6297SScott Long 	int target, lun;
2947f1c579b1SScott Long 
2948ad6d6297SScott Long 	pccb = srb->pccb;
2949ad6d6297SScott Long 	target = pccb->ccb_h.target_id;
2950ad6d6297SScott Long 	lun = pccb->ccb_h.target_lun;
295122f2616bSXin LI 	acb->pktRequestCount++;
2952ad6d6297SScott Long 	if(error != 0) {
2953ad6d6297SScott Long 		if(error != EFBIG) {
295444f05562SScott Long 			printf("arcmsr%d: unexpected error %x"
295544f05562SScott Long 				" returned from 'bus_dmamap_load' \n"
2956ad6d6297SScott Long 				, acb->pci_unit, error);
2957f1c579b1SScott Long 		}
2958ad6d6297SScott Long 		if((pccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
295915735becSScott Long 			pccb->ccb_h.status |= CAM_REQ_TOO_BIG;
2960f1c579b1SScott Long 		}
2961ad6d6297SScott Long 		arcmsr_srb_complete(srb, 0);
2962f1c579b1SScott Long 		return;
2963f1c579b1SScott Long 	}
2964ad6d6297SScott Long 	if(nseg > ARCMSR_MAX_SG_ENTRIES) {
2965ad6d6297SScott Long 		pccb->ccb_h.status |= CAM_REQ_TOO_BIG;
2966ad6d6297SScott Long 		arcmsr_srb_complete(srb, 0);
2967ad6d6297SScott Long 		return;
2968f1c579b1SScott Long 	}
2969ad6d6297SScott Long 	if(acb->acb_flags & ACB_F_BUS_RESET) {
2970ad6d6297SScott Long 		printf("arcmsr%d: bus reset and return busy \n", acb->pci_unit);
2971ad6d6297SScott Long 		pccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
2972ad6d6297SScott Long 		arcmsr_srb_complete(srb, 0);
2973ad6d6297SScott Long 		return;
2974ad6d6297SScott Long 	}
2975ad6d6297SScott Long 	if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
297622f2616bSXin LI 		u_int8_t block_cmd, cmd;
2977ad6d6297SScott Long 
29784aa947cbSWarner Losh 		cmd = scsiio_cdb_ptr(&pccb->csio)[0];
297922f2616bSXin LI 		block_cmd = cmd & 0x0f;
2980ad6d6297SScott Long 		if(block_cmd == 0x08 || block_cmd == 0x0a) {
2981ad6d6297SScott Long 			printf("arcmsr%d:block 'read/write' command "
298222f2616bSXin LI 				"with gone raid volume Cmd=0x%2x, TargetId=%d, Lun=%d \n"
298322f2616bSXin LI 				, acb->pci_unit, cmd, target, lun);
2984ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_DEV_NOT_THERE;
2985ad6d6297SScott Long 			arcmsr_srb_complete(srb, 0);
2986ad6d6297SScott Long 			return;
2987ad6d6297SScott Long 		}
2988ad6d6297SScott Long 	}
2989ad6d6297SScott Long 	if((pccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
2990ad6d6297SScott Long 		if(nseg != 0) {
2991ad6d6297SScott Long 			bus_dmamap_unload(acb->dm_segs_dmat, srb->dm_segs_dmamap);
2992ad6d6297SScott Long 		}
2993ad6d6297SScott Long 		arcmsr_srb_complete(srb, 0);
2994f1c579b1SScott Long 		return;
2995f1c579b1SScott Long 	}
2996abfdbca9SXin LI 	if(acb->srboutstandingcount >= acb->maxOutstanding) {
29977a7bc959SXin LI 		if((acb->acb_flags & ACB_F_CAM_DEV_QFRZN) == 0)
29987a7bc959SXin LI 		{
299915735becSScott Long 			xpt_freeze_simq(acb->psim, 1);
3000dc3a205bSScott Long 			acb->acb_flags |= ACB_F_CAM_DEV_QFRZN;
30017a7bc959SXin LI 		}
30027a7bc959SXin LI 		pccb->ccb_h.status &= ~CAM_SIM_QUEUED;
30037a7bc959SXin LI 		pccb->ccb_h.status |= CAM_REQUEUE_REQ;
3004ad6d6297SScott Long 		arcmsr_srb_complete(srb, 0);
3005ad6d6297SScott Long 		return;
3006f1c579b1SScott Long 	}
300715735becSScott Long 	pccb->ccb_h.status |= CAM_SIM_QUEUED;
3008ad6d6297SScott Long 	arcmsr_build_srb(srb, dm_segs, nseg);
3009ad6d6297SScott Long 	arcmsr_post_srb(acb, srb);
301022f2616bSXin LI 	if (pccb->ccb_h.timeout != CAM_TIME_INFINITY)
301122f2616bSXin LI 	{
301222f2616bSXin LI 		arcmsr_callout_init(&srb->ccb_callout);
301385c9dd9dSSteven Hartland 		callout_reset_sbt(&srb->ccb_callout, SBT_1MS *
301485c9dd9dSSteven Hartland 		    (pccb->ccb_h.timeout + (ARCMSR_TIMEOUT_DELAY * 1000)), 0,
301585c9dd9dSSteven Hartland 		    arcmsr_srb_timeout, srb, 0);
301622f2616bSXin LI 		srb->srb_flags |= SRB_FLAG_TIMER_START;
301722f2616bSXin LI 	}
3018f1c579b1SScott Long }
3019f1c579b1SScott Long /*
3020f1c579b1SScott Long *****************************************************************************************
3021f1c579b1SScott Long *****************************************************************************************
3022f1c579b1SScott Long */
3023ad6d6297SScott Long static u_int8_t arcmsr_seek_cmd2abort(union ccb *abortccb)
3024f1c579b1SScott Long {
3025ad6d6297SScott Long 	struct CommandControlBlock *srb;
3026ad6d6297SScott Long 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) abortccb->ccb_h.arcmsr_ccbacb_ptr;
302744f05562SScott Long 	u_int32_t intmask_org;
3028ad6d6297SScott Long 	int i = 0;
3029f1c579b1SScott Long 
3030ad6d6297SScott Long 	acb->num_aborts++;
3031f1c579b1SScott Long 	/*
3032ad6d6297SScott Long 	***************************************************************************
3033f1c579b1SScott Long 	** It is the upper layer do abort command this lock just prior to calling us.
3034f1c579b1SScott Long 	** First determine if we currently own this command.
3035f1c579b1SScott Long 	** Start by searching the device queue. If not found
3036f1c579b1SScott Long 	** at all, and the system wanted us to just abort the
3037f1c579b1SScott Long 	** command return success.
3038ad6d6297SScott Long 	***************************************************************************
3039f1c579b1SScott Long 	*/
3040ad6d6297SScott Long 	if(acb->srboutstandingcount != 0) {
304122f2616bSXin LI 		/* disable all outbound interrupt */
304222f2616bSXin LI 		intmask_org = arcmsr_disable_allintr(acb);
3043ad6d6297SScott Long 		for(i=0; i < ARCMSR_MAX_FREESRB_NUM; i++) {
3044ad6d6297SScott Long 			srb = acb->psrb_pool[i];
304522f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_START) {
3046ad6d6297SScott Long 				if(srb->pccb == abortccb) {
304722f2616bSXin LI 					srb->srb_state = ARCMSR_SRB_ABORTED;
3048123055f0SNathan Whitehorn 					printf("arcmsr%d:scsi id=%d lun=%jx abort srb '%p'"
3049ad6d6297SScott Long 						"outstanding command \n"
3050ad6d6297SScott Long 						, acb->pci_unit, abortccb->ccb_h.target_id
3051123055f0SNathan Whitehorn 						, (uintmax_t)abortccb->ccb_h.target_lun, srb);
3052ad6d6297SScott Long 					arcmsr_polling_srbdone(acb, srb);
305344f05562SScott Long 					/* enable outbound Post Queue, outbound doorbell Interrupt */
305444f05562SScott Long 					arcmsr_enable_allintr(acb, intmask_org);
3055ad6d6297SScott Long 					return (TRUE);
3056f1c579b1SScott Long 				}
305722f2616bSXin LI 			}
305822f2616bSXin LI 		}
305922f2616bSXin LI 		/* enable outbound Post Queue, outbound doorbell Interrupt */
306022f2616bSXin LI 		arcmsr_enable_allintr(acb, intmask_org);
306122f2616bSXin LI 	}
306222f2616bSXin LI 	return(FALSE);
306322f2616bSXin LI }
3064f1c579b1SScott Long /*
3065f1c579b1SScott Long ****************************************************************************
3066f1c579b1SScott Long ****************************************************************************
3067f1c579b1SScott Long */
3068ad6d6297SScott Long static void arcmsr_bus_reset(struct AdapterControlBlock *acb)
3069f1c579b1SScott Long {
3070ad6d6297SScott Long 	int retry = 0;
3071f1c579b1SScott Long 
3072ad6d6297SScott Long 	acb->num_resets++;
3073ad6d6297SScott Long 	acb->acb_flags |= ACB_F_BUS_RESET;
3074ad6d6297SScott Long 	while(acb->srboutstandingcount != 0 && retry < 400) {
307544f05562SScott Long 		arcmsr_interrupt(acb);
3076ad6d6297SScott Long 		UDELAY(25000);
3077ad6d6297SScott Long 		retry++;
3078ad6d6297SScott Long 	}
3079ad6d6297SScott Long 	arcmsr_iop_reset(acb);
3080ad6d6297SScott Long 	acb->acb_flags &= ~ACB_F_BUS_RESET;
3081f1c579b1SScott Long }
3082f1c579b1SScott Long /*
3083ad6d6297SScott Long **************************************************************************
3084ad6d6297SScott Long **************************************************************************
3085ad6d6297SScott Long */
3086ad6d6297SScott Long static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
3087ad6d6297SScott Long 		union ccb *pccb)
3088ad6d6297SScott Long {
3089ad6d6297SScott Long 	if (pccb->ccb_h.target_lun) {
309061ba2ac6SJim Harris 		pccb->ccb_h.status |= CAM_DEV_NOT_THERE;
3091ad6d6297SScott Long 		xpt_done(pccb);
3092ad6d6297SScott Long 		return;
3093ad6d6297SScott Long 	}
30947a7bc959SXin LI 	pccb->ccb_h.status |= CAM_REQ_CMP;
30954aa947cbSWarner Losh 	switch (scsiio_cdb_ptr(&pccb->csio)[0]) {
30967a7bc959SXin LI 	case INQUIRY: {
30977a7bc959SXin LI 		unsigned char inqdata[36];
30987a7bc959SXin LI 		char *buffer = pccb->csio.data_ptr;
30997a7bc959SXin LI 
3100231c8b71SXin LI 		inqdata[0] = T_PROCESSOR;	/* Periph Qualifier & Periph Dev Type */
3101231c8b71SXin LI 		inqdata[1] = 0;			/* rem media bit & Dev Type Modifier */
3102231c8b71SXin LI 		inqdata[2] = 0;			/* ISO, ECMA, & ANSI versions */
3103231c8b71SXin LI 		inqdata[3] = 0;
3104231c8b71SXin LI 		inqdata[4] = 31;		/* length of additional data */
3105231c8b71SXin LI 		inqdata[5] = 0;
3106231c8b71SXin LI 		inqdata[6] = 0;
3107231c8b71SXin LI 		inqdata[7] = 0;
3108231c8b71SXin LI 		strncpy(&inqdata[8], "Areca   ", 8);	/* Vendor Identification */
3109231c8b71SXin LI 		strncpy(&inqdata[16], "RAID controller ", 16);	/* Product Identification */
3110ad6d6297SScott Long 		strncpy(&inqdata[32], "R001", 4); /* Product Revision */
3111ad6d6297SScott Long 		memcpy(buffer, inqdata, sizeof(inqdata));
3112ad6d6297SScott Long 		xpt_done(pccb);
3113ad6d6297SScott Long 	}
3114ad6d6297SScott Long 	break;
3115ad6d6297SScott Long 	case WRITE_BUFFER:
3116ad6d6297SScott Long 	case READ_BUFFER: {
3117ad6d6297SScott Long 		if (arcmsr_iop_message_xfer(acb, pccb)) {
3118ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
3119ad6d6297SScott Long 			pccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
3120ad6d6297SScott Long 		}
3121ad6d6297SScott Long 		xpt_done(pccb);
3122ad6d6297SScott Long 	}
3123ad6d6297SScott Long 	break;
3124ad6d6297SScott Long 	default:
3125ad6d6297SScott Long 		xpt_done(pccb);
3126ad6d6297SScott Long 	}
3127ad6d6297SScott Long }
3128ad6d6297SScott Long /*
3129f1c579b1SScott Long *********************************************************************
3130f1c579b1SScott Long *********************************************************************
3131f1c579b1SScott Long */
3132ad6d6297SScott Long static void arcmsr_action(struct cam_sim *psim, union ccb *pccb)
3133f1c579b1SScott Long {
3134ad6d6297SScott Long 	struct AdapterControlBlock *acb;
3135f1c579b1SScott Long 
3136ad6d6297SScott Long 	acb = (struct AdapterControlBlock *) cam_sim_softc(psim);
3137ad6d6297SScott Long 	if(acb == NULL) {
3138ad6d6297SScott Long 		pccb->ccb_h.status |= CAM_REQ_INVALID;
3139f1c579b1SScott Long 		xpt_done(pccb);
3140f1c579b1SScott Long 		return;
3141f1c579b1SScott Long 	}
3142ad6d6297SScott Long 	switch (pccb->ccb_h.func_code) {
3143ad6d6297SScott Long 	case XPT_SCSI_IO: {
3144ad6d6297SScott Long 			struct CommandControlBlock *srb;
3145ad6d6297SScott Long 			int target = pccb->ccb_h.target_id;
3146dd0b4fb6SKonstantin Belousov 			int error;
3147f1c579b1SScott Long 
31484aa947cbSWarner Losh 			if (pccb->ccb_h.flags & CAM_CDB_PHYS) {
31494aa947cbSWarner Losh 				pccb->ccb_h.status = CAM_REQ_INVALID;
31504aa947cbSWarner Losh 				xpt_done(pccb);
31514aa947cbSWarner Losh 				return;
31524aa947cbSWarner Losh 			}
31534aa947cbSWarner Losh 
3154ad6d6297SScott Long 			if(target == 16) {
3155ad6d6297SScott Long 				/* virtual device for iop message transfer */
3156ad6d6297SScott Long 				arcmsr_handle_virtual_command(acb, pccb);
3157ad6d6297SScott Long 				return;
3158ad6d6297SScott Long 			}
3159ad6d6297SScott Long 			if((srb = arcmsr_get_freesrb(acb)) == NULL) {
3160ad6d6297SScott Long 				pccb->ccb_h.status |= CAM_RESRC_UNAVAIL;
3161f1c579b1SScott Long 				xpt_done(pccb);
3162f1c579b1SScott Long 				return;
3163f1c579b1SScott Long 			}
3164ad6d6297SScott Long 			pccb->ccb_h.arcmsr_ccbsrb_ptr = srb;
3165ad6d6297SScott Long 			pccb->ccb_h.arcmsr_ccbacb_ptr = acb;
3166ad6d6297SScott Long 			srb->pccb = pccb;
3167dd0b4fb6SKonstantin Belousov 			error =	bus_dmamap_load_ccb(acb->dm_segs_dmat
3168ad6d6297SScott Long 				, srb->dm_segs_dmamap
3169dd0b4fb6SKonstantin Belousov 				, pccb
3170231c8b71SXin LI 				, arcmsr_execute_srb, srb, /*flags*/0);
3171ad6d6297SScott Long 			if(error == EINPROGRESS) {
3172ad6d6297SScott Long 				xpt_freeze_simq(acb->psim, 1);
3173f1c579b1SScott Long 				pccb->ccb_h.status |= CAM_RELEASE_SIMQ;
3174f1c579b1SScott Long 			}
3175f1c579b1SScott Long 			break;
3176f1c579b1SScott Long 		}
3177ad6d6297SScott Long 	case XPT_PATH_INQ: {
3178f1c579b1SScott Long 			struct ccb_pathinq *cpi = &pccb->cpi;
3179f1c579b1SScott Long 
3180f1c579b1SScott Long 			cpi->version_num = 1;
3181f1c579b1SScott Long 			cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
3182f1c579b1SScott Long 			cpi->target_sprt = 0;
3183f1c579b1SScott Long 			cpi->hba_misc = 0;
3184f1c579b1SScott Long 			cpi->hba_eng_cnt = 0;
3185ad6d6297SScott Long 			cpi->max_target = ARCMSR_MAX_TARGETID;        /* 0-16 */
3186ad6d6297SScott Long 			cpi->max_lun = ARCMSR_MAX_TARGETLUN;	    /* 0-7 */
3187ad6d6297SScott Long 			cpi->initiator_id = ARCMSR_SCSI_INITIATOR_ID; /* 255 */
3188f1c579b1SScott Long 			cpi->bus_id = cam_sim_bus(psim);
31894195c7deSAlan Somers 			strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
31904195c7deSAlan Somers 			strlcpy(cpi->hba_vid, "ARCMSR", HBA_IDLEN);
31914195c7deSAlan Somers 			strlcpy(cpi->dev_name, cam_sim_name(psim), DEV_IDLEN);
3192f1c579b1SScott Long 			cpi->unit_number = cam_sim_unit(psim);
3193224a78aeSXin LI 			if(acb->adapter_bus_speed == ACB_BUS_SPEED_12G)
3194224a78aeSXin LI 				cpi->base_transfer_speed = 1200000;
3195224a78aeSXin LI 			else if(acb->adapter_bus_speed == ACB_BUS_SPEED_6G)
3196dac36688SXin LI 				cpi->base_transfer_speed = 600000;
3197dac36688SXin LI 			else
3198dac36688SXin LI 				cpi->base_transfer_speed = 300000;
3199dac36688SXin LI 			if((acb->vendor_device_id == PCIDevVenIDARC1880) ||
3200a1103e04SXin LI 			   (acb->vendor_device_id == PCIDevVenIDARC1884) ||
32017a7bc959SXin LI 			   (acb->vendor_device_id == PCIDevVenIDARC1680) ||
32027a7bc959SXin LI 			   (acb->vendor_device_id == PCIDevVenIDARC1214))
3203dac36688SXin LI 			{
3204dac36688SXin LI 				cpi->transport = XPORT_SAS;
3205dac36688SXin LI 				cpi->transport_version = 0;
3206dac36688SXin LI 				cpi->protocol_version = SCSI_REV_SPC2;
3207dac36688SXin LI 			}
3208dac36688SXin LI 			else
3209dac36688SXin LI 			{
3210fa9ed865SMatt Jacob 				cpi->transport = XPORT_SPI;
3211fa9ed865SMatt Jacob 				cpi->transport_version = 2;
3212fa9ed865SMatt Jacob 				cpi->protocol_version = SCSI_REV_2;
3213dac36688SXin LI 			}
3214dac36688SXin LI 			cpi->protocol = PROTO_SCSI;
3215ad6d6297SScott Long 			cpi->ccb_h.status |= CAM_REQ_CMP;
3216f1c579b1SScott Long 			xpt_done(pccb);
3217f1c579b1SScott Long 			break;
3218f1c579b1SScott Long 		}
3219ad6d6297SScott Long 	case XPT_ABORT: {
3220f1c579b1SScott Long 			union ccb *pabort_ccb;
3221f1c579b1SScott Long 
3222f1c579b1SScott Long 			pabort_ccb = pccb->cab.abort_ccb;
3223ad6d6297SScott Long 			switch (pabort_ccb->ccb_h.func_code) {
3224f1c579b1SScott Long 			case XPT_ACCEPT_TARGET_IO:
3225f1c579b1SScott Long 			case XPT_CONT_TARGET_IO:
3226ad6d6297SScott Long 				if(arcmsr_seek_cmd2abort(pabort_ccb)==TRUE) {
3227ad6d6297SScott Long 					pabort_ccb->ccb_h.status |= CAM_REQ_ABORTED;
3228f1c579b1SScott Long 					xpt_done(pabort_ccb);
3229ad6d6297SScott Long 					pccb->ccb_h.status |= CAM_REQ_CMP;
3230ad6d6297SScott Long 				} else {
3231f1c579b1SScott Long 					xpt_print_path(pabort_ccb->ccb_h.path);
3232f1c579b1SScott Long 					printf("Not found\n");
3233ad6d6297SScott Long 					pccb->ccb_h.status |= CAM_PATH_INVALID;
3234f1c579b1SScott Long 				}
3235f1c579b1SScott Long 				break;
3236f1c579b1SScott Long 			case XPT_SCSI_IO:
3237ad6d6297SScott Long 				pccb->ccb_h.status |= CAM_UA_ABORT;
3238f1c579b1SScott Long 				break;
3239f1c579b1SScott Long 			default:
3240ad6d6297SScott Long 				pccb->ccb_h.status |= CAM_REQ_INVALID;
3241f1c579b1SScott Long 				break;
3242f1c579b1SScott Long 			}
3243f1c579b1SScott Long 			xpt_done(pccb);
3244f1c579b1SScott Long 			break;
3245f1c579b1SScott Long 		}
3246f1c579b1SScott Long 	case XPT_RESET_BUS:
3247ad6d6297SScott Long 	case XPT_RESET_DEV: {
3248ad6d6297SScott Long 			u_int32_t	i;
3249f1c579b1SScott Long 
3250ad6d6297SScott Long 			arcmsr_bus_reset(acb);
3251ad6d6297SScott Long 			for (i=0; i < 500; i++) {
3252f1c579b1SScott Long 				DELAY(1000);
3253f1c579b1SScott Long 			}
3254ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_REQ_CMP;
3255f1c579b1SScott Long 			xpt_done(pccb);
3256f1c579b1SScott Long 			break;
3257f1c579b1SScott Long 		}
3258ad6d6297SScott Long 	case XPT_TERM_IO: {
3259ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_REQ_INVALID;
3260f1c579b1SScott Long 			xpt_done(pccb);
3261f1c579b1SScott Long 			break;
3262f1c579b1SScott Long 		}
3263ad6d6297SScott Long 	case XPT_GET_TRAN_SETTINGS: {
3264ad6d6297SScott Long 			struct ccb_trans_settings *cts;
3265ad6d6297SScott Long 
3266ad6d6297SScott Long 			if(pccb->ccb_h.target_id == 16) {
3267ad6d6297SScott Long 				pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL;
3268ad6d6297SScott Long 				xpt_done(pccb);
3269ad6d6297SScott Long 				break;
3270ad6d6297SScott Long 			}
3271ad6d6297SScott Long 			cts = &pccb->cts;
327244f05562SScott Long 			{
327344f05562SScott Long 				struct ccb_trans_settings_scsi *scsi;
327444f05562SScott Long 				struct ccb_trans_settings_spi *spi;
3275dac36688SXin LI 				struct ccb_trans_settings_sas *sas;
327644f05562SScott Long 
3277ad6d6297SScott Long 				scsi = &cts->proto_specific.scsi;
3278dac36688SXin LI 				scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
3279dac36688SXin LI 				scsi->valid = CTS_SCSI_VALID_TQ;
3280fa9ed865SMatt Jacob 				cts->protocol = PROTO_SCSI;
3281dac36688SXin LI 
3282dac36688SXin LI 				if((acb->vendor_device_id == PCIDevVenIDARC1880) ||
3283a1103e04SXin LI 				   (acb->vendor_device_id == PCIDevVenIDARC1884) ||
32847a7bc959SXin LI 				   (acb->vendor_device_id == PCIDevVenIDARC1680) ||
32857a7bc959SXin LI 				   (acb->vendor_device_id == PCIDevVenIDARC1214))
3286dac36688SXin LI 				{
3287dac36688SXin LI 					cts->protocol_version = SCSI_REV_SPC2;
3288dac36688SXin LI 					cts->transport_version = 0;
3289dac36688SXin LI 					cts->transport = XPORT_SAS;
3290dac36688SXin LI 					sas = &cts->xport_specific.sas;
3291dac36688SXin LI 					sas->valid = CTS_SAS_VALID_SPEED;
3292b23a1998SXin LI 					if (acb->adapter_bus_speed == ACB_BUS_SPEED_12G)
3293224a78aeSXin LI 						sas->bitrate = 1200000;
3294b23a1998SXin LI 					else if(acb->adapter_bus_speed == ACB_BUS_SPEED_6G)
3295dac36688SXin LI 						sas->bitrate = 600000;
3296b23a1998SXin LI 					else if(acb->adapter_bus_speed == ACB_BUS_SPEED_3G)
3297dac36688SXin LI 						sas->bitrate = 300000;
3298dac36688SXin LI 				}
3299dac36688SXin LI 				else
3300dac36688SXin LI 				{
3301fa9ed865SMatt Jacob 					cts->protocol_version = SCSI_REV_2;
3302fa9ed865SMatt Jacob 					cts->transport_version = 2;
3303dac36688SXin LI 					cts->transport = XPORT_SPI;
3304dac36688SXin LI 					spi = &cts->xport_specific.spi;
3305fa9ed865SMatt Jacob 					spi->flags = CTS_SPI_FLAGS_DISC_ENB;
3306b23a1998SXin LI 					if (acb->adapter_bus_speed == ACB_BUS_SPEED_6G)
3307b23a1998SXin LI 						spi->sync_period = 1;
3308b23a1998SXin LI 					else
3309dac36688SXin LI 						spi->sync_period = 2;
3310fa9ed865SMatt Jacob 					spi->sync_offset = 32;
3311fa9ed865SMatt Jacob 					spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
33129d98ff4dSScott Long 					spi->valid = CTS_SPI_VALID_DISC
33139d98ff4dSScott Long 						| CTS_SPI_VALID_SYNC_RATE
3314fa9ed865SMatt Jacob 						| CTS_SPI_VALID_SYNC_OFFSET
3315fa9ed865SMatt Jacob 						| CTS_SPI_VALID_BUS_WIDTH;
3316dac36688SXin LI 				}
331744f05562SScott Long 			}
3318ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_REQ_CMP;
3319ad6d6297SScott Long 			xpt_done(pccb);
3320ad6d6297SScott Long 			break;
3321ad6d6297SScott Long 		}
3322ad6d6297SScott Long 	case XPT_SET_TRAN_SETTINGS: {
3323ad6d6297SScott Long 			pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL;
3324ad6d6297SScott Long 			xpt_done(pccb);
3325ad6d6297SScott Long 			break;
3326ad6d6297SScott Long 		}
3327f3b080e6SMarius Strobl 	case XPT_CALC_GEOMETRY:
3328ad6d6297SScott Long 			if(pccb->ccb_h.target_id == 16) {
3329ad6d6297SScott Long 				pccb->ccb_h.status |= CAM_FUNC_NOTAVAIL;
3330ad6d6297SScott Long 				xpt_done(pccb);
3331ad6d6297SScott Long 				break;
3332ad6d6297SScott Long 			}
3333f3b080e6SMarius Strobl 			cam_calc_geometry(&pccb->ccg, 1);
3334f1c579b1SScott Long 			xpt_done(pccb);
3335f1c579b1SScott Long 			break;
3336f1c579b1SScott Long 	default:
3337ad6d6297SScott Long 		pccb->ccb_h.status |= CAM_REQ_INVALID;
3338f1c579b1SScott Long 		xpt_done(pccb);
3339f1c579b1SScott Long 		break;
3340f1c579b1SScott Long 	}
3341f1c579b1SScott Long }
3342f1c579b1SScott Long /*
3343f1c579b1SScott Long **********************************************************************
3344f1c579b1SScott Long **********************************************************************
3345f1c579b1SScott Long */
334644f05562SScott Long static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
3347f1c579b1SScott Long {
3348ad6d6297SScott Long 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
334944f05562SScott Long 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
335044f05562SScott Long 	if(!arcmsr_hba_wait_msgint_ready(acb)) {
3351ad6d6297SScott Long 		printf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit);
3352ad6d6297SScott Long 	}
3353f1c579b1SScott Long }
3354f1c579b1SScott Long /*
3355f1c579b1SScott Long **********************************************************************
3356f1c579b1SScott Long **********************************************************************
3357f1c579b1SScott Long */
335844f05562SScott Long static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
335944f05562SScott Long {
3360b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
336144f05562SScott Long 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
3362b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_START_BGRB);
336344f05562SScott Long 	if(!arcmsr_hbb_wait_msgint_ready(acb)) {
336444f05562SScott Long 		printf( "arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit);
336544f05562SScott Long 	}
336644f05562SScott Long }
336744f05562SScott Long /*
336844f05562SScott Long **********************************************************************
336944f05562SScott Long **********************************************************************
337044f05562SScott Long */
3371d74001adSXin LI static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *acb)
3372d74001adSXin LI {
3373d74001adSXin LI 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
3374d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
3375d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
3376d74001adSXin LI 	if(!arcmsr_hbc_wait_msgint_ready(acb)) {
3377d74001adSXin LI 		printf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit);
3378d74001adSXin LI 	}
3379d74001adSXin LI }
3380d74001adSXin LI /*
3381d74001adSXin LI **********************************************************************
3382d74001adSXin LI **********************************************************************
3383d74001adSXin LI */
33847a7bc959SXin LI static void arcmsr_start_hbd_bgrb(struct AdapterControlBlock *acb)
33857a7bc959SXin LI {
33867a7bc959SXin LI 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
33877a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
33887a7bc959SXin LI 	if(!arcmsr_hbd_wait_msgint_ready(acb)) {
33897a7bc959SXin LI 		printf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit);
33907a7bc959SXin LI 	}
33917a7bc959SXin LI }
33927a7bc959SXin LI /*
33937a7bc959SXin LI **********************************************************************
33947a7bc959SXin LI **********************************************************************
33957a7bc959SXin LI */
3396a1103e04SXin LI static void arcmsr_start_hbe_bgrb(struct AdapterControlBlock *acb)
3397a1103e04SXin LI {
3398a1103e04SXin LI 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
3399a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
3400a1103e04SXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3401a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
3402a1103e04SXin LI 	if(!arcmsr_hbe_wait_msgint_ready(acb)) {
3403a1103e04SXin LI 		printf("arcmsr%d: wait 'start adapter background rebulid' timeout \n", acb->pci_unit);
3404a1103e04SXin LI 	}
3405a1103e04SXin LI }
3406a1103e04SXin LI /*
3407a1103e04SXin LI **********************************************************************
3408a1103e04SXin LI **********************************************************************
3409a1103e04SXin LI */
341044f05562SScott Long static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
341144f05562SScott Long {
341244f05562SScott Long 	switch (acb->adapter_type) {
341344f05562SScott Long 	case ACB_ADAPTER_TYPE_A:
341444f05562SScott Long 		arcmsr_start_hba_bgrb(acb);
341544f05562SScott Long 		break;
341644f05562SScott Long 	case ACB_ADAPTER_TYPE_B:
341744f05562SScott Long 		arcmsr_start_hbb_bgrb(acb);
341844f05562SScott Long 		break;
3419d74001adSXin LI 	case ACB_ADAPTER_TYPE_C:
3420d74001adSXin LI 		arcmsr_start_hbc_bgrb(acb);
3421d74001adSXin LI 		break;
34227a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D:
34237a7bc959SXin LI 		arcmsr_start_hbd_bgrb(acb);
34247a7bc959SXin LI 		break;
3425a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E:
3426fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
3427a1103e04SXin LI 		arcmsr_start_hbe_bgrb(acb);
3428a1103e04SXin LI 		break;
342944f05562SScott Long 	}
343044f05562SScott Long }
343144f05562SScott Long /*
343244f05562SScott Long **********************************************************************
343344f05562SScott Long **
343444f05562SScott Long **********************************************************************
343544f05562SScott Long */
343644f05562SScott Long static void arcmsr_polling_hba_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
3437f1c579b1SScott Long {
3438ad6d6297SScott Long 	struct CommandControlBlock *srb;
343944f05562SScott Long 	u_int32_t flag_srb, outbound_intstatus, poll_srb_done=0, poll_count=0;
3440d74001adSXin LI 	u_int16_t	error;
3441f1c579b1SScott Long 
344244f05562SScott Long polling_ccb_retry:
3443ad6d6297SScott Long 	poll_count++;
3444d74001adSXin LI 	outbound_intstatus=CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_intstatus) & acb->outbound_int_enable;
3445d74001adSXin LI 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_intstatus, outbound_intstatus);	/*clear interrupt*/
344644f05562SScott Long 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3447ad6d6297SScott Long 	while(1) {
344844f05562SScott Long 		if((flag_srb = CHIP_REG_READ32(HBA_MessageUnit,
344944f05562SScott Long 			0, outbound_queueport)) == 0xFFFFFFFF) {
3450ad6d6297SScott Long 			if(poll_srb_done) {
3451ad6d6297SScott Long 				break;/*chip FIFO no ccb for completion already*/
3452ad6d6297SScott Long 			} else {
3453ad6d6297SScott Long 				UDELAY(25000);
3454d74001adSXin LI 				if ((poll_count > 100) && (poll_srb != NULL)) {
3455ad6d6297SScott Long 					break;
3456f1c579b1SScott Long 				}
345744f05562SScott Long 				goto polling_ccb_retry;
3458f1c579b1SScott Long 			}
3459ad6d6297SScott Long 		}
3460ad6d6297SScott Long 		/* check if command done with no error*/
346144f05562SScott Long 		srb = (struct CommandControlBlock *)
346244f05562SScott Long 			(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/
3463d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
346444f05562SScott Long 		poll_srb_done = (srb == poll_srb) ? 1:0;
346522f2616bSXin LI 		if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
346622f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_ABORTED) {
3467123055f0SNathan Whitehorn 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p'"
3468ad6d6297SScott Long 					"poll command abort successfully \n"
3469ad6d6297SScott Long 					, acb->pci_unit
3470ad6d6297SScott Long 					, srb->pccb->ccb_h.target_id
3471123055f0SNathan Whitehorn 					, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
3472ad6d6297SScott Long 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
3473ad6d6297SScott Long 				arcmsr_srb_complete(srb, 1);
3474ad6d6297SScott Long 				continue;
3475ad6d6297SScott Long 			}
3476ad6d6297SScott Long 			printf("arcmsr%d: polling get an illegal srb command done srb='%p'"
3477ad6d6297SScott Long 				"srboutstandingcount=%d \n"
3478ad6d6297SScott Long 				, acb->pci_unit
3479ad6d6297SScott Long 				, srb, acb->srboutstandingcount);
3480ad6d6297SScott Long 			continue;
3481ad6d6297SScott Long 		}
3482d74001adSXin LI 		arcmsr_report_srb_state(acb, srb, error);
3483ad6d6297SScott Long 	}	/*drain reply FIFO*/
3484f1c579b1SScott Long }
3485f1c579b1SScott Long /*
3486f1c579b1SScott Long **********************************************************************
348744f05562SScott Long **
3488ad6d6297SScott Long **********************************************************************
3489ad6d6297SScott Long */
349044f05562SScott Long static void arcmsr_polling_hbb_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
349144f05562SScott Long {
349244f05562SScott Long 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
349344f05562SScott Long 	struct CommandControlBlock *srb;
349444f05562SScott Long 	u_int32_t flag_srb, poll_srb_done=0, poll_count=0;
349544f05562SScott Long 	int index;
3496d74001adSXin LI 	u_int16_t	error;
349744f05562SScott Long 
349844f05562SScott Long polling_ccb_retry:
349944f05562SScott Long 	poll_count++;
3500b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN); /* clear doorbell interrupt */
350144f05562SScott Long 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
350244f05562SScott Long 	while(1) {
350344f05562SScott Long 		index = phbbmu->doneq_index;
350444f05562SScott Long 		if((flag_srb = phbbmu->done_qbuffer[index]) == 0) {
350544f05562SScott Long 			if(poll_srb_done) {
350644f05562SScott Long 				break;/*chip FIFO no ccb for completion already*/
350744f05562SScott Long 			} else {
350844f05562SScott Long 				UDELAY(25000);
3509d74001adSXin LI 				if ((poll_count > 100) && (poll_srb != NULL)) {
351044f05562SScott Long 					break;
351144f05562SScott Long 				}
351244f05562SScott Long 				goto polling_ccb_retry;
351344f05562SScott Long 			}
351444f05562SScott Long 		}
351544f05562SScott Long 		phbbmu->done_qbuffer[index] = 0;
351644f05562SScott Long 		index++;
351744f05562SScott Long 		index %= ARCMSR_MAX_HBB_POSTQUEUE;     /*if last index number set it to 0 */
351844f05562SScott Long 		phbbmu->doneq_index = index;
351944f05562SScott Long 		/* check if command done with no error*/
352044f05562SScott Long 		srb = (struct CommandControlBlock *)
352144f05562SScott Long 			(acb->vir2phy_offset+(flag_srb << 5));/*frame must be 32 bytes aligned*/
3522d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
352344f05562SScott Long 		poll_srb_done = (srb == poll_srb) ? 1:0;
352422f2616bSXin LI 		if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
352522f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_ABORTED) {
3526123055f0SNathan Whitehorn 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p'"
352744f05562SScott Long 					"poll command abort successfully \n"
352844f05562SScott Long 					, acb->pci_unit
352944f05562SScott Long 					, srb->pccb->ccb_h.target_id
3530123055f0SNathan Whitehorn 					, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
353144f05562SScott Long 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
353244f05562SScott Long 				arcmsr_srb_complete(srb, 1);
353344f05562SScott Long 				continue;
353444f05562SScott Long 			}
353544f05562SScott Long 			printf("arcmsr%d: polling get an illegal srb command done srb='%p'"
353644f05562SScott Long 				"srboutstandingcount=%d \n"
353744f05562SScott Long 				, acb->pci_unit
353844f05562SScott Long 				, srb, acb->srboutstandingcount);
353944f05562SScott Long 			continue;
354044f05562SScott Long 		}
3541d74001adSXin LI 		arcmsr_report_srb_state(acb, srb, error);
3542d74001adSXin LI 	}	/*drain reply FIFO*/
3543d74001adSXin LI }
3544d74001adSXin LI /*
3545d74001adSXin LI **********************************************************************
3546d74001adSXin LI **
3547d74001adSXin LI **********************************************************************
3548d74001adSXin LI */
3549d74001adSXin LI static void arcmsr_polling_hbc_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
3550d74001adSXin LI {
3551d74001adSXin LI 	struct CommandControlBlock *srb;
3552d74001adSXin LI 	u_int32_t flag_srb, poll_srb_done=0, poll_count=0;
3553d74001adSXin LI 	u_int16_t	error;
3554d74001adSXin LI 
3555d74001adSXin LI polling_ccb_retry:
3556d74001adSXin LI 	poll_count++;
3557d74001adSXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3558d74001adSXin LI 	while(1) {
3559d74001adSXin LI 		if(!(CHIP_REG_READ32(HBC_MessageUnit, 0, host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)) {
3560d74001adSXin LI 			if(poll_srb_done) {
3561d74001adSXin LI 				break;/*chip FIFO no ccb for completion already*/
3562d74001adSXin LI 			} else {
3563d74001adSXin LI 				UDELAY(25000);
3564d74001adSXin LI 				if ((poll_count > 100) && (poll_srb != NULL)) {
3565d74001adSXin LI 					break;
3566d74001adSXin LI 				}
3567d74001adSXin LI 				if (acb->srboutstandingcount == 0) {
3568d74001adSXin LI 					break;
3569d74001adSXin LI 				}
3570d74001adSXin LI 				goto polling_ccb_retry;
3571d74001adSXin LI 			}
3572d74001adSXin LI 		}
3573d74001adSXin LI 		flag_srb = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_queueport_low);
3574d74001adSXin LI 		/* check if command done with no error*/
357522f2616bSXin LI 		srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFE0));/*frame must be 32 bytes aligned*/
3576d74001adSXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1)?TRUE:FALSE;
3577d74001adSXin LI 		if (poll_srb != NULL)
3578d74001adSXin LI 			poll_srb_done = (srb == poll_srb) ? 1:0;
357922f2616bSXin LI 		if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
358022f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_ABORTED) {
3581123055f0SNathan Whitehorn 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p'poll command abort successfully \n"
3582123055f0SNathan Whitehorn 						, acb->pci_unit, srb->pccb->ccb_h.target_id, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
3583d74001adSXin LI 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
3584d74001adSXin LI 				arcmsr_srb_complete(srb, 1);
3585d74001adSXin LI 				continue;
3586d74001adSXin LI 			}
3587d74001adSXin LI 			printf("arcmsr%d: polling get an illegal srb command done srb='%p'srboutstandingcount=%d \n"
3588d74001adSXin LI 					, acb->pci_unit, srb, acb->srboutstandingcount);
3589d74001adSXin LI 			continue;
3590d74001adSXin LI 		}
3591d74001adSXin LI 		arcmsr_report_srb_state(acb, srb, error);
359244f05562SScott Long 	}	/*drain reply FIFO*/
359344f05562SScott Long }
359444f05562SScott Long /*
359544f05562SScott Long **********************************************************************
35967a7bc959SXin LI **
35977a7bc959SXin LI **********************************************************************
35987a7bc959SXin LI */
35997a7bc959SXin LI static void arcmsr_polling_hbd_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
36007a7bc959SXin LI {
36017a7bc959SXin LI 	struct HBD_MessageUnit0 *phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
36027a7bc959SXin LI 	struct CommandControlBlock *srb;
36037a7bc959SXin LI 	u_int32_t flag_srb, poll_srb_done=0, poll_count=0;
36047a7bc959SXin LI 	u_int32_t outbound_write_pointer;
36057a7bc959SXin LI 	u_int16_t	error, doneq_index;
36067a7bc959SXin LI 
36077a7bc959SXin LI polling_ccb_retry:
36087a7bc959SXin LI 	poll_count++;
36097a7bc959SXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
36107a7bc959SXin LI 	while(1) {
36117a7bc959SXin LI 		outbound_write_pointer = phbdmu->done_qbuffer[0].addressLow;
36127a7bc959SXin LI 		doneq_index = phbdmu->doneq_index;
36137a7bc959SXin LI 		if ((outbound_write_pointer & 0xFF) == (doneq_index & 0xFF)) {
36147a7bc959SXin LI 			if(poll_srb_done) {
36157a7bc959SXin LI 				break;/*chip FIFO no ccb for completion already*/
36167a7bc959SXin LI 			} else {
36177a7bc959SXin LI 				UDELAY(25000);
36187a7bc959SXin LI 				if ((poll_count > 100) && (poll_srb != NULL)) {
36197a7bc959SXin LI 					break;
36207a7bc959SXin LI 				}
36217a7bc959SXin LI 				if (acb->srboutstandingcount == 0) {
36227a7bc959SXin LI 					break;
36237a7bc959SXin LI 				}
36247a7bc959SXin LI 				goto polling_ccb_retry;
36257a7bc959SXin LI 			}
36267a7bc959SXin LI 		}
36277a7bc959SXin LI 		doneq_index = arcmsr_get_doneq_index(phbdmu);
36287a7bc959SXin LI 		flag_srb = phbdmu->done_qbuffer[(doneq_index & 0xFF)+1].addressLow;
36297a7bc959SXin LI 		/* check if command done with no error*/
36307a7bc959SXin LI 		srb = (struct CommandControlBlock *)(acb->vir2phy_offset+(flag_srb & 0xFFFFFFE0));/*frame must be 32 bytes aligned*/
36317a7bc959SXin LI 		error = (flag_srb & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
36327a7bc959SXin LI 		CHIP_REG_WRITE32(HBD_MessageUnit, 0, outboundlist_read_pointer, doneq_index);
36337a7bc959SXin LI 		if (poll_srb != NULL)
36347a7bc959SXin LI 			poll_srb_done = (srb == poll_srb) ? 1:0;
36357a7bc959SXin LI 		if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
36367a7bc959SXin LI 			if(srb->srb_state == ARCMSR_SRB_ABORTED) {
3637123055f0SNathan Whitehorn 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p'poll command abort successfully \n"
3638123055f0SNathan Whitehorn 						, acb->pci_unit, srb->pccb->ccb_h.target_id, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
36397a7bc959SXin LI 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
36407a7bc959SXin LI 				arcmsr_srb_complete(srb, 1);
36417a7bc959SXin LI 				continue;
36427a7bc959SXin LI 			}
36437a7bc959SXin LI 			printf("arcmsr%d: polling get an illegal srb command done srb='%p'srboutstandingcount=%d \n"
36447a7bc959SXin LI 					, acb->pci_unit, srb, acb->srboutstandingcount);
36457a7bc959SXin LI 			continue;
36467a7bc959SXin LI 		}
36477a7bc959SXin LI 		arcmsr_report_srb_state(acb, srb, error);
36487a7bc959SXin LI 	}	/*drain reply FIFO*/
36497a7bc959SXin LI }
36507a7bc959SXin LI /*
36517a7bc959SXin LI **********************************************************************
3652a1103e04SXin LI **
3653a1103e04SXin LI **********************************************************************
3654a1103e04SXin LI */
3655a1103e04SXin LI static void arcmsr_polling_hbe_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
3656a1103e04SXin LI {
3657a1103e04SXin LI 	struct CommandControlBlock *srb;
3658a1103e04SXin LI 	u_int32_t poll_srb_done=0, poll_count=0, doneq_index;
3659a1103e04SXin LI 	u_int16_t	error, cmdSMID;
3660a1103e04SXin LI 
3661a1103e04SXin LI polling_ccb_retry:
3662a1103e04SXin LI 	poll_count++;
3663a1103e04SXin LI 	bus_dmamap_sync(acb->srb_dmat, acb->srb_dmamap, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
3664a1103e04SXin LI 	while(1) {
3665a1103e04SXin LI 		doneq_index = acb->doneq_index;
3666a1103e04SXin LI 		if((CHIP_REG_READ32(HBE_MessageUnit, 0, reply_post_producer_index) & 0xFFFF) == doneq_index) {
3667a1103e04SXin LI 			if(poll_srb_done) {
3668a1103e04SXin LI 				break;/*chip FIFO no ccb for completion already*/
3669a1103e04SXin LI 			} else {
3670a1103e04SXin LI 				UDELAY(25000);
3671a1103e04SXin LI 				if ((poll_count > 100) && (poll_srb != NULL)) {
3672a1103e04SXin LI 					break;
3673a1103e04SXin LI 				}
3674a1103e04SXin LI 				if (acb->srboutstandingcount == 0) {
3675a1103e04SXin LI 					break;
3676a1103e04SXin LI 				}
3677a1103e04SXin LI 				goto polling_ccb_retry;
3678a1103e04SXin LI 			}
3679a1103e04SXin LI 		}
3680a1103e04SXin LI 		cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
3681a1103e04SXin LI 		doneq_index++;
3682a1103e04SXin LI 		if (doneq_index >= acb->completionQ_entry)
3683a1103e04SXin LI 			doneq_index = 0;
3684a1103e04SXin LI 		acb->doneq_index = doneq_index;
3685a1103e04SXin LI 		srb = acb->psrb_pool[cmdSMID];
3686a1103e04SXin LI 		error = (acb->pCompletionQ[doneq_index].cmdFlag & ARCMSR_SRBREPLY_FLAG_ERROR_MODE1) ? TRUE : FALSE;
3687a1103e04SXin LI 		if (poll_srb != NULL)
3688a1103e04SXin LI 			poll_srb_done = (srb == poll_srb) ? 1:0;
3689a1103e04SXin LI 		if((srb->acb != acb) || (srb->srb_state != ARCMSR_SRB_START)) {
3690a1103e04SXin LI 			if(srb->srb_state == ARCMSR_SRB_ABORTED) {
3691a1103e04SXin LI 				printf("arcmsr%d: scsi id=%d lun=%jx srb='%p'poll command abort successfully \n"
3692a1103e04SXin LI 						, acb->pci_unit, srb->pccb->ccb_h.target_id, (uintmax_t)srb->pccb->ccb_h.target_lun, srb);
3693a1103e04SXin LI 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
3694a1103e04SXin LI 				arcmsr_srb_complete(srb, 1);
3695a1103e04SXin LI 				continue;
3696a1103e04SXin LI 			}
3697a1103e04SXin LI 			printf("arcmsr%d: polling get an illegal srb command done srb='%p'srboutstandingcount=%d \n"
3698a1103e04SXin LI 					, acb->pci_unit, srb, acb->srboutstandingcount);
3699a1103e04SXin LI 			continue;
3700a1103e04SXin LI 		}
3701a1103e04SXin LI 		arcmsr_report_srb_state(acb, srb, error);
3702a1103e04SXin LI 	}	/*drain reply FIFO*/
3703a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, reply_post_producer_index, doneq_index);
3704a1103e04SXin LI }
3705a1103e04SXin LI /*
3706a1103e04SXin LI **********************************************************************
370744f05562SScott Long **********************************************************************
370844f05562SScott Long */
370944f05562SScott Long static void arcmsr_polling_srbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_srb)
371044f05562SScott Long {
371144f05562SScott Long 	switch (acb->adapter_type) {
3712fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_A:
371344f05562SScott Long 		arcmsr_polling_hba_srbdone(acb, poll_srb);
371444f05562SScott Long 		break;
3715fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_B:
371644f05562SScott Long 		arcmsr_polling_hbb_srbdone(acb, poll_srb);
371744f05562SScott Long 		break;
3718fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_C:
3719d74001adSXin LI 		arcmsr_polling_hbc_srbdone(acb, poll_srb);
3720d74001adSXin LI 		break;
3721fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_D:
37227a7bc959SXin LI 		arcmsr_polling_hbd_srbdone(acb, poll_srb);
37237a7bc959SXin LI 		break;
3724fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
3725fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
3726a1103e04SXin LI 		arcmsr_polling_hbe_srbdone(acb, poll_srb);
3727a1103e04SXin LI 		break;
372844f05562SScott Long 	}
372944f05562SScott Long }
373044f05562SScott Long /*
373144f05562SScott Long **********************************************************************
373244f05562SScott Long **********************************************************************
373344f05562SScott Long */
373444f05562SScott Long static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
3735ad6d6297SScott Long {
3736ad6d6297SScott Long 	char *acb_firm_model = acb->firm_model;
3737ad6d6297SScott Long 	char *acb_firm_version = acb->firm_version;
3738d74001adSXin LI 	char *acb_device_map = acb->device_map;
3739d74001adSXin LI 	size_t iop_firm_model = offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);	/*firm_model,15,60-67*/
3740d74001adSXin LI 	size_t iop_firm_version = offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);	/*firm_version,17,68-83*/
3741d74001adSXin LI 	size_t iop_device_map = offsetof(struct HBA_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
3742ad6d6297SScott Long 	int i;
3743ad6d6297SScott Long 
374444f05562SScott Long 	CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
374544f05562SScott Long 	if(!arcmsr_hba_wait_msgint_ready(acb)) {
3746d74001adSXin LI 		printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
3747ad6d6297SScott Long 	}
3748ad6d6297SScott Long 	i = 0;
3749ad6d6297SScott Long 	while(i < 8) {
375044f05562SScott Long 		*acb_firm_model = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i);
3751ad6d6297SScott Long 		/* 8 bytes firm_model, 15, 60-67*/
3752ad6d6297SScott Long 		acb_firm_model++;
3753ad6d6297SScott Long 		i++;
3754ad6d6297SScott Long 	}
3755ad6d6297SScott Long 	i=0;
3756ad6d6297SScott Long 	while(i < 16) {
375744f05562SScott Long 		*acb_firm_version = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i);
3758ad6d6297SScott Long 		/* 16 bytes firm_version, 17, 68-83*/
3759ad6d6297SScott Long 		acb_firm_version++;
3760ad6d6297SScott Long 		i++;
3761ad6d6297SScott Long 	}
3762d74001adSXin LI 	i=0;
3763d74001adSXin LI 	while(i < 16) {
3764d74001adSXin LI 		*acb_device_map = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i);
3765d74001adSXin LI 		acb_device_map++;
3766d74001adSXin LI 		i++;
3767d74001adSXin LI 	}
37681e7d660aSXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
3769d74001adSXin LI 	acb->firm_request_len = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[1]);   /*firm_request_len, 1, 04-07*/
3770d74001adSXin LI 	acb->firm_numbers_queue = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/
3771d74001adSXin LI 	acb->firm_sdram_size = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[3]);    /*firm_sdram_size, 3, 12-15*/
3772d74001adSXin LI 	acb->firm_ide_channels = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[4]);  /*firm_ide_channels, 4, 16-19*/
3773d74001adSXin LI 	acb->firm_cfg_version = CHIP_REG_READ32(HBA_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]);	/*firm_cfg_version,  25, 	  */
3774abfdbca9SXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD)
3775abfdbca9SXin LI 		acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD - 1;
3776abfdbca9SXin LI 	else
3777abfdbca9SXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
3778ad6d6297SScott Long }
3779ad6d6297SScott Long /*
3780ad6d6297SScott Long **********************************************************************
378144f05562SScott Long **********************************************************************
378244f05562SScott Long */
378344f05562SScott Long static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
378444f05562SScott Long {
3785b23a1998SXin LI 	struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
378644f05562SScott Long 	char *acb_firm_model = acb->firm_model;
378744f05562SScott Long 	char *acb_firm_version = acb->firm_version;
3788d74001adSXin LI 	char *acb_device_map = acb->device_map;
3789d74001adSXin LI 	size_t iop_firm_model = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);	/*firm_model,15,60-67*/
3790d74001adSXin LI 	size_t iop_firm_version = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);	/*firm_version,17,68-83*/
3791d74001adSXin LI 	size_t iop_device_map = offsetof(struct HBB_RWBUFFER, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
379244f05562SScott Long 	int i;
379344f05562SScott Long 
3794b23a1998SXin LI 	WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_GET_CONFIG);
379544f05562SScott Long 	if(!arcmsr_hbb_wait_msgint_ready(acb)) {
3796d74001adSXin LI 		printf( "arcmsr%d: wait" "'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
379744f05562SScott Long 	}
379844f05562SScott Long 	i = 0;
379944f05562SScott Long 	while(i < 8) {
380044f05562SScott Long 		*acb_firm_model = bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_model+i);
380144f05562SScott Long 		/* 8 bytes firm_model, 15, 60-67*/
380244f05562SScott Long 		acb_firm_model++;
380344f05562SScott Long 		i++;
380444f05562SScott Long 	}
380544f05562SScott Long 	i = 0;
380644f05562SScott Long 	while(i < 16) {
380744f05562SScott Long 		*acb_firm_version = bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_firm_version+i);
380844f05562SScott Long 		/* 16 bytes firm_version, 17, 68-83*/
380944f05562SScott Long 		acb_firm_version++;
381044f05562SScott Long 		i++;
381144f05562SScott Long 	}
3812d74001adSXin LI 	i = 0;
3813d74001adSXin LI 	while(i < 16) {
3814d74001adSXin LI 		*acb_device_map = bus_space_read_1(acb->btag[1], acb->bhandle[1], iop_device_map+i);
3815d74001adSXin LI 		acb_device_map++;
3816d74001adSXin LI 		i++;
3817d74001adSXin LI 	}
38181e7d660aSXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
3819d74001adSXin LI 	acb->firm_request_len = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[1]);   /*firm_request_len, 1, 04-07*/
3820d74001adSXin LI 	acb->firm_numbers_queue = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[2]); /*firm_numbers_queue, 2, 08-11*/
3821d74001adSXin LI 	acb->firm_sdram_size = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[3]);    /*firm_sdram_size, 3, 12-15*/
3822d74001adSXin LI 	acb->firm_ide_channels = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[4]);  /*firm_ide_channels, 4, 16-19*/
3823d74001adSXin LI 	acb->firm_cfg_version = CHIP_REG_READ32(HBB_RWBUFFER, 1, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]);	/*firm_cfg_version,  25, 	  */
3824abfdbca9SXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_HBB_POSTQUEUE)
3825abfdbca9SXin LI 		acb->maxOutstanding = ARCMSR_MAX_HBB_POSTQUEUE - 1;
3826abfdbca9SXin LI 	else
3827abfdbca9SXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
3828d74001adSXin LI }
3829d74001adSXin LI /*
3830d74001adSXin LI **********************************************************************
3831d74001adSXin LI **********************************************************************
3832d74001adSXin LI */
3833d74001adSXin LI static void arcmsr_get_hbc_config(struct AdapterControlBlock *acb)
3834d74001adSXin LI {
3835d74001adSXin LI 	char *acb_firm_model = acb->firm_model;
3836d74001adSXin LI 	char *acb_firm_version = acb->firm_version;
3837d74001adSXin LI 	char *acb_device_map = acb->device_map;
3838d74001adSXin LI 	size_t iop_firm_model = offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);   /*firm_model,15,60-67*/
3839d74001adSXin LI 	size_t iop_firm_version = offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/
3840d74001adSXin LI 	size_t iop_device_map = offsetof(struct HBC_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
3841d74001adSXin LI 	int i;
3842d74001adSXin LI 
3843d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
3844d74001adSXin LI 	CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
3845d74001adSXin LI 	if(!arcmsr_hbc_wait_msgint_ready(acb)) {
3846d74001adSXin LI 		printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
3847d74001adSXin LI 	}
3848d74001adSXin LI 	i = 0;
3849d74001adSXin LI 	while(i < 8) {
3850d74001adSXin LI 		*acb_firm_model = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i);
3851d74001adSXin LI 		/* 8 bytes firm_model, 15, 60-67*/
3852d74001adSXin LI 		acb_firm_model++;
3853d74001adSXin LI 		i++;
3854d74001adSXin LI 	}
3855d74001adSXin LI 	i = 0;
3856d74001adSXin LI 	while(i < 16) {
3857d74001adSXin LI 		*acb_firm_version = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i);
3858d74001adSXin LI 		/* 16 bytes firm_version, 17, 68-83*/
3859d74001adSXin LI 		acb_firm_version++;
3860d74001adSXin LI 		i++;
3861d74001adSXin LI 	}
3862d74001adSXin LI 	i = 0;
3863d74001adSXin LI 	while(i < 16) {
3864d74001adSXin LI 		*acb_device_map = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i);
3865d74001adSXin LI 		acb_device_map++;
3866d74001adSXin LI 		i++;
3867d74001adSXin LI 	}
38681e7d660aSXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
3869d74001adSXin LI 	acb->firm_request_len	= CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[1]);	/*firm_request_len,   1, 04-07*/
3870d74001adSXin LI 	acb->firm_numbers_queue	= CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[2]);	/*firm_numbers_queue, 2, 08-11*/
3871d74001adSXin LI 	acb->firm_sdram_size	= CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[3]);	/*firm_sdram_size,    3, 12-15*/
3872d74001adSXin LI 	acb->firm_ide_channels	= CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[4]);	/*firm_ide_channels,  4, 16-19*/
3873d74001adSXin LI 	acb->firm_cfg_version	= CHIP_REG_READ32(HBC_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]);	/*firm_cfg_version,  25, 	  */
3874abfdbca9SXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD)
3875abfdbca9SXin LI 		acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD - 1;
3876abfdbca9SXin LI 	else
3877abfdbca9SXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
387844f05562SScott Long }
387944f05562SScott Long /*
388044f05562SScott Long **********************************************************************
388144f05562SScott Long **********************************************************************
388244f05562SScott Long */
38837a7bc959SXin LI static void arcmsr_get_hbd_config(struct AdapterControlBlock *acb)
38847a7bc959SXin LI {
38857a7bc959SXin LI 	char *acb_firm_model = acb->firm_model;
38867a7bc959SXin LI 	char *acb_firm_version = acb->firm_version;
38877a7bc959SXin LI 	char *acb_device_map = acb->device_map;
38887a7bc959SXin LI 	size_t iop_firm_model = offsetof(struct HBD_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);   /*firm_model,15,60-67*/
38897a7bc959SXin LI 	size_t iop_firm_version = offsetof(struct HBD_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/
38907a7bc959SXin LI 	size_t iop_device_map = offsetof(struct HBD_MessageUnit, msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
38917a7bc959SXin LI 	int i;
38927a7bc959SXin LI 
38937a7bc959SXin LI 	if(CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_doorbell) & ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE)
38947a7bc959SXin LI 		CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, ARCMSR_HBDMU_IOP2DRV_MESSAGE_CMD_DONE_CLEAR);
38957a7bc959SXin LI 	CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
38967a7bc959SXin LI 	if(!arcmsr_hbd_wait_msgint_ready(acb)) {
38977a7bc959SXin LI 		printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
38987a7bc959SXin LI 	}
38997a7bc959SXin LI 	i = 0;
39007a7bc959SXin LI 	while(i < 8) {
39017a7bc959SXin LI 		*acb_firm_model = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i);
39027a7bc959SXin LI 		/* 8 bytes firm_model, 15, 60-67*/
39037a7bc959SXin LI 		acb_firm_model++;
39047a7bc959SXin LI 		i++;
39057a7bc959SXin LI 	}
39067a7bc959SXin LI 	i = 0;
39077a7bc959SXin LI 	while(i < 16) {
39087a7bc959SXin LI 		*acb_firm_version = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i);
39097a7bc959SXin LI 		/* 16 bytes firm_version, 17, 68-83*/
39107a7bc959SXin LI 		acb_firm_version++;
39117a7bc959SXin LI 		i++;
39127a7bc959SXin LI 	}
39137a7bc959SXin LI 	i = 0;
39147a7bc959SXin LI 	while(i < 16) {
39157a7bc959SXin LI 		*acb_device_map = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i);
39167a7bc959SXin LI 		acb_device_map++;
39177a7bc959SXin LI 		i++;
39187a7bc959SXin LI 	}
39191e7d660aSXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
3920b23a1998SXin LI 	acb->firm_request_len	= CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[1]);	/*firm_request_len,   1, 04-07*/
3921b23a1998SXin LI 	acb->firm_numbers_queue	= CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[2]);	/*firm_numbers_queue, 2, 08-11*/
3922b23a1998SXin LI 	acb->firm_sdram_size	= CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[3]);	/*firm_sdram_size,    3, 12-15*/
3923b23a1998SXin LI 	acb->firm_ide_channels	= CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[4]);	/*firm_ide_channels,  4, 16-19*/
39247a7bc959SXin LI 	acb->firm_cfg_version	= CHIP_REG_READ32(HBD_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]);	/*firm_cfg_version,  25, 	  */
3925abfdbca9SXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_HBD_POSTQUEUE)
3926abfdbca9SXin LI 		acb->maxOutstanding = ARCMSR_MAX_HBD_POSTQUEUE - 1;
3927abfdbca9SXin LI 	else
3928abfdbca9SXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
39297a7bc959SXin LI }
39307a7bc959SXin LI /*
39317a7bc959SXin LI **********************************************************************
39327a7bc959SXin LI **********************************************************************
39337a7bc959SXin LI */
3934a1103e04SXin LI static void arcmsr_get_hbe_config(struct AdapterControlBlock *acb)
3935a1103e04SXin LI {
3936a1103e04SXin LI 	char *acb_firm_model = acb->firm_model;
3937a1103e04SXin LI 	char *acb_firm_version = acb->firm_version;
3938a1103e04SXin LI 	char *acb_device_map = acb->device_map;
3939a1103e04SXin LI 	size_t iop_firm_model = offsetof(struct HBE_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);   /*firm_model,15,60-67*/
3940a1103e04SXin LI 	size_t iop_firm_version = offsetof(struct HBE_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]); /*firm_version,17,68-83*/
3941a1103e04SXin LI 	size_t iop_device_map = offsetof(struct HBE_MessageUnit,msgcode_rwbuffer[ARCMSR_FW_DEVMAP_OFFSET]);
3942a1103e04SXin LI 	int i;
3943a1103e04SXin LI 
3944a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
3945a1103e04SXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3946a1103e04SXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
3947a1103e04SXin LI 	if(!arcmsr_hbe_wait_msgint_ready(acb)) {
3948a1103e04SXin LI 		printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
3949a1103e04SXin LI 	}
3950a1103e04SXin LI 
3951a1103e04SXin LI 	i = 0;
3952a1103e04SXin LI 	while(i < 8) {
3953a1103e04SXin LI 		*acb_firm_model = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_model+i);
3954a1103e04SXin LI 		/* 8 bytes firm_model, 15, 60-67*/
3955a1103e04SXin LI 		acb_firm_model++;
3956a1103e04SXin LI 		i++;
3957a1103e04SXin LI 	}
3958a1103e04SXin LI 	i = 0;
3959a1103e04SXin LI 	while(i < 16) {
3960a1103e04SXin LI 		*acb_firm_version = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_firm_version+i);
3961a1103e04SXin LI 		/* 16 bytes firm_version, 17, 68-83*/
3962a1103e04SXin LI 		acb_firm_version++;
3963a1103e04SXin LI 		i++;
3964a1103e04SXin LI 	}
3965a1103e04SXin LI 	i = 0;
3966a1103e04SXin LI 	while(i < 16) {
3967a1103e04SXin LI 		*acb_device_map = bus_space_read_1(acb->btag[0], acb->bhandle[0], iop_device_map+i);
3968a1103e04SXin LI 		acb_device_map++;
3969a1103e04SXin LI 		i++;
3970a1103e04SXin LI 	}
3971a1103e04SXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
3972a1103e04SXin LI 	acb->firm_request_len	= CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[1]);	/*firm_request_len,   1, 04-07*/
3973a1103e04SXin LI 	acb->firm_numbers_queue	= CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[2]);	/*firm_numbers_queue, 2, 08-11*/
3974a1103e04SXin LI 	acb->firm_sdram_size	= CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[3]);	/*firm_sdram_size,    3, 12-15*/
3975a1103e04SXin LI 	acb->firm_ide_channels	= CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[4]);	/*firm_ide_channels,  4, 16-19*/
3976a1103e04SXin LI 	acb->firm_cfg_version	= CHIP_REG_READ32(HBE_MessageUnit, 0, msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]);	/*firm_cfg_version,  25, 	  */
3977a1103e04SXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD)
3978a1103e04SXin LI 		acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD - 1;
3979a1103e04SXin LI 	else
3980a1103e04SXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
3981a1103e04SXin LI }
3982a1103e04SXin LI /*
3983a1103e04SXin LI **********************************************************************
3984a1103e04SXin LI **********************************************************************
3985a1103e04SXin LI */
3986fa42a0bfSXin LI static void arcmsr_get_hbf_config(struct AdapterControlBlock *acb)
3987fa42a0bfSXin LI {
3988fa42a0bfSXin LI 	u_int32_t *acb_firm_model = (u_int32_t *)acb->firm_model;
3989fa42a0bfSXin LI 	u_int32_t *acb_firm_version = (u_int32_t *)acb->firm_version;
3990fa42a0bfSXin LI 	u_int32_t *acb_device_map = (u_int32_t *)acb->device_map;
3991fa42a0bfSXin LI 	size_t iop_firm_model = ARCMSR_FW_MODEL_OFFSET;   /*firm_model,15,60-67*/
3992fa42a0bfSXin LI 	size_t iop_firm_version = ARCMSR_FW_VERS_OFFSET; /*firm_version,17,68-83*/
3993fa42a0bfSXin LI 	size_t iop_device_map = ARCMSR_FW_DEVMAP_OFFSET;
3994fa42a0bfSXin LI 	int i;
3995fa42a0bfSXin LI 
3996fa42a0bfSXin LI 	CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_GET_CONFIG);
3997fa42a0bfSXin LI 	acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
3998fa42a0bfSXin LI 	CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
3999fa42a0bfSXin LI 	if(!arcmsr_hbe_wait_msgint_ready(acb))
4000fa42a0bfSXin LI 		printf("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", acb->pci_unit);
4001fa42a0bfSXin LI 
4002fa42a0bfSXin LI 	i = 0;
4003fa42a0bfSXin LI 	while(i < 2) {
4004fa42a0bfSXin LI 		*acb_firm_model = acb->msgcode_rwbuffer[iop_firm_model];
4005fa42a0bfSXin LI 		/* 8 bytes firm_model, 15, 60-67*/
4006fa42a0bfSXin LI 		acb_firm_model++;
4007fa42a0bfSXin LI 		iop_firm_model++;
4008fa42a0bfSXin LI 		i++;
4009fa42a0bfSXin LI 	}
4010fa42a0bfSXin LI 	i = 0;
4011fa42a0bfSXin LI 	while(i < 4) {
4012fa42a0bfSXin LI 		*acb_firm_version = acb->msgcode_rwbuffer[iop_firm_version];
4013fa42a0bfSXin LI 		/* 16 bytes firm_version, 17, 68-83*/
4014fa42a0bfSXin LI 		acb_firm_version++;
4015fa42a0bfSXin LI 		iop_firm_version++;
4016fa42a0bfSXin LI 		i++;
4017fa42a0bfSXin LI 	}
4018fa42a0bfSXin LI 	i = 0;
4019fa42a0bfSXin LI 	while(i < 4) {
4020fa42a0bfSXin LI 		*acb_device_map = acb->msgcode_rwbuffer[iop_device_map];
4021fa42a0bfSXin LI 		acb_device_map++;
4022fa42a0bfSXin LI 		iop_device_map++;
4023fa42a0bfSXin LI 		i++;
4024fa42a0bfSXin LI 	}
4025fa42a0bfSXin LI 	printf("Areca RAID adapter%d: %s F/W version %s \n", acb->pci_unit, acb->firm_model, acb->firm_version);
4026fa42a0bfSXin LI 	acb->firm_request_len	= acb->msgcode_rwbuffer[1];	/*firm_request_len,   1, 04-07*/
4027fa42a0bfSXin LI 	acb->firm_numbers_queue	= acb->msgcode_rwbuffer[2];	/*firm_numbers_queue, 2, 08-11*/
4028fa42a0bfSXin LI 	acb->firm_sdram_size	= acb->msgcode_rwbuffer[3];	/*firm_sdram_size,    3, 12-15*/
4029fa42a0bfSXin LI 	acb->firm_ide_channels	= acb->msgcode_rwbuffer[4];	/*firm_ide_channels,  4, 16-19*/
4030fa42a0bfSXin LI 	acb->firm_cfg_version	= acb->msgcode_rwbuffer[ARCMSR_FW_CFGVER_OFFSET]; /*firm_cfg_version,  25*/
4031fa42a0bfSXin LI 	if(acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD)
4032fa42a0bfSXin LI 		acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD - 1;
4033fa42a0bfSXin LI 	else
4034fa42a0bfSXin LI 		acb->maxOutstanding = acb->firm_numbers_queue - 1;
4035fa42a0bfSXin LI }
4036fa42a0bfSXin LI /*
4037fa42a0bfSXin LI **********************************************************************
4038fa42a0bfSXin LI **********************************************************************
4039fa42a0bfSXin LI */
404044f05562SScott Long static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
404144f05562SScott Long {
404244f05562SScott Long 	switch (acb->adapter_type) {
4043fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_A:
404444f05562SScott Long 		arcmsr_get_hba_config(acb);
404544f05562SScott Long 		break;
4046fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_B:
404744f05562SScott Long 		arcmsr_get_hbb_config(acb);
404844f05562SScott Long 		break;
4049fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_C:
4050d74001adSXin LI 		arcmsr_get_hbc_config(acb);
4051d74001adSXin LI 		break;
4052fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_D:
40537a7bc959SXin LI 		arcmsr_get_hbd_config(acb);
40547a7bc959SXin LI 		break;
4055fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
4056a1103e04SXin LI 		arcmsr_get_hbe_config(acb);
4057fa42a0bfSXin LI 		break;
4058fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F:
4059fa42a0bfSXin LI 		arcmsr_get_hbf_config(acb);
4060a1103e04SXin LI 		break;
406144f05562SScott Long 	}
406244f05562SScott Long }
406344f05562SScott Long /*
406444f05562SScott Long **********************************************************************
406544f05562SScott Long **********************************************************************
406644f05562SScott Long */
406744f05562SScott Long static void arcmsr_wait_firmware_ready( struct AdapterControlBlock *acb)
406844f05562SScott Long {
406944f05562SScott Long 	int	timeout=0;
407044f05562SScott Long 
407144f05562SScott Long 	switch (acb->adapter_type) {
407244f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
4073d74001adSXin LI 			while ((CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0)
407444f05562SScott Long 			{
407544f05562SScott Long 				if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */
407644f05562SScott Long 				{
4077d74001adSXin LI 					printf( "arcmsr%d:timed out waiting for firmware \n", acb->pci_unit);
407844f05562SScott Long 					return;
407944f05562SScott Long 				}
408044f05562SScott Long 				UDELAY(15000); /* wait 15 milli-seconds */
408144f05562SScott Long 			}
408244f05562SScott Long 		}
408344f05562SScott Long 		break;
408444f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
4085b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
4086b23a1998SXin LI 			while ((READ_CHIP_REG32(0, phbbmu->iop2drv_doorbell) & ARCMSR_MESSAGE_FIRMWARE_OK) == 0)
408744f05562SScott Long 			{
408844f05562SScott Long 				if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */
408944f05562SScott Long 				{
4090d74001adSXin LI 					printf( "arcmsr%d: timed out waiting for firmware \n", acb->pci_unit);
409144f05562SScott Long 					return;
409244f05562SScott Long 				}
409344f05562SScott Long 				UDELAY(15000); /* wait 15 milli-seconds */
409444f05562SScott Long 			}
4095b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_END_OF_INTERRUPT);
4096d74001adSXin LI 		}
4097d74001adSXin LI 		break;
4098d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
4099d74001adSXin LI 			while ((CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0)
4100d74001adSXin LI 			{
4101d74001adSXin LI 				if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */
4102d74001adSXin LI 				{
4103d74001adSXin LI 					printf( "arcmsr%d:timed out waiting for firmware ready\n", acb->pci_unit);
4104d74001adSXin LI 					return;
4105d74001adSXin LI 				}
4106d74001adSXin LI 				UDELAY(15000); /* wait 15 milli-seconds */
4107d74001adSXin LI 			}
410844f05562SScott Long 		}
410944f05562SScott Long 		break;
41107a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
41117a7bc959SXin LI 			while ((CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_HBDMU_MESSAGE_FIRMWARE_OK) == 0)
41127a7bc959SXin LI 			{
41137a7bc959SXin LI 				if (timeout++ > 2000) /* (2000*15)/1000 = 30 sec */
41147a7bc959SXin LI 				{
41157a7bc959SXin LI 					printf( "arcmsr%d:timed out waiting for firmware ready\n", acb->pci_unit);
41167a7bc959SXin LI 					return;
41177a7bc959SXin LI 				}
41187a7bc959SXin LI 				UDELAY(15000); /* wait 15 milli-seconds */
41197a7bc959SXin LI 			}
41207a7bc959SXin LI 		}
41217a7bc959SXin LI 		break;
4122fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
4123fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
4124a1103e04SXin LI 			while ((CHIP_REG_READ32(HBE_MessageUnit, 0, outbound_msgaddr1) & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0)
4125a1103e04SXin LI 			{
4126a1103e04SXin LI 				if (timeout++ > 4000) /* (4000*15)/1000 = 60 sec */
4127a1103e04SXin LI 				{
4128a1103e04SXin LI 					printf( "arcmsr%d:timed out waiting for firmware ready\n", acb->pci_unit);
4129a1103e04SXin LI 					return;
4130a1103e04SXin LI 				}
4131a1103e04SXin LI 				UDELAY(15000); /* wait 15 milli-seconds */
4132a1103e04SXin LI 			}
4133a1103e04SXin LI 		}
4134a1103e04SXin LI 		break;
413544f05562SScott Long 	}
413644f05562SScott Long }
413744f05562SScott Long /*
413844f05562SScott Long **********************************************************************
413944f05562SScott Long **********************************************************************
414044f05562SScott Long */
414144f05562SScott Long static void arcmsr_clear_doorbell_queue_buffer( struct AdapterControlBlock *acb)
414244f05562SScott Long {
4143d74001adSXin LI 	u_int32_t outbound_doorbell;
4144d74001adSXin LI 
414544f05562SScott Long 	switch (acb->adapter_type) {
414644f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
414744f05562SScott Long 			/* empty doorbell Qbuffer if door bell ringed */
4148d74001adSXin LI 			outbound_doorbell = CHIP_REG_READ32(HBA_MessageUnit, 0, outbound_doorbell);
4149d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, outbound_doorbell, outbound_doorbell);	/*clear doorbell interrupt */
4150d74001adSXin LI 			CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_doorbell, ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
415144f05562SScott Long 		}
415244f05562SScott Long 		break;
415344f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
4154b23a1998SXin LI 			struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
4155fc5ef1caSXin LI 			WRITE_CHIP_REG32(0, phbbmu->iop2drv_doorbell, ARCMSR_DOORBELL_INT_CLEAR_PATTERN);/*clear interrupt and message state*/
4156b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_DRV2IOP_DATA_READ_OK);
415744f05562SScott Long 			/* let IOP know data has been read */
415844f05562SScott Long 		}
415944f05562SScott Long 		break;
4160d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
4161d74001adSXin LI 			/* empty doorbell Qbuffer if door bell ringed */
4162d74001adSXin LI 			outbound_doorbell = CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell);
4163d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, outbound_doorbell_clear, outbound_doorbell);	/*clear doorbell interrupt */
4164d74001adSXin LI 			CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell, ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK);
41657a7bc959SXin LI 			CHIP_REG_READ32(HBC_MessageUnit, 0, outbound_doorbell_clear); /* Dummy read to force pci flush */
41667a7bc959SXin LI 			CHIP_REG_READ32(HBC_MessageUnit, 0, inbound_doorbell); /* Dummy read to force pci flush */
41677a7bc959SXin LI 		}
41687a7bc959SXin LI 		break;
41697a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
41707a7bc959SXin LI 			/* empty doorbell Qbuffer if door bell ringed */
41717a7bc959SXin LI 			outbound_doorbell = CHIP_REG_READ32(HBD_MessageUnit, 0, outbound_doorbell);
41727a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, outbound_doorbell, outbound_doorbell);	/*clear doorbell interrupt */
41737a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_doorbell, ARCMSR_HBDMU_DRV2IOP_DATA_OUT_READ);
4174d74001adSXin LI 		}
4175d74001adSXin LI 		break;
4176fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_E:
4177fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
4178a1103e04SXin LI 			/* empty doorbell Qbuffer if door bell ringed */
4179a1103e04SXin LI 			acb->in_doorbell = CHIP_REG_READ32(HBE_MessageUnit, 0, iobound_doorbell);
4180a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_status, 0);	/*clear doorbell interrupt */
4181a1103e04SXin LI 			acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
4182a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
4183a1103e04SXin LI 		}
4184a1103e04SXin LI 		break;
418544f05562SScott Long 	}
418644f05562SScott Long }
418744f05562SScott Long /*
418844f05562SScott Long ************************************************************************
418944f05562SScott Long ************************************************************************
419044f05562SScott Long */
419144f05562SScott Long static u_int32_t arcmsr_iop_confirm(struct AdapterControlBlock *acb)
419244f05562SScott Long {
419344f05562SScott Long 	unsigned long srb_phyaddr;
419444f05562SScott Long 	u_int32_t srb_phyaddr_hi32;
41957a7bc959SXin LI 	u_int32_t srb_phyaddr_lo32;
419644f05562SScott Long 
419744f05562SScott Long 	/*
419844f05562SScott Long 	********************************************************************
419944f05562SScott Long 	** here we need to tell iop 331 our freesrb.HighPart
420044f05562SScott Long 	** if freesrb.HighPart is not zero
420144f05562SScott Long 	********************************************************************
420244f05562SScott Long 	*/
4203d74001adSXin LI 	srb_phyaddr = (unsigned long) acb->srb_phyaddr.phyaddr;
4204d74001adSXin LI 	srb_phyaddr_hi32 = acb->srb_phyaddr.B.phyadd_high;
42057a7bc959SXin LI 	srb_phyaddr_lo32 = acb->srb_phyaddr.B.phyadd_low;
420644f05562SScott Long 	switch (acb->adapter_type) {
420744f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
420844f05562SScott Long 			if(srb_phyaddr_hi32 != 0) {
4209d74001adSXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG);
4210d74001adSXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, msgcode_rwbuffer[1], srb_phyaddr_hi32);
4211d74001adSXin LI 				CHIP_REG_WRITE32(HBA_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG);
421244f05562SScott Long 				if(!arcmsr_hba_wait_msgint_ready(acb)) {
4213d74001adSXin LI 					printf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit);
421444f05562SScott Long 					return FALSE;
421544f05562SScott Long 				}
421644f05562SScott Long 			}
421744f05562SScott Long 		}
421844f05562SScott Long 		break;
421944f05562SScott Long 		/*
422044f05562SScott Long 		***********************************************************************
422144f05562SScott Long 		**    if adapter type B, set window of "post command Q"
422244f05562SScott Long 		***********************************************************************
422344f05562SScott Long 		*/
422444f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
422544f05562SScott Long 			u_int32_t post_queue_phyaddr;
422644f05562SScott Long 			struct HBB_MessageUnit *phbbmu;
422744f05562SScott Long 
422844f05562SScott Long 			phbbmu = (struct HBB_MessageUnit *)acb->pmu;
422944f05562SScott Long 			phbbmu->postq_index = 0;
423044f05562SScott Long 			phbbmu->doneq_index = 0;
4231b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_SET_POST_WINDOW);
423244f05562SScott Long 			if(!arcmsr_hbb_wait_msgint_ready(acb)) {
4233d74001adSXin LI 				printf( "arcmsr%d: 'set window of post command Q' timeout\n", acb->pci_unit);
423444f05562SScott Long 				return FALSE;
423544f05562SScott Long 			}
423622f2616bSXin LI 			post_queue_phyaddr = srb_phyaddr + ARCMSR_SRBS_POOL_SIZE
423744f05562SScott Long 								+ offsetof(struct HBB_MessageUnit, post_qbuffer);
4238d74001adSXin LI 			CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); /* driver "set config" signature */
4239d74001adSXin LI 			CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[1], srb_phyaddr_hi32); /* normal should be zero */
4240d74001adSXin LI 			CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[2], post_queue_phyaddr); /* postQ size (256+8)*4 */
4241d74001adSXin LI 			CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[3], post_queue_phyaddr+1056); /* doneQ size (256+8)*4 */
4242d74001adSXin LI 			CHIP_REG_WRITE32(HBB_RWBUFFER, 1, msgcode_rwbuffer[4], 1056); /* srb maxQ size must be --> [(256+8)*4] */
4243b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_SET_CONFIG);
424444f05562SScott Long 			if(!arcmsr_hbb_wait_msgint_ready(acb)) {
424544f05562SScott Long 				printf( "arcmsr%d: 'set command Q window' timeout \n", acb->pci_unit);
424644f05562SScott Long 				return FALSE;
424744f05562SScott Long 			}
4248b23a1998SXin LI 			WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_START_DRIVER_MODE);
424944f05562SScott Long 			if(!arcmsr_hbb_wait_msgint_ready(acb)) {
425044f05562SScott Long 				printf( "arcmsr%d: 'start diver mode' timeout \n", acb->pci_unit);
425144f05562SScott Long 				return FALSE;
425244f05562SScott Long 			}
425344f05562SScott Long 		}
425444f05562SScott Long 		break;
4255d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
4256d74001adSXin LI 			if(srb_phyaddr_hi32 != 0) {
4257d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG);
4258d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit, 0, msgcode_rwbuffer[1], srb_phyaddr_hi32);
4259d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG);
4260d74001adSXin LI 				CHIP_REG_WRITE32(HBC_MessageUnit, 0, inbound_doorbell,ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE);
4261d74001adSXin LI 				if(!arcmsr_hbc_wait_msgint_ready(acb)) {
4262d74001adSXin LI 					printf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit);
4263d74001adSXin LI 					return FALSE;
4264d74001adSXin LI 				}
4265d74001adSXin LI 			}
4266d74001adSXin LI 		}
4267d74001adSXin LI 		break;
42687a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
42697a7bc959SXin LI 			u_int32_t post_queue_phyaddr, done_queue_phyaddr;
42707a7bc959SXin LI 			struct HBD_MessageUnit0 *phbdmu;
42717a7bc959SXin LI 
42727a7bc959SXin LI 			phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
42737a7bc959SXin LI 			phbdmu->postq_index = 0;
42747a7bc959SXin LI 			phbdmu->doneq_index = 0x40FF;
42757a7bc959SXin LI 			post_queue_phyaddr = srb_phyaddr_lo32 + ARCMSR_SRBS_POOL_SIZE
42767a7bc959SXin LI 								+ offsetof(struct HBD_MessageUnit0, post_qbuffer);
42777a7bc959SXin LI 			done_queue_phyaddr = srb_phyaddr_lo32 + ARCMSR_SRBS_POOL_SIZE
42787a7bc959SXin LI 								+ offsetof(struct HBD_MessageUnit0, done_qbuffer);
42797a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG); /* driver "set config" signature */
42807a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, msgcode_rwbuffer[1], srb_phyaddr_hi32);
42817a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, msgcode_rwbuffer[2], post_queue_phyaddr); /* postQ base */
42827a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, msgcode_rwbuffer[3], done_queue_phyaddr); /* doneQ base */
42837a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, msgcode_rwbuffer[4], 0x100);
42847a7bc959SXin LI 			CHIP_REG_WRITE32(HBD_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG);
42857a7bc959SXin LI 			if(!arcmsr_hbd_wait_msgint_ready(acb)) {
42867a7bc959SXin LI 				printf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit);
42877a7bc959SXin LI 				return FALSE;
42887a7bc959SXin LI 			}
42897a7bc959SXin LI 		}
42907a7bc959SXin LI 		break;
4291a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E: {
4292a1103e04SXin LI 			u_int32_t cdb_phyaddr_lo32;
4293a1103e04SXin LI 			cdb_phyaddr_lo32 = srb_phyaddr_lo32 + offsetof(struct CommandControlBlock, arcmsr_cdb);
4294a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[0], ARCMSR_SIGNATURE_SET_CONFIG);
4295a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[1], ARCMSR_SIGNATURE_1884);
4296a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[2], cdb_phyaddr_lo32);
4297a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[3], srb_phyaddr_hi32);
4298a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[4], SRB_SIZE);
4299a1103e04SXin LI 			cdb_phyaddr_lo32 = srb_phyaddr_lo32 + ARCMSR_SRBS_POOL_SIZE;
4300a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[5], cdb_phyaddr_lo32);
4301a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[6], srb_phyaddr_hi32);
4302a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, msgcode_rwbuffer[7], COMPLETION_Q_POOL_SIZE);
4303a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG);
4304a1103e04SXin LI 			acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
4305a1103e04SXin LI 			CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
4306a1103e04SXin LI 			if(!arcmsr_hbe_wait_msgint_ready(acb)) {
4307a1103e04SXin LI 				printf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit);
4308a1103e04SXin LI 				return FALSE;
4309a1103e04SXin LI 			}
4310a1103e04SXin LI 		}
4311a1103e04SXin LI 		break;
4312fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
4313fa42a0bfSXin LI 			u_int32_t cdb_phyaddr_lo32;
4314fa42a0bfSXin LI 			cdb_phyaddr_lo32 = srb_phyaddr_lo32 + offsetof(struct CommandControlBlock, arcmsr_cdb);
4315fa42a0bfSXin LI 			acb->msgcode_rwbuffer[0] = ARCMSR_SIGNATURE_SET_CONFIG;
4316fa42a0bfSXin LI 			acb->msgcode_rwbuffer[1] = ARCMSR_SIGNATURE_1886;
4317fa42a0bfSXin LI 			acb->msgcode_rwbuffer[2] = cdb_phyaddr_lo32;
4318fa42a0bfSXin LI 			acb->msgcode_rwbuffer[3] = srb_phyaddr_hi32;
4319fa42a0bfSXin LI 			acb->msgcode_rwbuffer[4] = SRB_SIZE;
4320fa42a0bfSXin LI 			cdb_phyaddr_lo32 = srb_phyaddr_lo32 + ARCMSR_SRBS_POOL_SIZE;
4321fa42a0bfSXin LI 			acb->msgcode_rwbuffer[5] = cdb_phyaddr_lo32;
4322fa42a0bfSXin LI 			acb->msgcode_rwbuffer[6] = srb_phyaddr_hi32;
4323fa42a0bfSXin LI 			acb->msgcode_rwbuffer[7] = COMPLETION_Q_POOL_SIZE;
4324fa42a0bfSXin LI 			CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_msgaddr0, ARCMSR_INBOUND_MESG0_SET_CONFIG);
4325fa42a0bfSXin LI 			acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
4326fa42a0bfSXin LI 			CHIP_REG_WRITE32(HBF_MessageUnit, 0, iobound_doorbell, acb->out_doorbell);
4327fa42a0bfSXin LI 			if(!arcmsr_hbe_wait_msgint_ready(acb)) {
4328fa42a0bfSXin LI 				printf( "arcmsr%d: 'set srb high part physical address' timeout \n", acb->pci_unit);
4329fa42a0bfSXin LI 				return FALSE;
4330fa42a0bfSXin LI 			}
4331fa42a0bfSXin LI 		}
4332fa42a0bfSXin LI 		break;
433344f05562SScott Long 	}
4334dac36688SXin LI 	return (TRUE);
433544f05562SScott Long }
433644f05562SScott Long /*
433744f05562SScott Long ************************************************************************
433844f05562SScott Long ************************************************************************
433944f05562SScott Long */
434044f05562SScott Long static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
434144f05562SScott Long {
4342a1103e04SXin LI 	if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
434344f05562SScott Long 	{
4344b23a1998SXin LI 		struct HBB_MessageUnit *phbbmu = (struct HBB_MessageUnit *)acb->pmu;
4345b23a1998SXin LI 		WRITE_CHIP_REG32(0, phbbmu->drv2iop_doorbell, ARCMSR_MESSAGE_ACTIVE_EOI_MODE);
434644f05562SScott Long 		if(!arcmsr_hbb_wait_msgint_ready(acb)) {
4347d74001adSXin LI 			printf( "arcmsr%d: 'iop enable eoi mode' timeout \n", acb->pci_unit);
434844f05562SScott Long 			return;
434944f05562SScott Long 		}
435044f05562SScott Long 	}
435144f05562SScott Long }
435244f05562SScott Long /*
435344f05562SScott Long **********************************************************************
4354ad6d6297SScott Long **********************************************************************
4355ad6d6297SScott Long */
4356ad6d6297SScott Long static void arcmsr_iop_init(struct AdapterControlBlock *acb)
4357ad6d6297SScott Long {
435844f05562SScott Long 	u_int32_t intmask_org;
4359ad6d6297SScott Long 
436044f05562SScott Long 	/* disable all outbound interrupt */
436144f05562SScott Long 	intmask_org = arcmsr_disable_allintr(acb);
436244f05562SScott Long 	arcmsr_wait_firmware_ready(acb);
436344f05562SScott Long 	arcmsr_iop_confirm(acb);
4364ad6d6297SScott Long 	arcmsr_get_firmware_spec(acb);
436544f05562SScott Long 	/*start background rebuild*/
4366ad6d6297SScott Long 	arcmsr_start_adapter_bgrb(acb);
436744f05562SScott Long 	/* empty doorbell Qbuffer if door bell ringed */
436844f05562SScott Long 	arcmsr_clear_doorbell_queue_buffer(acb);
436944f05562SScott Long 	arcmsr_enable_eoi_mode(acb);
437044f05562SScott Long 	/* enable outbound Post Queue, outbound doorbell Interrupt */
437144f05562SScott Long 	arcmsr_enable_allintr(acb, intmask_org);
4372ad6d6297SScott Long 	acb->acb_flags |= ACB_F_IOP_INITED;
4373ad6d6297SScott Long }
4374ad6d6297SScott Long /*
4375ad6d6297SScott Long **********************************************************************
4376f1c579b1SScott Long **********************************************************************
4377f1c579b1SScott Long */
4378231c8b71SXin LI static void arcmsr_map_free_srb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
4379f1c579b1SScott Long {
4380ad6d6297SScott Long 	struct AdapterControlBlock *acb = arg;
4381ad6d6297SScott Long 	struct CommandControlBlock *srb_tmp;
438244f05562SScott Long 	u_int32_t i;
4383ad6d6297SScott Long 	unsigned long srb_phyaddr = (unsigned long)segs->ds_addr;
4384f1c579b1SScott Long 
4385d74001adSXin LI 	acb->srb_phyaddr.phyaddr = srb_phyaddr;
43867a7bc959SXin LI 	srb_tmp = (struct CommandControlBlock *)acb->uncacheptr;
4387ad6d6297SScott Long 	for(i=0; i < ARCMSR_MAX_FREESRB_NUM; i++) {
438844f05562SScott Long 		if(bus_dmamap_create(acb->dm_segs_dmat,
438944f05562SScott Long 			 /*flags*/0, &srb_tmp->dm_segs_dmamap) != 0) {
4390ad6d6297SScott Long 			acb->acb_flags |= ACB_F_MAPFREESRB_FAILD;
439144f05562SScott Long 			printf("arcmsr%d:"
439244f05562SScott Long 			" srb dmamap bus_dmamap_create error\n", acb->pci_unit);
4393ad6d6297SScott Long 			return;
4394ad6d6297SScott Long 		}
4395a1103e04SXin LI 		if((acb->adapter_type == ACB_ADAPTER_TYPE_C) || (acb->adapter_type == ACB_ADAPTER_TYPE_D)
4396fa42a0bfSXin LI 			 || (acb->adapter_type == ACB_ADAPTER_TYPE_E) || (acb->adapter_type == ACB_ADAPTER_TYPE_F))
43977a7bc959SXin LI 		{
43987a7bc959SXin LI 			srb_tmp->cdb_phyaddr_low = srb_phyaddr;
43997a7bc959SXin LI 			srb_tmp->cdb_phyaddr_high = (u_int32_t)((srb_phyaddr >> 16) >> 16);
44007a7bc959SXin LI 		}
44017a7bc959SXin LI 		else
44027a7bc959SXin LI 			srb_tmp->cdb_phyaddr_low = srb_phyaddr >> 5;
4403ad6d6297SScott Long 		srb_tmp->acb = acb;
4404a1103e04SXin LI 		srb_tmp->smid = i << 16;
4405ad6d6297SScott Long 		acb->srbworkingQ[i] = acb->psrb_pool[i] = srb_tmp;
440622f2616bSXin LI 		srb_phyaddr = srb_phyaddr + SRB_SIZE;
440722f2616bSXin LI 		srb_tmp = (struct CommandControlBlock *)((unsigned long)srb_tmp + SRB_SIZE);
4408ad6d6297SScott Long 	}
4409fc5ef1caSXin LI 	if (acb->adapter_type == ACB_ADAPTER_TYPE_E)
4410a1103e04SXin LI 		acb->pCompletionQ = (pCompletion_Q)srb_tmp;
4411fa42a0bfSXin LI 	else if (acb->adapter_type == ACB_ADAPTER_TYPE_F) {
4412fa42a0bfSXin LI 		acb->pCompletionQ = (pCompletion_Q)srb_tmp;
4413fa42a0bfSXin LI 		acb->completeQ_phys = srb_phyaddr;
4414fa42a0bfSXin LI 		memset(acb->pCompletionQ, 0xff, COMPLETION_Q_POOL_SIZE);
4415fa42a0bfSXin LI 		acb->message_wbuffer = (u_int32_t *)((unsigned long)acb->pCompletionQ + COMPLETION_Q_POOL_SIZE);
4416fa42a0bfSXin LI 		acb->message_rbuffer = (u_int32_t *)((unsigned long)acb->message_wbuffer + 0x100);
4417fa42a0bfSXin LI 		acb->msgcode_rwbuffer = (u_int32_t *)((unsigned long)acb->message_wbuffer + 0x200);
4418fa42a0bfSXin LI 		memset((void *)acb->message_wbuffer, 0, MESG_RW_BUFFER_SIZE);
4419fa42a0bfSXin LI 	}
4420ad6d6297SScott Long 	acb->vir2phy_offset = (unsigned long)srb_tmp - (unsigned long)srb_phyaddr;
4421f1c579b1SScott Long }
4422f1c579b1SScott Long /*
4423f1c579b1SScott Long ************************************************************************
4424f1c579b1SScott Long ************************************************************************
4425f1c579b1SScott Long */
4426ad6d6297SScott Long static void arcmsr_free_resource(struct AdapterControlBlock *acb)
4427f1c579b1SScott Long {
4428f1c579b1SScott Long 	/* remove the control device */
4429ad6d6297SScott Long 	if(acb->ioctl_dev != NULL) {
4430ad6d6297SScott Long 		destroy_dev(acb->ioctl_dev);
4431f1c579b1SScott Long 	}
4432ad6d6297SScott Long 	bus_dmamap_unload(acb->srb_dmat, acb->srb_dmamap);
4433ad6d6297SScott Long 	bus_dmamap_destroy(acb->srb_dmat, acb->srb_dmamap);
4434ad6d6297SScott Long 	bus_dma_tag_destroy(acb->srb_dmat);
4435ad6d6297SScott Long 	bus_dma_tag_destroy(acb->dm_segs_dmat);
4436ad6d6297SScott Long 	bus_dma_tag_destroy(acb->parent_dmat);
4437f1c579b1SScott Long }
4438f1c579b1SScott Long /*
4439f1c579b1SScott Long ************************************************************************
4440f1c579b1SScott Long ************************************************************************
4441f1c579b1SScott Long */
44427a7bc959SXin LI static void arcmsr_mutex_init(struct AdapterControlBlock *acb)
44437a7bc959SXin LI {
44447a7bc959SXin LI 	ARCMSR_LOCK_INIT(&acb->isr_lock, "arcmsr isr lock");
44457a7bc959SXin LI 	ARCMSR_LOCK_INIT(&acb->srb_lock, "arcmsr srb lock");
44467a7bc959SXin LI 	ARCMSR_LOCK_INIT(&acb->postDone_lock, "arcmsr postQ lock");
44477a7bc959SXin LI 	ARCMSR_LOCK_INIT(&acb->qbuffer_lock, "arcmsr RW buffer lock");
44487a7bc959SXin LI }
44497a7bc959SXin LI /*
44507a7bc959SXin LI ************************************************************************
44517a7bc959SXin LI ************************************************************************
44527a7bc959SXin LI */
44537a7bc959SXin LI static void arcmsr_mutex_destroy(struct AdapterControlBlock *acb)
44547a7bc959SXin LI {
44557a7bc959SXin LI 	ARCMSR_LOCK_DESTROY(&acb->qbuffer_lock);
44567a7bc959SXin LI 	ARCMSR_LOCK_DESTROY(&acb->postDone_lock);
44577a7bc959SXin LI 	ARCMSR_LOCK_DESTROY(&acb->srb_lock);
44587a7bc959SXin LI 	ARCMSR_LOCK_DESTROY(&acb->isr_lock);
44597a7bc959SXin LI }
44607a7bc959SXin LI /*
44617a7bc959SXin LI ************************************************************************
44627a7bc959SXin LI ************************************************************************
44637a7bc959SXin LI */
4464ad6d6297SScott Long static u_int32_t arcmsr_initialize(device_t dev)
4465f1c579b1SScott Long {
4466ad6d6297SScott Long 	struct AdapterControlBlock *acb = device_get_softc(dev);
4467ad6d6297SScott Long 	u_int16_t pci_command;
446844f05562SScott Long 	int i, j,max_coherent_size;
4469dac36688SXin LI 	u_int32_t vendor_dev_id;
4470f1c579b1SScott Long 
4471dac36688SXin LI 	vendor_dev_id = pci_get_devid(dev);
4472dac36688SXin LI 	acb->vendor_device_id = vendor_dev_id;
4473224a78aeSXin LI 	acb->sub_device_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
4474dac36688SXin LI 	switch (vendor_dev_id) {
4475dac36688SXin LI 	case PCIDevVenIDARC1880:
4476dac36688SXin LI 	case PCIDevVenIDARC1882:
4477dac36688SXin LI 	case PCIDevVenIDARC1213:
4478dac36688SXin LI 	case PCIDevVenIDARC1223: {
4479d74001adSXin LI 			acb->adapter_type = ACB_ADAPTER_TYPE_C;
4480fc5ef1caSXin LI 			if ((acb->sub_device_id == ARECA_SUB_DEV_ID_1883) ||
4481fc5ef1caSXin LI 			    (acb->sub_device_id == ARECA_SUB_DEV_ID_1216) ||
4482fc5ef1caSXin LI 			    (acb->sub_device_id == ARECA_SUB_DEV_ID_1226))
4483224a78aeSXin LI 				acb->adapter_bus_speed = ACB_BUS_SPEED_12G;
4484224a78aeSXin LI 			else
4485dac36688SXin LI 				acb->adapter_bus_speed = ACB_BUS_SPEED_6G;
4486d74001adSXin LI 			max_coherent_size = ARCMSR_SRBS_POOL_SIZE;
4487d74001adSXin LI 		}
4488d74001adSXin LI 		break;
4489a1103e04SXin LI 	case PCIDevVenIDARC1884:
4490a1103e04SXin LI 		acb->adapter_type = ACB_ADAPTER_TYPE_E;
4491a1103e04SXin LI 		acb->adapter_bus_speed = ACB_BUS_SPEED_12G;
4492a1103e04SXin LI 		max_coherent_size = ARCMSR_SRBS_POOL_SIZE + COMPLETION_Q_POOL_SIZE;
4493a1103e04SXin LI 		acb->completionQ_entry = COMPLETION_Q_POOL_SIZE / sizeof(struct deliver_completeQ);
4494a1103e04SXin LI 		break;
4495fa42a0bfSXin LI 	case PCIDevVenIDARC1886_:
4496fa42a0bfSXin LI 	case PCIDevVenIDARC1886:
4497fa42a0bfSXin LI 		acb->adapter_type = ACB_ADAPTER_TYPE_F;
4498fa42a0bfSXin LI 		acb->adapter_bus_speed = ACB_BUS_SPEED_12G;
4499fa42a0bfSXin LI 		max_coherent_size = ARCMSR_SRBS_POOL_SIZE + COMPLETION_Q_POOL_SIZE + MESG_RW_BUFFER_SIZE;
4500fa42a0bfSXin LI 		acb->completionQ_entry = COMPLETION_Q_POOL_SIZE / sizeof(struct deliver_completeQ);
4501fa42a0bfSXin LI 		break;
45027a7bc959SXin LI 	case PCIDevVenIDARC1214: {
45037a7bc959SXin LI 			acb->adapter_type = ACB_ADAPTER_TYPE_D;
45047a7bc959SXin LI 			acb->adapter_bus_speed = ACB_BUS_SPEED_6G;
45057a7bc959SXin LI 			max_coherent_size = ARCMSR_SRBS_POOL_SIZE + (sizeof(struct HBD_MessageUnit0));
45067a7bc959SXin LI 		}
45077a7bc959SXin LI 		break;
4508231c8b71SXin LI 	case PCIDevVenIDARC1200:
450944f05562SScott Long 	case PCIDevVenIDARC1201: {
451044f05562SScott Long 			acb->adapter_type = ACB_ADAPTER_TYPE_B;
4511dac36688SXin LI 			acb->adapter_bus_speed = ACB_BUS_SPEED_3G;
4512d74001adSXin LI 			max_coherent_size = ARCMSR_SRBS_POOL_SIZE + (sizeof(struct HBB_MessageUnit));
451344f05562SScott Long 		}
451444f05562SScott Long 		break;
4515b23a1998SXin LI 	case PCIDevVenIDARC1203: {
4516b23a1998SXin LI 			acb->adapter_type = ACB_ADAPTER_TYPE_B;
4517b23a1998SXin LI 			acb->adapter_bus_speed = ACB_BUS_SPEED_6G;
4518b23a1998SXin LI 			max_coherent_size = ARCMSR_SRBS_POOL_SIZE + (sizeof(struct HBB_MessageUnit));
4519b23a1998SXin LI 		}
4520b23a1998SXin LI 		break;
452144f05562SScott Long 	case PCIDevVenIDARC1110:
452244f05562SScott Long 	case PCIDevVenIDARC1120:
452344f05562SScott Long 	case PCIDevVenIDARC1130:
452444f05562SScott Long 	case PCIDevVenIDARC1160:
452544f05562SScott Long 	case PCIDevVenIDARC1170:
452644f05562SScott Long 	case PCIDevVenIDARC1210:
452744f05562SScott Long 	case PCIDevVenIDARC1220:
452844f05562SScott Long 	case PCIDevVenIDARC1230:
4529231c8b71SXin LI 	case PCIDevVenIDARC1231:
453044f05562SScott Long 	case PCIDevVenIDARC1260:
4531231c8b71SXin LI 	case PCIDevVenIDARC1261:
453244f05562SScott Long 	case PCIDevVenIDARC1270:
453344f05562SScott Long 	case PCIDevVenIDARC1280:
4534d74001adSXin LI 	case PCIDevVenIDARC1212:
4535d74001adSXin LI 	case PCIDevVenIDARC1222:
453644f05562SScott Long 	case PCIDevVenIDARC1380:
453744f05562SScott Long 	case PCIDevVenIDARC1381:
453844f05562SScott Long 	case PCIDevVenIDARC1680:
453944f05562SScott Long 	case PCIDevVenIDARC1681: {
454044f05562SScott Long 			acb->adapter_type = ACB_ADAPTER_TYPE_A;
4541dac36688SXin LI 			acb->adapter_bus_speed = ACB_BUS_SPEED_3G;
454244f05562SScott Long 			max_coherent_size = ARCMSR_SRBS_POOL_SIZE;
454344f05562SScott Long 		}
454444f05562SScott Long 		break;
454544f05562SScott Long 	default: {
454644f05562SScott Long 			printf("arcmsr%d:"
454744f05562SScott Long 			" unknown RAID adapter type \n", device_get_unit(dev));
454844f05562SScott Long 			return ENOMEM;
454944f05562SScott Long 		}
455044f05562SScott Long 	}
4551b6f97155SScott Long 	if(bus_dma_tag_create(  /*PCI parent*/		bus_get_dma_tag(dev),
4552f1c579b1SScott Long 				/*alignemnt*/		1,
4553f1c579b1SScott Long 				/*boundary*/		0,
4554701d9f1fSScott Long 				/*lowaddr*/		BUS_SPACE_MAXADDR,
4555f1c579b1SScott Long 				/*highaddr*/		BUS_SPACE_MAXADDR,
4556f1c579b1SScott Long 				/*filter*/		NULL,
4557f1c579b1SScott Long 				/*filterarg*/		NULL,
4558f1c579b1SScott Long 				/*maxsize*/		BUS_SPACE_MAXSIZE_32BIT,
4559f1c579b1SScott Long 				/*nsegments*/		BUS_SPACE_UNRESTRICTED,
4560f1c579b1SScott Long 				/*maxsegsz*/		BUS_SPACE_MAXSIZE_32BIT,
4561f1c579b1SScott Long 				/*flags*/		0,
4562f1c579b1SScott Long 				/*lockfunc*/		NULL,
4563f1c579b1SScott Long 				/*lockarg*/		NULL,
4564231c8b71SXin LI 							&acb->parent_dmat) != 0)
4565f1c579b1SScott Long 	{
456644f05562SScott Long 		printf("arcmsr%d: parent_dmat bus_dma_tag_create failure!\n", device_get_unit(dev));
4567f1c579b1SScott Long 		return ENOMEM;
4568f1c579b1SScott Long 	}
4569231c8b71SXin LI 
4570f1c579b1SScott Long 	/* Create a single tag describing a region large enough to hold all of the s/g lists we will need. */
4571ad6d6297SScott Long 	if(bus_dma_tag_create(  /*parent_dmat*/		acb->parent_dmat,
4572f1c579b1SScott Long 				/*alignment*/		1,
4573f1c579b1SScott Long 				/*boundary*/		0,
457422f2616bSXin LI #ifdef PAE
457522f2616bSXin LI 				/*lowaddr*/		BUS_SPACE_MAXADDR_32BIT,
457622f2616bSXin LI #else
4577f1c579b1SScott Long 				/*lowaddr*/		BUS_SPACE_MAXADDR,
457822f2616bSXin LI #endif
4579f1c579b1SScott Long 				/*highaddr*/		BUS_SPACE_MAXADDR,
4580f1c579b1SScott Long 				/*filter*/		NULL,
4581f1c579b1SScott Long 				/*filterarg*/		NULL,
4582231c8b71SXin LI 				/*maxsize*/		ARCMSR_MAX_SG_ENTRIES * PAGE_SIZE * ARCMSR_MAX_FREESRB_NUM,
4583f1c579b1SScott Long 				/*nsegments*/		ARCMSR_MAX_SG_ENTRIES,
4584f1c579b1SScott Long 				/*maxsegsz*/		BUS_SPACE_MAXSIZE_32BIT,
4585ad6d6297SScott Long 				/*flags*/		0,
4586f1c579b1SScott Long 				/*lockfunc*/		busdma_lock_mutex,
45877a7bc959SXin LI 				/*lockarg*/		&acb->isr_lock,
4588231c8b71SXin LI 							&acb->dm_segs_dmat) != 0)
4589f1c579b1SScott Long 	{
4590ad6d6297SScott Long 		bus_dma_tag_destroy(acb->parent_dmat);
459144f05562SScott Long 		printf("arcmsr%d: dm_segs_dmat bus_dma_tag_create failure!\n", device_get_unit(dev));
4592f1c579b1SScott Long 		return ENOMEM;
4593f1c579b1SScott Long 	}
4594231c8b71SXin LI 
4595ad6d6297SScott Long 	/* DMA tag for our srb structures.... Allocate the freesrb memory */
4596ad6d6297SScott Long 	if(bus_dma_tag_create(  /*parent_dmat*/		acb->parent_dmat,
459744f05562SScott Long 				/*alignment*/		0x20,
4598f1c579b1SScott Long 				/*boundary*/		0,
4599f1c579b1SScott Long 				/*lowaddr*/		BUS_SPACE_MAXADDR_32BIT,
4600f1c579b1SScott Long 				/*highaddr*/		BUS_SPACE_MAXADDR,
4601f1c579b1SScott Long 				/*filter*/		NULL,
4602f1c579b1SScott Long 				/*filterarg*/		NULL,
460344f05562SScott Long 				/*maxsize*/		max_coherent_size,
4604f1c579b1SScott Long 				/*nsegments*/		1,
4605f1c579b1SScott Long 				/*maxsegsz*/		BUS_SPACE_MAXSIZE_32BIT,
4606701d9f1fSScott Long 				/*flags*/		0,
4607f1c579b1SScott Long 				/*lockfunc*/		NULL,
4608f1c579b1SScott Long 				/*lockarg*/		NULL,
4609231c8b71SXin LI 							&acb->srb_dmat) != 0)
4610f1c579b1SScott Long 	{
4611ad6d6297SScott Long 		bus_dma_tag_destroy(acb->dm_segs_dmat);
4612ad6d6297SScott Long 		bus_dma_tag_destroy(acb->parent_dmat);
461344f05562SScott Long 		printf("arcmsr%d: srb_dmat bus_dma_tag_create failure!\n", device_get_unit(dev));
4614f1c579b1SScott Long 		return ENXIO;
4615f1c579b1SScott Long 	}
4616f1c579b1SScott Long 	/* Allocation for our srbs */
4617d74001adSXin LI 	if(bus_dmamem_alloc(acb->srb_dmat, (void **)&acb->uncacheptr, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &acb->srb_dmamap) != 0) {
4618ad6d6297SScott Long 		bus_dma_tag_destroy(acb->srb_dmat);
4619ad6d6297SScott Long 		bus_dma_tag_destroy(acb->dm_segs_dmat);
4620ad6d6297SScott Long 		bus_dma_tag_destroy(acb->parent_dmat);
462144f05562SScott Long 		printf("arcmsr%d: srb_dmat bus_dmamem_alloc failure!\n", device_get_unit(dev));
4622f1c579b1SScott Long 		return ENXIO;
4623f1c579b1SScott Long 	}
4624f1c579b1SScott Long 	/* And permanently map them */
4625231c8b71SXin LI 	if(bus_dmamap_load(acb->srb_dmat, acb->srb_dmamap, acb->uncacheptr, max_coherent_size, arcmsr_map_free_srb, acb, /*flags*/0)) {
4626ad6d6297SScott Long 		bus_dma_tag_destroy(acb->srb_dmat);
4627ad6d6297SScott Long 		bus_dma_tag_destroy(acb->dm_segs_dmat);
4628ad6d6297SScott Long 		bus_dma_tag_destroy(acb->parent_dmat);
462944f05562SScott Long 		printf("arcmsr%d: srb_dmat bus_dmamap_load failure!\n", device_get_unit(dev));
4630f1c579b1SScott Long 		return ENXIO;
4631f1c579b1SScott Long 	}
4632f1c579b1SScott Long 	pci_command = pci_read_config(dev, PCIR_COMMAND, 2);
4633f1c579b1SScott Long 	pci_command |= PCIM_CMD_BUSMASTEREN;
4634f1c579b1SScott Long 	pci_command |= PCIM_CMD_PERRESPEN;
4635f1c579b1SScott Long 	pci_command |= PCIM_CMD_MWRICEN;
4636c68534f1SScott Long 	/* Enable Busmaster */
4637f1c579b1SScott Long 	pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
463844f05562SScott Long 	switch(acb->adapter_type) {
463944f05562SScott Long 	case ACB_ADAPTER_TYPE_A: {
464044f05562SScott Long 		u_int32_t rid0 = PCIR_BAR(0);
464144f05562SScott Long 		vm_offset_t	mem_base0;
464244f05562SScott Long 
4643eff83876SJustin Hibbits 		acb->sys_res_arcmsr[0] = bus_alloc_resource_any(dev,SYS_RES_MEMORY, &rid0, RF_ACTIVE);
464444f05562SScott Long 		if(acb->sys_res_arcmsr[0] == NULL) {
4645ad6d6297SScott Long 			arcmsr_free_resource(acb);
4646d74001adSXin LI 			printf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev));
4647f1c579b1SScott Long 			return ENOMEM;
4648f1c579b1SScott Long 		}
464944f05562SScott Long 		if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) {
4650ad6d6297SScott Long 			arcmsr_free_resource(acb);
4651d74001adSXin LI 			printf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev));
4652f1c579b1SScott Long 			return ENXIO;
4653f1c579b1SScott Long 		}
465444f05562SScott Long 		mem_base0 = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]);
465544f05562SScott Long 		if(mem_base0 == 0) {
4656ad6d6297SScott Long 			arcmsr_free_resource(acb);
4657d74001adSXin LI 			printf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev));
4658f1c579b1SScott Long 			return ENXIO;
4659f1c579b1SScott Long 		}
466044f05562SScott Long 		acb->btag[0] = rman_get_bustag(acb->sys_res_arcmsr[0]);
466144f05562SScott Long 		acb->bhandle[0] = rman_get_bushandle(acb->sys_res_arcmsr[0]);
466244f05562SScott Long 		acb->pmu = (struct MessageUnit_UNION *)mem_base0;
4663fc5ef1caSXin LI 		acb->rid[0] = rid0;
466444f05562SScott Long 		}
466544f05562SScott Long 		break;
466644f05562SScott Long 	case ACB_ADAPTER_TYPE_B: {
466744f05562SScott Long 		struct HBB_MessageUnit *phbbmu;
466844f05562SScott Long 		struct CommandControlBlock *freesrb;
466944f05562SScott Long 		u_int32_t rid[]={ PCIR_BAR(0), PCIR_BAR(2) };
467044f05562SScott Long 		vm_offset_t	mem_base[]={0,0};
467144f05562SScott Long 		for(i=0; i < 2; i++) {
4672fc5ef1caSXin LI 			acb->sys_res_arcmsr[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid[i], RF_ACTIVE);
467344f05562SScott Long 			if(acb->sys_res_arcmsr[i] == NULL) {
467444f05562SScott Long 				arcmsr_free_resource(acb);
4675d74001adSXin LI 				printf("arcmsr%d: bus_alloc_resource %d failure!\n", device_get_unit(dev), i);
467644f05562SScott Long 				return ENOMEM;
467744f05562SScott Long 			}
467844f05562SScott Long 			if(rman_get_start(acb->sys_res_arcmsr[i]) <= 0) {
467944f05562SScott Long 				arcmsr_free_resource(acb);
4680d74001adSXin LI 				printf("arcmsr%d: rman_get_start %d failure!\n", device_get_unit(dev), i);
468144f05562SScott Long 				return ENXIO;
468244f05562SScott Long 			}
468344f05562SScott Long 			mem_base[i] = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[i]);
468444f05562SScott Long 			if(mem_base[i] == 0) {
468544f05562SScott Long 				arcmsr_free_resource(acb);
4686d74001adSXin LI 				printf("arcmsr%d: rman_get_virtual %d failure!\n", device_get_unit(dev), i);
468744f05562SScott Long 				return ENXIO;
468844f05562SScott Long 			}
468944f05562SScott Long 			acb->btag[i] = rman_get_bustag(acb->sys_res_arcmsr[i]);
469044f05562SScott Long 			acb->bhandle[i] = rman_get_bushandle(acb->sys_res_arcmsr[i]);
469144f05562SScott Long 		}
469244f05562SScott Long 		freesrb = (struct CommandControlBlock *)acb->uncacheptr;
469322f2616bSXin LI 		acb->pmu = (struct MessageUnit_UNION *)((unsigned long)freesrb+ARCMSR_SRBS_POOL_SIZE);
469444f05562SScott Long 		phbbmu = (struct HBB_MessageUnit *)acb->pmu;
469544f05562SScott Long 		phbbmu->hbb_doorbell = (struct HBB_DOORBELL *)mem_base[0];
469644f05562SScott Long 		phbbmu->hbb_rwbuffer = (struct HBB_RWBUFFER *)mem_base[1];
4697b23a1998SXin LI 		if (vendor_dev_id == PCIDevVenIDARC1203) {
4698b23a1998SXin LI 			phbbmu->drv2iop_doorbell = offsetof(struct HBB_DOORBELL_1203, drv2iop_doorbell);
4699b23a1998SXin LI 			phbbmu->drv2iop_doorbell_mask = offsetof(struct HBB_DOORBELL_1203, drv2iop_doorbell_mask);
4700b23a1998SXin LI 			phbbmu->iop2drv_doorbell = offsetof(struct HBB_DOORBELL_1203, iop2drv_doorbell);
4701b23a1998SXin LI 			phbbmu->iop2drv_doorbell_mask = offsetof(struct HBB_DOORBELL_1203, iop2drv_doorbell_mask);
4702b23a1998SXin LI 		} else {
4703b23a1998SXin LI 			phbbmu->drv2iop_doorbell = offsetof(struct HBB_DOORBELL, drv2iop_doorbell);
4704b23a1998SXin LI 			phbbmu->drv2iop_doorbell_mask = offsetof(struct HBB_DOORBELL, drv2iop_doorbell_mask);
4705b23a1998SXin LI 			phbbmu->iop2drv_doorbell = offsetof(struct HBB_DOORBELL, iop2drv_doorbell);
4706b23a1998SXin LI 			phbbmu->iop2drv_doorbell_mask = offsetof(struct HBB_DOORBELL, iop2drv_doorbell_mask);
4707b23a1998SXin LI 		}
4708fc5ef1caSXin LI 		acb->rid[0] = rid[0];
4709fc5ef1caSXin LI 		acb->rid[1] = rid[1];
471044f05562SScott Long 		}
471144f05562SScott Long 		break;
4712d74001adSXin LI 	case ACB_ADAPTER_TYPE_C: {
4713d74001adSXin LI 		u_int32_t rid0 = PCIR_BAR(1);
4714d74001adSXin LI 		vm_offset_t	mem_base0;
4715d74001adSXin LI 
4716eff83876SJustin Hibbits 		acb->sys_res_arcmsr[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0, RF_ACTIVE);
4717d74001adSXin LI 		if(acb->sys_res_arcmsr[0] == NULL) {
4718d74001adSXin LI 			arcmsr_free_resource(acb);
4719d74001adSXin LI 			printf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev));
4720d74001adSXin LI 			return ENOMEM;
4721d74001adSXin LI 		}
4722d74001adSXin LI 		if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) {
4723d74001adSXin LI 			arcmsr_free_resource(acb);
4724d74001adSXin LI 			printf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev));
4725d74001adSXin LI 			return ENXIO;
4726d74001adSXin LI 		}
4727d74001adSXin LI 		mem_base0 = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]);
4728d74001adSXin LI 		if(mem_base0 == 0) {
4729d74001adSXin LI 			arcmsr_free_resource(acb);
4730d74001adSXin LI 			printf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev));
4731d74001adSXin LI 			return ENXIO;
4732d74001adSXin LI 		}
4733d74001adSXin LI 		acb->btag[0] = rman_get_bustag(acb->sys_res_arcmsr[0]);
4734d74001adSXin LI 		acb->bhandle[0] = rman_get_bushandle(acb->sys_res_arcmsr[0]);
4735d74001adSXin LI 		acb->pmu = (struct MessageUnit_UNION *)mem_base0;
4736fc5ef1caSXin LI 		acb->rid[0] = rid0;
4737d74001adSXin LI 		}
4738d74001adSXin LI 		break;
47397a7bc959SXin LI 	case ACB_ADAPTER_TYPE_D: {
47407a7bc959SXin LI 		struct HBD_MessageUnit0 *phbdmu;
47417a7bc959SXin LI 		u_int32_t rid0 = PCIR_BAR(0);
47427a7bc959SXin LI 		vm_offset_t	mem_base0;
47437a7bc959SXin LI 
4744eff83876SJustin Hibbits 		acb->sys_res_arcmsr[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0, RF_ACTIVE);
47457a7bc959SXin LI 		if(acb->sys_res_arcmsr[0] == NULL) {
47467a7bc959SXin LI 			arcmsr_free_resource(acb);
47477a7bc959SXin LI 			printf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev));
47487a7bc959SXin LI 			return ENOMEM;
47497a7bc959SXin LI 		}
47507a7bc959SXin LI 		if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) {
47517a7bc959SXin LI 			arcmsr_free_resource(acb);
47527a7bc959SXin LI 			printf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev));
47537a7bc959SXin LI 			return ENXIO;
47547a7bc959SXin LI 		}
47557a7bc959SXin LI 		mem_base0 = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]);
47567a7bc959SXin LI 		if(mem_base0 == 0) {
47577a7bc959SXin LI 			arcmsr_free_resource(acb);
47587a7bc959SXin LI 			printf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev));
47597a7bc959SXin LI 			return ENXIO;
47607a7bc959SXin LI 		}
47617a7bc959SXin LI 		acb->btag[0] = rman_get_bustag(acb->sys_res_arcmsr[0]);
47627a7bc959SXin LI 		acb->bhandle[0] = rman_get_bushandle(acb->sys_res_arcmsr[0]);
47637a7bc959SXin LI 		acb->pmu = (struct MessageUnit_UNION *)((unsigned long)acb->uncacheptr+ARCMSR_SRBS_POOL_SIZE);
47647a7bc959SXin LI 		phbdmu = (struct HBD_MessageUnit0 *)acb->pmu;
47657a7bc959SXin LI 		phbdmu->phbdmu = (struct HBD_MessageUnit *)mem_base0;
4766fc5ef1caSXin LI 		acb->rid[0] = rid0;
4767a1103e04SXin LI 		}
4768a1103e04SXin LI 		break;
4769a1103e04SXin LI 	case ACB_ADAPTER_TYPE_E: {
4770a1103e04SXin LI 		u_int32_t rid0 = PCIR_BAR(1);
4771a1103e04SXin LI 		vm_offset_t	mem_base0;
4772a1103e04SXin LI 
4773fc5ef1caSXin LI 		acb->sys_res_arcmsr[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0, RF_ACTIVE);
4774a1103e04SXin LI 		if(acb->sys_res_arcmsr[0] == NULL) {
4775a1103e04SXin LI 			arcmsr_free_resource(acb);
4776a1103e04SXin LI 			printf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev));
4777a1103e04SXin LI 			return ENOMEM;
4778a1103e04SXin LI 		}
4779a1103e04SXin LI 		if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) {
4780a1103e04SXin LI 			arcmsr_free_resource(acb);
4781a1103e04SXin LI 			printf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev));
4782a1103e04SXin LI 			return ENXIO;
4783a1103e04SXin LI 		}
4784a1103e04SXin LI 		mem_base0 = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]);
4785a1103e04SXin LI 		if(mem_base0 == 0) {
4786a1103e04SXin LI 			arcmsr_free_resource(acb);
4787a1103e04SXin LI 			printf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev));
4788a1103e04SXin LI 			return ENXIO;
4789a1103e04SXin LI 		}
4790a1103e04SXin LI 		acb->btag[0] = rman_get_bustag(acb->sys_res_arcmsr[0]);
4791a1103e04SXin LI 		acb->bhandle[0] = rman_get_bushandle(acb->sys_res_arcmsr[0]);
4792a1103e04SXin LI 		acb->pmu = (struct MessageUnit_UNION *)mem_base0;
4793a1103e04SXin LI 		acb->doneq_index = 0;
4794a1103e04SXin LI 		acb->in_doorbell = 0;
4795a1103e04SXin LI 		acb->out_doorbell = 0;
4796fc5ef1caSXin LI 		acb->rid[0] = rid0;
4797a1103e04SXin LI 		CHIP_REG_WRITE32(HBE_MessageUnit, 0, host_int_status, 0); /*clear interrupt*/
4798a1103e04SXin LI 		CHIP_REG_WRITE32(HBE_MessageUnit, 0, iobound_doorbell, ARCMSR_HBEMU_DOORBELL_SYNC); /* synchronize doorbell to 0 */
47997a7bc959SXin LI 		}
48007a7bc959SXin LI 		break;
4801fa42a0bfSXin LI 	case ACB_ADAPTER_TYPE_F: {
4802fa42a0bfSXin LI 		u_int32_t rid0 = PCIR_BAR(0);
4803fa42a0bfSXin LI 		vm_offset_t	mem_base0;
4804fa42a0bfSXin LI 		unsigned long	host_buffer_dma;
4805fa42a0bfSXin LI 
4806fa42a0bfSXin LI 		acb->sys_res_arcmsr[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0, RF_ACTIVE);
4807fa42a0bfSXin LI 		if(acb->sys_res_arcmsr[0] == NULL) {
4808fa42a0bfSXin LI 			arcmsr_free_resource(acb);
4809fa42a0bfSXin LI 			printf("arcmsr%d: bus_alloc_resource failure!\n", device_get_unit(dev));
4810fa42a0bfSXin LI 			return ENOMEM;
4811fa42a0bfSXin LI 		}
4812fa42a0bfSXin LI 		if(rman_get_start(acb->sys_res_arcmsr[0]) <= 0) {
4813fa42a0bfSXin LI 			arcmsr_free_resource(acb);
4814fa42a0bfSXin LI 			printf("arcmsr%d: rman_get_start failure!\n", device_get_unit(dev));
4815fa42a0bfSXin LI 			return ENXIO;
4816fa42a0bfSXin LI 		}
4817fa42a0bfSXin LI 		mem_base0 = (vm_offset_t) rman_get_virtual(acb->sys_res_arcmsr[0]);
4818fa42a0bfSXin LI 		if(mem_base0 == 0) {
4819fa42a0bfSXin LI 			arcmsr_free_resource(acb);
4820fa42a0bfSXin LI 			printf("arcmsr%d: rman_get_virtual failure!\n", device_get_unit(dev));
4821fa42a0bfSXin LI 			return ENXIO;
4822fa42a0bfSXin LI 		}
4823fa42a0bfSXin LI 		acb->btag[0] = rman_get_bustag(acb->sys_res_arcmsr[0]);
4824fa42a0bfSXin LI 		acb->bhandle[0] = rman_get_bushandle(acb->sys_res_arcmsr[0]);
4825fa42a0bfSXin LI 		acb->pmu = (struct MessageUnit_UNION *)mem_base0;
4826fa42a0bfSXin LI 		acb->doneq_index = 0;
4827fa42a0bfSXin LI 		acb->in_doorbell = 0;
4828fa42a0bfSXin LI 		acb->out_doorbell = 0;
4829fa42a0bfSXin LI 		acb->rid[0] = rid0;
4830fa42a0bfSXin LI 		arcmsr_wait_firmware_ready(acb);
4831fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, host_int_status, 0); /*clear interrupt*/
4832fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, iobound_doorbell, ARCMSR_HBEMU_DOORBELL_SYNC); /* synchronize doorbell to 0 */
4833fa42a0bfSXin LI 		host_buffer_dma = acb->completeQ_phys + COMPLETION_Q_POOL_SIZE;
4834fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_msgaddr0, (u_int32_t)(host_buffer_dma | 1));  /* host buffer low addr, bit0:1 all buffer active */
4835fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, inbound_msgaddr1, (u_int32_t)((host_buffer_dma >> 16) >> 16));/* host buffer high addr */
4836fa42a0bfSXin LI 		CHIP_REG_WRITE32(HBF_MessageUnit, 0, iobound_doorbell, ARCMSR_HBFMU_DOORBELL_SYNC1);       /* set host buffer physical address */
4837fa42a0bfSXin LI 		}
4838fa42a0bfSXin LI 		break;
483944f05562SScott Long 	}
4840ad6d6297SScott Long 	if(acb->acb_flags & ACB_F_MAPFREESRB_FAILD) {
4841ad6d6297SScott Long 		arcmsr_free_resource(acb);
484244f05562SScott Long 		printf("arcmsr%d: map free srb failure!\n", device_get_unit(dev));
4843f1c579b1SScott Long 		return ENXIO;
4844f1c579b1SScott Long 	}
4845d74001adSXin LI 	acb->acb_flags  |= (ACB_F_MESSAGE_WQBUFFER_CLEARED|ACB_F_MESSAGE_RQBUFFER_CLEARED|ACB_F_MESSAGE_WQBUFFER_READ);
4846ad6d6297SScott Long 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
4847ad6d6297SScott Long 	/*
4848ad6d6297SScott Long 	********************************************************************
4849ad6d6297SScott Long 	** init raid volume state
4850ad6d6297SScott Long 	********************************************************************
4851ad6d6297SScott Long 	*/
4852ad6d6297SScott Long 	for(i=0; i < ARCMSR_MAX_TARGETID; i++) {
4853ad6d6297SScott Long 		for(j=0; j < ARCMSR_MAX_TARGETLUN; j++) {
485444f05562SScott Long 			acb->devstate[i][j] = ARECA_RAID_GONE;
4855ad6d6297SScott Long 		}
4856ad6d6297SScott Long 	}
4857ad6d6297SScott Long 	arcmsr_iop_init(acb);
4858f1c579b1SScott Long 	return(0);
4859f1c579b1SScott Long }
4860a1103e04SXin LI 
4861a1103e04SXin LI static int arcmsr_setup_msix(struct AdapterControlBlock *acb)
4862a1103e04SXin LI {
4863a1103e04SXin LI 	int i;
4864a1103e04SXin LI 
4865a1103e04SXin LI 	for (i = 0; i < acb->msix_vectors; i++) {
4866fc5ef1caSXin LI 		acb->irq_id[i] = 1 + i;
4867a1103e04SXin LI 		acb->irqres[i] = bus_alloc_resource_any(acb->pci_dev,
4868a1103e04SXin LI 		    SYS_RES_IRQ, &acb->irq_id[i], RF_ACTIVE);
4869a1103e04SXin LI 		if (acb->irqres[i] == NULL) {
4870a1103e04SXin LI 			printf("arcmsr: Can't allocate MSI-X resource\n");
4871a1103e04SXin LI 			goto irq_alloc_failed;
4872a1103e04SXin LI 		}
4873a1103e04SXin LI 		if (bus_setup_intr(acb->pci_dev, acb->irqres[i],
4874a1103e04SXin LI 		    INTR_MPSAFE | INTR_TYPE_CAM, NULL, arcmsr_intr_handler,
4875a1103e04SXin LI 		    acb, &acb->ih[i])) {
4876a1103e04SXin LI 			printf("arcmsr: Cannot set up MSI-X interrupt handler\n");
4877a1103e04SXin LI 			goto irq_alloc_failed;
4878a1103e04SXin LI 		}
4879a1103e04SXin LI 	}
4880a1103e04SXin LI 	printf("arcmsr: MSI-X INT enabled\n");
4881a1103e04SXin LI 	acb->acb_flags |= ACB_F_MSIX_ENABLED;
4882a1103e04SXin LI 	return TRUE;
4883a1103e04SXin LI 
4884a1103e04SXin LI irq_alloc_failed:
4885a1103e04SXin LI 	arcmsr_teardown_intr(acb->pci_dev, acb);
4886a1103e04SXin LI 	return FALSE;
4887a1103e04SXin LI }
4888a1103e04SXin LI 
4889f1c579b1SScott Long /*
4890f1c579b1SScott Long ************************************************************************
4891f1c579b1SScott Long ************************************************************************
4892f1c579b1SScott Long */
4893f2aa0e9fSWarner Losh static int arcmsr_attach(device_t dev)
4894f1c579b1SScott Long {
4895ad6d6297SScott Long 	struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev);
4896ad6d6297SScott Long 	u_int32_t unit=device_get_unit(dev);
4897f1c579b1SScott Long 	struct ccb_setasync csa;
4898f1c579b1SScott Long 	struct cam_devq	*devq;	/* Device Queue to use for this SIM */
4899f1c579b1SScott Long 	struct resource	*irqres;
4900f1c579b1SScott Long 
4901ad6d6297SScott Long 	if(acb == NULL) {
4902ad6d6297SScott Long 		printf("arcmsr%d: cannot allocate softc\n", unit);
4903ad6d6297SScott Long 		return (ENOMEM);
4904ad6d6297SScott Long 	}
49057a7bc959SXin LI 	arcmsr_mutex_init(acb);
49061e7d660aSXin LI 	acb->pci_dev = dev;
49071e7d660aSXin LI 	acb->pci_unit = unit;
4908ad6d6297SScott Long 	if(arcmsr_initialize(dev)) {
4909ad6d6297SScott Long 		printf("arcmsr%d: initialize failure!\n", unit);
4910a1103e04SXin LI 		goto initialize_failed;
4911f1c579b1SScott Long 	}
4912f1c579b1SScott Long 	/* After setting up the adapter, map our interrupt */
4913a1103e04SXin LI 	acb->msix_vectors = ARCMSR_NUM_MSIX_VECTORS;
4914a1103e04SXin LI 	if (pci_alloc_msix(dev, &acb->msix_vectors) == 0) {
4915a1103e04SXin LI 		if (arcmsr_setup_msix(acb) == TRUE)
4916a1103e04SXin LI 			goto irqx;
4917a1103e04SXin LI 	}
4918fc5ef1caSXin LI 	acb->irq_id[0] = 0;
4919a1103e04SXin LI 	irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &acb->irq_id[0], RF_SHAREABLE | RF_ACTIVE);
4920ad6d6297SScott Long 	if(irqres == NULL ||
4921a1103e04SXin LI 		bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE, NULL, arcmsr_intr_handler, acb, &acb->ih[0])) {
4922f1c579b1SScott Long 		printf("arcmsr%d: unable to register interrupt handler!\n", unit);
4923a1103e04SXin LI 		goto setup_intr_failed;
4924f1c579b1SScott Long 	}
4925a1103e04SXin LI 	acb->irqres[0] = irqres;
4926a1103e04SXin LI irqx:
4927f1c579b1SScott Long 	/*
4928f1c579b1SScott Long 	 * Now let the CAM generic SCSI layer find the SCSI devices on
4929f1c579b1SScott Long 	 * the bus *  start queue to reset to the idle loop. *
4930f1c579b1SScott Long 	 * Create device queue of SIM(s) *  (MAX_START_JOB - 1) :
4931f1c579b1SScott Long 	 * max_sim_transactions
4932f1c579b1SScott Long 	*/
4933224a78aeSXin LI 	devq = cam_simq_alloc(acb->maxOutstanding);
4934ad6d6297SScott Long 	if(devq == NULL) {
4935ad6d6297SScott Long 		printf("arcmsr%d: cam_simq_alloc failure!\n", unit);
4936a1103e04SXin LI 		goto simq_alloc_failed;
4937f1c579b1SScott Long 	}
49387a7bc959SXin LI 	acb->psim = cam_sim_alloc(arcmsr_action, arcmsr_poll, "arcmsr", acb, unit, &acb->isr_lock, 1, ARCMSR_MAX_OUTSTANDING_CMD, devq);
4939ad6d6297SScott Long 	if(acb->psim == NULL) {
4940ad6d6297SScott Long 		printf("arcmsr%d: cam_sim_alloc failure!\n", unit);
4941a1103e04SXin LI 		goto sim_alloc_failed;
4942f1c579b1SScott Long 	}
49437a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
4944b50569b7SScott Long 	if(xpt_bus_register(acb->psim, dev, 0) != CAM_SUCCESS) {
4945ad6d6297SScott Long 		printf("arcmsr%d: xpt_bus_register failure!\n", unit);
4946a1103e04SXin LI 		goto xpt_bus_failed;
4947f1c579b1SScott Long 	}
4948d74001adSXin LI 	if(xpt_create_path(&acb->ppath, /* periph */ NULL, cam_sim_path(acb->psim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
4949ad6d6297SScott Long 		printf("arcmsr%d: xpt_create_path failure!\n", unit);
4950a1103e04SXin LI 		goto xpt_path_failed;
4951f1c579b1SScott Long 	}
4952f1c579b1SScott Long 	/*
4953f1c579b1SScott Long 	****************************************************
4954f1c579b1SScott Long 	*/
495545f57ce1SEdward Tomasz Napierala 	memset(&csa, 0, sizeof(csa));
4956ad6d6297SScott Long 	xpt_setup_ccb(&csa.ccb_h, acb->ppath, /*priority*/5);
4957f1c579b1SScott Long 	csa.ccb_h.func_code = XPT_SASYNC_CB;
4958f1c579b1SScott Long 	csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
4959f1c579b1SScott Long 	csa.callback = arcmsr_async;
4960ad6d6297SScott Long 	csa.callback_arg = acb->psim;
4961f1c579b1SScott Long 	xpt_action((union ccb *)&csa);
49627a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->isr_lock);
4963f1c579b1SScott Long 	/* Create the control device.  */
4964d74001adSXin LI 	acb->ioctl_dev = make_dev(&arcmsr_cdevsw, unit, UID_ROOT, GID_WHEEL /* GID_OPERATOR */, S_IRUSR | S_IWUSR, "arcmsr%d", unit);
4965d74001adSXin LI 
4966ad6d6297SScott Long 	(void)make_dev_alias(acb->ioctl_dev, "arc%d", unit);
496722f2616bSXin LI 	arcmsr_callout_init(&acb->devmap_callout);
4968d74001adSXin LI 	callout_reset(&acb->devmap_callout, 60 * hz, arcmsr_polling_devmap, acb);
4969dac36688SXin LI 	return (0);
4970a1103e04SXin LI xpt_path_failed:
4971a1103e04SXin LI 	xpt_bus_deregister(cam_sim_path(acb->psim));
4972a1103e04SXin LI xpt_bus_failed:
4973a1103e04SXin LI 	cam_sim_free(acb->psim, /* free_simq */ TRUE);
4974a1103e04SXin LI sim_alloc_failed:
4975a1103e04SXin LI 	cam_simq_free(devq);
4976a1103e04SXin LI simq_alloc_failed:
4977a1103e04SXin LI 	arcmsr_teardown_intr(dev, acb);
4978a1103e04SXin LI setup_intr_failed:
4979a1103e04SXin LI 	arcmsr_free_resource(acb);
4980a1103e04SXin LI initialize_failed:
4981a1103e04SXin LI 	arcmsr_mutex_destroy(acb);
4982a1103e04SXin LI 	return ENXIO;
4983f1c579b1SScott Long }
498422f2616bSXin LI 
4985f1c579b1SScott Long /*
4986f1c579b1SScott Long ************************************************************************
4987f1c579b1SScott Long ************************************************************************
4988f1c579b1SScott Long */
4989f2aa0e9fSWarner Losh static int arcmsr_probe(device_t dev)
4990f1c579b1SScott Long {
4991ad6d6297SScott Long 	u_int32_t id;
4992224a78aeSXin LI 	u_int16_t sub_device_id;
4993ad6d6297SScott Long 	static char buf[256];
49941e7d660aSXin LI 	char x_type[]={"unknown"};
4995ad6d6297SScott Long 	char *type;
4996ad6d6297SScott Long 	int raid6 = 1;
4997ad6d6297SScott Long 
4998ad6d6297SScott Long 	if (pci_get_vendor(dev) != PCI_VENDOR_ID_ARECA) {
4999ad6d6297SScott Long 		return (ENXIO);
5000ad6d6297SScott Long 	}
5001224a78aeSXin LI 	sub_device_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
5002ad6d6297SScott Long 	switch(id = pci_get_devid(dev)) {
5003f1c579b1SScott Long 	case PCIDevVenIDARC1110:
5004231c8b71SXin LI 	case PCIDevVenIDARC1200:
500544f05562SScott Long 	case PCIDevVenIDARC1201:
5006231c8b71SXin LI 	case PCIDevVenIDARC1210:
5007ad6d6297SScott Long 		raid6 = 0;
5008ad6d6297SScott Long 		/*FALLTHRU*/
5009ad6d6297SScott Long 	case PCIDevVenIDARC1120:
5010ad6d6297SScott Long 	case PCIDevVenIDARC1130:
5011ad6d6297SScott Long 	case PCIDevVenIDARC1160:
5012ad6d6297SScott Long 	case PCIDevVenIDARC1170:
5013f1c579b1SScott Long 	case PCIDevVenIDARC1220:
5014f1c579b1SScott Long 	case PCIDevVenIDARC1230:
5015231c8b71SXin LI 	case PCIDevVenIDARC1231:
5016f1c579b1SScott Long 	case PCIDevVenIDARC1260:
5017231c8b71SXin LI 	case PCIDevVenIDARC1261:
5018ad6d6297SScott Long 	case PCIDevVenIDARC1270:
5019ad6d6297SScott Long 	case PCIDevVenIDARC1280:
50207a7bc959SXin LI 		type = "SATA 3G";
5021ad6d6297SScott Long 		break;
5022d74001adSXin LI 	case PCIDevVenIDARC1212:
5023d74001adSXin LI 	case PCIDevVenIDARC1222:
5024ad6d6297SScott Long 	case PCIDevVenIDARC1380:
5025ad6d6297SScott Long 	case PCIDevVenIDARC1381:
5026ad6d6297SScott Long 	case PCIDevVenIDARC1680:
5027ad6d6297SScott Long 	case PCIDevVenIDARC1681:
5028d74001adSXin LI 		type = "SAS 3G";
5029d74001adSXin LI 		break;
5030d74001adSXin LI 	case PCIDevVenIDARC1880:
5031dac36688SXin LI 	case PCIDevVenIDARC1882:
5032dac36688SXin LI 	case PCIDevVenIDARC1213:
5033dac36688SXin LI 	case PCIDevVenIDARC1223:
5034fc5ef1caSXin LI 		if ((sub_device_id == ARECA_SUB_DEV_ID_1883) ||
5035fc5ef1caSXin LI 		    (sub_device_id == ARECA_SUB_DEV_ID_1216) ||
5036fc5ef1caSXin LI 		    (sub_device_id == ARECA_SUB_DEV_ID_1226))
5037224a78aeSXin LI 			type = "SAS 12G";
5038224a78aeSXin LI 		else
5039d74001adSXin LI 			type = "SAS 6G";
5040ad6d6297SScott Long 		break;
5041a1103e04SXin LI 	case PCIDevVenIDARC1884:
5042a1103e04SXin LI 		type = "SAS 12G";
5043a1103e04SXin LI 		break;
5044fa42a0bfSXin LI 	case PCIDevVenIDARC1886_:
5045fa42a0bfSXin LI 	case PCIDevVenIDARC1886:
5046fa42a0bfSXin LI 		type = "NVME,SAS-12G,SATA-6G";
5047fa42a0bfSXin LI 		break;
50487a7bc959SXin LI 	case PCIDevVenIDARC1214:
5049b23a1998SXin LI 	case PCIDevVenIDARC1203:
50507a7bc959SXin LI 		type = "SATA 6G";
50517a7bc959SXin LI 		break;
5052ad6d6297SScott Long 	default:
5053231c8b71SXin LI 		type = x_type;
50541e7d660aSXin LI 		raid6 = 0;
5055ad6d6297SScott Long 		break;
5056f1c579b1SScott Long 	}
5057231c8b71SXin LI 	if(type == x_type)
5058231c8b71SXin LI 		return(ENXIO);
50591e7d660aSXin LI 	sprintf(buf, "Areca %s Host Adapter RAID Controller %s\n%s\n",
50601e7d660aSXin LI 		type, raid6 ? "(RAID6 capable)" : "", ARCMSR_DRIVER_VERSION);
5061ad6d6297SScott Long 	device_set_desc_copy(dev, buf);
506203389298SXin LI 	return (BUS_PROBE_DEFAULT);
5063f1c579b1SScott Long }
5064f1c579b1SScott Long /*
5065f1c579b1SScott Long ************************************************************************
5066f1c579b1SScott Long ************************************************************************
5067f1c579b1SScott Long */
5068f2aa0e9fSWarner Losh static int arcmsr_shutdown(device_t dev)
5069f1c579b1SScott Long {
507044f05562SScott Long 	u_int32_t  i;
5071ad6d6297SScott Long 	struct CommandControlBlock *srb;
5072ad6d6297SScott Long 	struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev);
5073f1c579b1SScott Long 
5074f1c579b1SScott Long 	/* stop adapter background rebuild */
50757a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
507644f05562SScott Long 	/* disable all outbound interrupt */
5077*bca8e8c0SScott Long 	arcmsr_disable_allintr(acb);
5078ad6d6297SScott Long 	arcmsr_stop_adapter_bgrb(acb);
5079ad6d6297SScott Long 	arcmsr_flush_adapter_cache(acb);
5080f1c579b1SScott Long 	/* abort all outstanding command */
5081ad6d6297SScott Long 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
5082ad6d6297SScott Long 	acb->acb_flags &= ~ACB_F_IOP_INITED;
5083ad6d6297SScott Long 	if(acb->srboutstandingcount != 0) {
508444f05562SScott Long 		/*clear and abort all outbound posted Q*/
508544f05562SScott Long 		arcmsr_done4abort_postqueue(acb);
508644f05562SScott Long 		/* talk to iop 331 outstanding command aborted*/
5087ad6d6297SScott Long 		arcmsr_abort_allcmd(acb);
5088ad6d6297SScott Long 		for(i=0; i < ARCMSR_MAX_FREESRB_NUM; i++) {
5089ad6d6297SScott Long 			srb = acb->psrb_pool[i];
509022f2616bSXin LI 			if(srb->srb_state == ARCMSR_SRB_START) {
509122f2616bSXin LI 				srb->srb_state = ARCMSR_SRB_ABORTED;
5092ad6d6297SScott Long 				srb->pccb->ccb_h.status |= CAM_REQ_ABORTED;
5093ad6d6297SScott Long 				arcmsr_srb_complete(srb, 1);
5094f1c579b1SScott Long 			}
5095f1c579b1SScott Long 		}
5096f1c579b1SScott Long 	}
509722f2616bSXin LI 	acb->srboutstandingcount = 0;
5098ad6d6297SScott Long 	acb->workingsrb_doneindex = 0;
5099ad6d6297SScott Long 	acb->workingsrb_startindex = 0;
510022f2616bSXin LI 	acb->pktRequestCount = 0;
510122f2616bSXin LI 	acb->pktReturnCount = 0;
51027a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->isr_lock);
5103f2aa0e9fSWarner Losh 	return (0);
5104f1c579b1SScott Long }
5105f1c579b1SScott Long /*
5106f1c579b1SScott Long ************************************************************************
5107f1c579b1SScott Long ************************************************************************
5108f1c579b1SScott Long */
5109fc5ef1caSXin LI static void arcmsr_teardown_intr(device_t dev, struct AdapterControlBlock *acb)
5110a1103e04SXin LI {
5111a1103e04SXin LI 	int i;
5112a1103e04SXin LI 
5113a1103e04SXin LI 	if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
5114a1103e04SXin LI 		for (i = 0; i < acb->msix_vectors; i++) {
5115a1103e04SXin LI 			if (acb->ih[i])
5116a1103e04SXin LI 				bus_teardown_intr(dev, acb->irqres[i], acb->ih[i]);
5117a1103e04SXin LI 			if (acb->irqres[i] != NULL)
5118a1103e04SXin LI 				bus_release_resource(dev, SYS_RES_IRQ,
5119a1103e04SXin LI 				    acb->irq_id[i], acb->irqres[i]);
5120a1103e04SXin LI 
5121a1103e04SXin LI 			acb->ih[i] = NULL;
5122a1103e04SXin LI 		}
5123a1103e04SXin LI 		pci_release_msi(dev);
5124a1103e04SXin LI 	} else {
5125a1103e04SXin LI 		if (acb->ih[0])
5126a1103e04SXin LI 			bus_teardown_intr(dev, acb->irqres[0], acb->ih[0]);
5127a1103e04SXin LI 		if (acb->irqres[0] != NULL)
5128a1103e04SXin LI 			bus_release_resource(dev, SYS_RES_IRQ,
5129a1103e04SXin LI 			    acb->irq_id[0], acb->irqres[0]);
5130a1103e04SXin LI 		acb->ih[0] = NULL;
5131a1103e04SXin LI 	}
5132a1103e04SXin LI 
5133a1103e04SXin LI }
5134a1103e04SXin LI /*
5135a1103e04SXin LI ************************************************************************
5136a1103e04SXin LI ************************************************************************
5137a1103e04SXin LI */
5138f2aa0e9fSWarner Losh static int arcmsr_detach(device_t dev)
5139f1c579b1SScott Long {
5140ad6d6297SScott Long 	struct AdapterControlBlock *acb=(struct AdapterControlBlock *)device_get_softc(dev);
514144f05562SScott Long 	int i;
5142f1c579b1SScott Long 
5143d74001adSXin LI 	callout_stop(&acb->devmap_callout);
5144a1103e04SXin LI 	arcmsr_teardown_intr(dev, acb);
5145f1c579b1SScott Long 	arcmsr_shutdown(dev);
5146ad6d6297SScott Long 	arcmsr_free_resource(acb);
514744f05562SScott Long 	for(i=0; (acb->sys_res_arcmsr[i]!=NULL) && (i<2); i++) {
5148fc5ef1caSXin LI 		bus_release_resource(dev, SYS_RES_MEMORY, acb->rid[i], acb->sys_res_arcmsr[i]);
514944f05562SScott Long 	}
51507a7bc959SXin LI 	ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
5151ad6d6297SScott Long 	xpt_async(AC_LOST_DEVICE, acb->ppath, NULL);
5152ad6d6297SScott Long 	xpt_free_path(acb->ppath);
5153ad6d6297SScott Long 	xpt_bus_deregister(cam_sim_path(acb->psim));
5154ad6d6297SScott Long 	cam_sim_free(acb->psim, TRUE);
51557a7bc959SXin LI 	ARCMSR_LOCK_RELEASE(&acb->isr_lock);
51567a7bc959SXin LI 	arcmsr_mutex_destroy(acb);
5157f1c579b1SScott Long 	return (0);
5158f1c579b1SScott Long }
5159f1c579b1SScott Long 
516022f2616bSXin LI #ifdef ARCMSR_DEBUG1
516122f2616bSXin LI static void arcmsr_dump_data(struct AdapterControlBlock *acb)
516222f2616bSXin LI {
516322f2616bSXin LI 	if((acb->pktRequestCount - acb->pktReturnCount) == 0)
516422f2616bSXin LI 		return;
516522f2616bSXin LI 	printf("Command Request Count   =0x%x\n",acb->pktRequestCount);
516622f2616bSXin LI 	printf("Command Return Count    =0x%x\n",acb->pktReturnCount);
516722f2616bSXin LI 	printf("Command (Req-Rtn) Count =0x%x\n",(acb->pktRequestCount - acb->pktReturnCount));
516822f2616bSXin LI 	printf("Queued Command Count    =0x%x\n",acb->srboutstandingcount);
516922f2616bSXin LI }
517022f2616bSXin LI #endif
5171