hptiop.c revision 227912
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 227912 2011-11-23 21:43:51Z marius $");
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);
1271169412Sscottl
1272169412Sscottlstatic int hptiop_probe(device_t dev)
1273169412Sscottl{
1274169412Sscottl	struct hpt_iop_hba *hba;
1275175942Sscottl	u_int32_t id;
1276175942Sscottl	static char buf[256];
1277175942Sscottl	int sas = 0;
1278175942Sscottl	struct hptiop_adapter_ops *ops;
1279169412Sscottl
1280175942Sscottl	if (pci_get_vendor(dev) != 0x1103)
1281175942Sscottl		return (ENXIO);
1282175942Sscottl
1283175942Sscottl	id = pci_get_device(dev);
1284175942Sscottl
1285175942Sscottl	switch (id) {
1286224583Sdelphij		case 0x4322:
1287224583Sdelphij		case 0x4321:
1288175942Sscottl		case 0x4320:
1289175942Sscottl			sas = 1;
1290175942Sscottl		case 0x3220:
1291175942Sscottl		case 0x3320:
1292175942Sscottl		case 0x3410:
1293175942Sscottl		case 0x3520:
1294175942Sscottl		case 0x3510:
1295175942Sscottl		case 0x3511:
1296175942Sscottl		case 0x3521:
1297175942Sscottl		case 0x3522:
1298175942Sscottl		case 0x3540:
1299175942Sscottl			ops = &hptiop_itl_ops;
1300175942Sscottl			break;
1301175942Sscottl		case 0x3120:
1302175942Sscottl		case 0x3122:
1303175942Sscottl		case 0x3020:
1304175942Sscottl			ops = &hptiop_mv_ops;
1305175942Sscottl			break;
1306175942Sscottl		default:
1307175942Sscottl			return (ENXIO);
1308169412Sscottl	}
1309175942Sscottl
1310175942Sscottl	device_printf(dev, "adapter at PCI %d:%d:%d, IRQ %d\n",
1311175942Sscottl		pci_get_bus(dev), pci_get_slot(dev),
1312175942Sscottl		pci_get_function(dev), pci_get_irq(dev));
1313175942Sscottl
1314175942Sscottl	sprintf(buf, "RocketRAID %x %s Controller\n",
1315175942Sscottl				id, sas ? "SAS" : "SATA");
1316175942Sscottl	device_set_desc_copy(dev, buf);
1317175942Sscottl
1318175942Sscottl	hba = (struct hpt_iop_hba *)device_get_softc(dev);
1319175942Sscottl	bzero(hba, sizeof(struct hpt_iop_hba));
1320175942Sscottl	hba->ops = ops;
1321175942Sscottl
1322175942Sscottl	KdPrint(("hba->ops=%p\n", hba->ops));
1323175942Sscottl	return 0;
1324169412Sscottl}
1325169412Sscottl
1326169412Sscottlstatic int hptiop_attach(device_t dev)
1327169412Sscottl{
1328175942Sscottl	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)device_get_softc(dev);
1329169412Sscottl	struct hpt_iop_request_get_config  iop_config;
1330169412Sscottl	struct hpt_iop_request_set_config  set_config;
1331169412Sscottl	int rid = 0;
1332169412Sscottl	struct cam_devq *devq;
1333169412Sscottl	struct ccb_setasync ccb;
1334169412Sscottl	u_int32_t unit = device_get_unit(dev);
1335169412Sscottl
1336175942Sscottl	device_printf(dev, "%d RocketRAID 3xxx/4xxx controller driver %s\n",
1337175942Sscottl			unit, driver_version);
1338169412Sscottl
1339175942Sscottl	KdPrint(("hptiop: attach(%d, %d/%d/%d) ops=%p\n", unit,
1340175942Sscottl		pci_get_bus(dev), pci_get_slot(dev),
1341175942Sscottl		pci_get_function(dev), hba->ops));
1342175942Sscottl
1343169412Sscottl#if __FreeBSD_version >=440000
1344169412Sscottl	pci_enable_busmaster(dev);
1345169412Sscottl#endif
1346169412Sscottl	hba->pcidev = dev;
1347169412Sscottl	hba->pciunit = unit;
1348169412Sscottl
1349175942Sscottl	if (hba->ops->alloc_pci_res(hba))
1350169412Sscottl		return ENXIO;
1351169412Sscottl
1352175942Sscottl	if (hba->ops->iop_wait_ready(hba, 2000)) {
1353175942Sscottl		device_printf(dev, "adapter is not ready\n");
1354175942Sscottl		goto release_pci_res;
1355169412Sscottl	}
1356169412Sscottl
1357169412Sscottl#if (__FreeBSD_version >= 500000)
1358169412Sscottl	mtx_init(&hba->lock, "hptioplock", NULL, MTX_DEF);
1359169412Sscottl#endif
1360169412Sscottl
1361169412Sscottl	if (bus_dma_tag_create(NULL,/* parent */
1362169412Sscottl			1,  /* alignment */
1363169412Sscottl			0, /* boundary */
1364169412Sscottl			BUS_SPACE_MAXADDR,  /* lowaddr */
1365169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1366169412Sscottl			NULL, NULL,         /* filter, filterarg */
1367169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsize */
1368169412Sscottl			BUS_SPACE_UNRESTRICTED, /* nsegments */
1369169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1370169412Sscottl			0,      /* flags */
1371169412Sscottl#if __FreeBSD_version>502000
1372169412Sscottl			NULL,   /* lockfunc */
1373169412Sscottl			NULL,       /* lockfuncarg */
1374169412Sscottl#endif
1375169412Sscottl			&hba->parent_dmat   /* tag */))
1376169412Sscottl	{
1377175942Sscottl		device_printf(dev, "alloc parent_dmat failed\n");
1378175942Sscottl		goto release_pci_res;
1379169412Sscottl	}
1380169412Sscottl
1381175942Sscottl	if (hba->ops->internal_memalloc) {
1382175942Sscottl		if (hba->ops->internal_memalloc(hba)) {
1383175942Sscottl			device_printf(dev, "alloc srb_dmat failed\n");
1384175942Sscottl			goto destroy_parent_tag;
1385175942Sscottl		}
1386175942Sscottl	}
1387175942Sscottl
1388175942Sscottl	if (hba->ops->get_config(hba, &iop_config)) {
1389175942Sscottl		device_printf(dev, "get iop config failed.\n");
1390175942Sscottl		goto get_config_failed;
1391175942Sscottl	}
1392175942Sscottl
1393175942Sscottl	hba->firmware_version = iop_config.firmware_version;
1394175942Sscottl	hba->interface_version = iop_config.interface_version;
1395175942Sscottl	hba->max_requests = iop_config.max_requests;
1396175942Sscottl	hba->max_devices = iop_config.max_devices;
1397175942Sscottl	hba->max_request_size = iop_config.request_size;
1398175942Sscottl	hba->max_sg_count = iop_config.max_sg_count;
1399175942Sscottl
1400169412Sscottl	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1401169412Sscottl			4,  /* alignment */
1402169412Sscottl			BUS_SPACE_MAXADDR_32BIT+1, /* boundary */
1403169412Sscottl			BUS_SPACE_MAXADDR,  /* lowaddr */
1404169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1405169412Sscottl			NULL, NULL,         /* filter, filterarg */
1406169412Sscottl			PAGE_SIZE * (hba->max_sg_count-1),  /* maxsize */
1407169412Sscottl			hba->max_sg_count,  /* nsegments */
1408169412Sscottl			0x20000,    /* maxsegsize */
1409169412Sscottl			BUS_DMA_ALLOCNOW,       /* flags */
1410169412Sscottl#if __FreeBSD_version>502000
1411169412Sscottl			busdma_lock_mutex,  /* lockfunc */
1412169412Sscottl			&hba->lock,     /* lockfuncarg */
1413169412Sscottl#endif
1414169412Sscottl			&hba->io_dmat   /* tag */))
1415169412Sscottl	{
1416175942Sscottl		device_printf(dev, "alloc io_dmat failed\n");
1417175942Sscottl		goto get_config_failed;
1418169412Sscottl	}
1419169412Sscottl
1420169412Sscottl	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1421169412Sscottl			1,  /* alignment */
1422169412Sscottl			0, /* boundary */
1423169412Sscottl			BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
1424169412Sscottl			BUS_SPACE_MAXADDR,  /* highaddr */
1425169412Sscottl			NULL, NULL,         /* filter, filterarg */
1426169412Sscottl			HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE + 0x20,
1427169412Sscottl			1,  /* nsegments */
1428169412Sscottl			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1429169412Sscottl			0,      /* flags */
1430169412Sscottl#if __FreeBSD_version>502000
1431169412Sscottl			NULL,   /* lockfunc */
1432169412Sscottl			NULL,       /* lockfuncarg */
1433169412Sscottl#endif
1434169412Sscottl			&hba->srb_dmat  /* tag */))
1435169412Sscottl	{
1436175942Sscottl		device_printf(dev, "alloc srb_dmat failed\n");
1437175942Sscottl		goto destroy_io_dmat;
1438169412Sscottl	}
1439169412Sscottl
1440169412Sscottl	if (bus_dmamem_alloc(hba->srb_dmat, (void **)&hba->uncached_ptr,
1441169412Sscottl#if __FreeBSD_version>501000
1442175942Sscottl			BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1443169412Sscottl#else
1444175942Sscottl			BUS_DMA_WAITOK,
1445169412Sscottl#endif
1446175942Sscottl			&hba->srb_dmamap) != 0)
1447169412Sscottl	{
1448175942Sscottl		device_printf(dev, "srb bus_dmamem_alloc failed!\n");
1449175942Sscottl		goto destroy_srb_dmat;
1450169412Sscottl	}
1451169412Sscottl
1452169412Sscottl	if (bus_dmamap_load(hba->srb_dmat,
1453169412Sscottl			hba->srb_dmamap, hba->uncached_ptr,
1454169412Sscottl			(HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE) + 0x20,
1455169412Sscottl			hptiop_map_srb, hba, 0))
1456169412Sscottl	{
1457175942Sscottl		device_printf(dev, "bus_dmamap_load failed!\n");
1458175942Sscottl		goto srb_dmamem_free;
1459169412Sscottl	}
1460169412Sscottl
1461169412Sscottl	if ((devq = cam_simq_alloc(hba->max_requests - 1 )) == NULL) {
1462175942Sscottl		device_printf(dev, "cam_simq_alloc failed\n");
1463175942Sscottl		goto srb_dmamap_unload;
1464169412Sscottl	}
1465175942Sscottl
1466175942Sscottl#if __FreeBSD_version <700000
1467169412Sscottl	hba->sim = cam_sim_alloc(hptiop_action, hptiop_poll, driver_name,
1468175942Sscottl			hba, unit, hba->max_requests - 1, 1, devq);
1469175942Sscottl#else
1470175942Sscottl	hba->sim = cam_sim_alloc(hptiop_action, hptiop_poll, driver_name,
1471169412Sscottl			hba, unit, &Giant, hba->max_requests - 1, 1, devq);
1472175942Sscottl#endif
1473169412Sscottl	if (!hba->sim) {
1474175942Sscottl		device_printf(dev, "cam_sim_alloc failed\n");
1475169412Sscottl		cam_simq_free(devq);
1476175942Sscottl		goto srb_dmamap_unload;
1477169412Sscottl	}
1478175942Sscottl#if __FreeBSD_version <700000
1479175942Sscottl	if (xpt_bus_register(hba->sim, 0) != CAM_SUCCESS)
1480175942Sscottl#else
1481175942Sscottl	if (xpt_bus_register(hba->sim, dev, 0) != CAM_SUCCESS)
1482175942Sscottl#endif
1483175942Sscottl	{
1484175942Sscottl		device_printf(dev, "xpt_bus_register failed\n");
1485175942Sscottl		goto free_cam_sim;
1486169412Sscottl	}
1487169412Sscottl
1488169412Sscottl	if (xpt_create_path(&hba->path, /*periph */ NULL,
1489169412Sscottl			cam_sim_path(hba->sim), CAM_TARGET_WILDCARD,
1490175942Sscottl			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1491175942Sscottl		device_printf(dev, "xpt_create_path failed\n");
1492175942Sscottl		goto deregister_xpt_bus;
1493169412Sscottl	}
1494169412Sscottl
1495169412Sscottl	bzero(&set_config, sizeof(set_config));
1496175942Sscottl	set_config.iop_id = unit;
1497169412Sscottl	set_config.vbus_id = cam_sim_path(hba->sim);
1498169412Sscottl	set_config.max_host_request_size = HPT_SRB_MAX_REQ_SIZE;
1499169412Sscottl
1500175942Sscottl	if (hba->ops->set_config(hba, &set_config)) {
1501175942Sscottl		device_printf(dev, "set iop config failed.\n");
1502175942Sscottl		goto free_hba_path;
1503169412Sscottl	}
1504169412Sscottl
1505169412Sscottl	xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
1506169412Sscottl	ccb.ccb_h.func_code = XPT_SASYNC_CB;
1507169412Sscottl	ccb.event_enable = (AC_FOUND_DEVICE | AC_LOST_DEVICE);
1508169412Sscottl	ccb.callback = hptiop_async;
1509169412Sscottl	ccb.callback_arg = hba->sim;
1510169412Sscottl	xpt_action((union ccb *)&ccb);
1511169412Sscottl
1512169412Sscottl	rid = 0;
1513169412Sscottl	if ((hba->irq_res = bus_alloc_resource(hba->pcidev, SYS_RES_IRQ,
1514169412Sscottl			&rid, 0, ~0ul, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1515175942Sscottl		device_printf(dev, "allocate irq failed!\n");
1516175942Sscottl		goto free_hba_path;
1517169412Sscottl	}
1518169412Sscottl
1519175942Sscottl#if __FreeBSD_version <700000
1520169412Sscottl	if (bus_setup_intr(hba->pcidev, hba->irq_res, INTR_TYPE_CAM,
1521175942Sscottl				hptiop_pci_intr, hba, &hba->irq_handle))
1522175942Sscottl#else
1523175942Sscottl	if (bus_setup_intr(hba->pcidev, hba->irq_res, INTR_TYPE_CAM,
1524175942Sscottl				NULL, hptiop_pci_intr, hba, &hba->irq_handle))
1525175942Sscottl#endif
1526175942Sscottl	{
1527175942Sscottl		device_printf(dev, "allocate intr function failed!\n");
1528175942Sscottl		goto free_irq_resource;
1529169412Sscottl	}
1530169412Sscottl
1531175942Sscottl	if (hptiop_send_sync_msg(hba,
1532175942Sscottl			IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
1533175942Sscottl		device_printf(dev, "fail to start background task\n");
1534175942Sscottl		goto teartown_irq_resource;
1535169412Sscottl	}
1536169412Sscottl
1537175942Sscottl	hba->ops->enable_intr(hba);
1538175942Sscottl
1539169412Sscottl	hba->ioctl_dev = make_dev(&hptiop_cdevsw, unit,
1540169412Sscottl				UID_ROOT, GID_WHEEL /*GID_OPERATOR*/,
1541169412Sscottl				S_IRUSR | S_IWUSR, "%s%d", driver_name, unit);
1542169412Sscottl
1543169412Sscottl#if __FreeBSD_version < 503000
1544169412Sscottl	hba->ioctl_dev->si_drv1 = hba;
1545169412Sscottl#endif
1546169412Sscottl
1547169412Sscottl	return 0;
1548175942Sscottl
1549175942Sscottl
1550175942Sscottlteartown_irq_resource:
1551175942Sscottl	bus_teardown_intr(dev, hba->irq_res, hba->irq_handle);
1552175942Sscottl
1553175942Sscottlfree_irq_resource:
1554175942Sscottl	bus_release_resource(dev, SYS_RES_IRQ, 0, hba->irq_res);
1555175942Sscottl
1556175942Sscottlfree_hba_path:
1557175942Sscottl	xpt_free_path(hba->path);
1558175942Sscottl
1559175942Sscottlderegister_xpt_bus:
1560175942Sscottl	xpt_bus_deregister(cam_sim_path(hba->sim));
1561175942Sscottl
1562175942Sscottlfree_cam_sim:
1563175942Sscottl	cam_sim_free(hba->sim, /*free devq*/ TRUE);
1564175942Sscottl
1565175942Sscottlsrb_dmamap_unload:
1566175942Sscottl	if (hba->uncached_ptr)
1567175942Sscottl		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
1568175942Sscottl
1569175942Sscottlsrb_dmamem_free:
1570175942Sscottl	if (hba->uncached_ptr)
1571175942Sscottl		bus_dmamem_free(hba->srb_dmat,
1572175942Sscottl			hba->uncached_ptr, hba->srb_dmamap);
1573175942Sscottl
1574175942Sscottldestroy_srb_dmat:
1575175942Sscottl	if (hba->srb_dmat)
1576175942Sscottl		bus_dma_tag_destroy(hba->srb_dmat);
1577175942Sscottl
1578175942Sscottldestroy_io_dmat:
1579175942Sscottl	if (hba->io_dmat)
1580175942Sscottl		bus_dma_tag_destroy(hba->io_dmat);
1581175942Sscottl
1582175942Sscottlget_config_failed:
1583175942Sscottl	if (hba->ops->internal_memfree)
1584175942Sscottl		hba->ops->internal_memfree(hba);
1585175942Sscottl
1586175942Sscottldestroy_parent_tag:
1587175942Sscottl	if (hba->parent_dmat)
1588175942Sscottl		bus_dma_tag_destroy(hba->parent_dmat);
1589175942Sscottl
1590175942Sscottlrelease_pci_res:
1591175942Sscottl	if (hba->ops->release_pci_res)
1592175942Sscottl		hba->ops->release_pci_res(hba);
1593175942Sscottl
1594175942Sscottl	return ENXIO;
1595169412Sscottl}
1596169412Sscottl
1597169412Sscottlstatic int hptiop_detach(device_t dev)
1598169412Sscottl{
1599169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
1600169412Sscottl	int i;
1601169412Sscottl	int error = EBUSY;
1602169412Sscottl
1603169412Sscottl	hptiop_lock_adapter(hba);
1604175942Sscottl	for (i = 0; i < hba->max_devices; i++)
1605175942Sscottl		if (hptiop_os_query_remove_device(hba, i)) {
1606175942Sscottl			device_printf(dev, "%d file system is busy. id=%d",
1607169412Sscottl						hba->pciunit, i);
1608169412Sscottl			goto out;
1609169412Sscottl		}
1610169412Sscottl
1611169412Sscottl	if ((error = hptiop_shutdown(dev)) != 0)
1612169412Sscottl		goto out;
1613175942Sscottl	if (hptiop_send_sync_msg(hba,
1614175942Sscottl		IOPMU_INBOUND_MSG0_STOP_BACKGROUND_TASK, 60000))
1615169412Sscottl		goto out;
1616169412Sscottl
1617169412Sscottl	hptiop_release_resource(hba);
1618169412Sscottl	error = 0;
1619169412Sscottlout:
1620169412Sscottl	hptiop_unlock_adapter(hba);
1621169412Sscottl	return error;
1622169412Sscottl}
1623169412Sscottl
1624169412Sscottlstatic int hptiop_shutdown(device_t dev)
1625169412Sscottl{
1626169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
1627169412Sscottl
1628169412Sscottl	int error = 0;
1629169412Sscottl
1630169412Sscottl	if (hba->flag & HPT_IOCTL_FLAG_OPEN) {
1631175942Sscottl		device_printf(dev, "%d device is busy", hba->pciunit);
1632169412Sscottl		return EBUSY;
1633169412Sscottl	}
1634175942Sscottl
1635175942Sscottl	hba->ops->disable_intr(hba);
1636175942Sscottl
1637175942Sscottl	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
1638169412Sscottl		error = EBUSY;
1639169412Sscottl
1640169412Sscottl	return error;
1641169412Sscottl}
1642169412Sscottl
1643169412Sscottlstatic void hptiop_pci_intr(void *arg)
1644169412Sscottl{
1645169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
1646169412Sscottl	hptiop_lock_adapter(hba);
1647175942Sscottl	hba->ops->iop_intr(hba);
1648169412Sscottl	hptiop_unlock_adapter(hba);
1649169412Sscottl}
1650169412Sscottl
1651169412Sscottlstatic void hptiop_poll(struct cam_sim *sim)
1652169412Sscottl{
1653169412Sscottl	hptiop_pci_intr(cam_sim_softc(sim));
1654169412Sscottl}
1655169412Sscottl
1656169412Sscottlstatic void hptiop_async(void * callback_arg, u_int32_t code,
1657169412Sscottl					struct cam_path * path, void * arg)
1658169412Sscottl{
1659169412Sscottl}
1660169412Sscottl
1661175942Sscottlstatic void hptiop_enable_intr_itl(struct hpt_iop_hba *hba)
1662169412Sscottl{
1663175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_intmask,
1664169412Sscottl		~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0));
1665169412Sscottl}
1666169412Sscottl
1667175942Sscottlstatic void hptiop_enable_intr_mv(struct hpt_iop_hba *hba)
1668169412Sscottl{
1669169412Sscottl	u_int32_t int_mask;
1670169412Sscottl
1671175942Sscottl	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
1672175942Sscottl
1673175942Sscottl	int_mask |= MVIOP_MU_OUTBOUND_INT_POSTQUEUE
1674175942Sscottl			| MVIOP_MU_OUTBOUND_INT_MSG;
1675175942Sscottl    	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
1676169412Sscottl}
1677169412Sscottl
1678175942Sscottlstatic void hptiop_disable_intr_itl(struct hpt_iop_hba *hba)
1679175942Sscottl{
1680175942Sscottl	u_int32_t int_mask;
1681175942Sscottl
1682175942Sscottl	int_mask = BUS_SPACE_RD4_ITL(outbound_intmask);
1683175942Sscottl
1684175942Sscottl	int_mask |= IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0;
1685175942Sscottl	BUS_SPACE_WRT4_ITL(outbound_intmask, int_mask);
1686175942Sscottl	BUS_SPACE_RD4_ITL(outbound_intstatus);
1687175942Sscottl}
1688175942Sscottl
1689175942Sscottlstatic void hptiop_disable_intr_mv(struct hpt_iop_hba *hba)
1690175942Sscottl{
1691175942Sscottl	u_int32_t int_mask;
1692175942Sscottl	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
1693175942Sscottl
1694175942Sscottl	int_mask &= ~(MVIOP_MU_OUTBOUND_INT_MSG
1695175942Sscottl			| MVIOP_MU_OUTBOUND_INT_POSTQUEUE);
1696175942Sscottl	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
1697175942Sscottl	BUS_SPACE_RD4_MV0(outbound_intmask);
1698175942Sscottl}
1699175942Sscottl
1700169412Sscottlstatic int hptiop_reset_adapter(struct hpt_iop_hba * hba)
1701169412Sscottl{
1702175942Sscottl	return hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1703169412Sscottl}
1704169412Sscottl
1705169412Sscottlstatic void *hptiop_get_srb(struct hpt_iop_hba * hba)
1706169412Sscottl{
1707169412Sscottl	struct hpt_iop_srb * srb;
1708169412Sscottl
1709169412Sscottl	if (hba->srb_list) {
1710169412Sscottl		srb = hba->srb_list;
1711169412Sscottl		hba->srb_list = srb->next;
1712175942Sscottl		return srb;
1713169412Sscottl	}
1714169412Sscottl
1715175942Sscottl	return NULL;
1716169412Sscottl}
1717169412Sscottl
1718175942Sscottlstatic void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb)
1719169412Sscottl{
1720169412Sscottl	srb->next = hba->srb_list;
1721169412Sscottl	hba->srb_list = srb;
1722169412Sscottl}
1723169412Sscottl
1724169412Sscottlstatic void hptiop_action(struct cam_sim *sim, union ccb *ccb)
1725169412Sscottl{
1726169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)cam_sim_softc(sim);
1727169412Sscottl	struct hpt_iop_srb * srb;
1728169412Sscottl
1729169412Sscottl	switch (ccb->ccb_h.func_code) {
1730169412Sscottl
1731169412Sscottl	case XPT_SCSI_IO:
1732169412Sscottl		hptiop_lock_adapter(hba);
1733169412Sscottl		if (ccb->ccb_h.target_lun != 0 ||
1734175942Sscottl			ccb->ccb_h.target_id >= hba->max_devices ||
1735169412Sscottl			(ccb->ccb_h.flags & CAM_CDB_PHYS))
1736169412Sscottl		{
1737169412Sscottl			ccb->ccb_h.status = CAM_TID_INVALID;
1738169412Sscottl			xpt_done(ccb);
1739169412Sscottl			goto scsi_done;
1740169412Sscottl		}
1741169412Sscottl
1742169412Sscottl		if ((srb = hptiop_get_srb(hba)) == NULL) {
1743175942Sscottl			device_printf(hba->pcidev, "srb allocated failed");
1744169412Sscottl			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1745169412Sscottl			xpt_done(ccb);
1746169412Sscottl			goto scsi_done;
1747169412Sscottl		}
1748169412Sscottl
1749169412Sscottl		srb->ccb = ccb;
1750169412Sscottl
1751169412Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE)
1752169412Sscottl			hptiop_post_scsi_command(srb, NULL, 0, 0);
1753169412Sscottl		else if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
1754169412Sscottl			if ((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) {
1755169412Sscottl				int error;
1756169412Sscottl
1757169412Sscottl				error = bus_dmamap_load(hba->io_dmat,
1758175942Sscottl						srb->dma_map,
1759175942Sscottl						ccb->csio.data_ptr,
1760175942Sscottl						ccb->csio.dxfer_len,
1761175942Sscottl						hptiop_post_scsi_command,
1762175942Sscottl						srb, 0);
1763169412Sscottl
1764169412Sscottl				if (error && error != EINPROGRESS) {
1765175942Sscottl					device_printf(hba->pcidev,
1766175942Sscottl						"%d bus_dmamap_load error %d",
1767175942Sscottl						hba->pciunit, error);
1768169412Sscottl					xpt_freeze_simq(hba->sim, 1);
1769169412Sscottl					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1770169412Sscottlinvalid:
1771169412Sscottl					hptiop_free_srb(hba, srb);
1772169412Sscottl					xpt_done(ccb);
1773169412Sscottl					goto scsi_done;
1774169412Sscottl				}
1775169412Sscottl			}
1776169412Sscottl			else {
1777175942Sscottl				device_printf(hba->pcidev,
1778175942Sscottl					"CAM_DATA_PHYS not supported");
1779169412Sscottl				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1780169412Sscottl				goto invalid;
1781169412Sscottl			}
1782169412Sscottl		}
1783169412Sscottl		else {
1784169412Sscottl			struct bus_dma_segment *segs;
1785169412Sscottl
1786169412Sscottl			if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0 ||
1787169412Sscottl				(ccb->ccb_h.flags & CAM_DATA_PHYS) != 0) {
1788175942Sscottl				device_printf(hba->pcidev, "SCSI cmd failed");
1789169412Sscottl				ccb->ccb_h.status=CAM_PROVIDE_FAIL;
1790169412Sscottl				goto invalid;
1791169412Sscottl			}
1792169412Sscottl
1793169412Sscottl			segs = (struct bus_dma_segment *)ccb->csio.data_ptr;
1794169412Sscottl			hptiop_post_scsi_command(srb, segs,
1795169412Sscottl						ccb->csio.sglist_cnt, 0);
1796169412Sscottl		}
1797169412Sscottl
1798169412Sscottlscsi_done:
1799169412Sscottl		hptiop_unlock_adapter(hba);
1800169412Sscottl		return;
1801169412Sscottl
1802169412Sscottl	case XPT_RESET_BUS:
1803175942Sscottl		device_printf(hba->pcidev, "reset adapter");
1804169412Sscottl		hptiop_lock_adapter(hba);
1805169412Sscottl		hba->msg_done = 0;
1806169412Sscottl		hptiop_reset_adapter(hba);
1807169412Sscottl		hptiop_unlock_adapter(hba);
1808169412Sscottl		break;
1809169412Sscottl
1810169412Sscottl	case XPT_GET_TRAN_SETTINGS:
1811169412Sscottl	case XPT_SET_TRAN_SETTINGS:
1812169412Sscottl		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1813169412Sscottl		break;
1814169412Sscottl
1815169412Sscottl	case XPT_CALC_GEOMETRY:
1816227912Smarius#if __FreeBSD_version >= 500000
1817227912Smarius		cam_calc_geometry(&ccb->ccg, 1);
1818227912Smarius#else
1819169412Sscottl		ccb->ccg.heads = 255;
1820169412Sscottl		ccb->ccg.secs_per_track = 63;
1821169412Sscottl		ccb->ccg.cylinders = ccb->ccg.volume_size /
1822169412Sscottl				(ccb->ccg.heads * ccb->ccg.secs_per_track);
1823169412Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
1824227912Smarius#endif
1825169412Sscottl		break;
1826169412Sscottl
1827169412Sscottl	case XPT_PATH_INQ:
1828169412Sscottl	{
1829169412Sscottl		struct ccb_pathinq *cpi = &ccb->cpi;
1830169412Sscottl
1831169412Sscottl		cpi->version_num = 1;
1832169412Sscottl		cpi->hba_inquiry = PI_SDTR_ABLE;
1833169412Sscottl		cpi->target_sprt = 0;
1834169412Sscottl		cpi->hba_misc = PIM_NOBUSRESET;
1835169412Sscottl		cpi->hba_eng_cnt = 0;
1836175942Sscottl		cpi->max_target = hba->max_devices;
1837169412Sscottl		cpi->max_lun = 0;
1838169412Sscottl		cpi->unit_number = cam_sim_unit(sim);
1839169412Sscottl		cpi->bus_id = cam_sim_bus(sim);
1840175942Sscottl		cpi->initiator_id = hba->max_devices;
1841169412Sscottl		cpi->base_transfer_speed = 3300;
1842169412Sscottl
1843169412Sscottl		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1844169412Sscottl		strncpy(cpi->hba_vid, "HPT   ", HBA_IDLEN);
1845169412Sscottl		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1846209340Smav		cpi->transport = XPORT_SPI;
1847209340Smav		cpi->transport_version = 2;
1848209340Smav		cpi->protocol = PROTO_SCSI;
1849209340Smav		cpi->protocol_version = SCSI_REV_2;
1850169412Sscottl		cpi->ccb_h.status = CAM_REQ_CMP;
1851169412Sscottl		break;
1852169412Sscottl	}
1853169412Sscottl
1854169412Sscottl	default:
1855169412Sscottl		ccb->ccb_h.status = CAM_REQ_INVALID;
1856169412Sscottl		break;
1857169412Sscottl	}
1858169412Sscottl
1859169412Sscottl	xpt_done(ccb);
1860169412Sscottl	return;
1861169412Sscottl}
1862169412Sscottl
1863175942Sscottlstatic void hptiop_post_req_itl(struct hpt_iop_hba *hba,
1864175942Sscottl				struct hpt_iop_srb *srb,
1865175942Sscottl				bus_dma_segment_t *segs, int nsegs)
1866169412Sscottl{
1867169412Sscottl	int idx;
1868169412Sscottl	union ccb *ccb = srb->ccb;
1869169412Sscottl	u_int8_t *cdb;
1870169412Sscottl
1871175942Sscottl	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
1872175942Sscottl		cdb = ccb->csio.cdb_io.cdb_ptr;
1873175942Sscottl	else
1874175942Sscottl		cdb = ccb->csio.cdb_io.cdb_bytes;
1875169412Sscottl
1876175942Sscottl	KdPrint(("ccb=%p %x-%x-%x\n",
1877175942Sscottl		ccb, *(u_int32_t *)cdb, *((u_int32_t *)cdb+1), *((u_int32_t *)cdb+2)));
1878169412Sscottl
1879169412Sscottl	if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) {
1880175942Sscottl		u_int32_t iop_req32;
1881175942Sscottl		struct hpt_iop_request_scsi_command req;
1882169412Sscottl
1883175942Sscottl		iop_req32 = BUS_SPACE_RD4_ITL(inbound_queue);
1884175942Sscottl
1885175942Sscottl		if (iop_req32 == IOPMU_QUEUE_EMPTY) {
1886175942Sscottl			device_printf(hba->pcidev, "invaild req offset\n");
1887175942Sscottl			ccb->ccb_h.status = CAM_BUSY;
1888175942Sscottl			bus_dmamap_unload(hba->io_dmat, srb->dma_map);
1889175942Sscottl			hptiop_free_srb(hba, srb);
1890175942Sscottl			xpt_done(ccb);
1891175942Sscottl			return;
1892169412Sscottl		}
1893175942Sscottl
1894175942Sscottl		if (ccb->csio.dxfer_len && nsegs > 0) {
1895175942Sscottl			struct hpt_iopsg *psg = req.sg_list;
1896175942Sscottl			for (idx = 0; idx < nsegs; idx++, psg++) {
1897175942Sscottl				psg->pci_address = (u_int64_t)segs[idx].ds_addr;
1898175942Sscottl				psg->size = segs[idx].ds_len;
1899175942Sscottl				psg->eot = 0;
1900175942Sscottl			}
1901175942Sscottl			psg[-1].eot = 1;
1902175942Sscottl		}
1903175942Sscottl
1904175942Sscottl		bcopy(cdb, req.cdb, ccb->csio.cdb_len);
1905175942Sscottl
1906175942Sscottl		req.header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list)
1907175942Sscottl				+ nsegs*sizeof(struct hpt_iopsg);
1908175942Sscottl		req.header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
1909175942Sscottl		req.header.flags = 0;
1910175942Sscottl		req.header.result = IOP_RESULT_PENDING;
1911175942Sscottl		req.header.context = (u_int64_t)(unsigned long)srb;
1912175942Sscottl		req.dataxfer_length = ccb->csio.dxfer_len;
1913175942Sscottl		req.channel =  0;
1914175942Sscottl		req.target =  ccb->ccb_h.target_id;
1915175942Sscottl		req.lun =  ccb->ccb_h.target_lun;
1916175942Sscottl
1917175942Sscottl		bus_space_write_region_1(hba->bar0t, hba->bar0h, iop_req32,
1918175942Sscottl			(u_int8_t *)&req, req.header.size);
1919175942Sscottl
1920175942Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1921175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1922175942Sscottl				srb->dma_map, BUS_DMASYNC_PREREAD);
1923175942Sscottl		}
1924175942Sscottl		else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
1925175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1926175942Sscottl				srb->dma_map, BUS_DMASYNC_PREWRITE);
1927175942Sscottl
1928175942Sscottl		BUS_SPACE_WRT4_ITL(inbound_queue,iop_req32);
1929175942Sscottl	} else {
1930175942Sscottl		struct hpt_iop_request_scsi_command *req;
1931175942Sscottl
1932169412Sscottl		req = (struct hpt_iop_request_scsi_command *)srb;
1933175942Sscottl		if (ccb->csio.dxfer_len && nsegs > 0) {
1934175942Sscottl			struct hpt_iopsg *psg = req->sg_list;
1935175942Sscottl			for (idx = 0; idx < nsegs; idx++, psg++) {
1936175942Sscottl				psg->pci_address =
1937175942Sscottl					(u_int64_t)segs[idx].ds_addr;
1938175942Sscottl				psg->size = segs[idx].ds_len;
1939175942Sscottl				psg->eot = 0;
1940175942Sscottl			}
1941175942Sscottl			psg[-1].eot = 1;
1942175942Sscottl		}
1943169412Sscottl
1944175942Sscottl		bcopy(cdb, req->cdb, ccb->csio.cdb_len);
1945175942Sscottl
1946175942Sscottl		req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
1947175942Sscottl		req->header.result = IOP_RESULT_PENDING;
1948175942Sscottl		req->dataxfer_length = ccb->csio.dxfer_len;
1949175942Sscottl		req->channel =  0;
1950175942Sscottl		req->target =  ccb->ccb_h.target_id;
1951175942Sscottl		req->lun =  ccb->ccb_h.target_lun;
1952175942Sscottl		req->header.size = offsetof(struct hpt_iop_request_scsi_command, sg_list)
1953175942Sscottl			+ nsegs*sizeof(struct hpt_iopsg);
1954175942Sscottl		req->header.context = (u_int64_t)srb->index |
1955175942Sscottl						IOPMU_QUEUE_ADDR_HOST_BIT;
1956175942Sscottl		req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
1957175942Sscottl
1958175942Sscottl		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
1959175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1960175942Sscottl				srb->dma_map, BUS_DMASYNC_PREREAD);
1961175942Sscottl		}else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1962175942Sscottl			bus_dmamap_sync(hba->io_dmat,
1963175942Sscottl				srb->dma_map, BUS_DMASYNC_PREWRITE);
1964175942Sscottl		}
1965175942Sscottl
1966175942Sscottl		if (hba->firmware_version > 0x01020000
1967175942Sscottl			|| hba->interface_version > 0x01020000) {
1968175942Sscottl			u_int32_t size_bits;
1969175942Sscottl
1970175942Sscottl			if (req->header.size < 256)
1971175942Sscottl				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
1972175942Sscottl			else if (req->header.size < 512)
1973175942Sscottl				size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
1974175942Sscottl			else
1975175942Sscottl				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT
1976175942Sscottl						| IOPMU_QUEUE_ADDR_HOST_BIT;
1977175942Sscottl
1978175942Sscottl			BUS_SPACE_WRT4_ITL(inbound_queue,
1979175942Sscottl				(u_int32_t)srb->phy_addr | size_bits);
1980175942Sscottl		} else
1981175942Sscottl			BUS_SPACE_WRT4_ITL(inbound_queue, (u_int32_t)srb->phy_addr
1982175942Sscottl				|IOPMU_QUEUE_ADDR_HOST_BIT);
1983175942Sscottl	}
1984175942Sscottl}
1985175942Sscottl
1986175942Sscottlstatic void hptiop_post_req_mv(struct hpt_iop_hba *hba,
1987175942Sscottl				struct hpt_iop_srb *srb,
1988175942Sscottl				bus_dma_segment_t *segs, int nsegs)
1989175942Sscottl{
1990175942Sscottl	int idx, size;
1991175942Sscottl	union ccb *ccb = srb->ccb;
1992175942Sscottl	u_int8_t *cdb;
1993175942Sscottl	struct hpt_iop_request_scsi_command *req;
1994175942Sscottl	u_int64_t req_phy;
1995175942Sscottl
1996175942Sscottl    	req = (struct hpt_iop_request_scsi_command *)srb;
1997175942Sscottl	req_phy = srb->phy_addr;
1998175942Sscottl
1999169412Sscottl	if (ccb->csio.dxfer_len && nsegs > 0) {
2000169412Sscottl		struct hpt_iopsg *psg = req->sg_list;
2001169412Sscottl		for (idx = 0; idx < nsegs; idx++, psg++) {
2002169412Sscottl			psg->pci_address = (u_int64_t)segs[idx].ds_addr;
2003169412Sscottl			psg->size = segs[idx].ds_len;
2004169412Sscottl			psg->eot = 0;
2005169412Sscottl		}
2006169412Sscottl		psg[-1].eot = 1;
2007169412Sscottl	}
2008169412Sscottl	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
2009169412Sscottl		cdb = ccb->csio.cdb_io.cdb_ptr;
2010169412Sscottl	else
2011169412Sscottl		cdb = ccb->csio.cdb_io.cdb_bytes;
2012169412Sscottl
2013169412Sscottl	bcopy(cdb, req->cdb, ccb->csio.cdb_len);
2014169412Sscottl	req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2015169412Sscottl	req->header.result = IOP_RESULT_PENDING;
2016169412Sscottl	req->dataxfer_length = ccb->csio.dxfer_len;
2017175942Sscottl	req->channel = 0;
2018169412Sscottl	req->target =  ccb->ccb_h.target_id;
2019169412Sscottl	req->lun =  ccb->ccb_h.target_lun;
2020169412Sscottl	req->header.size = sizeof(struct hpt_iop_request_scsi_command)
2021175942Sscottl				- sizeof(struct hpt_iopsg)
2022175942Sscottl				+ nsegs * sizeof(struct hpt_iopsg);
2023169412Sscottl	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2024169412Sscottl		bus_dmamap_sync(hba->io_dmat,
2025175942Sscottl			srb->dma_map, BUS_DMASYNC_PREREAD);
2026169412Sscottl	}
2027169412Sscottl	else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
2028169412Sscottl		bus_dmamap_sync(hba->io_dmat,
2029175942Sscottl			srb->dma_map, BUS_DMASYNC_PREWRITE);
2030175942Sscottl	req->header.context = (u_int64_t)srb->index
2031175942Sscottl					<< MVIOP_REQUEST_NUMBER_START_BIT
2032175942Sscottl					| MVIOP_CMD_TYPE_SCSI;
2033175942Sscottl	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
2034175942Sscottl	size = req->header.size >> 8;
2035175942Sscottl	hptiop_mv_inbound_write(req_phy
2036175942Sscottl			| MVIOP_MU_QUEUE_ADDR_HOST_BIT
2037175942Sscottl			| (size > 3 ? 3 : size), hba);
2038169412Sscottl}
2039169412Sscottl
2040175942Sscottlstatic void hptiop_post_scsi_command(void *arg, bus_dma_segment_t *segs,
2041175942Sscottl					int nsegs, int error)
2042169412Sscottl{
2043175942Sscottl	struct hpt_iop_srb *srb = (struct hpt_iop_srb *)arg;
2044175942Sscottl	union ccb *ccb = srb->ccb;
2045175942Sscottl	struct hpt_iop_hba *hba = srb->hba;
2046169412Sscottl
2047175942Sscottl	if (error || nsegs > hba->max_sg_count) {
2048175942Sscottl		KdPrint(("hptiop: func_code=%x tid=%x lun=%x nsegs=%d\n",
2049175942Sscottl			ccb->ccb_h.func_code,
2050175942Sscottl			ccb->ccb_h.target_id,
2051175942Sscottl			ccb->ccb_h.target_lun, nsegs));
2052175942Sscottl		ccb->ccb_h.status = CAM_BUSY;
2053175942Sscottl		bus_dmamap_unload(hba->io_dmat, srb->dma_map);
2054169412Sscottl		hptiop_free_srb(hba, srb);
2055169412Sscottl		xpt_done(ccb);
2056175942Sscottl		return;
2057169412Sscottl	}
2058175942Sscottl
2059175942Sscottl	hba->ops->post_req(hba, srb, segs, nsegs);
2060169412Sscottl}
2061169412Sscottl
2062175942Sscottlstatic void hptiop_mv_map_ctlcfg(void *arg, bus_dma_segment_t *segs,
2063175942Sscottl				int nsegs, int error)
2064175942Sscottl{
2065175942Sscottl	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)arg;
2066175942Sscottl	hba->ctlcfgcmd_phy = ((u_int64_t)segs->ds_addr + 0x1F)
2067175942Sscottl				& ~(u_int64_t)0x1F;
2068175942Sscottl	hba->ctlcfg_ptr = (u_int8_t *)(((unsigned long)hba->ctlcfg_ptr + 0x1F)
2069175942Sscottl				& ~0x1F);
2070175942Sscottl}
2071175942Sscottl
2072169412Sscottlstatic void hptiop_map_srb(void *arg, bus_dma_segment_t *segs,
2073175942Sscottl				int nsegs, int error)
2074169412Sscottl{
2075169412Sscottl	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
2076169412Sscottl	bus_addr_t phy_addr = (segs->ds_addr + 0x1F) & ~(bus_addr_t)0x1F;
2077169412Sscottl	struct hpt_iop_srb *srb, *tmp_srb;
2078169412Sscottl	int i;
2079169412Sscottl
2080169412Sscottl	if (error || nsegs == 0) {
2081175942Sscottl		device_printf(hba->pcidev, "hptiop_map_srb error");
2082169412Sscottl		return;
2083169412Sscottl	}
2084169412Sscottl
2085169412Sscottl	/* map srb */
2086169412Sscottl	srb = (struct hpt_iop_srb *)
2087175942Sscottl		(((unsigned long)hba->uncached_ptr + 0x1F)
2088175942Sscottl		& ~(unsigned long)0x1F);
2089169412Sscottl
2090169412Sscottl	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2091169412Sscottl		tmp_srb = (struct hpt_iop_srb *)
2092169412Sscottl					((char *)srb + i * HPT_SRB_MAX_SIZE);
2093169412Sscottl		if (((unsigned long)tmp_srb & 0x1F) == 0) {
2094169412Sscottl			if (bus_dmamap_create(hba->io_dmat,
2095169412Sscottl						0, &tmp_srb->dma_map)) {
2096175942Sscottl				device_printf(hba->pcidev, "dmamap create failed");
2097169412Sscottl				return;
2098169412Sscottl			}
2099169412Sscottl
2100169412Sscottl			bzero(tmp_srb, sizeof(struct hpt_iop_srb));
2101169412Sscottl			tmp_srb->hba = hba;
2102169412Sscottl			tmp_srb->index = i;
2103175942Sscottl			if (hba->ctlcfg_ptr == 0) {/*itl iop*/
2104175942Sscottl				tmp_srb->phy_addr = (u_int64_t)(u_int32_t)
2105175942Sscottl							(phy_addr >> 5);
2106175942Sscottl				if (phy_addr & IOPMU_MAX_MEM_SUPPORT_MASK_32G)
2107175942Sscottl					tmp_srb->srb_flag =
2108175942Sscottl						HPT_SRB_FLAG_HIGH_MEM_ACESS;
2109175942Sscottl			} else {
2110175942Sscottl				tmp_srb->phy_addr = phy_addr;
2111175942Sscottl			}
2112175942Sscottl
2113169412Sscottl			hptiop_free_srb(hba, tmp_srb);
2114169412Sscottl			hba->srb[i] = tmp_srb;
2115169412Sscottl			phy_addr += HPT_SRB_MAX_SIZE;
2116169412Sscottl		}
2117169412Sscottl		else {
2118175942Sscottl			device_printf(hba->pcidev, "invalid alignment");
2119169412Sscottl			return;
2120169412Sscottl		}
2121169412Sscottl	}
2122169412Sscottl}
2123169412Sscottl
2124175942Sscottlstatic void hptiop_os_message_callback(struct hpt_iop_hba * hba, u_int32_t msg)
2125169412Sscottl{
2126169412Sscottl		hba->msg_done = 1;
2127169412Sscottl}
2128169412Sscottl
2129175942Sscottlstatic  int hptiop_os_query_remove_device(struct hpt_iop_hba * hba,
2130175942Sscottl						int target_id)
2131169412Sscottl{
2132169412Sscottl	struct cam_periph       *periph = NULL;
2133169412Sscottl	struct cam_path         *path;
2134169412Sscottl	int                     status, retval = 0;
2135169412Sscottl
2136169412Sscottl	status = xpt_create_path(&path, NULL, hba->sim->path_id, target_id, 0);
2137169412Sscottl
2138169412Sscottl	if (status == CAM_REQ_CMP) {
2139169412Sscottl		if ((periph = cam_periph_find(path, "da")) != NULL) {
2140169412Sscottl			if (periph->refcount >= 1) {
2141175942Sscottl				device_printf(hba->pcidev, "%d ,"
2142175942Sscottl					"target_id=0x%x,"
2143175942Sscottl					"refcount=%d",
2144169412Sscottl				    hba->pciunit, target_id, periph->refcount);
2145169412Sscottl				retval = -1;
2146169412Sscottl			}
2147169412Sscottl		}
2148169412Sscottl		xpt_free_path(path);
2149169412Sscottl	}
2150169412Sscottl	return retval;
2151169412Sscottl}
2152169412Sscottl
2153169412Sscottlstatic void hptiop_release_resource(struct hpt_iop_hba *hba)
2154169412Sscottl{
2155175942Sscottl	int i;
2156175942Sscottl	if (hba->path) {
2157175942Sscottl		struct ccb_setasync ccb;
2158169412Sscottl
2159169412Sscottl		xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
2160169412Sscottl		ccb.ccb_h.func_code = XPT_SASYNC_CB;
2161169412Sscottl		ccb.event_enable = 0;
2162169412Sscottl		ccb.callback = hptiop_async;
2163169412Sscottl		ccb.callback_arg = hba->sim;
2164169412Sscottl		xpt_action((union ccb *)&ccb);
2165169412Sscottl		xpt_free_path(hba->path);
2166169412Sscottl	}
2167169412Sscottl
2168169412Sscottl	if (hba->sim) {
2169169412Sscottl		xpt_bus_deregister(cam_sim_path(hba->sim));
2170169412Sscottl		cam_sim_free(hba->sim, TRUE);
2171169412Sscottl	}
2172169412Sscottl
2173175942Sscottl	if (hba->ctlcfg_dmat) {
2174175942Sscottl		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
2175175942Sscottl		bus_dmamem_free(hba->ctlcfg_dmat,
2176175942Sscottl					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
2177175942Sscottl		bus_dma_tag_destroy(hba->ctlcfg_dmat);
2178175942Sscottl	}
2179175942Sscottl
2180175942Sscottl	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2181175942Sscottl		struct hpt_iop_srb *srb = hba->srb[i];
2182175942Sscottl		if (srb->dma_map)
2183175942Sscottl			bus_dmamap_destroy(hba->io_dmat, srb->dma_map);
2184175942Sscottl	}
2185175942Sscottl
2186169412Sscottl	if (hba->srb_dmat) {
2187169412Sscottl		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
2188175942Sscottl		bus_dmamap_destroy(hba->srb_dmat, hba->srb_dmamap);
2189169412Sscottl		bus_dma_tag_destroy(hba->srb_dmat);
2190169412Sscottl	}
2191169412Sscottl
2192169412Sscottl	if (hba->io_dmat)
2193169412Sscottl		bus_dma_tag_destroy(hba->io_dmat);
2194169412Sscottl
2195169412Sscottl	if (hba->parent_dmat)
2196169412Sscottl		bus_dma_tag_destroy(hba->parent_dmat);
2197169412Sscottl
2198169412Sscottl	if (hba->irq_handle)
2199169412Sscottl		bus_teardown_intr(hba->pcidev, hba->irq_res, hba->irq_handle);
2200169412Sscottl
2201169412Sscottl	if (hba->irq_res)
2202175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_IRQ,
2203175942Sscottl					0, hba->irq_res);
2204169412Sscottl
2205169412Sscottl	if (hba->bar0_res)
2206169412Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2207169412Sscottl					hba->bar0_rid, hba->bar0_res);
2208175942Sscottl	if (hba->bar2_res)
2209175942Sscottl		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2210175942Sscottl					hba->bar2_rid, hba->bar2_res);
2211169412Sscottl	if (hba->ioctl_dev)
2212169412Sscottl		destroy_dev(hba->ioctl_dev);
2213169412Sscottl}
2214