hptiop.c revision 236379
1169412Sscottl/*
2175942Sscottl * HighPoint RR3xxx/4xxx RAID Driver for FreeBSD
3175942Sscottl * Copyright (C) 2007-2008 HighPoint Technologies, Inc. All Rights Reserved.
4175942Sscottl *
5169412Sscottl * Redistribution and use in source and binary forms, with or without
6169412Sscottl * modification, are permitted provided that the following conditions
7169412Sscottl * are met:
8169412Sscottl * 1. Redistributions of source code must retain the above copyright
9169412Sscottl *    notice, this list of conditions and the following disclaimer.
10169412Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11169412Sscottl *    notice, this list of conditions and the following disclaimer in the
12169412Sscottl *    documentation and/or other materials provided with the distribution.
13169412Sscottl *
14169412Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15169412Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16169412Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17169412Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18169412Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169412Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20169412Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21169412Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22169412Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169412Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24169412Sscottl * SUCH DAMAGE.
25169412Sscottl */
26175942Sscottl
27169412Sscottl#include <sys/cdefs.h>
28169412Sscottl__FBSDID("$FreeBSD: head/sys/dev/hptiop/hptiop.c 236379 2012-06-01 04:34:49Z eadler $");
29169412Sscottl
30169412Sscottl#include <sys/param.h>
31169412Sscottl#include <sys/types.h>
32169412Sscottl#include <sys/cons.h>
33169412Sscottl#if (__FreeBSD_version >= 500000)
34169412Sscottl#include <sys/time.h>
35169412Sscottl#include <sys/systm.h>
36169412Sscottl#else
37169412Sscottl#include <machine/clock.h>
38169412Sscottl#endif
39169412Sscottl
40169412Sscottl#include <sys/stat.h>
41169412Sscottl#include <sys/malloc.h>
42169412Sscottl#include <sys/conf.h>
43169412Sscottl#include <sys/libkern.h>
44169412Sscottl#include <sys/kernel.h>
45169412Sscottl
46169412Sscottl#if (__FreeBSD_version >= 500000)
47169412Sscottl#include <sys/kthread.h>
48169412Sscottl#include <sys/mutex.h>
49169412Sscottl#include <sys/module.h>
50169412Sscottl#endif
51169412Sscottl
52169412Sscottl#include <sys/eventhandler.h>
53169412Sscottl#include <sys/bus.h>
54169412Sscottl#include <sys/taskqueue.h>
55169412Sscottl#include <sys/ioccom.h>
56169412Sscottl
57169412Sscottl#include <machine/resource.h>
58169412Sscottl#include <machine/bus.h>
59169412Sscottl#include <machine/stdarg.h>
60169412Sscottl#include <sys/rman.h>
61169412Sscottl
62169412Sscottl#include <vm/vm.h>
63169412Sscottl#include <vm/pmap.h>
64169412Sscottl
65169412Sscottl#if (__FreeBSD_version >= 500000)
66169412Sscottl#include <dev/pci/pcireg.h>
67169412Sscottl#include <dev/pci/pcivar.h>
68169412Sscottl#else
69169412Sscottl#include <pci/pcivar.h>
70169412Sscottl#include <pci/pcireg.h>
71169412Sscottl#endif
72169412Sscottl
73169412Sscottl#if (__FreeBSD_version <= 500043)
74169412Sscottl#include <sys/devicestat.h>
75169412Sscottl#endif
76169412Sscottl
77169412Sscottl#include <cam/cam.h>
78169412Sscottl#include <cam/cam_ccb.h>
79169412Sscottl#include <cam/cam_sim.h>
80169412Sscottl#include <cam/cam_xpt_sim.h>
81169412Sscottl#include <cam/cam_debug.h>
82169412Sscottl#include <cam/cam_periph.h>
83169412Sscottl#include <cam/scsi/scsi_all.h>
84169412Sscottl#include <cam/scsi/scsi_message.h>
85169412Sscottl
86169412Sscottl#if (__FreeBSD_version < 500043)
87169412Sscottl#include <sys/bus_private.h>
88169412Sscottl#endif
89169412Sscottl
90169412Sscottl#include <dev/hptiop/hptiop.h>
91169412Sscottl
92169412Sscottlstatic char driver_name[] = "hptiop";
93175942Sscottlstatic char driver_version[] = "v1.3 (010208)";
94169412Sscottl
95169412Sscottlstatic devclass_t hptiop_devclass;
96169412Sscottl
97175942Sscottlstatic int hptiop_send_sync_msg(struct hpt_iop_hba *hba,
98175942Sscottl				u_int32_t msg, u_int32_t millisec);
99175942Sscottlstatic void hptiop_request_callback_itl(struct hpt_iop_hba *hba,
100175942Sscottl							u_int32_t req);
101175942Sscottlstatic void hptiop_request_callback_mv(struct hpt_iop_hba *hba, u_int64_t req);
102175942Sscottlstatic void hptiop_os_message_callback(struct hpt_iop_hba *hba, u_int32_t msg);
103175942Sscottlstatic int  hptiop_do_ioctl_itl(struct hpt_iop_hba *hba,
104175942Sscottl				struct hpt_iop_ioctl_param *pParams);
105175942Sscottlstatic int  hptiop_do_ioctl_mv(struct hpt_iop_hba *hba,
106175942Sscottl				struct hpt_iop_ioctl_param *pParams);
107175942Sscottlstatic int  hptiop_rescan_bus(struct hpt_iop_hba *hba);
108175942Sscottlstatic int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba);
109175942Sscottlstatic int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba);
110175942Sscottlstatic int hptiop_get_config_itl(struct hpt_iop_hba *hba,
111175942Sscottl				struct hpt_iop_request_get_config *config);
112175942Sscottlstatic int hptiop_get_config_mv(struct hpt_iop_hba *hba,
113175942Sscottl				struct hpt_iop_request_get_config *config);
114175942Sscottlstatic int hptiop_set_config_itl(struct hpt_iop_hba *hba,
115175942Sscottl				struct hpt_iop_request_set_config *config);
116175942Sscottlstatic int hptiop_set_config_mv(struct hpt_iop_hba *hba,
117175942Sscottl				struct hpt_iop_request_set_config *config);
118175942Sscottlstatic int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba);
119175942Sscottlstatic int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba);
120175942Sscottlstatic int  hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba,
121175942Sscottl			u_int32_t req32, struct hpt_iop_ioctl_param *pParams);
122175942Sscottlstatic int  hptiop_post_ioctl_command_mv(struct hpt_iop_hba *hba,
123175942Sscottl				struct hpt_iop_request_ioctl_command *req,
124175942Sscottl				struct hpt_iop_ioctl_param *pParams);
125175942Sscottlstatic void hptiop_post_req_itl(struct hpt_iop_hba *hba,
126175942Sscottl				struct hpt_iop_srb *srb,
127175942Sscottl				bus_dma_segment_t *segs, int nsegs);
128175942Sscottlstatic void hptiop_post_req_mv(struct hpt_iop_hba *hba,
129175942Sscottl				struct hpt_iop_srb *srb,
130175942Sscottl				bus_dma_segment_t *segs, int nsegs);
131175942Sscottlstatic void hptiop_post_msg_itl(struct hpt_iop_hba *hba, u_int32_t msg);
132175942Sscottlstatic void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg);
133175942Sscottlstatic void hptiop_enable_intr_itl(struct hpt_iop_hba *hba);
134175942Sscottlstatic void hptiop_enable_intr_mv(struct hpt_iop_hba *hba);
135175942Sscottlstatic void hptiop_disable_intr_itl(struct hpt_iop_hba *hba);
136175942Sscottlstatic void hptiop_disable_intr_mv(struct hpt_iop_hba *hba);
137175942Sscottlstatic void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb);
138175942Sscottlstatic int  hptiop_os_query_remove_device(struct hpt_iop_hba *hba, int tid);
139169412Sscottlstatic int  hptiop_probe(device_t dev);
140169412Sscottlstatic int  hptiop_attach(device_t dev);
141169412Sscottlstatic int  hptiop_detach(device_t dev);
142169412Sscottlstatic int  hptiop_shutdown(device_t dev);
143169412Sscottlstatic void hptiop_action(struct cam_sim *sim, union ccb *ccb);
144169412Sscottlstatic void hptiop_poll(struct cam_sim *sim);
145175942Sscottlstatic void hptiop_async(void *callback_arg, u_int32_t code,
146175942Sscottl					struct cam_path *path, void *arg);
147169412Sscottlstatic void hptiop_pci_intr(void *arg);
148175942Sscottlstatic void hptiop_release_resource(struct hpt_iop_hba *hba);
149175942Sscottlstatic int  hptiop_reset_adapter(struct hpt_iop_hba *hba);
150169412Sscottl
151169412Sscottlstatic d_open_t hptiop_open;
152169412Sscottlstatic d_close_t hptiop_close;
153169412Sscottlstatic d_ioctl_t hptiop_ioctl;
154169412Sscottl
155169412Sscottlstatic struct cdevsw hptiop_cdevsw = {
156169412Sscottl	.d_open = hptiop_open,
157169412Sscottl	.d_close = hptiop_close,
158169412Sscottl	.d_ioctl = hptiop_ioctl,
159169412Sscottl	.d_name = driver_name,
160169412Sscottl#if __FreeBSD_version>=503000
161169412Sscottl	.d_version = D_VERSION,
162169412Sscottl#endif
163169412Sscottl#if (__FreeBSD_version>=503000 && __FreeBSD_version<600034)
164169412Sscottl	.d_flags = D_NEEDGIANT,
165169412Sscottl#endif
166169412Sscottl#if __FreeBSD_version<600034
167169412Sscottl#if __FreeBSD_version>=501000
168169412Sscottl	.d_maj = MAJOR_AUTO,
169169412Sscottl#else
170169412Sscottl	.d_maj = HPT_DEV_MAJOR,
171169412Sscottl#endif
172169412Sscottl#endif
173169412Sscottl};
174169412Sscottl
175169412Sscottl#if __FreeBSD_version < 503000
176169412Sscottl#define hba_from_dev(dev) ((struct hpt_iop_hba *)(dev)->si_drv1)
177169412Sscottl#else
178169412Sscottl#define hba_from_dev(dev) \
179183397Sed	((struct hpt_iop_hba *)devclass_get_softc(hptiop_devclass, dev2unit(dev)))
180169412Sscottl#endif
181169412Sscottl
182175942Sscottl#define BUS_SPACE_WRT4_ITL(offset, value) bus_space_write_4(hba->bar0t,\
183175942Sscottl		hba->bar0h, offsetof(struct hpt_iopmu_itl, offset), (value))
184175942Sscottl#define BUS_SPACE_RD4_ITL(offset) bus_space_read_4(hba->bar0t,\
185175942Sscottl		hba->bar0h, offsetof(struct hpt_iopmu_itl, offset))
186175942Sscottl
187175942Sscottl#define BUS_SPACE_WRT4_MV0(offset, value) bus_space_write_4(hba->bar0t,\
188175942Sscottl		hba->bar0h, offsetof(struct hpt_iopmv_regs, offset), value)
189175942Sscottl#define BUS_SPACE_RD4_MV0(offset) bus_space_read_4(hba->bar0t,\
190175942Sscottl		hba->bar0h, offsetof(struct hpt_iopmv_regs, offset))
191175942Sscottl#define BUS_SPACE_WRT4_MV2(offset, value) bus_space_write_4(hba->bar2t,\
192175942Sscottl		hba->bar2h, offsetof(struct hpt_iopmu_mv, offset), value)
193175942Sscottl#define BUS_SPACE_RD4_MV2(offset) bus_space_read_4(hba->bar2t,\
194175942Sscottl		hba->bar2h, offsetof(struct hpt_iopmu_mv, offset))
195175942Sscottl
196169412Sscottlstatic int hptiop_open(ioctl_dev_t dev, int flags,
197169412Sscottl					int devtype, ioctl_thread_t proc)
198169412Sscottl{
199175942Sscottl	struct hpt_iop_hba *hba = hba_from_dev(dev);
200169412Sscottl
201169412Sscottl	if (hba==NULL)
202169412Sscottl		return ENXIO;
203169412Sscottl	if (hba->flag & HPT_IOCTL_FLAG_OPEN)
204169412Sscottl		return EBUSY;
205169412Sscottl	hba->flag |= HPT_IOCTL_FLAG_OPEN;
206169412Sscottl	return 0;
207169412Sscottl}
208169412Sscottl
209169412Sscottlstatic int hptiop_close(ioctl_dev_t dev, int flags,
210169412Sscottl					int devtype, ioctl_thread_t proc)
211169412Sscottl{
212175942Sscottl	struct hpt_iop_hba *hba = hba_from_dev(dev);
213169412Sscottl	hba->flag &= ~(u_int32_t)HPT_IOCTL_FLAG_OPEN;
214169412Sscottl	return 0;
215169412Sscottl}
216169412Sscottl
217169412Sscottlstatic int hptiop_ioctl(ioctl_dev_t dev, u_long cmd, caddr_t data,
218169412Sscottl					int flags, ioctl_thread_t proc)
219169412Sscottl{
220169412Sscottl	int ret = EFAULT;
221175942Sscottl	struct hpt_iop_hba *hba = hba_from_dev(dev);
222169412Sscottl
223169412Sscottl#if (__FreeBSD_version >= 500000)
224169412Sscottl	mtx_lock(&Giant);
225169412Sscottl#endif
226169412Sscottl
227169412Sscottl	switch (cmd) {
228169412Sscottl	case HPT_DO_IOCONTROL:
229175942Sscottl		ret = hba->ops->do_ioctl(hba,
230175942Sscottl				(struct hpt_iop_ioctl_param *)data);
231169412Sscottl		break;
232169412Sscottl	case HPT_SCAN_BUS:
233169412Sscottl		ret = hptiop_rescan_bus(hba);
234169412Sscottl		break;
235169412Sscottl	}
236169412Sscottl
237169412Sscottl#if (__FreeBSD_version >= 500000)
238169412Sscottl	mtx_unlock(&Giant);
239169412Sscottl#endif
240169412Sscottl
241169412Sscottl	return ret;
242169412Sscottl}
243169412Sscottl
244175942Sscottlstatic u_int64_t hptiop_mv_outbound_read(struct hpt_iop_hba *hba)
245169412Sscottl{
246175942Sscottl	u_int64_t p;
247175942Sscottl	u_int32_t outbound_tail = BUS_SPACE_RD4_MV2(outbound_tail);
248175942Sscottl	u_int32_t outbound_head = BUS_SPACE_RD4_MV2(outbound_head);
249175942Sscottl
250175942Sscottl	if (outbound_tail != outbound_head) {
251175942Sscottl		bus_space_read_region_4(hba->bar2t, hba->bar2h,
252175942Sscottl			offsetof(struct hpt_iopmu_mv,
253175942Sscottl				outbound_q[outbound_tail]),
254175942Sscottl			(u_int32_t *)&p, 2);
255175942Sscottl
256175942Sscottl		outbound_tail++;
257175942Sscottl
258175942Sscottl		if (outbound_tail == MVIOP_QUEUE_LEN)
259175942Sscottl			outbound_tail = 0;
260175942Sscottl
261175942Sscottl		BUS_SPACE_WRT4_MV2(outbound_tail, outbound_tail);
262175942Sscottl		return p;
263175942Sscottl	} else
264175942Sscottl		return 0;
265169412Sscottl}
266169412Sscottl
267175942Sscottlstatic void hptiop_mv_inbound_write(u_int64_t p, struct hpt_iop_hba *hba)
268169412Sscottl{
269175942Sscottl	u_int32_t inbound_head = BUS_SPACE_RD4_MV2(inbound_head);
270175942Sscottl	u_int32_t head = inbound_head + 1;
271175942Sscottl
272175942Sscottl	if (head == MVIOP_QUEUE_LEN)
273175942Sscottl		head = 0;
274175942Sscottl
275175942Sscottl	bus_space_write_region_4(hba->bar2t, hba->bar2h,
276175942Sscottl			offsetof(struct hpt_iopmu_mv, inbound_q[inbound_head]),
277175942Sscottl			(u_int32_t *)&p, 2);
278175942Sscottl	BUS_SPACE_WRT4_MV2(inbound_head, head);
279175942Sscottl	BUS_SPACE_WRT4_MV0(inbound_doorbell, MVIOP_MU_INBOUND_INT_POSTQUEUE);
280169412Sscottl}
281169412Sscottl
282175942Sscottlstatic void hptiop_post_msg_itl(struct hpt_iop_hba *hba, u_int32_t msg)
283169412Sscottl{
284175942Sscottl	BUS_SPACE_WRT4_ITL(inbound_msgaddr0, msg);
285175942Sscottl	BUS_SPACE_RD4_ITL(outbound_intstatus);
286169412Sscottl}
287169412Sscottl
288175942Sscottlstatic void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg)
289169412Sscottl{
290175942Sscottl
291175942Sscottl	BUS_SPACE_WRT4_MV2(inbound_msg, msg);
292175942Sscottl	BUS_SPACE_WRT4_MV0(inbound_doorbell, MVIOP_MU_INBOUND_INT_MSG);
293175942Sscottl
294175942Sscottl	BUS_SPACE_RD4_MV0(outbound_intmask);
295169412Sscottl}
296169412Sscottl
297175942Sscottlstatic int hptiop_wait_ready_itl(struct hpt_iop_hba * hba, u_int32_t millisec)
298169412Sscottl{
299169412Sscottl	u_int32_t req=0;
300169412Sscottl	int i;
301169412Sscottl
302169412Sscottl	for (i = 0; i < millisec; i++) {
303175942Sscottl		req = BUS_SPACE_RD4_ITL(inbound_queue);
304169412Sscottl		if (req != IOPMU_QUEUE_EMPTY)
305169412Sscottl			break;
306169412Sscottl		DELAY(1000);
307169412Sscottl	}
308169412Sscottl
309169412Sscottl	if (req!=IOPMU_QUEUE_EMPTY) {
310175942Sscottl		BUS_SPACE_WRT4_ITL(outbound_queue, req);
311175942Sscottl		BUS_SPACE_RD4_ITL(outbound_intstatus);
312169412Sscottl		return 0;
313169412Sscottl	}
314169412Sscottl
315169412Sscottl	return -1;
316169412Sscottl}
317169412Sscottl
318175942Sscottlstatic int hptiop_wait_ready_mv(struct hpt_iop_hba * hba, u_int32_t millisec)
319169412Sscottl{
320175942Sscottl	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec))
321175942Sscottl		return -1;
322175942Sscottl
323175942Sscottl	return 0;
324175942Sscottl}
325175942Sscottl
326175942Sscottlstatic void hptiop_request_callback_itl(struct hpt_iop_hba * hba,
327175942Sscottl							u_int32_t index)
328175942Sscottl{
329175942Sscottl	struct hpt_iop_srb *srb;
330175942Sscottl	struct hpt_iop_request_scsi_command *req=0;
331175942Sscottl	union ccb *ccb;
332175942Sscottl	u_int8_t *cdb;
333175942Sscottl	u_int32_t result, temp, dxfer;
334175942Sscottl	u_int64_t temp64;
335175942Sscottl
336175942Sscottl	if (index & IOPMU_QUEUE_MASK_HOST_BITS) { /*host req*/
337175942Sscottl		if (hba->firmware_version > 0x01020000 ||
338175942Sscottl			hba->interface_version > 0x01020000) {
339175942Sscottl			srb = hba->srb[index & ~(u_int32_t)
340175942Sscottl				(IOPMU_QUEUE_ADDR_HOST_BIT
341175942Sscottl				| IOPMU_QUEUE_REQUEST_RESULT_BIT)];
342175942Sscottl			req = (struct hpt_iop_request_scsi_command *)srb;
343175942Sscottl			if (index & IOPMU_QUEUE_REQUEST_RESULT_BIT)
344175942Sscottl				result = IOP_RESULT_SUCCESS;
345175942Sscottl			else
346175942Sscottl				result = req->header.result;
347175942Sscottl		} else {
348175942Sscottl			srb = hba->srb[index &
349175942Sscottl				~(u_int32_t)IOPMU_QUEUE_ADDR_HOST_BIT];
350175942Sscottl			req = (struct hpt_iop_request_scsi_command *)srb;
351175942Sscottl			result = req->header.result;
352175942Sscottl		}
353175942Sscottl		dxfer = req->dataxfer_length;
354175942Sscottl		goto srb_complete;
355175942Sscottl	}
356175942Sscottl
357175942Sscottl	/*iop req*/
358175942Sscottl	temp = bus_space_read_4(hba->bar0t, hba->bar0h, index +
359175942Sscottl		offsetof(struct hpt_iop_request_header, type));
360175942Sscottl	result = bus_space_read_4(hba->bar0t, hba->bar0h, index +
361175942Sscottl		offsetof(struct hpt_iop_request_header, result));
362175942Sscottl	switch(temp) {
363175942Sscottl	case IOP_REQUEST_TYPE_IOCTL_COMMAND:
364175942Sscottl	{
365175942Sscottl		temp64 = 0;
366175942Sscottl		bus_space_write_region_4(hba->bar0t, hba->bar0h, index +
367175942Sscottl			offsetof(struct hpt_iop_request_header, context),
368175942Sscottl			(u_int32_t *)&temp64, 2);
369175942Sscottl		wakeup((void *)((unsigned long)hba->u.itl.mu + index));
370175942Sscottl		break;
371175942Sscottl	}
372175942Sscottl
373175942Sscottl	case IOP_REQUEST_TYPE_SCSI_COMMAND:
374175942Sscottl		bus_space_read_region_4(hba->bar0t, hba->bar0h, index +
375175942Sscottl			offsetof(struct hpt_iop_request_header, context),
376175942Sscottl			(u_int32_t *)&temp64, 2);
377175942Sscottl		srb = (struct hpt_iop_srb *)(unsigned long)temp64;
378175942Sscottl		dxfer = bus_space_read_4(hba->bar0t, hba->bar0h,
379175942Sscottl				index + offsetof(struct hpt_iop_request_scsi_command,
380175942Sscottl				dataxfer_length));
381175942Sscottlsrb_complete:
382175942Sscottl		ccb = (union ccb *)srb->ccb;
383175942Sscottl		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
384175942Sscottl			cdb = ccb->csio.cdb_io.cdb_ptr;
385175942Sscottl		else
386175942Sscottl			cdb = ccb->csio.cdb_io.cdb_bytes;
387175942Sscottl
388175942Sscottl		if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */
389175942Sscottl			ccb->ccb_h.status = CAM_REQ_CMP;
390175942Sscottl			goto scsi_done;
391175942Sscottl		}
392175942Sscottl
393175942Sscottl		switch (result) {
394175942Sscottl		case IOP_RESULT_SUCCESS:
395175942Sscottl			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
396175942Sscottl			case CAM_DIR_IN:
397175942Sscottl				bus_dmamap_sync(hba->io_dmat,
398175942Sscottl					srb->dma_map, BUS_DMASYNC_POSTREAD);
399175942Sscottl				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
400175942Sscottl				break;
401175942Sscottl			case CAM_DIR_OUT:
402175942Sscottl				bus_dmamap_sync(hba->io_dmat,
403175942Sscottl					srb->dma_map, BUS_DMASYNC_POSTWRITE);
404175942Sscottl				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
405175942Sscottl				break;
406175942Sscottl			}
407175942Sscottl
408175942Sscottl			ccb->ccb_h.status = CAM_REQ_CMP;
409175942Sscottl			break;
410175942Sscottl
411175942Sscottl		case IOP_RESULT_BAD_TARGET:
412175942Sscottl			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
413175942Sscottl			break;
414175942Sscottl		case IOP_RESULT_BUSY:
415175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
416175942Sscottl			break;
417175942Sscottl		case IOP_RESULT_INVALID_REQUEST:
418175942Sscottl			ccb->ccb_h.status = CAM_REQ_INVALID;
419175942Sscottl			break;
420175942Sscottl		case IOP_RESULT_FAIL:
421175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
422175942Sscottl			break;
423175942Sscottl		case IOP_RESULT_RESET:
424175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
425175942Sscottl			break;
426175942Sscottl		case IOP_RESULT_CHECK_CONDITION:
427226350Smarius			memset(&ccb->csio.sense_data, 0,
428226350Smarius			    sizeof(ccb->csio.sense_data));
429226350Smarius			if (dxfer < ccb->csio.sense_len)
430226350Smarius				ccb->csio.sense_resid = ccb->csio.sense_len -
431226350Smarius				    dxfer;
432226350Smarius			else
433226350Smarius				ccb->csio.sense_resid = 0;
434175942Sscottl			if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) {/*iop*/
435175942Sscottl				bus_space_read_region_1(hba->bar0t, hba->bar0h,
436175942Sscottl					index + offsetof(struct hpt_iop_request_scsi_command,
437175942Sscottl					sg_list), (u_int8_t *)&ccb->csio.sense_data,
438175942Sscottl					MIN(dxfer, sizeof(ccb->csio.sense_data)));
439175942Sscottl			} else {
440175942Sscottl				memcpy(&ccb->csio.sense_data, &req->sg_list,
441175942Sscottl					MIN(dxfer, sizeof(ccb->csio.sense_data)));
442175942Sscottl			}
443175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
444175942Sscottl			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
445175942Sscottl			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
446175942Sscottl			break;
447175942Sscottl		default:
448175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
449175942Sscottl			break;
450175942Sscottl		}
451175942Sscottlscsi_done:
452175942Sscottl		if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS)
453175942Sscottl			BUS_SPACE_WRT4_ITL(outbound_queue, index);
454175942Sscottl
455175942Sscottl		ccb->csio.resid = ccb->csio.dxfer_len - dxfer;
456175942Sscottl
457175942Sscottl		hptiop_free_srb(hba, srb);
458175942Sscottl		xpt_done(ccb);
459175942Sscottl		break;
460175942Sscottl	}
461175942Sscottl}
462175942Sscottl
463175942Sscottlstatic void hptiop_drain_outbound_queue_itl(struct hpt_iop_hba *hba)
464175942Sscottl{
465175942Sscottl	u_int32_t req, temp;
466175942Sscottl
467175942Sscottl	while ((req = BUS_SPACE_RD4_ITL(outbound_queue)) !=IOPMU_QUEUE_EMPTY) {
468175942Sscottl		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
469175942Sscottl			hptiop_request_callback_itl(hba, req);
470175942Sscottl		else {
471175942Sscottl			struct hpt_iop_request_header *p;
472175942Sscottl
473175942Sscottl			p = (struct hpt_iop_request_header *)
474175942Sscottl				((char *)hba->u.itl.mu + req);
475175942Sscottl			temp = bus_space_read_4(hba->bar0t,
476175942Sscottl					hba->bar0h,req +
477175942Sscottl					offsetof(struct hpt_iop_request_header,
478175942Sscottl						flags));
479175942Sscottl			if (temp & IOP_REQUEST_FLAG_SYNC_REQUEST) {
480175942Sscottl				u_int64_t temp64;
481175942Sscottl				bus_space_read_region_4(hba->bar0t,
482175942Sscottl					hba->bar0h,req +
483175942Sscottl					offsetof(struct hpt_iop_request_header,
484175942Sscottl						context),
485175942Sscottl					(u_int32_t *)&temp64, 2);
486175942Sscottl				if (temp64) {
487175942Sscottl					hptiop_request_callback_itl(hba, req);
488175942Sscottl				} else {
489175942Sscottl					temp64 = 1;
490175942Sscottl					bus_space_write_region_4(hba->bar0t,
491175942Sscottl						hba->bar0h,req +
492175942Sscottl						offsetof(struct hpt_iop_request_header,
493175942Sscottl							context),
494175942Sscottl						(u_int32_t *)&temp64, 2);
495175942Sscottl				}
496175942Sscottl			} else
497175942Sscottl				hptiop_request_callback_itl(hba, req);
498175942Sscottl		}
499175942Sscottl	}
500175942Sscottl}
501175942Sscottl
502175942Sscottlstatic int hptiop_intr_itl(struct hpt_iop_hba * hba)
503175942Sscottl{
504169412Sscottl	u_int32_t status;
505169412Sscottl	int ret = 0;
506169412Sscottl
507175942Sscottl	status = BUS_SPACE_RD4_ITL(outbound_intstatus);
508169412Sscottl
509169412Sscottl	if (status & IOPMU_OUTBOUND_INT_MSG0) {
510175942Sscottl		u_int32_t msg = BUS_SPACE_RD4_ITL(outbound_msgaddr0);
511175942Sscottl		KdPrint(("hptiop: received outbound msg %x\n", msg));
512175942Sscottl		BUS_SPACE_WRT4_ITL(outbound_intstatus, IOPMU_OUTBOUND_INT_MSG0);
513175942Sscottl		hptiop_os_message_callback(hba, msg);
514169412Sscottl		ret = 1;
515169412Sscottl	}
516169412Sscottl
517169412Sscottl	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
518175942Sscottl		hptiop_drain_outbound_queue_itl(hba);
519175942Sscottl		ret = 1;
520175942Sscottl	}
521175942Sscottl
522175942Sscottl	return ret;
523175942Sscottl}
524175942Sscottl
525175942Sscottlstatic void hptiop_request_callback_mv(struct hpt_iop_hba * hba,
526175942Sscottl							u_int64_t _tag)
527175942Sscottl{
528175942Sscottl	u_int32_t context = (u_int32_t)_tag;
529175942Sscottl
530175942Sscottl	if (context & MVIOP_CMD_TYPE_SCSI) {
531175942Sscottl		struct hpt_iop_srb *srb;
532175942Sscottl		struct hpt_iop_request_scsi_command *req;
533175942Sscottl		union ccb *ccb;
534175942Sscottl		u_int8_t *cdb;
535175942Sscottl
536175942Sscottl		srb = hba->srb[context >> MVIOP_REQUEST_NUMBER_START_BIT];
537175942Sscottl		req = (struct hpt_iop_request_scsi_command *)srb;
538175942Sscottl		ccb = (union ccb *)srb->ccb;
539175942Sscottl		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
540175942Sscottl			cdb = ccb->csio.cdb_io.cdb_ptr;
541175942Sscottl		else
542175942Sscottl			cdb = ccb->csio.cdb_io.cdb_bytes;
543175942Sscottl
544175942Sscottl		if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */
545175942Sscottl			ccb->ccb_h.status = CAM_REQ_CMP;
546175942Sscottl			goto scsi_done;
547175942Sscottl		}
548175942Sscottl		if (context & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)
549175942Sscottl			req->header.result = IOP_RESULT_SUCCESS;
550175942Sscottl
551175942Sscottl		switch (req->header.result) {
552175942Sscottl		case IOP_RESULT_SUCCESS:
553175942Sscottl			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
554175942Sscottl			case CAM_DIR_IN:
555175942Sscottl				bus_dmamap_sync(hba->io_dmat,
556175942Sscottl					srb->dma_map, BUS_DMASYNC_POSTREAD);
557175942Sscottl				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
558175942Sscottl				break;
559175942Sscottl			case CAM_DIR_OUT:
560175942Sscottl				bus_dmamap_sync(hba->io_dmat,
561175942Sscottl					srb->dma_map, BUS_DMASYNC_POSTWRITE);
562175942Sscottl				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
563175942Sscottl				break;
564169412Sscottl			}
565175942Sscottl			ccb->ccb_h.status = CAM_REQ_CMP;
566175942Sscottl			break;
567175942Sscottl		case IOP_RESULT_BAD_TARGET:
568175942Sscottl			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
569175942Sscottl			break;
570175942Sscottl		case IOP_RESULT_BUSY:
571175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
572175942Sscottl			break;
573175942Sscottl		case IOP_RESULT_INVALID_REQUEST:
574175942Sscottl			ccb->ccb_h.status = CAM_REQ_INVALID;
575175942Sscottl			break;
576175942Sscottl		case IOP_RESULT_FAIL:
577175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
578175942Sscottl			break;
579175942Sscottl		case IOP_RESULT_RESET:
580175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
581175942Sscottl			break;
582175942Sscottl		case IOP_RESULT_CHECK_CONDITION:
583226350Smarius			memset(&ccb->csio.sense_data, 0,
584226350Smarius			    sizeof(ccb->csio.sense_data));
585226350Smarius			if (req->dataxfer_length < ccb->csio.sense_len)
586226350Smarius				ccb->csio.sense_resid = ccb->csio.sense_len -
587226350Smarius				    req->dataxfer_length;
588226350Smarius			else
589226350Smarius				ccb->csio.sense_resid = 0;
590175942Sscottl			memcpy(&ccb->csio.sense_data, &req->sg_list,
591175942Sscottl				MIN(req->dataxfer_length, sizeof(ccb->csio.sense_data)));
592175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
593175942Sscottl			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
594175942Sscottl			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
595175942Sscottl			break;
596175942Sscottl		default:
597175942Sscottl			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
598175942Sscottl			break;
599169412Sscottl		}
600175942Sscottlscsi_done:
601175942Sscottl		ccb->csio.resid = ccb->csio.dxfer_len - req->dataxfer_length;
602175942Sscottl
603175942Sscottl		hptiop_free_srb(hba, srb);
604175942Sscottl		xpt_done(ccb);
605175942Sscottl	} else if (context & MVIOP_CMD_TYPE_IOCTL) {
606175942Sscottl		struct hpt_iop_request_ioctl_command *req = hba->ctlcfg_ptr;
607175942Sscottl		if (context & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)
608175942Sscottl			hba->config_done = 1;
609175942Sscottl		else
610175942Sscottl			hba->config_done = -1;
611175942Sscottl		wakeup(req);
612175942Sscottl	} else if (context &
613175942Sscottl			(MVIOP_CMD_TYPE_SET_CONFIG |
614175942Sscottl				MVIOP_CMD_TYPE_GET_CONFIG))
615175942Sscottl		hba->config_done = 1;
616175942Sscottl	else {
617175942Sscottl		device_printf(hba->pcidev, "wrong callback type\n");
618175942Sscottl	}
619175942Sscottl}
620175942Sscottl
621175942Sscottlstatic void hptiop_drain_outbound_queue_mv(struct hpt_iop_hba * hba)
622175942Sscottl{
623175942Sscottl	u_int64_t req;
624175942Sscottl
625175942Sscottl	while ((req = hptiop_mv_outbound_read(hba))) {
626175942Sscottl		if (req & MVIOP_MU_QUEUE_ADDR_HOST_BIT) {
627175942Sscottl			if (req & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) {
628175942Sscottl				hptiop_request_callback_mv(hba, req);
629175942Sscottl			}
630175942Sscottl	    	}
631175942Sscottl	}
632175942Sscottl}
633175942Sscottl
634175942Sscottlstatic int hptiop_intr_mv(struct hpt_iop_hba * hba)
635175942Sscottl{
636175942Sscottl	u_int32_t status;
637175942Sscottl	int ret = 0;
638175942Sscottl
639175942Sscottl	status = BUS_SPACE_RD4_MV0(outbound_doorbell);
640175942Sscottl
641175942Sscottl	if (status)
642175942Sscottl		BUS_SPACE_WRT4_MV0(outbound_doorbell, ~status);
643175942Sscottl
644175942Sscottl	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
645175942Sscottl		u_int32_t msg = BUS_SPACE_RD4_MV2(outbound_msg);
646175942Sscottl		KdPrint(("hptiop: received outbound msg %x\n", msg));
647175942Sscottl		hptiop_os_message_callback(hba, msg);
648169412Sscottl		ret = 1;
649169412Sscottl	}
650175942Sscottl
651175942Sscottl	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
652175942Sscottl		hptiop_drain_outbound_queue_mv(hba);
653175942Sscottl		ret = 1;
654175942Sscottl	}
655175942Sscottl
656169412Sscottl	return ret;
657169412Sscottl}
658169412Sscottl
659175942Sscottlstatic int hptiop_send_sync_request_itl(struct hpt_iop_hba * hba,
660175942Sscottl					u_int32_t req32, u_int32_t millisec)
661169412Sscottl{
662169412Sscottl	u_int32_t i;
663175942Sscottl	u_int64_t temp64;
664169412Sscottl
665175942Sscottl	BUS_SPACE_WRT4_ITL(inbound_queue, req32);
666175942Sscottl	BUS_SPACE_RD4_ITL(outbound_intstatus);
667169412Sscottl
668169412Sscottl	for (i = 0; i < millisec; i++) {
669175942Sscottl		hptiop_intr_itl(hba);
670175942Sscottl		bus_space_read_region_4(hba->bar0t, hba->bar0h, req32 +
671175942Sscottl			offsetof(struct hpt_iop_request_header, context),
672175942Sscottl			(u_int32_t *)&temp64, 2);
673175942Sscottl		if (temp64)
674169412Sscottl			return 0;
675169412Sscottl		DELAY(1000);
676169412Sscottl	}
677169412Sscottl
678169412Sscottl	return -1;
679169412Sscottl}
680169412Sscottl
681175942Sscottlstatic int hptiop_send_sync_request_mv(struct hpt_iop_hba *hba,
682175942Sscottl					void *req, u_int32_t millisec)
683169412Sscottl{
684169412Sscottl	u_int32_t i;
685175942Sscottl	u_int64_t phy_addr;
686175942Sscottl	hba->config_done = 0;
687169412Sscottl
688175942Sscottl	phy_addr = hba->ctlcfgcmd_phy |
689175942Sscottl			(u_int64_t)MVIOP_MU_QUEUE_ADDR_HOST_BIT;
690175942Sscottl	((struct hpt_iop_request_get_config *)req)->header.flags |=
691175942Sscottl		IOP_REQUEST_FLAG_SYNC_REQUEST |
692175942Sscottl		IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
693175942Sscottl	hptiop_mv_inbound_write(phy_addr, hba);
694175942Sscottl	BUS_SPACE_RD4_MV0(outbound_intmask);
695169412Sscottl
696175942Sscottl	for (i = 0; i < millisec; i++) {
697175942Sscottl		hptiop_intr_mv(hba);
698175942Sscottl		if (hba->config_done)
699175942Sscottl			return 0;
700175942Sscottl		DELAY(1000);
701175942Sscottl	}
702175942Sscottl	return -1;
703175942Sscottl}
704169412Sscottl
705175942Sscottlstatic int hptiop_send_sync_msg(struct hpt_iop_hba *hba,
706175942Sscottl					u_int32_t msg, u_int32_t millisec)
707175942Sscottl{
708175942Sscottl	u_int32_t i;
709169412Sscottl
710175942Sscottl	hba->msg_done = 0;
711175942Sscottl	hba->ops->post_msg(hba, msg);
712175942Sscottl
713175942Sscottl	for (i=0; i<millisec; i++) {
714175942Sscottl		hba->ops->iop_intr(hba);
715175942Sscottl		if (hba->msg_done)
716169412Sscottl			break;
717169412Sscottl		DELAY(1000);
718169412Sscottl	}
719169412Sscottl
720175942Sscottl	return hba->msg_done? 0 : -1;
721169412Sscottl}
722169412Sscottl
723175942Sscottlstatic int hptiop_get_config_itl(struct hpt_iop_hba * hba,
724175942Sscottl				struct hpt_iop_request_get_config * config)
725169412Sscottl{
726175942Sscottl	u_int32_t req32;
727169412Sscottl
728175942Sscottl	config->header.size = sizeof(struct hpt_iop_request_get_config);
729175942Sscottl	config->header.type = IOP_REQUEST_TYPE_GET_CONFIG;
730175942Sscottl	config->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
731175942Sscottl	config->header.result = IOP_RESULT_PENDING;
732175942Sscottl	config->header.context = 0;
733175942Sscottl
734175942Sscottl	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
735175942Sscottl	if (req32 == IOPMU_QUEUE_EMPTY)
736169412Sscottl		return -1;
737169412Sscottl
738175942Sscottl	bus_space_write_region_4(hba->bar0t, hba->bar0h,
739175942Sscottl			req32, (u_int32_t *)config,
740175942Sscottl			sizeof(struct hpt_iop_request_header) >> 2);
741175942Sscottl
742175942Sscottl	if (hptiop_send_sync_request_itl(hba, req32, 20000)) {
743175942Sscottl		KdPrint(("hptiop: get config send cmd failed"));
744175942Sscottl		return -1;
745175942Sscottl	}
746175942Sscottl
747175942Sscottl	bus_space_read_region_4(hba->bar0t, hba->bar0h,
748175942Sscottl			req32, (u_int32_t *)config,
749175942Sscottl			sizeof(struct hpt_iop_request_get_config) >> 2);
750175942Sscottl
751175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_queue, req32);
752175942Sscottl
753175942Sscottl	return 0;
754175942Sscottl}
755175942Sscottl
756175942Sscottlstatic int hptiop_get_config_mv(struct hpt_iop_hba * hba,
757175942Sscottl				struct hpt_iop_request_get_config * config)
758175942Sscottl{
759175942Sscottl	struct hpt_iop_request_get_config *req;
760175942Sscottl
761175942Sscottl	if (!(req = hba->ctlcfg_ptr))
762175942Sscottl		return -1;
763175942Sscottl
764169412Sscottl	req->header.flags = 0;
765169412Sscottl	req->header.type = IOP_REQUEST_TYPE_GET_CONFIG;
766169412Sscottl	req->header.size = sizeof(struct hpt_iop_request_get_config);
767169412Sscottl	req->header.result = IOP_RESULT_PENDING;
768175942Sscottl	req->header.context = MVIOP_CMD_TYPE_GET_CONFIG;
769169412Sscottl
770175942Sscottl	if (hptiop_send_sync_request_mv(hba, req, 20000)) {
771175942Sscottl		KdPrint(("hptiop: get config send cmd failed"));
772169412Sscottl		return -1;
773169412Sscottl	}
774169412Sscottl
775169412Sscottl	*config = *req;
776169412Sscottl	return 0;
777169412Sscottl}
778169412Sscottl
779175942Sscottlstatic int hptiop_set_config_itl(struct hpt_iop_hba *hba,
780175942Sscottl				struct hpt_iop_request_set_config *config)
781169412Sscottl{
782169412Sscottl	u_int32_t req32;
783169412Sscottl
784175942Sscottl	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
785175942Sscottl
786169412Sscottl	if (req32 == IOPMU_QUEUE_EMPTY)
787169412Sscottl		return -1;
788169412Sscottl
789175942Sscottl	config->header.size = sizeof(struct hpt_iop_request_set_config);
790175942Sscottl	config->header.type = IOP_REQUEST_TYPE_SET_CONFIG;
791175942Sscottl	config->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
792175942Sscottl	config->header.result = IOP_RESULT_PENDING;
793175942Sscottl	config->header.context = 0;
794175942Sscottl
795175942Sscottl	bus_space_write_region_4(hba->bar0t, hba->bar0h, req32,
796175942Sscottl		(u_int32_t *)config,
797175942Sscottl		sizeof(struct hpt_iop_request_set_config) >> 2);
798175942Sscottl
799175942Sscottl	if (hptiop_send_sync_request_itl(hba, req32, 20000)) {
800175942Sscottl		KdPrint(("hptiop: set config send cmd failed"));
801175942Sscottl		return -1;
802175942Sscottl	}
803175942Sscottl
804175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_queue, req32);
805175942Sscottl
806175942Sscottl	return 0;
807175942Sscottl}
808175942Sscottl
809175942Sscottlstatic int hptiop_set_config_mv(struct hpt_iop_hba *hba,
810175942Sscottl				struct hpt_iop_request_set_config *config)
811175942Sscottl{
812175942Sscottl	struct hpt_iop_request_set_config *req;
813175942Sscottl
814175942Sscottl	if (!(req = hba->ctlcfg_ptr))
815175942Sscottl		return -1;
816175942Sscottl
817169412Sscottl	memcpy((u_int8_t *)req + sizeof(struct hpt_iop_request_header),
818169412Sscottl		(u_int8_t *)config + sizeof(struct hpt_iop_request_header),
819175942Sscottl		sizeof(struct hpt_iop_request_set_config) -
820175942Sscottl			sizeof(struct hpt_iop_request_header));
821175942Sscottl
822169412Sscottl	req->header.flags = 0;
823169412Sscottl	req->header.type = IOP_REQUEST_TYPE_SET_CONFIG;
824169412Sscottl	req->header.size = sizeof(struct hpt_iop_request_set_config);
825169412Sscottl	req->header.result = IOP_RESULT_PENDING;
826175942Sscottl	req->header.context = MVIOP_CMD_TYPE_SET_CONFIG;
827169412Sscottl
828175942Sscottl	if (hptiop_send_sync_request_mv(hba, req, 20000)) {
829175942Sscottl		KdPrint(("hptiop: set config send cmd failed"));
830169412Sscottl		return -1;
831169412Sscottl	}
832169412Sscottl
833169412Sscottl	return 0;
834169412Sscottl}
835169412Sscottl
836175942Sscottlstatic int hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba,
837175942Sscottl				u_int32_t req32,
838175942Sscottl				struct hpt_iop_ioctl_param *pParams)
839169412Sscottl{
840175942Sscottl	u_int64_t temp64;
841175942Sscottl	struct hpt_iop_request_ioctl_command req;
842169412Sscottl
843175942Sscottl	if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) >
844175942Sscottl			(hba->max_request_size -
845175942Sscottl			offsetof(struct hpt_iop_request_ioctl_command, buf))) {
846175942Sscottl		device_printf(hba->pcidev, "request size beyond max value");
847175942Sscottl		return -1;
848175942Sscottl	}
849175942Sscottl
850175942Sscottl	req.header.size = offsetof(struct hpt_iop_request_ioctl_command, buf)
851175942Sscottl		+ pParams->nInBufferSize;
852175942Sscottl	req.header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND;
853175942Sscottl	req.header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
854175942Sscottl	req.header.result = IOP_RESULT_PENDING;
855175942Sscottl	req.header.context = req32 + (u_int64_t)(unsigned long)hba->u.itl.mu;
856175942Sscottl	req.ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode);
857175942Sscottl	req.inbuf_size = pParams->nInBufferSize;
858175942Sscottl	req.outbuf_size = pParams->nOutBufferSize;
859175942Sscottl	req.bytes_returned = 0;
860175942Sscottl
861175942Sscottl	bus_space_write_region_4(hba->bar0t, hba->bar0h, req32, (u_int32_t *)&req,
862175942Sscottl		offsetof(struct hpt_iop_request_ioctl_command, buf)>>2);
863175942Sscottl
864175942Sscottl	hptiop_lock_adapter(hba);
865175942Sscottl
866175942Sscottl	BUS_SPACE_WRT4_ITL(inbound_queue, req32);
867175942Sscottl	BUS_SPACE_RD4_ITL(outbound_intstatus);
868175942Sscottl
869175942Sscottl	bus_space_read_region_4(hba->bar0t, hba->bar0h, req32 +
870175942Sscottl		offsetof(struct hpt_iop_request_ioctl_command, header.context),
871175942Sscottl		(u_int32_t *)&temp64, 2);
872175942Sscottl	while (temp64) {
873175942Sscottl		if (hptiop_sleep(hba, (void *)((unsigned long)hba->u.itl.mu + req32),
874175942Sscottl				PPAUSE, "hptctl", HPT_OSM_TIMEOUT)==0)
875175942Sscottl			break;
876175942Sscottl		hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
877175942Sscottl		bus_space_read_region_4(hba->bar0t, hba->bar0h,req32 +
878175942Sscottl			offsetof(struct hpt_iop_request_ioctl_command,
879175942Sscottl				header.context),
880175942Sscottl			(u_int32_t *)&temp64, 2);
881175942Sscottl	}
882175942Sscottl
883175942Sscottl	hptiop_unlock_adapter(hba);
884175942Sscottl	return 0;
885175942Sscottl}
886175942Sscottl
887175942Sscottlstatic int hptiop_bus_space_copyin(struct hpt_iop_hba *hba, u_int32_t bus, void *user, int size)
888175942Sscottl{
889175942Sscottl	unsigned char byte;
890175942Sscottl	int i;
891175942Sscottl
892175942Sscottl	for (i=0; i<size; i++) {
893175942Sscottl		if (copyin((u_int8_t *)user + i, &byte, 1))
894175942Sscottl			return -1;
895175942Sscottl		bus_space_write_1(hba->bar0t, hba->bar0h, bus + i, byte);
896175942Sscottl	}
897175942Sscottl
898175942Sscottl	return 0;
899175942Sscottl}
900175942Sscottl
901175942Sscottlstatic int hptiop_bus_space_copyout(struct hpt_iop_hba *hba, u_int32_t bus, void *user, int size)
902175942Sscottl{
903175942Sscottl	unsigned char byte;
904175942Sscottl	int i;
905175942Sscottl
906175942Sscottl	for (i=0; i<size; i++) {
907175942Sscottl		byte = bus_space_read_1(hba->bar0t, hba->bar0h, bus + i);
908175942Sscottl		if (copyout(&byte, (u_int8_t *)user + i, 1))
909175942Sscottl			return -1;
910175942Sscottl	}
911175942Sscottl
912175942Sscottl	return 0;
913175942Sscottl}
914175942Sscottl
915175942Sscottlstatic int hptiop_do_ioctl_itl(struct hpt_iop_hba *hba,
916175942Sscottl				struct hpt_iop_ioctl_param * pParams)
917175942Sscottl{
918175942Sscottl	u_int32_t req32;
919175942Sscottl	u_int32_t result;
920175942Sscottl
921169412Sscottl	if ((pParams->Magic != HPT_IOCTL_MAGIC) &&
922169412Sscottl		(pParams->Magic != HPT_IOCTL_MAGIC32))
923169412Sscottl		return EFAULT;
924175942Sscottl
925175942Sscottl	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
926175942Sscottl	if (req32 == IOPMU_QUEUE_EMPTY)
927169412Sscottl		return EFAULT;
928169412Sscottl
929169412Sscottl	if (pParams->nInBufferSize)
930175942Sscottl		if (hptiop_bus_space_copyin(hba, req32 +
931175942Sscottl			offsetof(struct hpt_iop_request_ioctl_command, buf),
932175942Sscottl			(void *)pParams->lpInBuffer, pParams->nInBufferSize))
933169412Sscottl			goto invalid;
934169412Sscottl
935175942Sscottl	if (hptiop_post_ioctl_command_itl(hba, req32, pParams))
936169412Sscottl		goto invalid;
937169412Sscottl
938175942Sscottl	result = bus_space_read_4(hba->bar0t, hba->bar0h, req32 +
939175942Sscottl			offsetof(struct hpt_iop_request_ioctl_command,
940175942Sscottl				header.result));
941175942Sscottl
942175942Sscottl	if (result == IOP_RESULT_SUCCESS) {
943169412Sscottl		if (pParams->nOutBufferSize)
944175942Sscottl			if (hptiop_bus_space_copyout(hba, req32 +
945175942Sscottl				offsetof(struct hpt_iop_request_ioctl_command, buf) +
946169412Sscottl					((pParams->nInBufferSize + 3) & ~3),
947175942Sscottl				(void *)pParams->lpOutBuffer, pParams->nOutBufferSize))
948169412Sscottl				goto invalid;
949169412Sscottl
950175942Sscottl		if (pParams->lpBytesReturned) {
951175942Sscottl			if (hptiop_bus_space_copyout(hba, req32 +
952175942Sscottl				offsetof(struct hpt_iop_request_ioctl_command, bytes_returned),
953175942Sscottl				(void *)pParams->lpBytesReturned, sizeof(unsigned  long)))
954169412Sscottl				goto invalid;
955175942Sscottl		}
956175942Sscottl
957175942Sscottl		BUS_SPACE_WRT4_ITL(outbound_queue, req32);
958175942Sscottl
959169412Sscottl		return 0;
960169412Sscottl	} else{
961169412Sscottlinvalid:
962175942Sscottl		BUS_SPACE_WRT4_ITL(outbound_queue, req32);
963175942Sscottl
964169412Sscottl		return EFAULT;
965169412Sscottl	}
966169412Sscottl}
967169412Sscottl
968175942Sscottlstatic int hptiop_post_ioctl_command_mv(struct hpt_iop_hba *hba,
969175942Sscottl				struct hpt_iop_request_ioctl_command *req,
970175942Sscottl				struct hpt_iop_ioctl_param *pParams)
971169412Sscottl{
972175942Sscottl	u_int64_t req_phy;
973175942Sscottl	int size = 0;
974175942Sscottl
975175942Sscottl	if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) >
976175942Sscottl			(hba->max_request_size -
977175942Sscottl			offsetof(struct hpt_iop_request_ioctl_command, buf))) {
978175942Sscottl		device_printf(hba->pcidev, "request size beyond max value");
979169412Sscottl		return -1;
980169412Sscottl	}
981169412Sscottl
982169412Sscottl	req->ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode);
983169412Sscottl	req->inbuf_size = pParams->nInBufferSize;
984169412Sscottl	req->outbuf_size = pParams->nOutBufferSize;
985175942Sscottl	req->header.size = offsetof(struct hpt_iop_request_ioctl_command, buf)
986175942Sscottl					+ pParams->nInBufferSize;
987175942Sscottl	req->header.context = (u_int64_t)MVIOP_CMD_TYPE_IOCTL;
988169412Sscottl	req->header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND;
989169412Sscottl	req->header.result = IOP_RESULT_PENDING;
990175942Sscottl	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
991175942Sscottl	size = req->header.size >> 8;
992175942Sscottl	size = size > 3 ? 3 : size;
993175942Sscottl	req_phy = hba->ctlcfgcmd_phy | MVIOP_MU_QUEUE_ADDR_HOST_BIT | size;
994175942Sscottl	hptiop_mv_inbound_write(req_phy, hba);
995169412Sscottl
996175942Sscottl	BUS_SPACE_RD4_MV0(outbound_intmask);
997169412Sscottl
998175942Sscottl	while (hba->config_done == 0) {
999175942Sscottl		if (hptiop_sleep(hba, req, PPAUSE,
1000175942Sscottl			"hptctl", HPT_OSM_TIMEOUT)==0)
1001175942Sscottl			continue;
1002175942Sscottl		hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1003169412Sscottl	}
1004169412Sscottl	return 0;
1005169412Sscottl}
1006169412Sscottl
1007175942Sscottlstatic int hptiop_do_ioctl_mv(struct hpt_iop_hba *hba,
1008175942Sscottl				struct hpt_iop_ioctl_param *pParams)
1009175942Sscottl{
1010175942Sscottl	struct hpt_iop_request_ioctl_command *req;
1011175942Sscottl
1012175942Sscottl	if ((pParams->Magic != HPT_IOCTL_MAGIC) &&
1013175942Sscottl		(pParams->Magic != HPT_IOCTL_MAGIC32))
1014175942Sscottl		return EFAULT;
1015175942Sscottl
1016175942Sscottl	req = (struct hpt_iop_request_ioctl_command *)(hba->ctlcfg_ptr);
1017175942Sscottl	hba->config_done = 0;
1018175942Sscottl	hptiop_lock_adapter(hba);
1019175942Sscottl	if (pParams->nInBufferSize)
1020175942Sscottl		if (copyin((void *)pParams->lpInBuffer,
1021175942Sscottl				req->buf, pParams->nInBufferSize))
1022175942Sscottl			goto invalid;
1023175942Sscottl	if (hptiop_post_ioctl_command_mv(hba, req, pParams))
1024175942Sscottl		goto invalid;
1025175942Sscottl
1026175942Sscottl	if (hba->config_done == 1) {
1027175942Sscottl		if (pParams->nOutBufferSize)
1028175942Sscottl			if (copyout(req->buf +
1029175942Sscottl				((pParams->nInBufferSize + 3) & ~3),
1030175942Sscottl				(void *)pParams->lpOutBuffer,
1031175942Sscottl				pParams->nOutBufferSize))
1032175942Sscottl				goto invalid;
1033175942Sscottl
1034175942Sscottl		if (pParams->lpBytesReturned)
1035175942Sscottl			if (copyout(&req->bytes_returned,
1036175942Sscottl				(void*)pParams->lpBytesReturned,
1037175942Sscottl				sizeof(u_int32_t)))
1038175942Sscottl				goto invalid;
1039175942Sscottl		hptiop_unlock_adapter(hba);
1040175942Sscottl		return 0;
1041175942Sscottl	} else{
1042175942Sscottlinvalid:
1043175942Sscottl		hptiop_unlock_adapter(hba);
1044175942Sscottl		return EFAULT;
1045175942Sscottl	}
1046175942Sscottl}
1047175942Sscottl
1048169412Sscottlstatic int  hptiop_rescan_bus(struct hpt_iop_hba * hba)
1049169412Sscottl{
1050169412Sscottl	union ccb           *ccb;
1051203108Smav
1052203108Smav	if ((ccb = xpt_alloc_ccb()) == NULL)
1053203108Smav		return(ENOMEM);
1054203108Smav	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(hba->sim),
1055203108Smav		CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1056203108Smav		xpt_free_ccb(ccb);
1057169412Sscottl		return(EIO);
1058203108Smav	}
1059203108Smav	xpt_rescan(ccb);
1060169412Sscottl	return(0);
1061169412Sscottl}
1062169412Sscottl
1063169412Sscottlstatic  bus_dmamap_callback_t   hptiop_map_srb;
1064169412Sscottlstatic  bus_dmamap_callback_t   hptiop_post_scsi_command;
1065175942Sscottlstatic  bus_dmamap_callback_t   hptiop_mv_map_ctlcfg;
1066169412Sscottl
1067175942Sscottlstatic int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba)
1068175942Sscottl{
1069175942Sscottl	hba->bar0_rid = 0x10;
1070175942Sscottl	hba->bar0_res = bus_alloc_resource_any(hba->pcidev,
1071175942Sscottl			SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE);
1072175942Sscottl
1073175942Sscottl	if (hba->bar0_res == NULL) {
1074175942Sscottl		device_printf(hba->pcidev,
1075175942Sscottl			"failed to get iop base adrress.\n");
1076175942Sscottl		return -1;
1077175942Sscottl	}
1078175942Sscottl	hba->bar0t = rman_get_bustag(hba->bar0_res);
1079175942Sscottl	hba->bar0h = rman_get_bushandle(hba->bar0_res);
1080175942Sscottl	hba->u.itl.mu = (struct hpt_iopmu_itl *)
1081175942Sscottl				rman_get_virtual(hba->bar0_res);
1082175942Sscottl
1083175942Sscottl	if (!hba->u.itl.mu) {
1084175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1085175942Sscottl					hba->bar0_rid, hba->bar0_res);
1086175942Sscottl		device_printf(hba->pcidev, "alloc mem res failed\n");
1087175942Sscottl		return -1;
1088175942Sscottl	}
1089175942Sscottl
1090175942Sscottl	return 0;
1091175942Sscottl}
1092175942Sscottl
1093175942Sscottlstatic int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba)
1094175942Sscottl{
1095175942Sscottl	hba->bar0_rid = 0x10;
1096175942Sscottl	hba->bar0_res = bus_alloc_resource_any(hba->pcidev,
1097175942Sscottl			SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE);
1098175942Sscottl
1099175942Sscottl	if (hba->bar0_res == NULL) {
1100175942Sscottl		device_printf(hba->pcidev, "failed to get iop bar0.\n");
1101175942Sscottl		return -1;
1102175942Sscottl	}
1103175942Sscottl	hba->bar0t = rman_get_bustag(hba->bar0_res);
1104175942Sscottl	hba->bar0h = rman_get_bushandle(hba->bar0_res);
1105175942Sscottl	hba->u.mv.regs = (struct hpt_iopmv_regs *)
1106175942Sscottl				rman_get_virtual(hba->bar0_res);
1107175942Sscottl
1108175942Sscottl	if (!hba->u.mv.regs) {
1109175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1110175942Sscottl					hba->bar0_rid, hba->bar0_res);
1111175942Sscottl		device_printf(hba->pcidev, "alloc bar0 mem res failed\n");
1112175942Sscottl		return -1;
1113175942Sscottl	}
1114175942Sscottl
1115175942Sscottl	hba->bar2_rid = 0x18;
1116175942Sscottl	hba->bar2_res = bus_alloc_resource_any(hba->pcidev,
1117175942Sscottl			SYS_RES_MEMORY, &hba->bar2_rid, RF_ACTIVE);
1118175942Sscottl
1119175942Sscottl	if (hba->bar2_res == NULL) {
1120175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1121175942Sscottl					hba->bar0_rid, hba->bar0_res);
1122175942Sscottl		device_printf(hba->pcidev, "failed to get iop bar2.\n");
1123175942Sscottl		return -1;
1124175942Sscottl	}
1125175942Sscottl
1126175942Sscottl	hba->bar2t = rman_get_bustag(hba->bar2_res);
1127175942Sscottl	hba->bar2h = rman_get_bushandle(hba->bar2_res);
1128175942Sscottl	hba->u.mv.mu = (struct hpt_iopmu_mv *)rman_get_virtual(hba->bar2_res);
1129175942Sscottl
1130175942Sscottl	if (!hba->u.mv.mu) {
1131175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1132175942Sscottl					hba->bar0_rid, hba->bar0_res);
1133175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1134175942Sscottl					hba->bar2_rid, hba->bar2_res);
1135175942Sscottl		device_printf(hba->pcidev, "alloc mem bar2 res failed\n");
1136175942Sscottl		return -1;
1137175942Sscottl	}
1138175942Sscottl
1139175942Sscottl	return 0;
1140175942Sscottl}
1141175942Sscottl
1142175942Sscottlstatic void hptiop_release_pci_res_itl(struct hpt_iop_hba *hba)
1143175942Sscottl{
1144175942Sscottl	if (hba->bar0_res)
1145175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1146175942Sscottl			hba->bar0_rid, hba->bar0_res);
1147175942Sscottl}
1148175942Sscottl
1149175942Sscottlstatic void hptiop_release_pci_res_mv(struct hpt_iop_hba *hba)
1150175942Sscottl{
1151175942Sscottl	if (hba->bar0_res)
1152175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1153175942Sscottl			hba->bar0_rid, hba->bar0_res);
1154175942Sscottl	if (hba->bar2_res)
1155175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1156175942Sscottl			hba->bar2_rid, hba->bar2_res);
1157175942Sscottl}
1158175942Sscottl
1159175942Sscottlstatic int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba)
1160175942Sscottl{
1161175942Sscottl	if (bus_dma_tag_create(hba->parent_dmat,
1162175942Sscottl				1,
1163175942Sscottl				0,
1164175942Sscottl				BUS_SPACE_MAXADDR_32BIT,
1165175942Sscottl				BUS_SPACE_MAXADDR,
1166175942Sscottl				NULL, NULL,
1167175942Sscottl				0x800 - 0x8,
1168175942Sscottl				1,
1169175942Sscottl				BUS_SPACE_MAXSIZE_32BIT,
1170175942Sscottl				BUS_DMA_ALLOCNOW,
1171175942Sscottl#if __FreeBSD_version > 502000
1172175942Sscottl				NULL,
1173175942Sscottl				NULL,
1174175942Sscottl#endif
1175175942Sscottl                           		&hba->ctlcfg_dmat)) {
1176175942Sscottl		device_printf(hba->pcidev, "alloc ctlcfg_dmat failed\n");
1177175942Sscottl		return -1;
1178175942Sscottl	}
1179175942Sscottl
1180175942Sscottl	if (bus_dmamem_alloc(hba->ctlcfg_dmat, (void **)&hba->ctlcfg_ptr,
1181175942Sscottl#if __FreeBSD_version>501000
1182175942Sscottl		BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1183175942Sscottl#else
1184175942Sscottl		BUS_DMA_WAITOK,
1185175942Sscottl#endif
1186175942Sscottl		&hba->ctlcfg_dmamap) != 0) {
1187175942Sscottl			device_printf(hba->pcidev,
1188175942Sscottl					"bus_dmamem_alloc failed!\n");
1189175942Sscottl			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1190175942Sscottl			return -1;
1191175942Sscottl	}
1192175942Sscottl
1193175942Sscottl	if (bus_dmamap_load(hba->ctlcfg_dmat,
1194175942Sscottl			hba->ctlcfg_dmamap, hba->ctlcfg_ptr,
1195175942Sscottl			MVIOP_IOCTLCFG_SIZE,
1196175942Sscottl			hptiop_mv_map_ctlcfg, hba, 0)) {
1197175942Sscottl		device_printf(hba->pcidev, "bus_dmamap_load failed!\n");
1198175942Sscottl		if (hba->ctlcfg_dmat)
1199175942Sscottl			bus_dmamem_free(hba->ctlcfg_dmat,
1200175942Sscottl				hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1201175942Sscottl			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1202175942Sscottl		return -1;
1203175942Sscottl	}
1204175942Sscottl
1205175942Sscottl	return 0;
1206175942Sscottl}
1207175942Sscottl
1208175942Sscottlstatic int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba)
1209175942Sscottl{
1210175942Sscottl	if (hba->ctlcfg_dmat) {
1211175942Sscottl		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
1212175942Sscottl		bus_dmamem_free(hba->ctlcfg_dmat,
1213175942Sscottl					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1214175942Sscottl		bus_dma_tag_destroy(hba->ctlcfg_dmat);
1215175942Sscottl	}
1216175942Sscottl
1217175942Sscottl	return 0;
1218175942Sscottl}
1219175942Sscottl
1220169412Sscottl/*
1221169412Sscottl * CAM driver interface
1222169412Sscottl */
1223169412Sscottlstatic device_method_t driver_methods[] = {
1224169412Sscottl	/* Device interface */
1225169412Sscottl	DEVMETHOD(device_probe,     hptiop_probe),
1226169412Sscottl	DEVMETHOD(device_attach,    hptiop_attach),
1227169412Sscottl	DEVMETHOD(device_detach,    hptiop_detach),
1228169412Sscottl	DEVMETHOD(device_shutdown,  hptiop_shutdown),
1229169412Sscottl	{ 0, 0 }
1230169412Sscottl};
1231169412Sscottl
1232175942Sscottlstatic struct hptiop_adapter_ops hptiop_itl_ops = {
1233175942Sscottl	.iop_wait_ready    = hptiop_wait_ready_itl,
1234175942Sscottl	.internal_memalloc = 0,
1235175942Sscottl	.internal_memfree  = 0,
1236175942Sscottl	.alloc_pci_res     = hptiop_alloc_pci_res_itl,
1237175942Sscottl	.release_pci_res   = hptiop_release_pci_res_itl,
1238175942Sscottl	.enable_intr       = hptiop_enable_intr_itl,
1239175942Sscottl	.disable_intr      = hptiop_disable_intr_itl,
1240175942Sscottl	.get_config        = hptiop_get_config_itl,
1241175942Sscottl	.set_config        = hptiop_set_config_itl,
1242175942Sscottl	.iop_intr          = hptiop_intr_itl,
1243175942Sscottl	.post_msg          = hptiop_post_msg_itl,
1244175942Sscottl	.post_req          = hptiop_post_req_itl,
1245175942Sscottl	.do_ioctl          = hptiop_do_ioctl_itl,
1246175942Sscottl};
1247175942Sscottl
1248175942Sscottlstatic struct hptiop_adapter_ops hptiop_mv_ops = {
1249175942Sscottl	.iop_wait_ready    = hptiop_wait_ready_mv,
1250175942Sscottl	.internal_memalloc = hptiop_internal_memalloc_mv,
1251175942Sscottl	.internal_memfree  = hptiop_internal_memfree_mv,
1252175942Sscottl	.alloc_pci_res     = hptiop_alloc_pci_res_mv,
1253175942Sscottl	.release_pci_res   = hptiop_release_pci_res_mv,
1254175942Sscottl	.enable_intr       = hptiop_enable_intr_mv,
1255175942Sscottl	.disable_intr      = hptiop_disable_intr_mv,
1256175942Sscottl	.get_config        = hptiop_get_config_mv,
1257175942Sscottl	.set_config        = hptiop_set_config_mv,
1258175942Sscottl	.iop_intr          = hptiop_intr_mv,
1259175942Sscottl	.post_msg          = hptiop_post_msg_mv,
1260175942Sscottl	.post_req          = hptiop_post_req_mv,
1261175942Sscottl	.do_ioctl          = hptiop_do_ioctl_mv,
1262175942Sscottl};
1263175942Sscottl
1264169412Sscottlstatic driver_t hptiop_pci_driver = {
1265169412Sscottl	driver_name,
1266169412Sscottl	driver_methods,
1267169412Sscottl	sizeof(struct hpt_iop_hba)
1268169412Sscottl};
1269169412Sscottl
1270169412SscottlDRIVER_MODULE(hptiop, pci, hptiop_pci_driver, hptiop_devclass, 0, 0);
1271236379SeadlerMODULE_DEPEND(hptiop, cam, 1, 1, 1);
1272169412Sscottl
1273169412Sscottlstatic int hptiop_probe(device_t dev)
1274169412Sscottl{
1275169412Sscottl	struct hpt_iop_hba *hba;
1276175942Sscottl	u_int32_t id;
1277175942Sscottl	static char buf[256];
1278175942Sscottl	int sas = 0;
1279175942Sscottl	struct hptiop_adapter_ops *ops;
1280169412Sscottl
1281175942Sscottl	if (pci_get_vendor(dev) != 0x1103)
1282175942Sscottl		return (ENXIO);
1283175942Sscottl
1284175942Sscottl	id = pci_get_device(dev);
1285175942Sscottl
1286175942Sscottl	switch (id) {
1287224583Sdelphij		case 0x4322:
1288224583Sdelphij		case 0x4321:
1289175942Sscottl		case 0x4320:
1290175942Sscottl			sas = 1;
1291175942Sscottl		case 0x3220:
1292175942Sscottl		case 0x3320:
1293175942Sscottl		case 0x3410:
1294175942Sscottl		case 0x3520:
1295175942Sscottl		case 0x3510:
1296175942Sscottl		case 0x3511:
1297175942Sscottl		case 0x3521:
1298175942Sscottl		case 0x3522:
1299175942Sscottl		case 0x3540:
1300175942Sscottl			ops = &hptiop_itl_ops;
1301175942Sscottl			break;
1302175942Sscottl		case 0x3120:
1303175942Sscottl		case 0x3122:
1304175942Sscottl		case 0x3020:
1305175942Sscottl			ops = &hptiop_mv_ops;
1306175942Sscottl			break;
1307175942Sscottl		default:
1308175942Sscottl			return (ENXIO);
1309169412Sscottl	}
1310175942Sscottl
1311175942Sscottl	device_printf(dev, "adapter at PCI %d:%d:%d, IRQ %d\n",
1312175942Sscottl		pci_get_bus(dev), pci_get_slot(dev),
1313175942Sscottl		pci_get_function(dev), pci_get_irq(dev));
1314175942Sscottl
1315175942Sscottl	sprintf(buf, "RocketRAID %x %s Controller\n",
1316175942Sscottl				id, sas ? "SAS" : "SATA");
1317175942Sscottl	device_set_desc_copy(dev, buf);
1318175942Sscottl
1319175942Sscottl	hba = (struct hpt_iop_hba *)device_get_softc(dev);
1320175942Sscottl	bzero(hba, sizeof(struct hpt_iop_hba));
1321175942Sscottl	hba->ops = ops;
1322175942Sscottl
1323175942Sscottl	KdPrint(("hba->ops=%p\n", hba->ops));
1324175942Sscottl	return 0;
1325169412Sscottl}
1326169412Sscottl
1327169412Sscottlstatic int hptiop_attach(device_t dev)
1328169412Sscottl{
1329175942Sscottl	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)device_get_softc(dev);
1330169412Sscottl	struct hpt_iop_request_get_config  iop_config;
1331169412Sscottl	struct hpt_iop_request_set_config  set_config;
1332169412Sscottl	int rid = 0;
1333169412Sscottl	struct cam_devq *devq;
1334169412Sscottl	struct ccb_setasync ccb;
1335169412Sscottl	u_int32_t unit = device_get_unit(dev);
1336169412Sscottl
1337175942Sscottl	device_printf(dev, "%d RocketRAID 3xxx/4xxx controller driver %s\n",
1338175942Sscottl			unit, driver_version);
1339169412Sscottl
1340175942Sscottl	KdPrint(("hptiop: attach(%d, %d/%d/%d) ops=%p\n", unit,
1341175942Sscottl		pci_get_bus(dev), pci_get_slot(dev),
1342175942Sscottl		pci_get_function(dev), hba->ops));
1343175942Sscottl
1344169412Sscottl#if __FreeBSD_version >=440000
1345169412Sscottl	pci_enable_busmaster(dev);
1346169412Sscottl#endif
1347169412Sscottl	hba->pcidev = dev;
1348169412Sscottl	hba->pciunit = unit;
1349169412Sscottl
1350175942Sscottl	if (hba->ops->alloc_pci_res(hba))
1351169412Sscottl		return ENXIO;
1352169412Sscottl
1353175942Sscottl	if (hba->ops->iop_wait_ready(hba, 2000)) {
1354175942Sscottl		device_printf(dev, "adapter is not ready\n");
1355175942Sscottl		goto release_pci_res;
1356169412Sscottl	}
1357169412Sscottl
1358169412Sscottl#if (__FreeBSD_version >= 500000)
1359169412Sscottl	mtx_init(&hba->lock, "hptioplock", NULL, MTX_DEF);
1360169412Sscottl#endif
1361169412Sscottl
1362232854Sscottl	if (bus_dma_tag_create(bus_get_dma_tag(dev),/* PCI parent */
1363169412Sscottl			1,  /* alignment */
1364169412Sscottl			0, /* boundary */
1365169412Sscottl			BUS_SPACE_MAXADDR,  /* lowaddr */
1366169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1367169412Sscottl			NULL, NULL,         /* filter, filterarg */
1368169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsize */
1369169412Sscottl			BUS_SPACE_UNRESTRICTED, /* nsegments */
1370169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1371169412Sscottl			0,      /* flags */
1372169412Sscottl#if __FreeBSD_version>502000
1373169412Sscottl			NULL,   /* lockfunc */
1374169412Sscottl			NULL,       /* lockfuncarg */
1375169412Sscottl#endif
1376169412Sscottl			&hba->parent_dmat   /* tag */))
1377169412Sscottl	{
1378175942Sscottl		device_printf(dev, "alloc parent_dmat failed\n");
1379175942Sscottl		goto release_pci_res;
1380169412Sscottl	}
1381169412Sscottl
1382175942Sscottl	if (hba->ops->internal_memalloc) {
1383175942Sscottl		if (hba->ops->internal_memalloc(hba)) {
1384175942Sscottl			device_printf(dev, "alloc srb_dmat failed\n");
1385175942Sscottl			goto destroy_parent_tag;
1386175942Sscottl		}
1387175942Sscottl	}
1388175942Sscottl
1389175942Sscottl	if (hba->ops->get_config(hba, &iop_config)) {
1390175942Sscottl		device_printf(dev, "get iop config failed.\n");
1391175942Sscottl		goto get_config_failed;
1392175942Sscottl	}
1393175942Sscottl
1394175942Sscottl	hba->firmware_version = iop_config.firmware_version;
1395175942Sscottl	hba->interface_version = iop_config.interface_version;
1396175942Sscottl	hba->max_requests = iop_config.max_requests;
1397175942Sscottl	hba->max_devices = iop_config.max_devices;
1398175942Sscottl	hba->max_request_size = iop_config.request_size;
1399175942Sscottl	hba->max_sg_count = iop_config.max_sg_count;
1400175942Sscottl
1401169412Sscottl	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1402169412Sscottl			4,  /* alignment */
1403169412Sscottl			BUS_SPACE_MAXADDR_32BIT+1, /* boundary */
1404169412Sscottl			BUS_SPACE_MAXADDR,  /* lowaddr */
1405169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1406169412Sscottl			NULL, NULL,         /* filter, filterarg */
1407169412Sscottl			PAGE_SIZE * (hba->max_sg_count-1),  /* maxsize */
1408169412Sscottl			hba->max_sg_count,  /* nsegments */
1409169412Sscottl			0x20000,    /* maxsegsize */
1410169412Sscottl			BUS_DMA_ALLOCNOW,       /* flags */
1411169412Sscottl#if __FreeBSD_version>502000
1412169412Sscottl			busdma_lock_mutex,  /* lockfunc */
1413169412Sscottl			&hba->lock,     /* lockfuncarg */
1414169412Sscottl#endif
1415169412Sscottl			&hba->io_dmat   /* tag */))
1416169412Sscottl	{
1417175942Sscottl		device_printf(dev, "alloc io_dmat failed\n");
1418175942Sscottl		goto get_config_failed;
1419169412Sscottl	}
1420169412Sscottl
1421169412Sscottl	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1422169412Sscottl			1,  /* alignment */
1423169412Sscottl			0, /* boundary */
1424169412Sscottl			BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
1425169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1426169412Sscottl			NULL, NULL,         /* filter, filterarg */
1427169412Sscottl			HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE + 0x20,
1428169412Sscottl			1,  /* nsegments */
1429169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1430169412Sscottl			0,      /* flags */
1431169412Sscottl#if __FreeBSD_version>502000
1432169412Sscottl			NULL,   /* lockfunc */
1433169412Sscottl			NULL,       /* lockfuncarg */
1434169412Sscottl#endif
1435169412Sscottl			&hba->srb_dmat  /* tag */))
1436169412Sscottl	{
1437175942Sscottl		device_printf(dev, "alloc srb_dmat failed\n");
1438175942Sscottl		goto destroy_io_dmat;
1439169412Sscottl	}
1440169412Sscottl
1441169412Sscottl	if (bus_dmamem_alloc(hba->srb_dmat, (void **)&hba->uncached_ptr,
1442169412Sscottl#if __FreeBSD_version>501000
1443175942Sscottl			BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1444169412Sscottl#else
1445175942Sscottl			BUS_DMA_WAITOK,
1446169412Sscottl#endif
1447175942Sscottl			&hba->srb_dmamap) != 0)
1448169412Sscottl	{
1449175942Sscottl		device_printf(dev, "srb bus_dmamem_alloc failed!\n");
1450175942Sscottl		goto destroy_srb_dmat;
1451169412Sscottl	}
1452169412Sscottl
1453169412Sscottl	if (bus_dmamap_load(hba->srb_dmat,
1454169412Sscottl			hba->srb_dmamap, hba->uncached_ptr,
1455169412Sscottl			(HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE) + 0x20,
1456169412Sscottl			hptiop_map_srb, hba, 0))
1457169412Sscottl	{
1458175942Sscottl		device_printf(dev, "bus_dmamap_load failed!\n");
1459175942Sscottl		goto srb_dmamem_free;
1460169412Sscottl	}
1461169412Sscottl
1462169412Sscottl	if ((devq = cam_simq_alloc(hba->max_requests - 1 )) == NULL) {
1463175942Sscottl		device_printf(dev, "cam_simq_alloc failed\n");
1464175942Sscottl		goto srb_dmamap_unload;
1465169412Sscottl	}
1466175942Sscottl
1467175942Sscottl#if __FreeBSD_version <700000
1468169412Sscottl	hba->sim = cam_sim_alloc(hptiop_action, hptiop_poll, driver_name,
1469175942Sscottl			hba, unit, hba->max_requests - 1, 1, devq);
1470175942Sscottl#else
1471175942Sscottl	hba->sim = cam_sim_alloc(hptiop_action, hptiop_poll, driver_name,
1472169412Sscottl			hba, unit, &Giant, hba->max_requests - 1, 1, devq);
1473175942Sscottl#endif
1474169412Sscottl	if (!hba->sim) {
1475175942Sscottl		device_printf(dev, "cam_sim_alloc failed\n");
1476169412Sscottl		cam_simq_free(devq);
1477175942Sscottl		goto srb_dmamap_unload;
1478169412Sscottl	}
1479175942Sscottl#if __FreeBSD_version <700000
1480175942Sscottl	if (xpt_bus_register(hba->sim, 0) != CAM_SUCCESS)
1481175942Sscottl#else
1482175942Sscottl	if (xpt_bus_register(hba->sim, dev, 0) != CAM_SUCCESS)
1483175942Sscottl#endif
1484175942Sscottl	{
1485175942Sscottl		device_printf(dev, "xpt_bus_register failed\n");
1486175942Sscottl		goto free_cam_sim;
1487169412Sscottl	}
1488169412Sscottl
1489169412Sscottl	if (xpt_create_path(&hba->path, /*periph */ NULL,
1490169412Sscottl			cam_sim_path(hba->sim), CAM_TARGET_WILDCARD,
1491175942Sscottl			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1492175942Sscottl		device_printf(dev, "xpt_create_path failed\n");
1493175942Sscottl		goto deregister_xpt_bus;
1494169412Sscottl	}
1495169412Sscottl
1496169412Sscottl	bzero(&set_config, sizeof(set_config));
1497175942Sscottl	set_config.iop_id = unit;
1498169412Sscottl	set_config.vbus_id = cam_sim_path(hba->sim);
1499169412Sscottl	set_config.max_host_request_size = HPT_SRB_MAX_REQ_SIZE;
1500169412Sscottl
1501175942Sscottl	if (hba->ops->set_config(hba, &set_config)) {
1502175942Sscottl		device_printf(dev, "set iop config failed.\n");
1503175942Sscottl		goto free_hba_path;
1504169412Sscottl	}
1505169412Sscottl
1506169412Sscottl	xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
1507169412Sscottl	ccb.ccb_h.func_code = XPT_SASYNC_CB;
1508169412Sscottl	ccb.event_enable = (AC_FOUND_DEVICE | AC_LOST_DEVICE);
1509169412Sscottl	ccb.callback = hptiop_async;
1510169412Sscottl	ccb.callback_arg = hba->sim;
1511169412Sscottl	xpt_action((union ccb *)&ccb);
1512169412Sscottl
1513169412Sscottl	rid = 0;
1514169412Sscottl	if ((hba->irq_res = bus_alloc_resource(hba->pcidev, SYS_RES_IRQ,
1515169412Sscottl			&rid, 0, ~0ul, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1516175942Sscottl		device_printf(dev, "allocate irq failed!\n");
1517175942Sscottl		goto free_hba_path;
1518169412Sscottl	}
1519169412Sscottl
1520175942Sscottl#if __FreeBSD_version <700000
1521169412Sscottl	if (bus_setup_intr(hba->pcidev, hba->irq_res, INTR_TYPE_CAM,
1522175942Sscottl				hptiop_pci_intr, hba, &hba->irq_handle))
1523175942Sscottl#else
1524175942Sscottl	if (bus_setup_intr(hba->pcidev, hba->irq_res, INTR_TYPE_CAM,
1525175942Sscottl				NULL, hptiop_pci_intr, hba, &hba->irq_handle))
1526175942Sscottl#endif
1527175942Sscottl	{
1528175942Sscottl		device_printf(dev, "allocate intr function failed!\n");
1529175942Sscottl		goto free_irq_resource;
1530169412Sscottl	}
1531169412Sscottl
1532175942Sscottl	if (hptiop_send_sync_msg(hba,
1533175942Sscottl			IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
1534175942Sscottl		device_printf(dev, "fail to start background task\n");
1535175942Sscottl		goto teartown_irq_resource;
1536169412Sscottl	}
1537169412Sscottl
1538175942Sscottl	hba->ops->enable_intr(hba);
1539175942Sscottl
1540169412Sscottl	hba->ioctl_dev = make_dev(&hptiop_cdevsw, unit,
1541169412Sscottl				UID_ROOT, GID_WHEEL /*GID_OPERATOR*/,
1542169412Sscottl				S_IRUSR | S_IWUSR, "%s%d", driver_name, unit);
1543169412Sscottl
1544169412Sscottl#if __FreeBSD_version < 503000
1545169412Sscottl	hba->ioctl_dev->si_drv1 = hba;
1546169412Sscottl#endif
1547169412Sscottl
1548169412Sscottl	return 0;
1549175942Sscottl
1550175942Sscottl
1551175942Sscottlteartown_irq_resource:
1552175942Sscottl	bus_teardown_intr(dev, hba->irq_res, hba->irq_handle);
1553175942Sscottl
1554175942Sscottlfree_irq_resource:
1555175942Sscottl	bus_release_resource(dev, SYS_RES_IRQ, 0, hba->irq_res);
1556175942Sscottl
1557175942Sscottlfree_hba_path:
1558175942Sscottl	xpt_free_path(hba->path);
1559175942Sscottl
1560175942Sscottlderegister_xpt_bus:
1561175942Sscottl	xpt_bus_deregister(cam_sim_path(hba->sim));
1562175942Sscottl
1563175942Sscottlfree_cam_sim:
1564175942Sscottl	cam_sim_free(hba->sim, /*free devq*/ TRUE);
1565175942Sscottl
1566175942Sscottlsrb_dmamap_unload:
1567175942Sscottl	if (hba->uncached_ptr)
1568175942Sscottl		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
1569175942Sscottl
1570175942Sscottlsrb_dmamem_free:
1571175942Sscottl	if (hba->uncached_ptr)
1572175942Sscottl		bus_dmamem_free(hba->srb_dmat,
1573175942Sscottl			hba->uncached_ptr, hba->srb_dmamap);
1574175942Sscottl
1575175942Sscottldestroy_srb_dmat:
1576175942Sscottl	if (hba->srb_dmat)
1577175942Sscottl		bus_dma_tag_destroy(hba->srb_dmat);
1578175942Sscottl
1579175942Sscottldestroy_io_dmat:
1580175942Sscottl	if (hba->io_dmat)
1581175942Sscottl		bus_dma_tag_destroy(hba->io_dmat);
1582175942Sscottl
1583175942Sscottlget_config_failed:
1584175942Sscottl	if (hba->ops->internal_memfree)
1585175942Sscottl		hba->ops->internal_memfree(hba);
1586175942Sscottl
1587175942Sscottldestroy_parent_tag:
1588175942Sscottl	if (hba->parent_dmat)
1589175942Sscottl		bus_dma_tag_destroy(hba->parent_dmat);
1590175942Sscottl
1591175942Sscottlrelease_pci_res:
1592175942Sscottl	if (hba->ops->release_pci_res)
1593175942Sscottl		hba->ops->release_pci_res(hba);
1594175942Sscottl
1595175942Sscottl	return ENXIO;
1596169412Sscottl}
1597169412Sscottl
1598169412Sscottlstatic int hptiop_detach(device_t dev)
1599169412Sscottl{
1600169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
1601169412Sscottl	int i;
1602169412Sscottl	int error = EBUSY;
1603169412Sscottl
1604169412Sscottl	hptiop_lock_adapter(hba);
1605175942Sscottl	for (i = 0; i < hba->max_devices; i++)
1606175942Sscottl		if (hptiop_os_query_remove_device(hba, i)) {
1607175942Sscottl			device_printf(dev, "%d file system is busy. id=%d",
1608169412Sscottl						hba->pciunit, i);
1609169412Sscottl			goto out;
1610169412Sscottl		}
1611169412Sscottl
1612169412Sscottl	if ((error = hptiop_shutdown(dev)) != 0)
1613169412Sscottl		goto out;
1614175942Sscottl	if (hptiop_send_sync_msg(hba,
1615175942Sscottl		IOPMU_INBOUND_MSG0_STOP_BACKGROUND_TASK, 60000))
1616169412Sscottl		goto out;
1617169412Sscottl
1618169412Sscottl	hptiop_release_resource(hba);
1619169412Sscottl	error = 0;
1620169412Sscottlout:
1621169412Sscottl	hptiop_unlock_adapter(hba);
1622169412Sscottl	return error;
1623169412Sscottl}
1624169412Sscottl
1625169412Sscottlstatic int hptiop_shutdown(device_t dev)
1626169412Sscottl{
1627169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
1628169412Sscottl
1629169412Sscottl	int error = 0;
1630169412Sscottl
1631169412Sscottl	if (hba->flag & HPT_IOCTL_FLAG_OPEN) {
1632175942Sscottl		device_printf(dev, "%d device is busy", hba->pciunit);
1633169412Sscottl		return EBUSY;
1634169412Sscottl	}
1635175942Sscottl
1636175942Sscottl	hba->ops->disable_intr(hba);
1637175942Sscottl
1638175942Sscottl	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
1639169412Sscottl		error = EBUSY;
1640169412Sscottl
1641169412Sscottl	return error;
1642169412Sscottl}
1643169412Sscottl
1644169412Sscottlstatic void hptiop_pci_intr(void *arg)
1645169412Sscottl{
1646169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
1647169412Sscottl	hptiop_lock_adapter(hba);
1648175942Sscottl	hba->ops->iop_intr(hba);
1649169412Sscottl	hptiop_unlock_adapter(hba);
1650169412Sscottl}
1651169412Sscottl
1652169412Sscottlstatic void hptiop_poll(struct cam_sim *sim)
1653169412Sscottl{
1654169412Sscottl	hptiop_pci_intr(cam_sim_softc(sim));
1655169412Sscottl}
1656169412Sscottl
1657169412Sscottlstatic void hptiop_async(void * callback_arg, u_int32_t code,
1658169412Sscottl					struct cam_path * path, void * arg)
1659169412Sscottl{
1660169412Sscottl}
1661169412Sscottl
1662175942Sscottlstatic void hptiop_enable_intr_itl(struct hpt_iop_hba *hba)
1663169412Sscottl{
1664175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_intmask,
1665169412Sscottl		~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0));
1666169412Sscottl}
1667169412Sscottl
1668175942Sscottlstatic void hptiop_enable_intr_mv(struct hpt_iop_hba *hba)
1669169412Sscottl{
1670169412Sscottl	u_int32_t int_mask;
1671169412Sscottl
1672175942Sscottl	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
1673175942Sscottl
1674175942Sscottl	int_mask |= MVIOP_MU_OUTBOUND_INT_POSTQUEUE
1675175942Sscottl			| MVIOP_MU_OUTBOUND_INT_MSG;
1676175942Sscottl    	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
1677169412Sscottl}
1678169412Sscottl
1679175942Sscottlstatic void hptiop_disable_intr_itl(struct hpt_iop_hba *hba)
1680175942Sscottl{
1681175942Sscottl	u_int32_t int_mask;
1682175942Sscottl
1683175942Sscottl	int_mask = BUS_SPACE_RD4_ITL(outbound_intmask);
1684175942Sscottl
1685175942Sscottl	int_mask |= IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0;
1686175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_intmask, int_mask);
1687175942Sscottl	BUS_SPACE_RD4_ITL(outbound_intstatus);
1688175942Sscottl}
1689175942Sscottl
1690175942Sscottlstatic void hptiop_disable_intr_mv(struct hpt_iop_hba *hba)
1691175942Sscottl{
1692175942Sscottl	u_int32_t int_mask;
1693175942Sscottl	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
1694175942Sscottl
1695175942Sscottl	int_mask &= ~(MVIOP_MU_OUTBOUND_INT_MSG
1696175942Sscottl			| MVIOP_MU_OUTBOUND_INT_POSTQUEUE);
1697175942Sscottl	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
1698175942Sscottl	BUS_SPACE_RD4_MV0(outbound_intmask);
1699175942Sscottl}
1700175942Sscottl
1701169412Sscottlstatic int hptiop_reset_adapter(struct hpt_iop_hba * hba)
1702169412Sscottl{
1703175942Sscottl	return hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1704169412Sscottl}
1705169412Sscottl
1706169412Sscottlstatic void *hptiop_get_srb(struct hpt_iop_hba * hba)
1707169412Sscottl{
1708169412Sscottl	struct hpt_iop_srb * srb;
1709169412Sscottl
1710169412Sscottl	if (hba->srb_list) {
1711169412Sscottl		srb = hba->srb_list;
1712169412Sscottl		hba->srb_list = srb->next;
1713175942Sscottl		return srb;
1714169412Sscottl	}
1715169412Sscottl
1716175942Sscottl	return NULL;
1717169412Sscottl}
1718169412Sscottl
1719175942Sscottlstatic void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb)
1720169412Sscottl{
1721169412Sscottl	srb->next = hba->srb_list;
1722169412Sscottl	hba->srb_list = srb;
1723169412Sscottl}
1724169412Sscottl
1725169412Sscottlstatic void hptiop_action(struct cam_sim *sim, union ccb *ccb)
1726169412Sscottl{
1727169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)cam_sim_softc(sim);
1728169412Sscottl	struct hpt_iop_srb * srb;
1729169412Sscottl
1730169412Sscottl	switch (ccb->ccb_h.func_code) {
1731169412Sscottl
1732169412Sscottl	case XPT_SCSI_IO:
1733169412Sscottl		hptiop_lock_adapter(hba);
1734169412Sscottl		if (ccb->ccb_h.target_lun != 0 ||
1735175942Sscottl			ccb->ccb_h.target_id >= hba->max_devices ||
1736169412Sscottl			(ccb->ccb_h.flags & CAM_CDB_PHYS))
1737169412Sscottl		{
1738169412Sscottl			ccb->ccb_h.status = CAM_TID_INVALID;
1739169412Sscottl			xpt_done(ccb);
1740169412Sscottl			goto scsi_done;
1741169412Sscottl		}
1742169412Sscottl
1743169412Sscottl		if ((srb = hptiop_get_srb(hba)) == NULL) {
1744175942Sscottl			device_printf(hba->pcidev, "srb allocated failed");
1745169412Sscottl			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1746169412Sscottl			xpt_done(ccb);
1747169412Sscottl			goto scsi_done;
1748169412Sscottl		}
1749169412Sscottl
1750169412Sscottl		srb->ccb = ccb;
1751169412Sscottl
1752169412Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
1753169412Sscottl			hptiop_post_scsi_command(srb, NULL, 0, 0);
1754169412Sscottl		else if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
1755169412Sscottl			if ((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) {
1756169412Sscottl				int error;
1757169412Sscottl
1758169412Sscottl				error = bus_dmamap_load(hba->io_dmat,
1759175942Sscottl						srb->dma_map,
1760175942Sscottl						ccb->csio.data_ptr,
1761175942Sscottl						ccb->csio.dxfer_len,
1762175942Sscottl						hptiop_post_scsi_command,
1763175942Sscottl						srb, 0);
1764169412Sscottl
1765169412Sscottl				if (error && error != EINPROGRESS) {
1766175942Sscottl					device_printf(hba->pcidev,
1767175942Sscottl						"%d bus_dmamap_load error %d",
1768175942Sscottl						hba->pciunit, error);
1769169412Sscottl					xpt_freeze_simq(hba->sim, 1);
1770169412Sscottl					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1771169412Sscottlinvalid:
1772169412Sscottl					hptiop_free_srb(hba, srb);
1773169412Sscottl					xpt_done(ccb);
1774169412Sscottl					goto scsi_done;
1775169412Sscottl				}
1776169412Sscottl			}
1777169412Sscottl			else {
1778175942Sscottl				device_printf(hba->pcidev,
1779175942Sscottl					"CAM_DATA_PHYS not supported");
1780169412Sscottl				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1781169412Sscottl				goto invalid;
1782169412Sscottl			}
1783169412Sscottl		}
1784169412Sscottl		else {
1785169412Sscottl			struct bus_dma_segment *segs;
1786169412Sscottl
1787169412Sscottl			if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0 ||
1788169412Sscottl				(ccb->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1789175942Sscottl				device_printf(hba->pcidev, "SCSI cmd failed");
1790169412Sscottl				ccb->ccb_h.status=CAM_PROVIDE_FAIL;
1791169412Sscottl				goto invalid;
1792169412Sscottl			}
1793169412Sscottl
1794169412Sscottl			segs = (struct bus_dma_segment *)ccb->csio.data_ptr;
1795169412Sscottl			hptiop_post_scsi_command(srb, segs,
1796169412Sscottl						ccb->csio.sglist_cnt, 0);
1797169412Sscottl		}
1798169412Sscottl
1799169412Sscottlscsi_done:
1800169412Sscottl		hptiop_unlock_adapter(hba);
1801169412Sscottl		return;
1802169412Sscottl
1803169412Sscottl	case XPT_RESET_BUS:
1804175942Sscottl		device_printf(hba->pcidev, "reset adapter");
1805169412Sscottl		hptiop_lock_adapter(hba);
1806169412Sscottl		hba->msg_done = 0;
1807169412Sscottl		hptiop_reset_adapter(hba);
1808169412Sscottl		hptiop_unlock_adapter(hba);
1809169412Sscottl		break;
1810169412Sscottl
1811169412Sscottl	case XPT_GET_TRAN_SETTINGS:
1812169412Sscottl	case XPT_SET_TRAN_SETTINGS:
1813169412Sscottl		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1814169412Sscottl		break;
1815169412Sscottl
1816169412Sscottl	case XPT_CALC_GEOMETRY:
1817227912Smarius#if __FreeBSD_version >= 500000
1818227912Smarius		cam_calc_geometry(&ccb->ccg, 1);
1819227912Smarius#else
1820169412Sscottl		ccb->ccg.heads = 255;
1821169412Sscottl		ccb->ccg.secs_per_track = 63;
1822169412Sscottl		ccb->ccg.cylinders = ccb->ccg.volume_size /
1823169412Sscottl				(ccb->ccg.heads * ccb->ccg.secs_per_track);
1824169412Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
1825227912Smarius#endif
1826169412Sscottl		break;
1827169412Sscottl
1828169412Sscottl	case XPT_PATH_INQ:
1829169412Sscottl	{
1830169412Sscottl		struct ccb_pathinq *cpi = &ccb->cpi;
1831169412Sscottl
1832169412Sscottl		cpi->version_num = 1;
1833169412Sscottl		cpi->hba_inquiry = PI_SDTR_ABLE;
1834169412Sscottl		cpi->target_sprt = 0;
1835169412Sscottl		cpi->hba_misc = PIM_NOBUSRESET;
1836169412Sscottl		cpi->hba_eng_cnt = 0;
1837175942Sscottl		cpi->max_target = hba->max_devices;
1838169412Sscottl		cpi->max_lun = 0;
1839169412Sscottl		cpi->unit_number = cam_sim_unit(sim);
1840169412Sscottl		cpi->bus_id = cam_sim_bus(sim);
1841175942Sscottl		cpi->initiator_id = hba->max_devices;
1842169412Sscottl		cpi->base_transfer_speed = 3300;
1843169412Sscottl
1844169412Sscottl		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1845169412Sscottl		strncpy(cpi->hba_vid, "HPT   ", HBA_IDLEN);
1846169412Sscottl		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1847209340Smav		cpi->transport = XPORT_SPI;
1848209340Smav		cpi->transport_version = 2;
1849209340Smav		cpi->protocol = PROTO_SCSI;
1850209340Smav		cpi->protocol_version = SCSI_REV_2;
1851169412Sscottl		cpi->ccb_h.status = CAM_REQ_CMP;
1852169412Sscottl		break;
1853169412Sscottl	}
1854169412Sscottl
1855169412Sscottl	default:
1856169412Sscottl		ccb->ccb_h.status = CAM_REQ_INVALID;
1857169412Sscottl		break;
1858169412Sscottl	}
1859169412Sscottl
1860169412Sscottl	xpt_done(ccb);
1861169412Sscottl	return;
1862169412Sscottl}
1863169412Sscottl
1864175942Sscottlstatic void hptiop_post_req_itl(struct hpt_iop_hba *hba,
1865175942Sscottl				struct hpt_iop_srb *srb,
1866175942Sscottl				bus_dma_segment_t *segs, int nsegs)
1867169412Sscottl{
1868169412Sscottl	int idx;
1869169412Sscottl	union ccb *ccb = srb->ccb;
1870169412Sscottl	u_int8_t *cdb;
1871169412Sscottl
1872175942Sscottl	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
1873175942Sscottl		cdb = ccb->csio.cdb_io.cdb_ptr;
1874175942Sscottl	else
1875175942Sscottl		cdb = ccb->csio.cdb_io.cdb_bytes;
1876169412Sscottl
1877175942Sscottl	KdPrint(("ccb=%p %x-%x-%x\n",
1878175942Sscottl		ccb, *(u_int32_t *)cdb, *((u_int32_t *)cdb+1), *((u_int32_t *)cdb+2)));
1879169412Sscottl
1880169412Sscottl	if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) {
1881175942Sscottl		u_int32_t iop_req32;
1882175942Sscottl		struct hpt_iop_request_scsi_command req;
1883169412Sscottl
1884175942Sscottl		iop_req32 = BUS_SPACE_RD4_ITL(inbound_queue);
1885175942Sscottl
1886175942Sscottl		if (iop_req32 == IOPMU_QUEUE_EMPTY) {
1887175942Sscottl			device_printf(hba->pcidev, "invaild req offset\n");
1888175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
1889175942Sscottl			bus_dmamap_unload(hba->io_dmat, srb->dma_map);
1890175942Sscottl			hptiop_free_srb(hba, srb);
1891175942Sscottl			xpt_done(ccb);
1892175942Sscottl			return;
1893169412Sscottl		}
1894175942Sscottl
1895175942Sscottl		if (ccb->csio.dxfer_len && nsegs > 0) {
1896175942Sscottl			struct hpt_iopsg *psg = req.sg_list;
1897175942Sscottl			for (idx = 0; idx < nsegs; idx++, psg++) {
1898175942Sscottl				psg->pci_address = (u_int64_t)segs[idx].ds_addr;
1899175942Sscottl				psg->size = segs[idx].ds_len;
1900175942Sscottl				psg->eot = 0;
1901175942Sscottl			}
1902175942Sscottl			psg[-1].eot = 1;
1903175942Sscottl		}
1904175942Sscottl
1905175942Sscottl		bcopy(cdb, req.cdb, ccb->csio.cdb_len);
1906175942Sscottl
1907175942Sscottl		req.header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list)
1908175942Sscottl				+ nsegs*sizeof(struct hpt_iopsg);
1909175942Sscottl		req.header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
1910175942Sscottl		req.header.flags = 0;
1911175942Sscottl		req.header.result = IOP_RESULT_PENDING;
1912175942Sscottl		req.header.context = (u_int64_t)(unsigned long)srb;
1913175942Sscottl		req.dataxfer_length = ccb->csio.dxfer_len;
1914175942Sscottl		req.channel =  0;
1915175942Sscottl		req.target =  ccb->ccb_h.target_id;
1916175942Sscottl		req.lun =  ccb->ccb_h.target_lun;
1917175942Sscottl
1918175942Sscottl		bus_space_write_region_1(hba->bar0t, hba->bar0h, iop_req32,
1919175942Sscottl			(u_int8_t *)&req, req.header.size);
1920175942Sscottl
1921175942Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1922175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1923175942Sscottl				srb->dma_map, BUS_DMASYNC_PREREAD);
1924175942Sscottl		}
1925175942Sscottl		else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
1926175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1927175942Sscottl				srb->dma_map, BUS_DMASYNC_PREWRITE);
1928175942Sscottl
1929175942Sscottl		BUS_SPACE_WRT4_ITL(inbound_queue,iop_req32);
1930175942Sscottl	} else {
1931175942Sscottl		struct hpt_iop_request_scsi_command *req;
1932175942Sscottl
1933169412Sscottl		req = (struct hpt_iop_request_scsi_command *)srb;
1934175942Sscottl		if (ccb->csio.dxfer_len && nsegs > 0) {
1935175942Sscottl			struct hpt_iopsg *psg = req->sg_list;
1936175942Sscottl			for (idx = 0; idx < nsegs; idx++, psg++) {
1937175942Sscottl				psg->pci_address =
1938175942Sscottl					(u_int64_t)segs[idx].ds_addr;
1939175942Sscottl				psg->size = segs[idx].ds_len;
1940175942Sscottl				psg->eot = 0;
1941175942Sscottl			}
1942175942Sscottl			psg[-1].eot = 1;
1943175942Sscottl		}
1944169412Sscottl
1945175942Sscottl		bcopy(cdb, req->cdb, ccb->csio.cdb_len);
1946175942Sscottl
1947175942Sscottl		req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
1948175942Sscottl		req->header.result = IOP_RESULT_PENDING;
1949175942Sscottl		req->dataxfer_length = ccb->csio.dxfer_len;
1950175942Sscottl		req->channel =  0;
1951175942Sscottl		req->target =  ccb->ccb_h.target_id;
1952175942Sscottl		req->lun =  ccb->ccb_h.target_lun;
1953175942Sscottl		req->header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list)
1954175942Sscottl			+ nsegs*sizeof(struct hpt_iopsg);
1955175942Sscottl		req->header.context = (u_int64_t)srb->index |
1956175942Sscottl						IOPMU_QUEUE_ADDR_HOST_BIT;
1957175942Sscottl		req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
1958175942Sscottl
1959175942Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1960175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1961175942Sscottl				srb->dma_map, BUS_DMASYNC_PREREAD);
1962175942Sscottl		}else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1963175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1964175942Sscottl				srb->dma_map, BUS_DMASYNC_PREWRITE);
1965175942Sscottl		}
1966175942Sscottl
1967175942Sscottl		if (hba->firmware_version > 0x01020000
1968175942Sscottl			|| hba->interface_version > 0x01020000) {
1969175942Sscottl			u_int32_t size_bits;
1970175942Sscottl
1971175942Sscottl			if (req->header.size < 256)
1972175942Sscottl				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
1973175942Sscottl			else if (req->header.size < 512)
1974175942Sscottl				size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
1975175942Sscottl			else
1976175942Sscottl				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT
1977175942Sscottl						| IOPMU_QUEUE_ADDR_HOST_BIT;
1978175942Sscottl
1979175942Sscottl			BUS_SPACE_WRT4_ITL(inbound_queue,
1980175942Sscottl				(u_int32_t)srb->phy_addr | size_bits);
1981175942Sscottl		} else
1982175942Sscottl			BUS_SPACE_WRT4_ITL(inbound_queue, (u_int32_t)srb->phy_addr
1983175942Sscottl				|IOPMU_QUEUE_ADDR_HOST_BIT);
1984175942Sscottl	}
1985175942Sscottl}
1986175942Sscottl
1987175942Sscottlstatic void hptiop_post_req_mv(struct hpt_iop_hba *hba,
1988175942Sscottl				struct hpt_iop_srb *srb,
1989175942Sscottl				bus_dma_segment_t *segs, int nsegs)
1990175942Sscottl{
1991175942Sscottl	int idx, size;
1992175942Sscottl	union ccb *ccb = srb->ccb;
1993175942Sscottl	u_int8_t *cdb;
1994175942Sscottl	struct hpt_iop_request_scsi_command *req;
1995175942Sscottl	u_int64_t req_phy;
1996175942Sscottl
1997175942Sscottl    	req = (struct hpt_iop_request_scsi_command *)srb;
1998175942Sscottl	req_phy = srb->phy_addr;
1999175942Sscottl
2000169412Sscottl	if (ccb->csio.dxfer_len && nsegs > 0) {
2001169412Sscottl		struct hpt_iopsg *psg = req->sg_list;
2002169412Sscottl		for (idx = 0; idx < nsegs; idx++, psg++) {
2003169412Sscottl			psg->pci_address = (u_int64_t)segs[idx].ds_addr;
2004169412Sscottl			psg->size = segs[idx].ds_len;
2005169412Sscottl			psg->eot = 0;
2006169412Sscottl		}
2007169412Sscottl		psg[-1].eot = 1;
2008169412Sscottl	}
2009169412Sscottl	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
2010169412Sscottl		cdb = ccb->csio.cdb_io.cdb_ptr;
2011169412Sscottl	else
2012169412Sscottl		cdb = ccb->csio.cdb_io.cdb_bytes;
2013169412Sscottl
2014169412Sscottl	bcopy(cdb, req->cdb, ccb->csio.cdb_len);
2015169412Sscottl	req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2016169412Sscottl	req->header.result = IOP_RESULT_PENDING;
2017169412Sscottl	req->dataxfer_length = ccb->csio.dxfer_len;
2018175942Sscottl	req->channel = 0;
2019169412Sscottl	req->target =  ccb->ccb_h.target_id;
2020169412Sscottl	req->lun =  ccb->ccb_h.target_lun;
2021169412Sscottl	req->header.size = sizeof(struct hpt_iop_request_scsi_command)
2022175942Sscottl				- sizeof(struct hpt_iopsg)
2023175942Sscottl				+ nsegs * sizeof(struct hpt_iopsg);
2024169412Sscottl	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2025169412Sscottl		bus_dmamap_sync(hba->io_dmat,
2026175942Sscottl			srb->dma_map, BUS_DMASYNC_PREREAD);
2027169412Sscottl	}
2028169412Sscottl	else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
2029169412Sscottl		bus_dmamap_sync(hba->io_dmat,
2030175942Sscottl			srb->dma_map, BUS_DMASYNC_PREWRITE);
2031175942Sscottl	req->header.context = (u_int64_t)srb->index
2032175942Sscottl					<< MVIOP_REQUEST_NUMBER_START_BIT
2033175942Sscottl					| MVIOP_CMD_TYPE_SCSI;
2034175942Sscottl	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
2035175942Sscottl	size = req->header.size >> 8;
2036175942Sscottl	hptiop_mv_inbound_write(req_phy
2037175942Sscottl			| MVIOP_MU_QUEUE_ADDR_HOST_BIT
2038175942Sscottl			| (size > 3 ? 3 : size), hba);
2039169412Sscottl}
2040169412Sscottl
2041175942Sscottlstatic void hptiop_post_scsi_command(void *arg, bus_dma_segment_t *segs,
2042175942Sscottl					int nsegs, int error)
2043169412Sscottl{
2044175942Sscottl	struct hpt_iop_srb *srb = (struct hpt_iop_srb *)arg;
2045175942Sscottl	union ccb *ccb = srb->ccb;
2046175942Sscottl	struct hpt_iop_hba *hba = srb->hba;
2047169412Sscottl
2048175942Sscottl	if (error || nsegs > hba->max_sg_count) {
2049175942Sscottl		KdPrint(("hptiop: func_code=%x tid=%x lun=%x nsegs=%d\n",
2050175942Sscottl			ccb->ccb_h.func_code,
2051175942Sscottl			ccb->ccb_h.target_id,
2052175942Sscottl			ccb->ccb_h.target_lun, nsegs));
2053175942Sscottl		ccb->ccb_h.status = CAM_BUSY;
2054175942Sscottl		bus_dmamap_unload(hba->io_dmat, srb->dma_map);
2055169412Sscottl		hptiop_free_srb(hba, srb);
2056169412Sscottl		xpt_done(ccb);
2057175942Sscottl		return;
2058169412Sscottl	}
2059175942Sscottl
2060175942Sscottl	hba->ops->post_req(hba, srb, segs, nsegs);
2061169412Sscottl}
2062169412Sscottl
2063175942Sscottlstatic void hptiop_mv_map_ctlcfg(void *arg, bus_dma_segment_t *segs,
2064175942Sscottl				int nsegs, int error)
2065175942Sscottl{
2066175942Sscottl	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)arg;
2067175942Sscottl	hba->ctlcfgcmd_phy = ((u_int64_t)segs->ds_addr + 0x1F)
2068175942Sscottl				& ~(u_int64_t)0x1F;
2069175942Sscottl	hba->ctlcfg_ptr = (u_int8_t *)(((unsigned long)hba->ctlcfg_ptr + 0x1F)
2070175942Sscottl				& ~0x1F);
2071175942Sscottl}
2072175942Sscottl
2073169412Sscottlstatic void hptiop_map_srb(void *arg, bus_dma_segment_t *segs,
2074175942Sscottl				int nsegs, int error)
2075169412Sscottl{
2076169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
2077169412Sscottl	bus_addr_t phy_addr = (segs->ds_addr + 0x1F) & ~(bus_addr_t)0x1F;
2078169412Sscottl	struct hpt_iop_srb *srb, *tmp_srb;
2079169412Sscottl	int i;
2080169412Sscottl
2081169412Sscottl	if (error || nsegs == 0) {
2082175942Sscottl		device_printf(hba->pcidev, "hptiop_map_srb error");
2083169412Sscottl		return;
2084169412Sscottl	}
2085169412Sscottl
2086169412Sscottl	/* map srb */
2087169412Sscottl	srb = (struct hpt_iop_srb *)
2088175942Sscottl		(((unsigned long)hba->uncached_ptr + 0x1F)
2089175942Sscottl		& ~(unsigned long)0x1F);
2090169412Sscottl
2091169412Sscottl	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2092169412Sscottl		tmp_srb = (struct hpt_iop_srb *)
2093169412Sscottl					((char *)srb + i * HPT_SRB_MAX_SIZE);
2094169412Sscottl		if (((unsigned long)tmp_srb & 0x1F) == 0) {
2095169412Sscottl			if (bus_dmamap_create(hba->io_dmat,
2096169412Sscottl						0, &tmp_srb->dma_map)) {
2097175942Sscottl				device_printf(hba->pcidev, "dmamap create failed");
2098169412Sscottl				return;
2099169412Sscottl			}
2100169412Sscottl
2101169412Sscottl			bzero(tmp_srb, sizeof(struct hpt_iop_srb));
2102169412Sscottl			tmp_srb->hba = hba;
2103169412Sscottl			tmp_srb->index = i;
2104175942Sscottl			if (hba->ctlcfg_ptr == 0) {/*itl iop*/
2105175942Sscottl				tmp_srb->phy_addr = (u_int64_t)(u_int32_t)
2106175942Sscottl							(phy_addr >> 5);
2107175942Sscottl				if (phy_addr & IOPMU_MAX_MEM_SUPPORT_MASK_32G)
2108175942Sscottl					tmp_srb->srb_flag =
2109175942Sscottl						HPT_SRB_FLAG_HIGH_MEM_ACESS;
2110175942Sscottl			} else {
2111175942Sscottl				tmp_srb->phy_addr = phy_addr;
2112175942Sscottl			}
2113175942Sscottl
2114169412Sscottl			hptiop_free_srb(hba, tmp_srb);
2115169412Sscottl			hba->srb[i] = tmp_srb;
2116169412Sscottl			phy_addr += HPT_SRB_MAX_SIZE;
2117169412Sscottl		}
2118169412Sscottl		else {
2119175942Sscottl			device_printf(hba->pcidev, "invalid alignment");
2120169412Sscottl			return;
2121169412Sscottl		}
2122169412Sscottl	}
2123169412Sscottl}
2124169412Sscottl
2125175942Sscottlstatic void hptiop_os_message_callback(struct hpt_iop_hba * hba, u_int32_t msg)
2126169412Sscottl{
2127169412Sscottl		hba->msg_done = 1;
2128169412Sscottl}
2129169412Sscottl
2130175942Sscottlstatic  int hptiop_os_query_remove_device(struct hpt_iop_hba * hba,
2131175942Sscottl						int target_id)
2132169412Sscottl{
2133169412Sscottl	struct cam_periph       *periph = NULL;
2134169412Sscottl	struct cam_path         *path;
2135169412Sscottl	int                     status, retval = 0;
2136169412Sscottl
2137169412Sscottl	status = xpt_create_path(&path, NULL, hba->sim->path_id, target_id, 0);
2138169412Sscottl
2139169412Sscottl	if (status == CAM_REQ_CMP) {
2140169412Sscottl		if ((periph = cam_periph_find(path, "da")) != NULL) {
2141169412Sscottl			if (periph->refcount >= 1) {
2142175942Sscottl				device_printf(hba->pcidev, "%d ,"
2143175942Sscottl					"target_id=0x%x,"
2144175942Sscottl					"refcount=%d",
2145169412Sscottl				    hba->pciunit, target_id, periph->refcount);
2146169412Sscottl				retval = -1;
2147169412Sscottl			}
2148169412Sscottl		}
2149169412Sscottl		xpt_free_path(path);
2150169412Sscottl	}
2151169412Sscottl	return retval;
2152169412Sscottl}
2153169412Sscottl
2154169412Sscottlstatic void hptiop_release_resource(struct hpt_iop_hba *hba)
2155169412Sscottl{
2156175942Sscottl	int i;
2157175942Sscottl	if (hba->path) {
2158175942Sscottl		struct ccb_setasync ccb;
2159169412Sscottl
2160169412Sscottl		xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
2161169412Sscottl		ccb.ccb_h.func_code = XPT_SASYNC_CB;
2162169412Sscottl		ccb.event_enable = 0;
2163169412Sscottl		ccb.callback = hptiop_async;
2164169412Sscottl		ccb.callback_arg = hba->sim;
2165169412Sscottl		xpt_action((union ccb *)&ccb);
2166169412Sscottl		xpt_free_path(hba->path);
2167169412Sscottl	}
2168169412Sscottl
2169169412Sscottl	if (hba->sim) {
2170169412Sscottl		xpt_bus_deregister(cam_sim_path(hba->sim));
2171169412Sscottl		cam_sim_free(hba->sim, TRUE);
2172169412Sscottl	}
2173169412Sscottl
2174175942Sscottl	if (hba->ctlcfg_dmat) {
2175175942Sscottl		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
2176175942Sscottl		bus_dmamem_free(hba->ctlcfg_dmat,
2177175942Sscottl					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
2178175942Sscottl		bus_dma_tag_destroy(hba->ctlcfg_dmat);
2179175942Sscottl	}
2180175942Sscottl
2181175942Sscottl	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2182175942Sscottl		struct hpt_iop_srb *srb = hba->srb[i];
2183175942Sscottl		if (srb->dma_map)
2184175942Sscottl			bus_dmamap_destroy(hba->io_dmat, srb->dma_map);
2185175942Sscottl	}
2186175942Sscottl
2187169412Sscottl	if (hba->srb_dmat) {
2188169412Sscottl		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
2189175942Sscottl		bus_dmamap_destroy(hba->srb_dmat, hba->srb_dmamap);
2190169412Sscottl		bus_dma_tag_destroy(hba->srb_dmat);
2191169412Sscottl	}
2192169412Sscottl
2193169412Sscottl	if (hba->io_dmat)
2194169412Sscottl		bus_dma_tag_destroy(hba->io_dmat);
2195169412Sscottl
2196169412Sscottl	if (hba->parent_dmat)
2197169412Sscottl		bus_dma_tag_destroy(hba->parent_dmat);
2198169412Sscottl
2199169412Sscottl	if (hba->irq_handle)
2200169412Sscottl		bus_teardown_intr(hba->pcidev, hba->irq_res, hba->irq_handle);
2201169412Sscottl
2202169412Sscottl	if (hba->irq_res)
2203175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_IRQ,
2204175942Sscottl					0, hba->irq_res);
2205169412Sscottl
2206169412Sscottl	if (hba->bar0_res)
2207169412Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2208169412Sscottl					hba->bar0_rid, hba->bar0_res);
2209175942Sscottl	if (hba->bar2_res)
2210175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2211175942Sscottl					hba->bar2_rid, hba->bar2_res);
2212169412Sscottl	if (hba->ioctl_dev)
2213169412Sscottl		destroy_dev(hba->ioctl_dev);
2214169412Sscottl}
2215